Compare commits
48 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
2d536cd611 | |||
40412a300a | |||
819539247e | |||
ee90e7f95b | |||
ad3b451659 | |||
74ab9d25db | |||
a5424eb370 | |||
6f99689add | |||
7ea4b8696e | |||
6d37cd93e3 | |||
7875b777e5 | |||
ede11131fe | |||
347b9cb278 | |||
1a2f7627d3 | |||
b3fb28be38 | |||
d2497d64a2 | |||
f7eff123be | |||
a1ca7ace77 | |||
02370c6bfa | |||
2f13be9dd8 | |||
4c798ea76a | |||
af31b41782 | |||
4374b83464 | |||
147123b202 | |||
2a2410e9bf | |||
fdabbe866f | |||
dac830fc7c | |||
019b4aa5ae | |||
3a293a2e0c | |||
73de143ec5 | |||
5068b4660e | |||
fd656cd543 | |||
291b3f3778 | |||
4ee84d6442 | |||
59df950e11 | |||
03a687179c | |||
ae84a68e11 | |||
c5490cb321 | |||
04b7cc9544 | |||
7498390180 | |||
4ac28a2c10 | |||
61c1c3245c | |||
cb9fe4e5c9 | |||
c7e7aa6fb5 | |||
1261321992 | |||
6d1ddad428 | |||
eae3c794fa | |||
db7a37d647 |
@@ -17,7 +17,7 @@ include(cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME mcolor
|
||||
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
|
||||
URL https://git.redacted.cc/maxine/mcolor/archive/Release-1.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
@@ -27,17 +27,17 @@ CPMAddPackage(
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReWindow
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-32.zip
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-34.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME GLAD
|
||||
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo_depthtexture_shadow.zip
|
||||
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo_depthtexture_shadow_anisotropic_instanced.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jlog
|
||||
URL https://git.redacted.cc/josh/jlog/Prerelease-16.zip
|
||||
URL https://git.redacted.cc/josh/jlog/Prerelease-19.zip
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
11
README.md
11
README.md
@@ -19,12 +19,17 @@ Yet Another C++ Rendering Toolkit
|
||||
|
||||
### J2D
|
||||
* DrawPoint
|
||||
* DrawLine / DrawGradientLine
|
||||
* DrawLine / DrawGradientLine / DrawDottedLine / DrawDashedLine / DrawLines
|
||||
* DrawSprite / DrawPartialSprite
|
||||
* OutlineRect / FillRect / FillGradientRect / FillRoundedRect
|
||||
* DrawRenderTarget / DrawPartialRenderTarget
|
||||
* OutlineRect / OutlineRoundedRect / OutlineChamferRect
|
||||
* FillRect / FillGradientRect / FillRoundedRect / FillChamferRect
|
||||
* OutlineCircle / FillCircle
|
||||
* OutlineTriangle / FillTriangle
|
||||
* OutlineTriangle / FillTriangle / FillGradientTriangle
|
||||
* DrawString
|
||||
* DrawCubicBezierCurve
|
||||
* DrawArc
|
||||
* OutlineEllipse / FillEllipse
|
||||
|
||||
### J3D
|
||||
* DrawLine
|
||||
|
30
assets/shader_programs/shared.glsl
Normal file
30
assets/shader_programs/shared.glsl
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef include_shared
|
||||
#define include_shared
|
||||
#version 120
|
||||
|
||||
vec3 rgb2hsb( in vec3 c ){
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz),
|
||||
vec4(c.gb, K.xy),
|
||||
step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r),
|
||||
vec4(c.r, p.yzx),
|
||||
step(p.x, c.r));
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
|
||||
d / (q.x + e),
|
||||
q.x);
|
||||
}
|
||||
|
||||
// Function from Iñigo Quiles
|
||||
// https://www.shadertoy.com/view/MsS3Wc
|
||||
vec3 hsb2rgb( in vec3 c ){
|
||||
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
|
||||
6.0)-3.0)-1.0,
|
||||
0.0,
|
||||
1.0 );
|
||||
rgb = rgb*rgb*(3.0-2.0*rgb);
|
||||
return c.z * mix(vec3(1.0), rgb, c.y);
|
||||
}
|
||||
#endif
|
@@ -1,5 +1,154 @@
|
||||
#version 120
|
||||
|
||||
#define J2D_DrawPoint 1
|
||||
#define J2D_DrawPoints 2
|
||||
#define J2D_DrawLine 3
|
||||
#define J2D_DrawLines 4
|
||||
#define J2D_DrawDottedLine 5
|
||||
#define J2D_DrawDashedLine 6
|
||||
#define J2D_DrawGradientLine 7
|
||||
#define J2D_OutlineRect 8
|
||||
#define J2D_OutlineRoundedRect 9
|
||||
#define J2D_OutlineChamferRect 10
|
||||
#define J2D_FillRect 11
|
||||
#define J2D_FillGradientRect 12
|
||||
#define J2D_FillRoundedRect 13
|
||||
#define J2D_FillChamferRect 14
|
||||
#define J2D_DrawRenderTarget 15
|
||||
#define J2D_DrawPartialRenderTarget 16
|
||||
#define J2D_DrawSprite 17
|
||||
#define J2D_DrawAlphaMaskSprite 18
|
||||
#define J2D_DrawPartialSprite 19
|
||||
#define J2D_DrawMirrorSprite 20
|
||||
#define J2D_OutlineCircle 21
|
||||
#define J2D_FillCircle 22
|
||||
#define J2D_OutlineTriangle 23
|
||||
#define J2D_FillTriangle 24
|
||||
#define J2D_FillGradientTriangle 25
|
||||
#define J2D_DrawCubicBezierCurve 26
|
||||
#define J2D_OutlinePolygon 27
|
||||
#define J2D_DrawString 28
|
||||
#define J2D_DrawArc 29
|
||||
|
||||
|
||||
uniform int JGL_RENDERING_ROUTINE;
|
||||
uniform bool JGL_INSTANCED_RENDERING;
|
||||
|
||||
// The number of texture units that have been set.
|
||||
uniform int TEXTURE_UNIT_SET_COUNT;
|
||||
|
||||
// The color manually set with glColor4f, glColor4ubv etc.
|
||||
varying vec4 v_color;
|
||||
|
||||
// Texture unit 0 - 7 (8 - 31 will come later).
|
||||
uniform sampler2D GL_TEXTURE0;
|
||||
uniform sampler2D GL_TEXTURE1;
|
||||
uniform sampler2D GL_TEXTURE2;
|
||||
uniform sampler2D GL_TEXTURE3;
|
||||
uniform sampler2D GL_TEXTURE4;
|
||||
uniform sampler2D GL_TEXTURE5;
|
||||
uniform sampler2D GL_TEXTURE6;
|
||||
uniform sampler2D GL_TEXTURE7;
|
||||
|
||||
// Texture coordinates.
|
||||
varying vec2 GL_TEXTURE0_COORD;
|
||||
varying vec2 GL_TEXTURE1_COORD;
|
||||
varying vec2 GL_TEXTURE2_COORD;
|
||||
varying vec2 GL_TEXTURE3_COORD;
|
||||
varying vec2 GL_TEXTURE4_COORD;
|
||||
varying vec2 GL_TEXTURE5_COORD;
|
||||
varying vec2 GL_TEXTURE6_COORD;
|
||||
varying vec2 GL_TEXTURE7_COORD;
|
||||
|
||||
void DrawColorOnly() {
|
||||
gl_FragColor = v_color;
|
||||
}
|
||||
|
||||
void SampleTextureUnits() {
|
||||
if (JGL_RENDERING_ROUTINE == J2D_DrawString)
|
||||
gl_FragColor = vec4(v_color.rgb, v_color.a * texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD).a);
|
||||
|
||||
// Draw sprite, partial sprite, mirror sprite, render target, partial render target.
|
||||
else if (TEXTURE_UNIT_SET_COUNT == 1)
|
||||
gl_FragColor = v_color * texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD);
|
||||
|
||||
// Draw alpha masked sprite.
|
||||
else if (TEXTURE_UNIT_SET_COUNT == 2) {
|
||||
vec4 color_texture = texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD);
|
||||
float alpha_mask = texture2D(GL_TEXTURE1, GL_TEXTURE1_COORD).a;
|
||||
gl_FragColor = vec4(v_color.rgb * color_texture.rgb, v_color.a * alpha_mask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Default() {
|
||||
if (TEXTURE_UNIT_SET_COUNT == 0) {
|
||||
DrawColorOnly(); return;
|
||||
}
|
||||
SampleTextureUnits();
|
||||
}
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(1, 1, 1, 1);
|
||||
/* If you want behavior per JGL draw function, Or for specific ones. The order here matters because some JGL functions call others.
|
||||
if (JGL_RENDERING_ROUTINE == J2D_DrawRenderTarget)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialRenderTarget)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawAlphaMaskSprite)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawMirrorSprite)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawSprite)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawString)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoint)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoints)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawCubicBezierCurve)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawLine)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawLines)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawDottedLine)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawDashedLine)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawGradientLine)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRoundedRect)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillChamferRect)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillRoundedRect)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientRect)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRect)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillRect)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineCircle)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillCircle)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineTriangle)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillTriangle)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientTriangle)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlinePolygon)
|
||||
Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawArc)
|
||||
Default();
|
||||
else { Default(); }
|
||||
*/
|
||||
Default();
|
||||
}
|
@@ -1,7 +1,155 @@
|
||||
#version 120
|
||||
// TODO this will fail if we don't have the extension.
|
||||
#extension GL_ARB_instanced_arrays : enable
|
||||
|
||||
attribute vec2 position;
|
||||
#define J2D_DrawPoint 1
|
||||
#define J2D_DrawPoints 2
|
||||
#define J2D_DrawLine 3
|
||||
#define J2D_DrawLines 4
|
||||
#define J2D_DrawDottedLine 5
|
||||
#define J2D_DrawDashedLine 6
|
||||
#define J2D_DrawGradientLine 7
|
||||
#define J2D_OutlineRect 8
|
||||
#define J2D_OutlineRoundedRect 9
|
||||
#define J2D_OutlineChamferRect 10
|
||||
#define J2D_FillRect 11
|
||||
#define J2D_FillGradientRect 12
|
||||
#define J2D_FillRoundedRect 13
|
||||
#define J2D_FillChamferRect 14
|
||||
#define J2D_DrawRenderTarget 15
|
||||
#define J2D_DrawPartialRenderTarget 16
|
||||
#define J2D_DrawSprite 17
|
||||
#define J2D_DrawAlphaMaskSprite 18
|
||||
#define J2D_DrawPartialSprite 19
|
||||
#define J2D_DrawMirrorSprite 20
|
||||
#define J2D_OutlineCircle 21
|
||||
#define J2D_FillCircle 22
|
||||
#define J2D_OutlineTriangle 23
|
||||
#define J2D_FillTriangle 24
|
||||
#define J2D_FillGradientTriangle 25
|
||||
#define J2D_DrawCubicBezierCurve 26
|
||||
#define J2D_OutlinePolygon 27
|
||||
#define J2D_DrawString 28
|
||||
#define J2D_DrawArc 29
|
||||
|
||||
uniform int JGL_RENDERING_ROUTINE;
|
||||
uniform bool JGL_INSTANCED_RENDERING;
|
||||
|
||||
// The color manually set with glColor4f, glColor4ubv etc etc.
|
||||
varying vec4 v_color;
|
||||
|
||||
// Local space vertices for instanced rendering.
|
||||
attribute vec2 a_vertex_position; // 0
|
||||
|
||||
// The position at which to render the instance.
|
||||
attribute vec2 a_instance_position; // 1
|
||||
|
||||
// The scale of the instance.
|
||||
attribute vec2 a_instance_size; // 2
|
||||
|
||||
// The color of the instance.
|
||||
attribute vec4 a_instance_color; // 3
|
||||
|
||||
// The texture coordinates in each texture unit.
|
||||
varying vec2 GL_TEXTURE0_COORD;
|
||||
varying vec2 GL_TEXTURE1_COORD;
|
||||
varying vec2 GL_TEXTURE2_COORD;
|
||||
varying vec2 GL_TEXTURE3_COORD;
|
||||
varying vec2 GL_TEXTURE4_COORD;
|
||||
varying vec2 GL_TEXTURE5_COORD;
|
||||
varying vec2 GL_TEXTURE6_COORD;
|
||||
varying vec2 GL_TEXTURE7_COORD;
|
||||
|
||||
vec4 Default() {
|
||||
v_color = gl_Color;
|
||||
return gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
|
||||
vec4 DefaultInstanced() {
|
||||
v_color = a_instance_color;
|
||||
vec2 scaled = a_vertex_position * a_instance_size;
|
||||
vec2 world_pos = scaled + a_instance_position;
|
||||
return gl_ModelViewProjectionMatrix * vec4(world_pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
#include "shared.glsl"
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position.x, position.y, 1.0, 1.0);
|
||||
GL_TEXTURE0_COORD = gl_MultiTexCoord0.xy;
|
||||
GL_TEXTURE1_COORD = gl_MultiTexCoord1.xy;
|
||||
GL_TEXTURE2_COORD = gl_MultiTexCoord2.xy;
|
||||
GL_TEXTURE3_COORD = gl_MultiTexCoord3.xy;
|
||||
GL_TEXTURE4_COORD = gl_MultiTexCoord4.xy;
|
||||
GL_TEXTURE5_COORD = gl_MultiTexCoord5.xy;
|
||||
GL_TEXTURE6_COORD = gl_MultiTexCoord6.xy;
|
||||
GL_TEXTURE7_COORD = gl_MultiTexCoord7.xy;
|
||||
|
||||
|
||||
|
||||
/* If you want behavior per JGL draw function, Or for specific ones. The order here matters because some JGL functions call others.
|
||||
if (JGL_RENDERING_ROUTINE == J2D_DrawRenderTarget)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialRenderTarget)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawAlphaMaskSprite)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawMirrorSprite)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawSprite)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawString)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoint)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoints)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawCubicBezierCurve)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawLine)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawLines)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawDottedLine)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawDashedLine)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawGradientLine)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRoundedRect)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillChamferRect)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillRoundedRect)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientRect)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRect)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillRect)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineCircle)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillCircle)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlineTriangle)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillTriangle)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientTriangle)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_OutlinePolygon)
|
||||
gl_Position = Default();
|
||||
else if (JGL_RENDERING_ROUTINE == J2D_DrawArc)
|
||||
gl_Position = Default();
|
||||
else { gl_Position = Default(); }
|
||||
*/
|
||||
|
||||
if (JGL_INSTANCED_RENDERING)
|
||||
gl_Position = DefaultInstanced();
|
||||
else
|
||||
gl_Position = Default();
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <Color4.hpp>
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <JGL/types/Enums.h>
|
||||
#include <JGL/types/Instance.h>
|
||||
#include <JGL/types/FontCache.h>
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
@@ -29,6 +30,8 @@
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <JGL/types/VertexArray.h>
|
||||
#include <JGL/types/TextureAtlas.h>
|
||||
#include <JGL/types/Shader.h>
|
||||
|
||||
// Fonts that are included by default.
|
||||
namespace JGL::Fonts {
|
||||
@@ -45,6 +48,8 @@ namespace JGL::ShapeCache {
|
||||
// Facing straight out.
|
||||
inline VRamList* j2d_default_normal_data = nullptr;
|
||||
inline VRamList* square_origin_topleft_vertex_data = nullptr;
|
||||
inline VRamList* draw_points_positions = nullptr;
|
||||
inline VRamList* draw_points_colors = nullptr;
|
||||
void Init();
|
||||
}
|
||||
|
||||
@@ -53,8 +58,10 @@ namespace JGL {
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
using namespace J3ML::Geometry;
|
||||
|
||||
[[nodiscard]] bool Init(const Vector2& window_size, float fovY, float far_plane);
|
||||
void Update(const Vector2& window_size);
|
||||
[[nodiscard]] bool Init(const Vector2i& window_size, float fovY, float far_plane);
|
||||
void Update(const Vector2i& window_size);
|
||||
/// Clear the default framebuffer for the OpenGL context (0).
|
||||
void ClearScreen(const Color4& clear_color);
|
||||
inline void PurgeFontCache() { JGL::fontCache.purgeCache(); }
|
||||
|
||||
|
||||
@@ -72,7 +79,7 @@ namespace JGL::J2D {
|
||||
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 3D content in between our calls.
|
||||
/// @param render_target
|
||||
/// @param clear_buffers
|
||||
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
|
||||
void Begin(RenderTarget* render_target = nullptr, Shader* shader = nullptr, bool clear_buffers = false);
|
||||
|
||||
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// @see Begin().
|
||||
@@ -94,7 +101,14 @@ namespace JGL::J2D {
|
||||
|
||||
/// Plots a series of pixel-points on the screen, in a batch.
|
||||
/// @note This is more performant for multiple points than plotting them individually.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param colors A set of 4 channel color values. @see class Color4.
|
||||
/// @param points A set of x,y points to render.
|
||||
/// @param radius The size of the point to plot. By default, a single pixel.
|
||||
void DrawPoints(const Color4* color, const Vector2* points, int point_count, float radius = 1.f);
|
||||
|
||||
/// Plots a series of pixel-points on the screen, in a batch.
|
||||
/// @note This is more performant for multiple points than plotting them individually.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param points A set of x,y points to render.
|
||||
/// @param radius The size of the point to plot. By default, a single pixel.
|
||||
void DrawPoints(const Color4& color, const Vector2* points, int point_count, float radius = 1.f);
|
||||
@@ -151,6 +165,8 @@ namespace JGL::J2D {
|
||||
/// @param thickness The width at which to render the lines.
|
||||
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
|
||||
|
||||
void BatchOutlineRect(const Instance2D* instances, float thickness, const size_t& instance_count);
|
||||
|
||||
/// Draws an outline of a rectangle with rounded corners onto the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
@@ -175,12 +191,13 @@ namespace JGL::J2D {
|
||||
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
|
||||
|
||||
/// Draws a filled rectangle where the color transitions across it.
|
||||
/// @param color1 A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param color2 A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param gradient See enum Direction
|
||||
/// @param top_left_color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param bottom_left_color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param bottom_right_color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param top_right_color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
/// @param size The width and height of the rectangle.
|
||||
void FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size);
|
||||
void FillGradientRect(const Color4& top_left_color, const Color4& bottom_left_color, const Color4& bottom_right_color, const Color4& top_right_color, const Vector2& pos, const Vector2& size);
|
||||
|
||||
/// Draws a filled rectangle with rounded corners on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -190,6 +207,8 @@ namespace JGL::J2D {
|
||||
/// @param subdivisions The amount of sub-divisions (and calculations) to be performed per-arc rounding corner.
|
||||
void FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
|
||||
|
||||
void BatchFillRoundedRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, float radius, unsigned int subdivisions, const size_t& count);
|
||||
|
||||
/// Draws a filled rectangle with chamfered (beveled) corners on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param pos The top-left corner of the rectangle.
|
||||
@@ -230,6 +249,10 @@ namespace JGL::J2D {
|
||||
void DrawSprite(const RenderTarget* render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
void DrawSprite(const TextureAtlas* texture_atlas, const AtlasRegion& atlas_region, const Vector2& position, float rad_rotation, const Vector2& origin = Vector2(0, 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White);
|
||||
void DrawSprite(const TextureAtlas& texture_atlas, const AtlasRegion& atlas_region, const Vector2& position, float rad_rotation, const Vector2& origin = Vector2(0, 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White);
|
||||
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
@@ -325,7 +348,7 @@ namespace JGL::J2D {
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param tri The triangle defined by its vertices (A, B, and C).
|
||||
void FillTriangle(const Color4& color, const Triangle2D& tri);
|
||||
void FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
|
||||
void FillTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
|
||||
|
||||
/// Fills a triangle defined by the provided vertices with a gradient that transitions smoothly between the three specified colors at each corner.
|
||||
/// @param a_color The color at vertex A of the triangle.
|
||||
@@ -362,8 +385,9 @@ namespace JGL::J2D {
|
||||
/// @param scale The value (in both axes) to scale the text by. Defaults to {1,1}.
|
||||
/// @param size The point-size at which to render the font out. Re-using the same point-size allows efficient glyph caching.
|
||||
/// @param font The font to use for rendering. @see Font.
|
||||
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font = Fonts::Jupiteroid);
|
||||
void DrawString(const Color4& color, const std::string& text, float x, float y, u32 size, float scale = 1.f, const Font& font = Fonts::Jupiteroid);
|
||||
|
||||
void DrawString(const Color4& color, const std::string& text, const Vector2& pos, u32 size, float scale = 1.f, const Font& font = Fonts::Jupiteroid);
|
||||
|
||||
/// Draws an Arc (section of a circle) to the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -381,6 +405,9 @@ namespace JGL::J2D {
|
||||
void FillPolygon(const Color4& color, const std::vector<Vector2>& points);
|
||||
void OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness = 1, int subdivisions = 8);
|
||||
void FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions = 8);
|
||||
|
||||
void BatchFillRect(const Instance2D* instances, const size_t& instance_count);
|
||||
void BatchFillCircle(const Instance2D* instances, float subdivisions, const size_t& instance_count);
|
||||
}
|
||||
|
||||
/// Drawing functions for 3D objects.
|
||||
|
@@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace JGL {
|
||||
|
||||
#define stringify(name) # name
|
||||
|
||||
enum class Direction : u8 {
|
||||
None = 0,
|
||||
Vertical = 1,
|
||||
@@ -18,55 +21,61 @@ namespace JGL {
|
||||
}
|
||||
|
||||
static std::string to_string(const JGL::Direction& direction) {
|
||||
switch (direction) {
|
||||
case JGL::Direction::None:
|
||||
return "None";
|
||||
case JGL::Direction::Vertical:
|
||||
return "Vertical";
|
||||
case JGL::Direction::Horizontal:
|
||||
return "Horizontal";
|
||||
case JGL::Direction::Diagonal_NWSE:
|
||||
return "Diagonal_NWSE";
|
||||
case JGL::Direction::Diagonal_SWNE:
|
||||
return "Diagonal_SWNE";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
return stringify(direction);
|
||||
}
|
||||
|
||||
enum class MSAA_SAMPLE_RATE : u8 {
|
||||
MSAA_NONE = 0,
|
||||
// TODO come up with a cleaner way to type out sample-rates before release.
|
||||
// :shrug:, I'm not very creative. - Redacted.
|
||||
/*enum class MSAA_SAMPLE_RATE : u8 {
|
||||
NONE = 0,
|
||||
MSAA_2X = 1,
|
||||
MSAA_4X = 2,
|
||||
MSAA_8X = 3
|
||||
};
|
||||
|
||||
static std::string to_string(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
|
||||
switch (sample_rate) {
|
||||
case MSAA_SAMPLE_RATE::MSAA_NONE:
|
||||
return "No MSAA";
|
||||
case MSAA_SAMPLE_RATE::MSAA_2X:
|
||||
return "MSAA 2x";
|
||||
case MSAA_SAMPLE_RATE::MSAA_4X:
|
||||
return "MSAA 4x";
|
||||
case MSAA_SAMPLE_RATE::MSAA_8X:
|
||||
return "MSAA 8x";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
enum class ANISOTROPY_SAMPLE_RATE : u8 {
|
||||
NONE = 0,
|
||||
ANISOTROPY_2X = 2,
|
||||
ANISOTROPY_4X = 4,
|
||||
ANISOTROPY_8X = 8,
|
||||
ANISOTROPY_16X = 16
|
||||
};*/
|
||||
|
||||
/// This enumeration is used by both MSAA and Anisotropic Filtering.
|
||||
/// However, higher rates may not be supported by one, or the other.
|
||||
/// This additionally depends on what your graphics supports.
|
||||
enum class SampleRate : u8 {
|
||||
NONE = 0, X0 = 0,
|
||||
X2 = 2,
|
||||
X4 = 4,
|
||||
X8 = 8,
|
||||
X16 = 16,
|
||||
};
|
||||
|
||||
enum class FilteringMode : u8 {
|
||||
NEAREST = 0, // Fastest for 2D, Sometimes causes graphical issues.
|
||||
BILINEAR = 1, // Fast and pretty, The best for 2D.
|
||||
|
||||
// Mipmapping uses approx 30% more v-ram.
|
||||
MIPMAP_NEAREST = 2, // Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues.
|
||||
MIPMAP_BILINEAR = 3, // Bilinear with mipmaps, Fast and pretty. Uses more vram.
|
||||
MIPMAP_TRILINEAR = 4 // Prettier, But still looks weird at very steep angles.
|
||||
};
|
||||
|
||||
enum class WrappingMode : u8 {
|
||||
REPEAT = 0,
|
||||
MIRRORED_REPEAT = 1,
|
||||
CLAMP_TO_EDGE = 2,
|
||||
CLAMP_TO_BORDER = 3 // Effectively the same as clamp_to_edge
|
||||
};
|
||||
|
||||
|
||||
enum class ColorFormat : bool { RGB = false, RGBA = true };
|
||||
|
||||
static std::string to_string(const JGL::SampleRate& sample_rate) {
|
||||
return stringify(sample_rate);
|
||||
}
|
||||
static int to_int(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
|
||||
switch (sample_rate) {
|
||||
case MSAA_SAMPLE_RATE::MSAA_NONE:
|
||||
return 0;
|
||||
case MSAA_SAMPLE_RATE::MSAA_2X:
|
||||
return 2;
|
||||
case MSAA_SAMPLE_RATE::MSAA_4X:
|
||||
return 4;
|
||||
case MSAA_SAMPLE_RATE::MSAA_8X:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
static int to_int(const JGL::SampleRate& sample_rate) {
|
||||
return (int)sample_rate;
|
||||
}
|
||||
}
|
||||
|
@@ -22,11 +22,11 @@ private:
|
||||
std::array<GLfloat, 12> texcoords;
|
||||
public:
|
||||
int x2offset = 0, y2offset = 0, w = 0, h = 0;
|
||||
float advanceX = 0, advanceY = 0;
|
||||
float advanceX = 0, advanceY = 0, ascent = 0, descent = 0;
|
||||
|
||||
//CachedGlyph(GLuint texture_id, char c);
|
||||
CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2o, float y2o, float w, float h, float advX, float advY);
|
||||
char getCharacter() const;
|
||||
CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2o, float y2o, float w, float h, float advX, float advY, float asc, float desc);
|
||||
[[nodiscard]] char getCharacter() const;
|
||||
[[nodiscard]] std::array<GLfloat, 12> getTexCoords() const;
|
||||
};
|
||||
|
||||
|
49
include/JGL/types/Instance.h
Normal file
49
include/JGL/types/Instance.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <Colors.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
struct Instance2D;
|
||||
struct Instance3D;
|
||||
}
|
||||
|
||||
/// Information provided to JGL for each instance of an object you're rendering in a batch.
|
||||
/// @note This is non-negotiable. This information is interleaved in *the same buffer* in v-ram for performance reasons - Redacted.
|
||||
struct JGL::Instance2D {
|
||||
public:
|
||||
Color4 color;
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
Vector2 scale;
|
||||
float rotation;
|
||||
public:
|
||||
/// @param position The position of the instance in world space.
|
||||
/// @param size The size of the instance.
|
||||
/// @param scale A multiplier to be applied to the size.
|
||||
/// @param rotation The rotation in radians.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4.
|
||||
/// @note If the thing you're drawing is textured you probably want Colors::White
|
||||
Instance2D(const Color4& color, const Vector2& position, const Vector2& size, const Vector2& scale = Vector2::One, float rotation = 0.0f) :
|
||||
color(color), position(position), size(size), scale(scale), rotation(rotation) {};
|
||||
Instance2D() = default;
|
||||
~Instance2D() = default;
|
||||
};
|
||||
|
||||
struct JGL::Instance3D {
|
||||
public:
|
||||
Matrix4x4 instance_matrix;
|
||||
Color4 color;
|
||||
public:
|
||||
/// @param instance_matrix A matrix containing rotation matrix, position, and scale.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4.
|
||||
/// @note If the thing you're drawing is textured you probably want Colors::White
|
||||
Instance3D(const Matrix4x4& instance_matrix, const Color4& color) : instance_matrix(instance_matrix), color(color) {};
|
||||
Instance3D() = default;
|
||||
~Instance3D() = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@@ -12,6 +12,8 @@ namespace JGL {
|
||||
}
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2i;
|
||||
|
||||
/// A
|
||||
class JGL::RenderTarget {
|
||||
private:
|
||||
Color4 clear_color{0,0,0,0};
|
||||
@@ -21,32 +23,33 @@ private:
|
||||
GLuint framebuffer_object = 0;
|
||||
GLuint depth_buffer = 0;
|
||||
const Texture* texture = nullptr;
|
||||
MSAA_SAMPLE_RATE msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
SampleRate msaa_sample_rate = SampleRate::NONE;
|
||||
GLuint msaa_framebuffer_object = 0;
|
||||
GLuint msaa_depth_buffer = 0;
|
||||
GLuint msaa_render_buffer = 0;
|
||||
void Erase();
|
||||
public:
|
||||
/// @returns The Render Target currently in use by OpenGL.
|
||||
/// @note Zero is the screen.
|
||||
/// @returns A handle to the RenderTarget currently in use by OpenGL.
|
||||
/// @note zero is returned when no RenderTarget is in use.
|
||||
static GLuint GetActiveGLFramebufferHandle();
|
||||
|
||||
/// Changes the Render Target that OpenGL will draw on.
|
||||
/// @param render_target The new Render Target for OpenGL to draw on.
|
||||
/// Changes the RenderTarget that OpenGL will draw on.
|
||||
/// @param render_target The new RenderTarget for OpenGL to draw on.
|
||||
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
|
||||
|
||||
/// Changes the size of the renderable area of this Render Target.
|
||||
/// Changes the size of the render-able area of this RenderTarget.
|
||||
/// @param new_size new width & height in pixels.
|
||||
/// @note The data stored in this Render Target will be lost.
|
||||
void Resize(const Vector2i& new_size);
|
||||
|
||||
/// Sets the MSAA mode for this Render Target.
|
||||
/// @returns false if the mode isn't available, true for success.
|
||||
[[nodiscard]] bool SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
|
||||
[[nodiscard]] bool SetMSAAEnabled(SampleRate sample_rate);
|
||||
|
||||
/// If you're using MSAA and not using J2D || J3D Begin & End you must do this.
|
||||
void MSAABlit() const;
|
||||
|
||||
void RegenerateMipMaps();
|
||||
/// Copy one Render Target onto another. Will break if they're not the same size.
|
||||
// TODO support different sizes. If the destination is too small fix it for them but log a warning.
|
||||
static void Blit(const RenderTarget& source, RenderTarget* destination, const Vector2i& position = {0, 0});
|
||||
@@ -70,7 +73,7 @@ public:
|
||||
[[nodiscard]] Vector2i GetDimensions() const;
|
||||
|
||||
/// @returns The currently selected MSAA Sample Rate.
|
||||
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
|
||||
[[nodiscard]] SampleRate GetMSAASampleRate() const;
|
||||
|
||||
/// @returns Whether or not this Render Target is using MSAA.
|
||||
[[nodiscard]] bool MSAAEnabled() const;
|
||||
@@ -91,10 +94,11 @@ public:
|
||||
/// @returns The color that should be used to clear this Render Target.
|
||||
[[nodiscard]] Color4 GetClearColor() const;
|
||||
|
||||
|
||||
/// @returns The color information for this Render Target.
|
||||
/// @note Both the CPU & GPU cannot do anything while this takes place. It's very slow.
|
||||
/// @note The CPU thread this is called from & the GPU cannot do anything while this takes place. It's very slow.
|
||||
[[nodiscard]] std::vector<GLfloat> GetPixels() const;
|
||||
|
||||
[[nodiscard]] static Vector2i MaxSize();
|
||||
public:
|
||||
/// Create a Render Target from a Render Target that already exists.
|
||||
/** @note Render Targets that are copies of another will copy the Texture.
|
||||
@@ -113,7 +117,8 @@ public:
|
||||
/// @param clear_color The color to be used if you want to clear the Render Target.
|
||||
/// @param use_depth Whether or not this Render Target will have depth information.
|
||||
/// @param sample_rate The MSAA sample rate this Render Target will use.
|
||||
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false,
|
||||
SampleRate sample_rate = SampleRate::NONE, FilteringMode filteirng_mode = FilteringMode::NEAREST);
|
||||
|
||||
/// Deletes this Render Target.
|
||||
/** @note If this Render Target was made with a Texture that already existed
|
||||
|
121
include/JGL/types/Shader.h
Normal file
121
include/JGL/types/Shader.h
Normal file
@@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "glad/glad.h"
|
||||
#include <Event.h>
|
||||
|
||||
// LearnOpenGL::Shader
|
||||
// OpenGL Shader Class Wrapper
|
||||
// Updated by dawsh
|
||||
// https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/shader.h
|
||||
|
||||
namespace JGL {
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
class Shader;
|
||||
}
|
||||
|
||||
/// TODO: Eventually support Hot-reloading shaders like in shadertoy. Should help tremendously with debugging.
|
||||
|
||||
class JGL::Shader {
|
||||
public:
|
||||
static inline Event<std::string, std::string> OnCompilationErrorMessage;
|
||||
|
||||
static bool HasFile(const std::filesystem::path& path)
|
||||
{
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
static std::string ReadFile(const std::filesystem::path& path);
|
||||
|
||||
/// The default constructor does not initialize any member values.
|
||||
Shader() = default;
|
||||
|
||||
/// Creates a shader by compiling a vertex and fragment program from the sources in the respective filesystem paths.
|
||||
Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
|
||||
|
||||
/// Creates a shader by compiling a vertex and fragment program from the respective GLSL source-strings.
|
||||
Shader(const std::string& vertex_code, const std::string& fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
|
||||
|
||||
/// @return True if the shader program successfully loaded and compiled.
|
||||
[[nodiscard]] bool Loaded() const;
|
||||
/// @return The integer handle that OpenGL links to this shader program.
|
||||
[[nodiscard]] unsigned int Handle() const;
|
||||
/// Enable this shader. All rendering performed thereafter will be affected by this shader code.
|
||||
/// @see UseDefault.
|
||||
|
||||
// TODO: Implement for hot-reloading.
|
||||
void Reload();
|
||||
// TODO: Implement for hot-reloading.
|
||||
void Unload();
|
||||
|
||||
/// @return The Uniform variable linked to the specified name.
|
||||
/// A Uniform is global a variable that is unique per shader program object, and can be accessed from any shader at any stage in the shader program.
|
||||
GLint Uniform(const std::string& name) const;
|
||||
|
||||
/// @return The Attribute variable linked to the specified name.
|
||||
/// Attributes differ from Uniforms in that their value is different for each instance of the shader-program as it is running.
|
||||
[[nodiscard]] GLint Attribute(const std::string& name) const;
|
||||
|
||||
/// Sets a `uniform bool name = value` in the shader program.
|
||||
void SetBool (const std::string& name, bool value) const;
|
||||
/// Sets a `uniform int name = value` in the shader program.
|
||||
void SetInt (const std::string& name, int value) const;
|
||||
/// Sets a `uniform float name = value` in the shader program.
|
||||
void SetFloat(const std::string& name, float value) const;
|
||||
/// Sets a `uniform vec2 name = value` in the shader program.
|
||||
/// @note GLSL has builtin vec2, while we implement a Vector2 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Vector2.
|
||||
void SetVector2(const std::string& name, const Vector2& value) const;
|
||||
/// Sets a `uniform vec2 name = value` in the shader program.
|
||||
/// @note GLSL has builtin vec2, while we implement a Vector2 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Vector2.
|
||||
void SetVector2(const std::string& name, float x, float y) const;
|
||||
/// Sets a `uniform vec3 name = value` in the shader program.
|
||||
/// @note GLSL has builtin vec3, while we implement a Vector3 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Vector3.
|
||||
void SetVector3(const std::string& name, const Vector3& value) const;
|
||||
/// Sets a `uniform vec3 name = value` in the shader program.
|
||||
/// @note GLSL has builtin vec3, while we implement a Vector3 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Vector3.
|
||||
void SetVector3(const std::string& name, float x, float y, float z) const;
|
||||
/// Sets a `uniform vec4 name = value` in the shader program.
|
||||
/// @note GLSL has builtin vec4, while we implement aVector4 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Vector4.
|
||||
void SetVector4(const std::string& name, const Vector4& value) const;
|
||||
/// Sets a `uniform vec4 name = value` in the shader program.
|
||||
/// @note GLSL has builtin vec4, while we implement a Vector4 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Vector4.
|
||||
void SetVector4(const std::string& name, float x, float y, float z, float w) const;
|
||||
|
||||
/// Sets a `uniform mat2 name = value` in the shader program.
|
||||
/// @note GLSL has builtin mat2, while we implement a Matrix2x2 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Matrix2x2
|
||||
void SetMatrix2x2(const std::string& name, const Matrix2x2& value) const;
|
||||
|
||||
/// Sets a `uniform mat3 name = value` in the shader program.
|
||||
/// @note GLSL has builtin mat3, while we implement a Matrix3x3 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Matrix3x3
|
||||
void SetMatrix3x3(const std::string& name, const Matrix3x3& value) const;
|
||||
|
||||
/// Sets a `uniform mat4 name = value` in the shader program.
|
||||
/// @note GLSL has builtin mat4, while we implement a Matrix4x4 type. Please be aware there may be differences in implementation between them!
|
||||
/// @see class J3ML::LinearAlgebra::Matrix4x4
|
||||
void SetMatrix4x4(const std::string& name, const Matrix4x4& value) const;
|
||||
|
||||
|
||||
// TODO: Implement Uniform-Setters for GLSL types that do not have a J3ML corollary (dmat3x4, dvec4, etc).
|
||||
|
||||
protected:
|
||||
private:
|
||||
unsigned int id = 0;
|
||||
std::string vertexPath;
|
||||
std::string vertexSource;
|
||||
std::string fragmentSource;
|
||||
std::string fragmentPath;
|
||||
mutable std::unordered_map<std::string, GLint> uniform_location_cache;
|
||||
static void checkCompileErrors(GLuint shader, const std::string& type);
|
||||
};
|
@@ -4,30 +4,13 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
#include <Color3.hpp>
|
||||
#include <Color4.hpp>
|
||||
#include <JGL/types/Enums.h>
|
||||
|
||||
namespace JGL {
|
||||
using J3ML::LinearAlgebra::Vector2i;
|
||||
|
||||
enum class FilteringMode : u8 {
|
||||
NEAREST = 0, // Fastest for 2D, Sometimes causes graphical issues.
|
||||
BILINEAR = 1, // Fast and pretty, The best for 2D.
|
||||
|
||||
MIPMAP_NEAREST = 2, // Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues. Uses more vram.
|
||||
MIPMAP_BILINEAR = 3, // Bilinear with mipmaps, Fast and pretty. Uses more vram.
|
||||
MIPMAP_TRILINEAR = 4 // The prettiest. Still decent speed. Uses more vram.
|
||||
};
|
||||
|
||||
enum class WrappingMode : u8 {
|
||||
REPEAT = 0,
|
||||
MIRRORED_REPEAT = 1,
|
||||
CLAMP_TO_EDGE = 2,
|
||||
CLAMP_TO_BORDER = 3 // Effectively the same as clamp_to_edge
|
||||
};
|
||||
enum class ColorFormat : bool { RGB = false, RGBA = true };
|
||||
class Texture;
|
||||
}
|
||||
|
||||
/// TODO handle the case of a texture being loaded that exceeds the max texture size.
|
||||
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
|
||||
class JGL::Texture {
|
||||
protected:
|
||||
@@ -37,9 +20,11 @@ protected:
|
||||
ColorFormat format = ColorFormat::RGBA;
|
||||
FilteringMode filtering_mode;
|
||||
WrappingMode wrapping_mode;
|
||||
SampleRate anisotropy;
|
||||
void load(const unsigned char* pixels);
|
||||
std::vector<unsigned char> png(const std::filesystem::path& file);
|
||||
std::vector<unsigned char> bmp(const std::filesystem::path& file);
|
||||
[[nodiscard]] bool SizeExceedsMaximum(const Vector2i& size);
|
||||
public:
|
||||
/// @returns A handle used to identify this texture.
|
||||
[[nodiscard]] unsigned int GetHandle() const;
|
||||
@@ -49,6 +34,8 @@ public:
|
||||
[[nodiscard]] FilteringMode GetFilteringMode() const;
|
||||
/// @returns The way this texture behaves when used on geometry of different sizes.
|
||||
[[nodiscard]] WrappingMode GetWrappingMode() const;
|
||||
/// @returns The current level of anisotropic filtering for this texture.
|
||||
[[nodiscard]] SampleRate GetAnisotropySampleRate() const;
|
||||
/// @returns The orientation of this texture in v-ram.
|
||||
/// @note true is right-side-up because OpenGL defaults to upside-down.
|
||||
[[nodiscard]] bool Inverted() const;
|
||||
@@ -58,18 +45,25 @@ public:
|
||||
[[nodiscard]] std::vector<Color4> GetPixelData() const;
|
||||
public:
|
||||
/// Load a texture from a file,
|
||||
explicit Texture(const std::filesystem::path& file, FilteringMode filtering_mode = FilteringMode::BILINEAR, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE, bool invert_y = true);
|
||||
explicit Texture(const std::filesystem::path& file, FilteringMode filtering_mode = FilteringMode::BILINEAR,
|
||||
SampleRate anisotropy = SampleRate::NONE, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE, bool invert_y = true);
|
||||
/// Load a texture from raw pixels.
|
||||
Texture(const Color4* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode);
|
||||
Texture(const Color4* pixels, const Vector2i& size, FilteringMode filtering_mode = FilteringMode::BILINEAR,
|
||||
SampleRate anisotropy = SampleRate::NONE, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE);
|
||||
/// Load a texture from raw pixels.
|
||||
Texture(const Color3* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode);
|
||||
/// Construct a Texture Atlas from many different textures.
|
||||
/// @note THIS IS UNFINISHED.
|
||||
Texture(const Texture* textures, const size_t& texture_count);
|
||||
Texture(const Color3* pixels, const Vector2i& size, FilteringMode filtering_mode = FilteringMode::BILINEAR,
|
||||
SampleRate anisotropy = SampleRate::NONE, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE);
|
||||
/// Initialize a texture filled with trash data.
|
||||
/// @see RenderTarget
|
||||
explicit Texture(const Vector2i& size);
|
||||
|
||||
explicit Texture(const Vector2i& size, FilteringMode filtering_mode = FilteringMode::NEAREST);
|
||||
Texture(const Texture& rhs);
|
||||
Texture() = default;
|
||||
~Texture();
|
||||
public:
|
||||
/// @returns True if this system supports anisotropy.
|
||||
// TODO add a similar mechanism for MSAA so the extension isn't required.
|
||||
static enum SampleRate MaxAnisotropySampleRate();
|
||||
/// @returns The biggest size for a texture on this system.
|
||||
/// @note on modern systems this is *usually* ridiculous.
|
||||
[[nodiscard]] static Vector2i MaxSize();
|
||||
};
|
35
include/JGL/types/TextureAtlas.h
Normal file
35
include/JGL/types/TextureAtlas.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <JGL/types/Texture.h>
|
||||
|
||||
namespace JGL {
|
||||
struct AtlasRegion {
|
||||
Vector2i position = { 0, 0 };
|
||||
Vector2i size = { 0, 0 };
|
||||
};
|
||||
class TextureAtlas;
|
||||
}
|
||||
|
||||
// A texture which actually contains multiple such that you can pass it in to draw sprite or draw partial sprite.
|
||||
// It also makes for more efficient sprite batch because you don't have to swap textures between.
|
||||
class JGL::TextureAtlas : public Texture {
|
||||
protected:
|
||||
std::vector<AtlasRegion> regions;
|
||||
public:
|
||||
unsigned int RegionCount() { return regions.size(); }
|
||||
[[nodiscard]] AtlasRegion GetRegion(unsigned int region) const;
|
||||
public:
|
||||
/// Create a texture atlas from multiple separate images.
|
||||
/// @param pixels The array(s) of pixels.
|
||||
/// @param sizes The size of each image.
|
||||
/// @param texture_count The number of textures this atlas will contain.
|
||||
TextureAtlas(const Color4** pixels, const Vector2i** sizes, unsigned int texture_count, FilteringMode filtering_mode = FilteringMode::NEAREST);
|
||||
|
||||
/// Create a texture atlas from a single image
|
||||
/// @param pixels The array of pixels.
|
||||
/// @param size The size of the image.
|
||||
/// @param regions The individual regions that will make up your atlas.
|
||||
/// @param region_count The number of regions there are.
|
||||
TextureAtlas(const Color4* pixels, const Vector2i& size, AtlasRegion** regions, unsigned int region_count, FilteringMode filtering_mode = FilteringMode::NEAREST, SampleRate anisotropy = SampleRate::NONE);
|
||||
~TextureAtlas() = default;
|
||||
};
|
@@ -5,52 +5,68 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <Color4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class VRamList;
|
||||
/// A hint for OpenGL on how the VBO is to be used.
|
||||
enum VRamUsageHint : GLenum {
|
||||
// Never updated after creation.
|
||||
Fixed = GL_STATIC_DRAW,
|
||||
// Modified occasionally.
|
||||
Dynamic = GL_DYNAMIC_DRAW,
|
||||
// Constantly modified and used one or a few times.
|
||||
Stream = GL_STREAM_DRAW
|
||||
};
|
||||
}
|
||||
|
||||
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in VRam.
|
||||
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in V-ram.
|
||||
class JGL::VRamList {
|
||||
private:
|
||||
VRamUsageHint usage_hint = Fixed;
|
||||
GLuint list_handle = 0;
|
||||
long num_elements = 0;
|
||||
long byte_count = 0;
|
||||
bool element_array_buffer = false;
|
||||
/// "Spin Locking" fix for multi-threading.
|
||||
bool spin_lock = false;
|
||||
// TODO mutex lock.
|
||||
void load(const GLfloat* data, const long& size);
|
||||
void load(const GLuint* data, const long& size);
|
||||
void SetData(void* data, const long& count);
|
||||
void UpdateData(void* data, const long& offset, const long& count);
|
||||
void Erase();
|
||||
public:
|
||||
VRamList(const GLuint* data, const long& count);
|
||||
VRamList(const GLfloat* data, const long& count);
|
||||
VRamList(const Vector2* data, const long& count);
|
||||
VRamList(const Vector3* data, const long& count);
|
||||
VRamList(const Vector4* data, const long& count);
|
||||
VRamList(const GLuint* data, const long& count, VRamUsageHint hint = Fixed);
|
||||
VRamList(const GLfloat* data, const long& count, VRamUsageHint hint = Fixed);
|
||||
VRamList(const Vector2* data, const long& count, VRamUsageHint hint = Fixed);
|
||||
VRamList(const Vector3* data, const long& count, VRamUsageHint hint = Fixed);
|
||||
VRamList(const Vector4* data, const long& count, VRamUsageHint hint = Fixed);
|
||||
VRamList(const Color4* data, const long& count, VRamUsageHint hint = Fixed);
|
||||
/// Allocate an empty VBO
|
||||
/// @param byte_count the size of the buffer in bytes.
|
||||
/// @param element_array_buffer if applicable, whether the buffer is to be used for GLuint indices.
|
||||
/// @param hint A hint to the graphics driver for what the buffer is to be used for.
|
||||
VRamList(const size_t& byte_count, bool element_array_buffer, VRamUsageHint hint = Fixed);
|
||||
|
||||
~VRamList();
|
||||
/** Copying around the VBO data to a new VBO like this is slow.
|
||||
* Pass to function by const reference or pointer always. */
|
||||
VRamList(const VRamList& rhs);
|
||||
VRamList() : list_handle(0), num_elements(0), element_array_buffer(false), spin_lock(false) {}
|
||||
VRamList() : list_handle(0), byte_count(0), element_array_buffer(false) {}
|
||||
public:
|
||||
[[nodiscard]] GLuint GetHandle() const;
|
||||
[[nodiscard]] GLuint Handle() const;
|
||||
/// Returns the number of elements in the list.
|
||||
[[nodiscard]] long GetLength() const;
|
||||
[[nodiscard]] long Length() const;
|
||||
/// Returns the size of the data in bytes.
|
||||
[[nodiscard]] size_t GetDataSize() const;
|
||||
[[nodiscard]] size_t Size() const;
|
||||
/** Get VBO data back from the GPU. This is *bad* because the CPU is going to wait
|
||||
* for the transfer to finish. Has limited use other than testing. */
|
||||
[[nodiscard]] std::vector<GLfloat> GetDataF() const;
|
||||
[[nodiscard]] std::vector<GLuint> GetDataUI() const;
|
||||
[[nodiscard]] bool IsFloatArray() const;
|
||||
/** Replace the data of an existing VBO in it's entirety. Must be same type. */
|
||||
void SetData(const GLfloat* data, const long& count);
|
||||
void SetData(const Vector2* data, const long& count);
|
||||
void SetData(const Vector3* data, const long& count);
|
||||
void SetData(const Vector4* data, const long& count);
|
||||
void SetData(const Color4* data, const long& count);
|
||||
|
||||
void SetData(const GLuint* data, const long& count);
|
||||
void SetData(const Vector2i* data, const long& count);
|
||||
@@ -58,11 +74,17 @@ public:
|
||||
/** Update only a portion of the data in a VBO. Must be same type.
|
||||
* "offset" refers the number of Typename T into the buffer the data you want to change is.
|
||||
* For ex, offset 0 and length of 1 overwrites the first value. Offset 1 the second etc */
|
||||
|
||||
// TODO provide a bool to specify whether the current buffer should be orphaned.
|
||||
void UpdateData(const GLfloat* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector2* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector3* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector4* data, const long& offset, const long& count);
|
||||
|
||||
void UpdateData(const Color4* data, const long& offset, const long& count);
|
||||
void UpdateData(const GLuint* data, const long& offset, const long& count);
|
||||
void UpdateData(const Vector2i* data, const long& offset, const long& count);
|
||||
|
||||
// Update only a portion of the data in a VBO using bytes.
|
||||
// TODO This version of the function has no protection for out of bounds writes.
|
||||
void UpdateData(const uint8_t* data, const long& offset, const long& count);
|
||||
};
|
77
main.cpp
77
main.cpp
@@ -7,6 +7,7 @@
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <ReWindow/Logger.h>
|
||||
#include <JGL/types/VertexArray.h>
|
||||
#include <JGL/types/Shader.h>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using namespace JGL::Fonts;
|
||||
@@ -14,7 +15,7 @@ using namespace JGL;
|
||||
using JGL::Font;
|
||||
|
||||
float fps = 0.0f;
|
||||
|
||||
std::vector<Instance2D> rect_instances;
|
||||
/// A draggable 2D point that highlights when moused over and when clicked.
|
||||
class Gizmo
|
||||
{
|
||||
@@ -111,6 +112,8 @@ JGL::Font FreeSans;
|
||||
Texture* image;
|
||||
Texture* image_mask;
|
||||
RenderTarget* j2d_render_target;
|
||||
Shader* shader;
|
||||
Vector2 result;
|
||||
|
||||
class JGLDemoWindow : public ReWindow::OpenGLWindow
|
||||
{
|
||||
@@ -118,7 +121,7 @@ public:
|
||||
void initGL() {
|
||||
camera = new Camera;
|
||||
|
||||
if (!JGL::Init({(float) GetSize().x, (float) GetSize().y}, 75, 100))
|
||||
if (!JGL::Init({ GetSize().x, GetSize().y}, 75, 100))
|
||||
Logger::Fatal("Initialization failed.");
|
||||
|
||||
// Load a custom font.
|
||||
@@ -128,25 +131,33 @@ public:
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
image = new Texture("assets/sprites/Re3D.png", FilteringMode::BILINEAR);
|
||||
image = new Texture("assets/sprites/Re3D.png", FilteringMode::MIPMAP_NEAREST);
|
||||
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
|
||||
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false,
|
||||
SampleRate::NONE, FilteringMode::MIPMAP_NEAREST);
|
||||
|
||||
//Texture::MultiplyByAlphaMask(*image, *image_mask);
|
||||
|
||||
shader = new Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"),
|
||||
{{"a_vertex_position", 0}, {"a_instance_position", 1}, {"a_instance_size", 2}, {"a_instance_color", 3}});
|
||||
|
||||
result = Jupiteroid.MeasureString("The quick black fox jumps over the lazy dog.", 16);
|
||||
for (unsigned int i = 0; i < 100; i++)
|
||||
rect_instances.emplace_back(Colors::Red, Vector2(420, 420), Vector2(20, 20));
|
||||
}
|
||||
|
||||
EulerAngleXYZ textAngle = {0,0,0};
|
||||
float fov = 90;
|
||||
u8 pulse = 0;
|
||||
float pulse = 0;
|
||||
float sprite_radians = 0;
|
||||
bool fov_increasing = true;
|
||||
int blit_pos = 0;
|
||||
|
||||
void display() {
|
||||
pulse++;
|
||||
|
||||
pulse += 20 * delta_time;
|
||||
float dt = GetDeltaTime();
|
||||
|
||||
JGL::Update({(float) GetSize().x, (float) GetSize().y});
|
||||
JGL::Update({ GetSize().x, GetSize().y });
|
||||
|
||||
if (fov_increasing)
|
||||
fov += 0.025;
|
||||
@@ -165,39 +176,40 @@ public:
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
|
||||
|
||||
camera->render();
|
||||
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
|
||||
/* if rendering to screen space directly. */
|
||||
auto test_light = PointLight({2,1,2}, {pulse,pulse,pulse, 255}, {pulse, pulse, pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
|
||||
auto test_light = PointLight({2,1,2}, {(u8) pulse,(u8) pulse,(u8) pulse, 255}, {(u8) pulse, (u8) pulse, (u8) pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
|
||||
// If a 3D object has transparency. The things you'd like to see through it must be drawn before.
|
||||
|
||||
|
||||
J3D::Begin();
|
||||
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
|
||||
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
|
||||
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
|
||||
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
|
||||
Sphere sphere = {{0,0, 0.5f}, 0.2125};
|
||||
Sphere sphere = {{1,0, 0.5f}, 0.2125};
|
||||
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 8, 8, true);
|
||||
J3D::RequiredLight(&test_light);
|
||||
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
|
||||
J3D::WireframeAABB(Colors::Gray, {0,0,0.5f}, {0.11f, 0.06f, 0.11f});
|
||||
|
||||
AABB boxes[1] = {{Vector3(-0.2125, -0.2125,0.28750), Vector3(0.2125,0.2125,0.7125)}};
|
||||
J3D::BatchWireframeAABB(Colors::Yellow, boxes, 1, 1);
|
||||
|
||||
J3D::WireframeAABB(Colors::Yellow, {0.5, 0, 0.5}, {0.125, 0.125, 0.125}, 1);
|
||||
J3D::End();
|
||||
|
||||
J2D::Begin(j2d_render_target, true);
|
||||
//JGL::ClearScreen(Colors::Red);
|
||||
J2D::Begin(j2d_render_target, shader, true);
|
||||
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
|
||||
J2D::BatchFillRect(rect_instances.data(), rect_instances.size());
|
||||
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawPartialSprite(image, Vector2(225, 300), Vector2(image->GetDimensions()) * 0.25, Vector2(image->GetDimensions()) * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
|
||||
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
|
||||
J2D::FillGradientRect(Colors::Red, Colors::Green, Colors::Blue, Colors::White, {100,52}, {100,100});
|
||||
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
|
||||
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
|
||||
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
|
||||
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
|
||||
auto box = JGL::Fonts::Jupiteroid.MeasureString("Hello g", 16);
|
||||
|
||||
J2D::FillChamferRect(Colors::Reds::LightSalmon, {150, 400}, {64, 64}, 5);
|
||||
J2D::OutlineRoundedRect(Colors::Reds::LightCoral, {250, 350}, {128, 128}, 10, 2);
|
||||
@@ -205,16 +217,15 @@ public:
|
||||
J2D::FillGradientTriangle(Color4(Colors::Red), Color4(Colors::Green), Color4(Colors::Blue), {{0, 275}, {0, 375}, {100, 375}});
|
||||
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
|
||||
J2D::DrawGradientLine(Colors::Red, Colors::Blue, {105, 375}, {200, 275}, 2);
|
||||
auto result = Jupiteroid.MeasureString("Jupiteroid Font", 16);
|
||||
J2D::DrawString(Colors::Green, "The quick black fox jumps over the lazy dog.", 0, 20, 1, 16);
|
||||
J2D::OutlineRect(Colors::Red, {0, 20}, result, 1);
|
||||
|
||||
//J2D::FillRect(Colors::Gray, {0, 0}, result);
|
||||
J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
|
||||
J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
|
||||
J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
|
||||
J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
|
||||
//J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
|
||||
//J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
|
||||
//J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
|
||||
//J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
|
||||
std::array<Vector2, 5> polygon = {Vector2(200, 400), {220, 420}, {220, 430}, {230, 410}, {200, 400}};
|
||||
J2D::OutlinePolygon(Colors::White, polygon.data(), polygon.size());
|
||||
//J2D::FillPolygon(Colors::White, {{200, 400}, {220, 420}, {220, 430}, {230, 410}, {200, 400}});
|
||||
J2D::DrawCubicBezierCurve(Colors::Blues::CornflowerBlue,
|
||||
a.position,
|
||||
b.position,
|
||||
@@ -226,23 +237,17 @@ public:
|
||||
b.Draw();
|
||||
c.Draw();
|
||||
d.Draw();
|
||||
|
||||
J2D::End();
|
||||
RenderTarget::Blit(Colors::Red, {0, 0}, j2d_render_target);
|
||||
|
||||
//Draw the Render Target that we just drew all that stuff onto.
|
||||
|
||||
J2D::Begin();
|
||||
J2D::Begin(nullptr, nullptr, true);
|
||||
J2D::DrawRenderTarget(j2d_render_target, {0, 0});
|
||||
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
|
||||
//J2D::DrawSprite(, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
|
||||
//J2D::DrawSprite( {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
//J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
|
||||
J2D::End();
|
||||
|
||||
}
|
||||
|
||||
void OnRefresh(float elapsed) override {
|
||||
|
||||
fps = GetRefreshRate();
|
||||
|
||||
if (IsKeyDown(Keys::RightArrow))
|
||||
@@ -317,6 +322,10 @@ int main(int argc, char** argv) {
|
||||
if (!file.is_open())
|
||||
return -1;
|
||||
|
||||
Shader::OnCompilationErrorMessage += [] (std::string type, std::string info) {
|
||||
std::cout << type << ", " << info << std::endl;
|
||||
};
|
||||
|
||||
/*
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
|
17
src/JGL.cpp
17
src/JGL.cpp
@@ -10,7 +10,7 @@
|
||||
namespace JGL {
|
||||
using namespace J3ML;
|
||||
|
||||
bool Init(const Vector2& window_size, float fovY, float far_plane) {
|
||||
bool Init(const Vector2i& ws, float fovY, float far_plane) {
|
||||
gladLoadGL();
|
||||
if (!MeetsRequirements()) {
|
||||
Logger::Fatal("The graphics driver does not meet the minimum requirements to run this program.");
|
||||
@@ -20,15 +20,18 @@ namespace JGL {
|
||||
InitTextEngine();
|
||||
Fonts::Init();
|
||||
ShapeCache::Init();
|
||||
OpenGLState::window_size = window_size;
|
||||
JGL::window_size = ws;
|
||||
J3D::fov = fovY;
|
||||
J3D::far_plane = far_plane;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update(const Vector2& window_size) {
|
||||
OpenGLState::window_size = window_size;
|
||||
glViewport(0, 0, (int) window_size.x, (int) window_size.y);
|
||||
void Update(const Vector2i& ws) {
|
||||
if (state_stack.Size())
|
||||
Logger::Error("You shouldn't be running JGL::Update while inside a J2D or J3D context.");
|
||||
|
||||
JGL::window_size = ws;
|
||||
glViewport(0, 0, window_size.x, window_size.y);
|
||||
}
|
||||
|
||||
bool MeetsRequirements() {
|
||||
@@ -40,6 +43,10 @@ namespace JGL {
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_shadow)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_draw_instanced)
|
||||
supports_instanced = false;
|
||||
if (!GLAD_GL_ARB_instanced_arrays)
|
||||
supports_instanced = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -47,11 +47,22 @@ void JGL::ShapeCache::Init() {
|
||||
cube_normal_data = new VRamList(vertex_normals.data(), vertex_normals.size());
|
||||
|
||||
if (!square_origin_topleft_vertex_data) {
|
||||
std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {1, 0}, {1, -1}, {0, -1} };
|
||||
//std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {1, 0}, {1, -1}, {0, -1} };
|
||||
std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {0, 1}, {1, 1}, {1, 0} };
|
||||
square_origin_topleft_vertex_data = new VRamList(square_vertices.data(), square_vertices.size());
|
||||
}
|
||||
if (!j2d_default_normal_data) {
|
||||
std::array<GLfloat, 3> normal {0, 0, 1};
|
||||
j2d_default_normal_data = new VRamList(normal.data(), normal.size());
|
||||
}
|
||||
|
||||
if (!draw_points_colors) {
|
||||
std::array<Color4, 1> color = { Colors::Transparent };
|
||||
draw_points_colors = new VRamList(color.data(), color.size(), Stream);
|
||||
}
|
||||
|
||||
if (!draw_points_positions) {
|
||||
std::array<Vector2, 1> position = { Vector2::Zero };
|
||||
draw_points_positions = new VRamList(position.data(), position.size(), Stream);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ void JGL::J3D::ChangeFarPlane(float far_plane) {
|
||||
|
||||
void JGL::J3D::RequiredLight(const JGL::LightBase* light) {
|
||||
bool success = false;
|
||||
for (auto& i : required_lights)
|
||||
for (auto& i : current_state.required_lights)
|
||||
if (i == nullptr) {
|
||||
i = light;
|
||||
success = true;
|
||||
@@ -41,86 +41,82 @@ void JGL::J3D::RequiredLight(const JGL::LightBase* light) {
|
||||
|
||||
void JGL::J3D::OptionalLights(const JGL::LightBase** lights, const size_t& light_count) {
|
||||
for (size_t i = 0; i < light_count; i++)
|
||||
optional_lights.push_back(lights[i]);
|
||||
current_state.optional_lights.push_back(lights[i]);
|
||||
}
|
||||
|
||||
void JGL::J3D::Begin(bool two_pass) {
|
||||
auto aspect = (float) OpenGLState::window_size.x / (float) OpenGLState::window_size.y;
|
||||
auto aspect = (float) window_size.x / (float) window_size.y;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMultMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
|
||||
glLoadMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
//Get what the draw color was before we did anything.
|
||||
glGetFloatv(GL_CURRENT_COLOR, OpenGLState::oldColor);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
glGetFloatv(GL_CURRENT_COLOR, current_state.draw_color);
|
||||
glColor4fv(current_state.draw_color);
|
||||
|
||||
if (!glIsEnabled(GL_DEPTH_TEST))
|
||||
OpenGLState::wasDepthTestEnabled = false,
|
||||
current_state.depth_test = false,
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
OpenGLState::wasDepthTestEnabled = true;
|
||||
current_state.depth_test = true;
|
||||
|
||||
OpenGLState::wasVertexArraysEnabled = false;
|
||||
current_state.vertex_array = false;
|
||||
if (!glIsEnabled(GL_VERTEX_ARRAY))
|
||||
OpenGLState::wasVertexArraysEnabled = false,
|
||||
current_state.vertex_array = false,
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_NORMAL_ARRAY))
|
||||
OpenGLState::wasNormalArrayEnabled = true,
|
||||
current_state.normal_array = true,
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
|
||||
OpenGLState::wasTextureCoordArrayEnabled = true,
|
||||
current_state.texture_coordinate_array = true,
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_2D))
|
||||
OpenGLState::wasTexture2DEnabled = true,
|
||||
current_state.texture_2D = true,
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
OpenGLState::wasCullFaceEnabled = false;
|
||||
current_state.cull_face = false;
|
||||
if (glIsEnabled(GL_CULL_FACE))
|
||||
OpenGLState::wasCullFaceEnabled = true,
|
||||
current_state.cull_face = true,
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (!glIsEnabled(GL_BLEND))
|
||||
OpenGLState::wasBlendEnabled = false,
|
||||
current_state.blend = false,
|
||||
glEnable(GL_BLEND),
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
OpenGLState::wasBlendEnabled = true;
|
||||
current_state.blend = true;
|
||||
|
||||
// Reset the lights.
|
||||
required_lights = empty_light_array;
|
||||
optional_lights = {};
|
||||
current_state.required_lights = empty_light_array;
|
||||
current_state.optional_lights = {};
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
if (!inJ2D)
|
||||
inJ3D = true;
|
||||
else
|
||||
Logger::Error("Beginning J3D context inside of J2D context?");
|
||||
}
|
||||
|
||||
void JGL::J3D::End() {
|
||||
if (!OpenGLState::wasDepthTestEnabled)
|
||||
if (!current_state.depth_test)
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (!OpenGLState::wasVertexArraysEnabled)
|
||||
if (!current_state.vertex_array)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (OpenGLState::wasTexture2DEnabled)
|
||||
if (current_state.texture_2D)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (!OpenGLState::wasBlendEnabled)
|
||||
if (!current_state.blend)
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (OpenGLState::wasCullFaceEnabled)
|
||||
if (current_state.cull_face)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
if (OpenGLState::wasNormalArrayEnabled)
|
||||
if (current_state.normal_array)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (OpenGLState::wasTextureCoordArrayEnabled)
|
||||
if (current_state.texture_coordinate_array)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_LIGHTING)) {
|
||||
@@ -135,25 +131,21 @@ void JGL::J3D::End() {
|
||||
glDisable(GL_LIGHT7);
|
||||
}
|
||||
|
||||
required_lights = empty_light_array;
|
||||
optional_lights = {};
|
||||
current_state.required_lights = empty_light_array;
|
||||
current_state.optional_lights = {};
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
inJ3D = false;
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
Vector3 vertices[] = {A, B};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
@@ -166,9 +158,6 @@ void JGL::J3D::WireframeSphere(const Color4& color, const Sphere& sphere, float
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
// Create one sphere with a radius of 1 about 0, 0.
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
|
||||
@@ -204,7 +193,7 @@ void JGL::J3D::BatchWireframeSphere(const Color4& color, const Sphere* spheres,
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
@@ -247,8 +236,9 @@ void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spher
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
// TODO allocate once.
|
||||
VRamList vertex_data(vertices.data(), vertices.size());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.Handle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
// Render each sphere in the batch at their given position and radius.
|
||||
@@ -256,21 +246,17 @@ void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spher
|
||||
glPushMatrix();
|
||||
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.Length());
|
||||
if (draw_stacks)
|
||||
glRotatef(90, 0, 1, 0),
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.Length());
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness,
|
||||
unsigned int subdivisions) {
|
||||
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
void JGL::J3D::WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int subdivisions) {
|
||||
|
||||
// NOTE2SELF: Code i'm borrowing this from uses float-packed-arrays rather than discrete Vectors
|
||||
// working on translating that correctly...
|
||||
@@ -341,9 +327,6 @@ void JGL::J3D::WireframeIcosphere(const Color4& color, const Vector3& position,
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeIcosahedron(const Color4& color, const Vector3& position, float radius, float thickness) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
|
||||
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
|
||||
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
|
||||
@@ -382,15 +365,16 @@ void JGL::J3D::WireframeIcosahedron(const Color4& color, const Vector3& position
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const size_t& box_count, float thickness) {
|
||||
glColor4ubv(color.ptr());
|
||||
glLineWidth(thickness);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->Handle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->Handle());
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
|
||||
@@ -398,11 +382,11 @@ void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const
|
||||
glPushMatrix();
|
||||
glTranslatef(center.x, center.y, center.z);
|
||||
glScalef(delta.x, delta.y, delta.z);
|
||||
glDrawArrays(GL_LINES, 0, ShapeCache::cube_vertex_data->GetLength());
|
||||
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->Length(), GL_UNSIGNED_INT, nullptr);
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeAABB(const Color4& color, const Vector3& pos, const Vector3& radii, float thickness) {
|
||||
@@ -411,14 +395,11 @@ void JGL::J3D::WireframeAABB(const Color4& color, const Vector3& pos, const Vect
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->Handle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->Handle());
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
@@ -427,7 +408,7 @@ void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_
|
||||
if (UsingLighting()) {
|
||||
using_lights = true;
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->GetHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->Handle());
|
||||
glNormalPointer(GL_FLOAT, sizeof(float), nullptr);
|
||||
}
|
||||
|
||||
@@ -445,7 +426,7 @@ void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
if (using_lights)
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisable(GL_CULL_FACE);
|
||||
@@ -464,9 +445,6 @@ void JGL::J3D::FillSphere(const Color4& color, const Sphere& sphere, unsigned in
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, unsigned int sectors, unsigned int stacks) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
|
||||
std::vector<unsigned int> indices; indices.reserve(sectors * stacks * 6);
|
||||
@@ -509,8 +487,8 @@ void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const
|
||||
VRamList index_data(indices.data(), indices.size());
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.GetHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.Handle());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.Handle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
for (size_t i = 0; i < sphere_count; i++) {
|
||||
@@ -518,12 +496,12 @@ void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawElements(GL_TRIANGLES, index_data.GetLength(), GL_UNSIGNED_INT, nullptr);
|
||||
glDrawElements(GL_TRIANGLES, index_data.Length(), GL_UNSIGNED_INT, nullptr);
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillSphere(const Color4& color, const Vector3& position, float radius, unsigned int sectors, unsigned int stacks) {
|
||||
@@ -556,7 +534,7 @@ void JGL::J3D::BatchWireframeOBB(const Color4& color, const OBB* boxes, const si
|
||||
glDrawElements(GL_LINES, indices.size(), GL_UNSIGNED_INT, indices.data());
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeOBB(const Color4& color, const OBB& obb, float thickness) {
|
||||
@@ -586,23 +564,21 @@ void JGL::J3D::DrawCubicBezierCurve(const Color4& color, const Vector3& controlA
|
||||
}
|
||||
|
||||
void JGL::J3D::DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->GetHandle());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->Handle());
|
||||
glVertexPointer(3, GL_FLOAT, 0, nullptr);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
//glScalef(1,1,1);
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->GetLength());
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->Length());
|
||||
glPopMatrix();
|
||||
|
||||
//glDrawElements(GL_LINES, vertex_array.GetIndices()->GetLength(), GL_UNSIGNED_INT, nullptr);
|
||||
//std::cout << vertex_array.GetVertices()->GetLength() << std::endl;
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
|
@@ -86,7 +86,10 @@ namespace JGL {
|
||||
u1, v0
|
||||
};
|
||||
|
||||
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
|
||||
float ascent = font.face->size->metrics.ascender / 64.0f;
|
||||
float descent = -font.face->size->metrics.descender / 64.0f;
|
||||
|
||||
cachedFont->appendGlyph(new CachedGlyph((char) charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6), ascent, descent));
|
||||
|
||||
xoffset += g->bitmap.width;
|
||||
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
|
||||
@@ -95,7 +98,7 @@ namespace JGL {
|
||||
return cachedFont;
|
||||
}
|
||||
|
||||
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
|
||||
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, u32 size, float scale, const Font& font) {
|
||||
// Offset by height to render at "correct" location.
|
||||
y += size;
|
||||
|
||||
@@ -134,7 +137,7 @@ namespace JGL {
|
||||
continue;
|
||||
|
||||
x2 = x + glyph->x2offset * scale;
|
||||
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
|
||||
y2 = y - glyph->y2offset * scale;
|
||||
w = glyph->w * scale;
|
||||
h = glyph->h * scale;
|
||||
x += glyph->advanceX * scale;
|
||||
@@ -156,9 +159,19 @@ namespace JGL {
|
||||
}
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
|
||||
|
||||
if (current_state.current_shader)
|
||||
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 1),
|
||||
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawString);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
|
||||
|
||||
if (current_state.current_shader)
|
||||
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 0),
|
||||
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glColor4fv(default_state.draw_color);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
@@ -238,13 +251,23 @@ namespace JGL {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
/*
|
||||
if (current_state.current_shader)
|
||||
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawString);
|
||||
*/
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
|
||||
|
||||
/*
|
||||
if (current_state.current_shader)
|
||||
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
|
||||
*/
|
||||
|
||||
if (!draw_back_face)
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glColor4fv(current_state.draw_color);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glPopMatrix();
|
||||
|
@@ -4,19 +4,19 @@
|
||||
|
||||
// TODO handle the case that a required light is in the list of optional lights.
|
||||
void JGL::J3D::SelectLights(const Vector3& position) {
|
||||
std::array<const LightBase*, 8> result = required_lights;
|
||||
std::array<const LightBase*, 8> result = current_state.required_lights;
|
||||
|
||||
unsigned int required_light_count = 0;
|
||||
for (const auto& i : result)
|
||||
if (i) required_light_count++;
|
||||
|
||||
// If there is optional lights.
|
||||
if (!optional_lights.empty()) {
|
||||
if (!current_state.optional_lights.empty()) {
|
||||
// The number of lights we need to solve for
|
||||
unsigned int remaining_lights = 8 - required_light_count;
|
||||
|
||||
std::vector<std::pair<float, const LightBase*>> light_influence;
|
||||
for (const auto* light: optional_lights)
|
||||
for (const auto* light: current_state.optional_lights)
|
||||
light_influence.emplace_back(light->GetAttenuationAtPosition(position), light);
|
||||
|
||||
// Sort by biggest influence.
|
||||
@@ -82,11 +82,11 @@ void JGL::J3D::ResetLights() {
|
||||
}
|
||||
|
||||
bool JGL::J3D::UsingLighting() {
|
||||
if (!optional_lights.empty())
|
||||
if (!current_state.optional_lights.empty())
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i < required_lights.size(); i++)
|
||||
if (required_lights[i])
|
||||
for (unsigned int i = 0; i < current_state.required_lights.size(); i++)
|
||||
if (current_state.required_lights[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -117,3 +117,101 @@ std::vector<Vector3> JGL::TriangleMeshVertexNormals(const Vector3* vertices, con
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
void JGL::StateStack::Push(const JGL::State& state) {
|
||||
states.push_back(state);
|
||||
}
|
||||
|
||||
void JGL::StateStack::Pop() {
|
||||
states.pop_back();
|
||||
}
|
||||
|
||||
JGL::State* JGL::StateStack::PreviousState() {
|
||||
if (states.empty())
|
||||
return nullptr;
|
||||
|
||||
return &states.back();
|
||||
}
|
||||
|
||||
JGL::State JGL::State::SaveState(const State& state) {
|
||||
State result;
|
||||
|
||||
result.depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
result.vertex_array = glIsEnabled(GL_VERTEX_ARRAY);
|
||||
result.normal_array = glIsEnabled(GL_NORMAL_ARRAY);
|
||||
result.cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
result.blend = glIsEnabled(GL_BLEND);
|
||||
result.texture_2D = glIsEnabled(GL_TEXTURE_2D);
|
||||
result.texture_coordinate_array = glIsEnabled(GL_TEXTURE_COORD_ARRAY);
|
||||
result.color_array = glIsEnabled(GL_COLOR_ARRAY);
|
||||
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &result.selected_texture_unit);
|
||||
result.selected_texture_unit -= GL_TEXTURE0;
|
||||
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, result.clear_color);
|
||||
glGetFloatv(GL_CURRENT_COLOR, result.draw_color);
|
||||
glGetIntegerv(GL_VIEWPORT, result.viewport);
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&result.current_fbo);
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &result.current_shader_handle);
|
||||
result.current_shader = state.current_shader;
|
||||
glGetIntegerv(GL_BLEND_SRC, &result.blend_func[0]);
|
||||
glGetIntegerv(GL_BLEND_DST, &result.blend_func[1]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void JGL::State::RestoreState(const State& state) {
|
||||
if (state.depth_test)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (state.vertex_array)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (state.normal_array)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (state.cull_face)
|
||||
glEnable(GL_CULL_FACE);
|
||||
else
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (state.blend)
|
||||
glEnable(GL_BLEND);
|
||||
else
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
|
||||
glClientActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
|
||||
|
||||
if (state.texture_2D)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
else
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
if (state.texture_coordinate_array)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (state.color_array)
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
if (state.current_shader)
|
||||
glUseProgram(state.current_shader->Handle());
|
||||
else
|
||||
glUseProgram(0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, state.current_fbo);
|
||||
glViewport(state.viewport[0], state.viewport[1], state.viewport[2], state.viewport[3]);
|
||||
glClearColor(state.clear_color[0], state.clear_color[1], state.clear_color[2], state.clear_color[3]);
|
||||
glColor4f(state.draw_color[0], state.draw_color[1], state.draw_color[2], state.draw_color[3]);
|
||||
glBlendFunc(state.blend_func[0], state.blend_func[1]);
|
||||
}
|
||||
|
@@ -6,47 +6,118 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/types/Light.h>
|
||||
#include <JGL/types/Shader.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
namespace JGL {
|
||||
inline constexpr std::array<const LightBase*, 8> empty_light_array = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
|
||||
inline bool inJ2D = false;
|
||||
inline bool inJ3D = false;
|
||||
std::vector<Vector3> TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count);
|
||||
class State;
|
||||
class StateStack;
|
||||
enum RENDERING_ROUTINE_ID : int32_t;
|
||||
}
|
||||
|
||||
namespace JGL::OpenGLState {
|
||||
inline JGL::RenderTarget* render_target = nullptr;
|
||||
inline Vector2 window_size;
|
||||
enum JGL::RENDERING_ROUTINE_ID : int32_t {
|
||||
J2D_DrawPoint = 1,
|
||||
J2D_DrawPoints = 2,
|
||||
J2D_DrawLine = 3,
|
||||
J2D_DrawLines = 4,
|
||||
J2D_DrawDottedLine = 5,
|
||||
J2D_DrawDashedLine = 6,
|
||||
J2D_DrawGradientLine = 7,
|
||||
J2D_OutlineRect = 8,
|
||||
J2D_OutlineRoundedRect = 9,
|
||||
J2D_OutlineChamferRect = 10,
|
||||
J2D_FillRect = 11,
|
||||
J2D_FillGradientRect = 12,
|
||||
J2D_FillRoundedRect = 13,
|
||||
J2D_FillChamferRect = 14,
|
||||
J2D_DrawRenderTarget = 15,
|
||||
J2D_DrawPartialRenderTarget = 16,
|
||||
J2D_DrawSprite = 17,
|
||||
J2D_DrawAlphaMaskSprite = 18,
|
||||
J2D_DrawPartialSprite = 19,
|
||||
J2D_DrawMirrorSprite = 20,
|
||||
J2D_OutlineCircle = 21,
|
||||
J2D_FillCircle = 22,
|
||||
J2D_OutlineTriangle = 23,
|
||||
J2D_FillTriangle = 24,
|
||||
J2D_FillGradientTriangle = 25,
|
||||
J2D_DrawCubicBezierCurve = 26,
|
||||
J2D_OutlinePolygon = 27,
|
||||
J2D_DrawString = 28,
|
||||
J2D_DrawArc = 29,
|
||||
};
|
||||
|
||||
inline GLfloat oldColor[4] = {0, 0, 0, 1};
|
||||
inline GLfloat baseColor[4] = {1, 1, 1, 1};
|
||||
class JGL::State {
|
||||
public:
|
||||
|
||||
inline GLuint current_fbo = 0;
|
||||
inline GLint viewport[4] = {0, 0, 0, 0};
|
||||
//Matrix4x4 transformation = Matrix4x4::Identity;
|
||||
GLfloat clear_color[4] = {0, 0, 0, 1};
|
||||
GLfloat draw_color[4] = {1, 1, 1, 1};
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
GLint blend_func[2];
|
||||
GLuint current_fbo = 0;
|
||||
RenderTarget* current_render_target = nullptr;
|
||||
GLint current_shader_handle = 0;
|
||||
Shader* current_shader = nullptr;
|
||||
|
||||
inline bool wasTexture2DEnabled = false;
|
||||
inline bool wasTextureCoordArrayEnabled = false;
|
||||
inline bool wasNormalArrayEnabled = false;
|
||||
bool texture_2D = false;
|
||||
bool texture_coordinate_array = false;
|
||||
bool normal_array = false;
|
||||
bool depth_test = false;
|
||||
bool vertex_array = false;
|
||||
bool cull_face = false;
|
||||
bool blend = false;
|
||||
bool color_array = false;
|
||||
GLint selected_texture_unit = 0;
|
||||
// List of lights required for each object in the scene. up-to 8. For example, the sun. Or a flash-light.
|
||||
std::array<const LightBase*, 8> required_lights{};
|
||||
// List of all lights in the scene.
|
||||
std::vector<const LightBase*> optional_lights{};
|
||||
public:
|
||||
static State SaveState(const State& state);
|
||||
static void RestoreState(const State& state);
|
||||
};
|
||||
|
||||
inline bool wasDepthTestEnabled = false;
|
||||
inline bool wasVertexArraysEnabled = false;
|
||||
inline bool wasCullFaceEnabled = false;
|
||||
inline bool wasBlendEnabled = false;
|
||||
inline bool wasColorArrayEnabled = false;
|
||||
inline GLint activeTextureUnit = 0;
|
||||
class JGL::StateStack {
|
||||
private:
|
||||
std::vector<State> states{};
|
||||
public:
|
||||
size_t Size() { return states.size(); }
|
||||
void Push(const State& state);
|
||||
void Pop();
|
||||
State* PreviousState();
|
||||
public:
|
||||
StateStack() = default;
|
||||
~StateStack() = default;
|
||||
};
|
||||
|
||||
namespace JGL {
|
||||
inline constexpr std::array<const LightBase*, 8> empty_light_array = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
|
||||
std::vector<Vector3> TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count);
|
||||
inline StateStack state_stack;
|
||||
inline Vector2i window_size;
|
||||
inline bool supports_instanced = true;
|
||||
}
|
||||
|
||||
namespace JGL::J2D {
|
||||
inline std::array<const LightBase*, 8> required_lights;
|
||||
inline std::vector<const LightBase*> light_array;
|
||||
// On windoze this can't be constexpr?
|
||||
inline State default_state
|
||||
{
|
||||
{0, 0, 0, 1},
|
||||
{1, 1, 1, 1},
|
||||
{0, 0, 0, 0},
|
||||
{GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
|
||||
0, nullptr, 0, nullptr, false, false,
|
||||
false, false, true, true,
|
||||
true, false, 0,
|
||||
{}, {}
|
||||
};
|
||||
|
||||
inline State current_state;
|
||||
}
|
||||
|
||||
namespace JGL::J3D {
|
||||
// List of lights required for each objects in the scene. up-to 8. For example, the sun. Or a flash-light.
|
||||
inline std::array<const LightBase*, 8> required_lights;
|
||||
// List of all lights in the scene.
|
||||
inline std::vector<const LightBase*> optional_lights;
|
||||
inline State current_state;
|
||||
inline float far_plane = 0;
|
||||
inline float fov = 0;
|
||||
// Enables lighting and selects the correct lights to use.
|
||||
|
@@ -108,61 +108,32 @@ namespace JGL {
|
||||
return Font(path);
|
||||
}
|
||||
|
||||
Vector2 Font::MeasureString(const std::string &text, unsigned int ptSize) {
|
||||
Vector2 extents = Vector2(0,0);
|
||||
bool font_of_size_in_cache = false;
|
||||
Vector2 Font::MeasureString(const std::string& text, unsigned int ptSize) {
|
||||
Vector2 extents = Vector2::Zero;
|
||||
|
||||
for(const auto& f : fontCache.getFonts()) {
|
||||
if (f->getFontSize() == ptSize) {
|
||||
font_of_size_in_cache = true;
|
||||
break;
|
||||
for(auto& f : fontCache.getFonts()) {
|
||||
if (f->getFontIndex() == this->index) {
|
||||
for (const char &c: text) {
|
||||
auto glyph = f->getGlyph(c);
|
||||
extents.x += glyph->advanceX;
|
||||
extents.y = glyph->ascent + glyph->descent;
|
||||
}
|
||||
return extents;
|
||||
}
|
||||
}
|
||||
|
||||
if (font_of_size_in_cache) {
|
||||
CachedFont* font;
|
||||
|
||||
for (auto* f: fontCache.getFonts())
|
||||
if (f->getFontSize() == ptSize)
|
||||
font = f;
|
||||
|
||||
for (const char& c : text)
|
||||
extents.x += font->getGlyph(c)->advanceX;
|
||||
|
||||
extents.y = ptSize;
|
||||
return extents;
|
||||
}
|
||||
|
||||
jlog::Warning("Measuring a font size that is not cached, Defaulting to Jupiteroid.");
|
||||
FT_Set_Pixel_Sizes(Fonts::Jupiteroid.face, ptSize, ptSize);
|
||||
|
||||
// No cache
|
||||
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
|
||||
for (const char& c : text) {
|
||||
// TODO: Fix segfault
|
||||
//FT_GlyphSlot slot = Fonts::Jupiteroid.face->glyph;
|
||||
//auto glyph_index = FT_Get_Char_Index(Fonts::Jupiteroid.face, c);
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
auto glyph_index = FT_Get_Char_Index(this->face, c);
|
||||
|
||||
//auto error = FT_Load_Glyph(Fonts::Jupiteroid.face, glyph_index, FT_LOAD_DEFAULT);
|
||||
auto error = FT_Load_Glyph(this->face, glyph_index, FT_LOAD_DEFAULT);
|
||||
|
||||
if (error)
|
||||
continue;
|
||||
|
||||
|
||||
Vector2 advance = {static_cast<float>(slot->advance.x >> 6),
|
||||
static_cast<float>(slot->advance.y >> 6)};
|
||||
|
||||
|
||||
extents += advance;
|
||||
|
||||
// Gives smaller results than we'd want.
|
||||
if (extents.y < slot->metrics.height / 64)
|
||||
extents.y = slot->metrics.height / 64;
|
||||
|
||||
// Just fucking hardcode it, we know the glyph height is roughly always the ptSize anyway.
|
||||
if (extents.y < ptSize)
|
||||
extents.y = ptSize;
|
||||
extents.x += static_cast<float>(slot->advance.x >> 6);
|
||||
extents.y = (face->size->metrics.ascender / 64.0f) + (-face->size->metrics.descender / 64.0f);
|
||||
}
|
||||
return extents;
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
|
||||
return texcoords;
|
||||
}
|
||||
|
||||
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
|
||||
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY, float asc, float desc) {
|
||||
character = c;
|
||||
this->x2offset = x2offset;
|
||||
this->y2offset = y2offset;
|
||||
@@ -19,6 +19,8 @@ CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offs
|
||||
this->advanceX = advanceX;
|
||||
this->advanceY = advanceY;
|
||||
this->texcoords = texcoords;
|
||||
this->ascent = asc;
|
||||
this->descent = desc;
|
||||
}
|
||||
|
||||
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
|
||||
|
@@ -44,7 +44,7 @@ void JGL::RenderTarget::Erase() {
|
||||
glDeleteFramebuffers(1, &framebuffer_object);
|
||||
|
||||
if (MSAAEnabled())
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
SetMSAAEnabled(SampleRate::NONE);
|
||||
}
|
||||
|
||||
Color4 JGL::RenderTarget::GetClearColor() const {
|
||||
@@ -76,7 +76,7 @@ JGL::RenderTarget::RenderTarget(const JGL::Texture* texture, const Color4& clear
|
||||
texture_created_by_us = false;
|
||||
}
|
||||
|
||||
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
|
||||
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, SampleRate sample_rate, FilteringMode filtering_mode) {
|
||||
if (size.x < 1 || size.y < 1)
|
||||
Logger::Fatal("Creating a render target where the color attachment is empty?");
|
||||
|
||||
@@ -85,7 +85,7 @@ JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color,
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
//Textures behave strangely if they're not square aaaaaaaaaaaaa.
|
||||
|
||||
texture = new Texture(size);
|
||||
texture = new Texture(size, filtering_mode);
|
||||
glGenFramebuffers(1, &framebuffer_object);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
glViewport(0,0, size.x, size.y);
|
||||
@@ -116,7 +116,7 @@ JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color,
|
||||
this->size = size;
|
||||
texture_created_by_us = true;
|
||||
|
||||
if (sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
if (sample_rate != SampleRate::NONE)
|
||||
SetMSAAEnabled(sample_rate);
|
||||
}
|
||||
|
||||
@@ -140,30 +140,10 @@ void JGL::RenderTarget::Resize(const Vector2i& new_size) {
|
||||
glGetIntegerv(GL_VIEWPORT, old_viewport);
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
|
||||
|
||||
/* If what was previously not part of the renderable area is big enough
|
||||
* to just set the new size. */
|
||||
if (new_size.x <= texture->GetDimensions().x && new_size.y <= texture->GetDimensions().y) {
|
||||
size = new_size;
|
||||
|
||||
// Clear.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
auto cc = GetClearColor();
|
||||
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
|
||||
glViewport(0,0, size.x, size.y);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (using_depth)
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
|
||||
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
//If we have to remake the texture.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
|
||||
// Erase it.
|
||||
delete texture;
|
||||
|
||||
@@ -181,8 +161,8 @@ void JGL::RenderTarget::Resize(const Vector2i& new_size) {
|
||||
|
||||
//Disable & Re-enable MSAA so the msaa buffer is remade with the correct dimensions.
|
||||
if (MSAAEnabled()) {
|
||||
MSAA_SAMPLE_RATE current_sample_rate = msaa_sample_rate;
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
SampleRate current_sample_rate = msaa_sample_rate;
|
||||
SetMSAAEnabled(SampleRate::NONE);
|
||||
SetMSAAEnabled(current_sample_rate);
|
||||
}
|
||||
}
|
||||
@@ -197,15 +177,15 @@ bool JGL::RenderTarget::OwnsTexture() const {
|
||||
return texture_created_by_us;
|
||||
}
|
||||
|
||||
JGL::MSAA_SAMPLE_RATE JGL::RenderTarget::GetMSAASampleRate() const {
|
||||
JGL::SampleRate JGL::RenderTarget::GetMSAASampleRate() const {
|
||||
return msaa_sample_rate;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::MSAAEnabled() const {
|
||||
return msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
return msaa_sample_rate != SampleRate::NONE;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
bool JGL::RenderTarget::SetMSAAEnabled(JGL::SampleRate sample_rate) {
|
||||
// If we'd be setting the same sample_rate we already have.
|
||||
if (sample_rate == msaa_sample_rate)
|
||||
return false;
|
||||
@@ -215,7 +195,7 @@ bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
return false;
|
||||
|
||||
// Remove it if they request no msaa or if what they requested is different than what they already have.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE || msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE) {
|
||||
if (sample_rate == SampleRate::NONE || msaa_sample_rate != SampleRate::NONE) {
|
||||
if(using_depth)
|
||||
glDeleteRenderbuffers(1, &msaa_depth_buffer);
|
||||
|
||||
@@ -225,10 +205,10 @@ bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
msaa_framebuffer_object = 0;
|
||||
msaa_depth_buffer = 0;
|
||||
msaa_render_buffer = 0;
|
||||
msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
msaa_sample_rate = SampleRate::NONE;
|
||||
|
||||
// Only return here if they specifically requested no MSAA. else continue to change mode.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
if (sample_rate == SampleRate::NONE)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -240,27 +220,26 @@ bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, ¤t_renderbuffer);
|
||||
glGenRenderbuffers(1, &msaa_render_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa_render_buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, JGL::to_int(sample_rate), GL_RGBA, size.x, size.y);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, to_int(sample_rate), GL_RGBA, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa_render_buffer);
|
||||
|
||||
if (using_depth) {
|
||||
glGenRenderbuffers(1, &msaa_depth_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa_depth_buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, JGL::to_int(sample_rate), GL_DEPTH_COMPONENT, size.x, size.y);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, to_int(sample_rate), GL_DEPTH_COMPONENT, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaa_depth_buffer);
|
||||
}
|
||||
|
||||
bool failure = false;
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
failure = true,
|
||||
Logger::Fatal("A new MSAA " + std::to_string(to_int(sample_rate)) + "x framebuffer couldn't be allocated.");
|
||||
failure = true, Logger::Fatal("A new " + to_string(sample_rate) + " framebuffer couldn't be allocated.");
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, current_renderbuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
msaa_sample_rate = sample_rate;
|
||||
|
||||
if (failure)
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
SetMSAAEnabled(SampleRate::NONE);
|
||||
return failure;
|
||||
}
|
||||
|
||||
@@ -283,19 +262,6 @@ void JGL::RenderTarget::MSAABlit() const {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
// Fixes using render targets on a texture that has mipmaps.
|
||||
if (GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_NEAREST
|
||||
|| GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_BILINEAR ||
|
||||
GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_TRILINEAR) {
|
||||
GLint current_texture = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, GetTexture()->GetHandle());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, current_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination, const Vector2i& position) {
|
||||
@@ -322,7 +288,7 @@ void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget*
|
||||
|
||||
void JGL::RenderTarget::Blit(const Texture* source, RenderTarget* destination, const Vector2i& position) {
|
||||
auto temp = new RenderTarget(source);
|
||||
Blit(*temp, destination);
|
||||
Blit(*temp, destination, position);
|
||||
delete temp;
|
||||
}
|
||||
|
||||
@@ -381,3 +347,22 @@ JGL::RenderTarget::RenderTarget(const JGL::RenderTarget& rhs) {
|
||||
|
||||
operator delete(this_render_target);
|
||||
}
|
||||
|
||||
Vector2i JGL::RenderTarget::MaxSize() {
|
||||
return Texture::MaxSize();
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::RegenerateMipMaps() {
|
||||
// Fixes using render targets on a texture that has mipmaps.
|
||||
if (GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_NEAREST
|
||||
|| GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_BILINEAR ||
|
||||
GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_TRILINEAR) {
|
||||
GLint current_texture = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, GetTexture()->GetHandle());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, current_texture);
|
||||
}
|
||||
}
|
||||
|
269
src/types/Shader.cpp
Normal file
269
src/types/Shader.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
#include <JGL/types/Shader.h>
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace JGL {
|
||||
|
||||
class ShaderPreprocessor {
|
||||
public:
|
||||
std::string include_keyword = "#include";
|
||||
ShaderPreprocessor() {}
|
||||
std::string LoadShaderFile(const std::filesystem::path& filepath)
|
||||
{
|
||||
// if size is 0, it indicates, that we are at the top of the recursive load stack
|
||||
bool stack_top = (already_included.size() == 0);
|
||||
|
||||
if (stack_top) {
|
||||
already_included.emplace_back(filepath.string());
|
||||
}
|
||||
|
||||
std::string ret_data = "";
|
||||
std::ifstream file(filepath);
|
||||
|
||||
if (!file.good())
|
||||
{
|
||||
std::cout << "ERROR [ ShaderLoader::load_shader ]: Failed to start fstream, check if '" << filepath << "' exists\n";
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
if (file.is_open()) {
|
||||
std::string line;
|
||||
while (getline(file, line)) {
|
||||
if (line.find(include_keyword) == 0)
|
||||
{
|
||||
// Get path between double quotes
|
||||
std::string rel_include_path = extract_first_between(line.substr(include_keyword.length()), '"', '"');
|
||||
|
||||
// Modify path according to os
|
||||
// TODO: Use std::filesystem dummy...
|
||||
// later, let me get this stolen code to work first.
|
||||
#ifdef _WIN32
|
||||
std::replace(rel_include_path.begin(), rel_include_path.end(), '/', '\\');
|
||||
#elif __linux__
|
||||
std::replace(rel_include_path.begin(), rel_include_path.end(), '\\', '/');
|
||||
#endif
|
||||
std::string full_include_path = extract_path(filepath.string()) + rel_include_path;
|
||||
|
||||
// Avoid including self
|
||||
if (filepath == full_include_path) {
|
||||
std::cout << "WARNING [ ShaderLoader::load_shader ]: '"<< filepath <<"' tried to include itself\n";
|
||||
continue;
|
||||
} else {
|
||||
bool include_flag = true;
|
||||
// check if the current file is already included
|
||||
for (const auto& file_to_check : already_included) {
|
||||
// Avoid duplicate includes
|
||||
if (file_to_check == full_include_path) {
|
||||
include_flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not yet included, push path to include vector and replace line with file contents
|
||||
if (include_flag) {
|
||||
already_included.push_back(full_include_path);
|
||||
// Repeat recursively.
|
||||
ret_data += LoadShaderFile(full_include_path) + '\n';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret_data += line + "\n";
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
std::cout << "ERROR [ ShaderLoader::load_shader ]: Unable to open file '" << filepath << "'\n";
|
||||
}
|
||||
|
||||
// We are back to the first call
|
||||
if (stack_top) {
|
||||
already_included.clear();
|
||||
}
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string PreprocessShaderSource(const std::string& source);
|
||||
private:
|
||||
std::vector<std::string> already_included;
|
||||
/// Helper function that strips filename from a path, basically getting the path to the directory containing the file.
|
||||
std::string extract_path(const std::string& path)
|
||||
{
|
||||
// find the position of the last directory separator.
|
||||
std::size_t pos = path.find_last_of("\\/");
|
||||
|
||||
// strip fname from path
|
||||
if (pos != std::string::npos) {
|
||||
return path.substr(0, pos+1);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
std::string extract_first_between(const std::string& input, char start_symbol, char end_symbol)
|
||||
{
|
||||
size_t start_index = input.find(start_symbol);
|
||||
size_t end_index = input.find(end_symbol, start_index+1);
|
||||
|
||||
std::string extracted = "";
|
||||
if (start_index != std::string::npos && end_index != std::string::npos) {
|
||||
extracted = input.substr(start_index + 1, end_index - start_index - 1);
|
||||
} else {
|
||||
std::cout << "ERROR [ ShaderLoader::extract_first_between ]: Start '" << start_symbol << "' or end symbol '" << end_symbol << "' not found" << std::endl;
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
};
|
||||
|
||||
Shader::Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path, const std::vector<std::pair<std::string, GLint>>& attribute_bindings) :
|
||||
Shader(ReadFile(vertex_source_path), ReadFile(fragment_source_path), attribute_bindings) {
|
||||
vertexPath = vertex_source_path.string();
|
||||
fragmentPath = fragment_source_path.string();
|
||||
}
|
||||
|
||||
void Shader::checkCompileErrors(GLuint shader, const std::string& type) {
|
||||
GLint success;
|
||||
GLchar infoLog[1024];
|
||||
|
||||
if (type != "PROGRAM") {
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(shader, 1024, nullptr, infoLog);
|
||||
OnCompilationErrorMessage.Invoke( std::format("COMPILATION_ERROR: {}", type), infoLog);
|
||||
}
|
||||
} else {
|
||||
glGetProgramiv(shader, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetProgramInfoLog(shader, 1024, nullptr, infoLog);
|
||||
OnCompilationErrorMessage.Invoke(std::format("COMPILATION_ERROR: {}", type), infoLog);
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
std::cout << "Shader compiled successfully" << std::endl;
|
||||
}
|
||||
|
||||
GLint Shader::Uniform(const std::string &name) const {
|
||||
auto it = uniform_location_cache.find(name);
|
||||
if (it == uniform_location_cache.end()) {
|
||||
auto location = glGetUniformLocation(id, name.c_str());
|
||||
uniform_location_cache[name] = location;
|
||||
return location;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
GLint Shader::Attribute(const std::string &name) const {
|
||||
return glGetAttribLocation(id, name.c_str());
|
||||
}
|
||||
|
||||
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings) {
|
||||
vertexSource = vertex_code;
|
||||
fragmentSource = fragment_code;
|
||||
|
||||
const char* vShaderCode = vertex_code.c_str();
|
||||
const char* fShaderCode = fragment_code.c_str();
|
||||
|
||||
// 2. Compile shaders.
|
||||
unsigned int vertex, fragment;
|
||||
|
||||
// vertex shader.
|
||||
vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertex, 1, &vShaderCode, nullptr);
|
||||
glCompileShader(vertex);
|
||||
checkCompileErrors(vertex, "VERTEX");
|
||||
|
||||
// fragment shader
|
||||
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment, 1, &fShaderCode, nullptr);
|
||||
glCompileShader(fragment);
|
||||
checkCompileErrors(fragment, "FRAGMENT");
|
||||
|
||||
// shader Program
|
||||
id = glCreateProgram();
|
||||
|
||||
// bind attribute locations.
|
||||
for (auto& a: attribute_bindings)
|
||||
glBindAttribLocation(id, a.second, a.first.c_str());
|
||||
|
||||
glAttachShader(id, vertex);
|
||||
glAttachShader(id, fragment);
|
||||
glLinkProgram(id);
|
||||
checkCompileErrors(id, "PROGRAM");
|
||||
|
||||
// delete the shaders as they're linked into our program now and are no longer necessary
|
||||
glDeleteShader(vertex);
|
||||
glDeleteShader(fragment);
|
||||
}
|
||||
|
||||
bool Shader::Loaded() const { return id != 0; }
|
||||
|
||||
unsigned int Shader::Handle() const { return id;}
|
||||
|
||||
void Shader::SetBool(const std::string &name, bool value) const { glUniform1i(Uniform(name), (int)value); }
|
||||
|
||||
void Shader::SetInt(const std::string &name, int value) const { glUniform1i(Uniform(name), value); }
|
||||
|
||||
void Shader::SetFloat(const std::string &name, float value) const { glUniform1f(Uniform(name), value); }
|
||||
|
||||
void Shader::SetVector2(const std::string &name, const Vector2 &value) const { glUniform2f(Uniform(name), value.x, value.y); }
|
||||
|
||||
void Shader::SetVector2(const std::string &name, float x, float y) const { glUniform2f(Uniform(name), x, y); }
|
||||
|
||||
void Shader::SetVector3(const std::string &name, const Vector3 &value) const { glUniform3f(Uniform(name), value.x, value.y, value.z); }
|
||||
|
||||
void Shader::SetVector3(const std::string &name, float x, float y, float z) const { glUniform3f(Uniform(name), x, y, z); }
|
||||
|
||||
void Shader::SetVector4(const std::string &name, const Vector4 &value) const { glUniform4f(Uniform(name), value.x, value.y, value.z, value.w); }
|
||||
|
||||
void Shader::SetVector4(const std::string &name, float x, float y, float z, float w) const { glUniform4f(Uniform(name), x, y, z, w); }
|
||||
|
||||
void Shader::SetMatrix2x2(const std::string &name, const Matrix2x2 &value) const {
|
||||
/// TODO: Verify if glsl expects row-major or col-major!!
|
||||
bool transpose = false;
|
||||
glUniformMatrix2fv(Uniform(name), 4, transpose, value.ptr());
|
||||
}
|
||||
|
||||
void Shader::SetMatrix3x3(const std::string &name, const Matrix3x3 &value) const {
|
||||
/// TODO: Verify if glsl expects row-major or col-major!!
|
||||
bool transpose = false;
|
||||
glUniformMatrix3fv(Uniform(name), 9, transpose, value.ptr());
|
||||
}
|
||||
|
||||
void Shader::SetMatrix4x4(const std::string &name, const Matrix4x4 &value) const {
|
||||
/// TODO: Verify if glsl expects row-major or col-major!!
|
||||
bool transpose = false;
|
||||
glUniformMatrix4fv(Uniform(name), 16, transpose, value.ptr());
|
||||
}
|
||||
|
||||
std::string Shader::ReadFile(const std::filesystem::path &path) {
|
||||
/*std::string contents;
|
||||
|
||||
std::ifstream file;
|
||||
|
||||
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
|
||||
try {
|
||||
// Open Files
|
||||
file.open(path);
|
||||
std::stringstream stream;
|
||||
|
||||
// Read file's buffer contents into streams
|
||||
stream << file.rdbuf();
|
||||
|
||||
// close file handlers
|
||||
file.close();
|
||||
|
||||
// convert stream into string
|
||||
contents = stream.str();
|
||||
|
||||
return contents;
|
||||
} catch (std::ifstream::failure& e) {
|
||||
std::cout << "ERROR::FILE_READ_FAILURE: " << e.what() << std::endl;
|
||||
return "";
|
||||
}*/
|
||||
|
||||
ShaderPreprocessor processor;
|
||||
return processor.LoadShaderFile(path);
|
||||
}
|
||||
}
|
@@ -9,8 +9,8 @@
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
Texture::Texture(const std::filesystem::path& file, FilteringMode filtering_mode, WrappingMode wrapping_mode, bool invert_y) :
|
||||
invert_y(invert_y), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode) {
|
||||
Texture::Texture(const std::filesystem::path& file, FilteringMode filtering_mode, SampleRate anisotropy, WrappingMode wrapping_mode, bool invert_y) :
|
||||
invert_y(invert_y), filtering_mode(filtering_mode), anisotropy(anisotropy), wrapping_mode(wrapping_mode) {
|
||||
std::vector<unsigned char> pixels{};
|
||||
|
||||
std::ifstream ifStream(file, std::ios::in | std::ios::binary);
|
||||
@@ -30,7 +30,7 @@ invert_y(invert_y), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode)
|
||||
|
||||
|
||||
if (invert_y) {
|
||||
unsigned int row_size = size.x * 4;;
|
||||
unsigned int row_size = size.x * 4;
|
||||
if (format == ColorFormat::RGB)
|
||||
row_size = size.x * 3;
|
||||
|
||||
@@ -51,7 +51,7 @@ std::vector<unsigned char> Texture::png(const std::filesystem::path& file) {
|
||||
std::vector<unsigned char> result{};
|
||||
int channels;
|
||||
|
||||
unsigned char* image_data = stbi_load(file.c_str(), &size.x, &size.y, &channels, 0);
|
||||
unsigned char* image_data = stbi_load(file.string().c_str(), &size.x, &size.y, &channels, 0);
|
||||
if (!image_data)
|
||||
Logger::Fatal("Trying to load a texture from: " + file.string() + "but we couldn't read the file.");
|
||||
|
||||
@@ -98,7 +98,9 @@ std::vector<unsigned char> Texture::bmp(const std::filesystem::path& file) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture::Texture(const Vector2i& size) : invert_y(true), format(ColorFormat::RGBA), size(size), filtering_mode(FilteringMode::NEAREST), wrapping_mode(WrappingMode::CLAMP_TO_EDGE) {
|
||||
Texture::Texture(const Vector2i& size, FilteringMode filtering_mode) : invert_y(true), format(ColorFormat::RGBA), size(size), filtering_mode(filtering_mode), wrapping_mode(WrappingMode::CLAMP_TO_EDGE) {
|
||||
if (SizeExceedsMaximum(size))
|
||||
Logger::Error("Creating a texture where the size is bigger than the maximum for this system, use Texture::MaximumSize() to check for this beforehand.");
|
||||
GLuint previous_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
|
||||
|
||||
@@ -107,6 +109,27 @@ Texture::Texture(const Vector2i& size) : invert_y(true), format(ColorFormat::RGB
|
||||
//NEAREST
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
if (filtering_mode == FilteringMode::NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if (filtering_mode == FilteringMode::MIPMAP_NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_TRILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
//Clamp
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
@@ -114,8 +137,11 @@ Texture::Texture(const Vector2i& size) : invert_y(true), format(ColorFormat::RGB
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glBindTexture(GL_TEXTURE_2D, previous_texture);
|
||||
}
|
||||
|
||||
void Texture::load(const unsigned char* pixels) {
|
||||
// TODO a static member function to query for this.
|
||||
if (SizeExceedsMaximum(size))
|
||||
Logger::Error("Creating a texture where the size is bigger than the maximum for this system.");
|
||||
|
||||
GLuint previous_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
|
||||
|
||||
@@ -144,17 +170,9 @@ void Texture::load(const unsigned char* pixels) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
|
||||
if (filtering_mode == FilteringMode::NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_NEAREST ||
|
||||
filtering_mode == FilteringMode::MIPMAP_BILINEAR ||
|
||||
filtering_mode == FilteringMode::MIPMAP_TRILINEAR) {
|
||||
if (filtering_mode == FilteringMode::MIPMAP_NEAREST ||
|
||||
filtering_mode == FilteringMode::MIPMAP_BILINEAR ||
|
||||
filtering_mode == FilteringMode::MIPMAP_TRILINEAR) {
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
@@ -170,6 +188,28 @@ void Texture::load(const unsigned char* pixels) {
|
||||
else if (filtering_mode == FilteringMode::MIPMAP_TRILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if (anisotropy != SampleRate::NONE) {
|
||||
if (anisotropy > MaxAnisotropySampleRate())
|
||||
Logger::Error("Anisotropy set higher than the maximum value for this system, disabled, use Texture::MaxAnisotropy()."),
|
||||
anisotropy = SampleRate::NONE;
|
||||
else
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, (int) anisotropy);
|
||||
}
|
||||
}
|
||||
|
||||
else if (filtering_mode == FilteringMode::NEAREST || filtering_mode == FilteringMode::BILINEAR) {
|
||||
if (filtering_mode == FilteringMode::NEAREST)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
else if (filtering_mode == FilteringMode::BILINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR),
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if (anisotropy != SampleRate::NONE)
|
||||
Logger::Error("Anisotropy only applies when using mipmaps with a 3D perspective, disabled."),
|
||||
anisotropy = SampleRate::NONE;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, previous_texture);
|
||||
}
|
||||
@@ -221,13 +261,13 @@ WrappingMode Texture::GetWrappingMode() const {
|
||||
return wrapping_mode;
|
||||
}
|
||||
|
||||
Texture::Texture(const Color4* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode) :
|
||||
size(size), format(format), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode) {
|
||||
Texture::Texture(const Color4* pixels, const Vector2i& size, FilteringMode filtering_mode, SampleRate anisotropy, WrappingMode wrapping_mode) :
|
||||
size(size), format(ColorFormat::RGBA), filtering_mode(filtering_mode), anisotropy(anisotropy), wrapping_mode(wrapping_mode) {
|
||||
load((unsigned char*) pixels);
|
||||
}
|
||||
|
||||
Texture::Texture(const Color3* pixels, const Vector2i& size, const ColorFormat& format, FilteringMode filtering_mode, WrappingMode wrapping_mode) :
|
||||
size(size), format(format), filtering_mode(filtering_mode), wrapping_mode(wrapping_mode) {
|
||||
Texture::Texture(const Color3* pixels, const Vector2i& size, FilteringMode filtering_mode, SampleRate anisotropy, WrappingMode wrapping_mode) :
|
||||
size(size), format(ColorFormat::RGB), filtering_mode(filtering_mode), anisotropy(anisotropy), wrapping_mode(wrapping_mode) {
|
||||
load((unsigned char*) pixels);
|
||||
}
|
||||
|
||||
@@ -253,22 +293,36 @@ Texture::Texture(const Texture& rhs) {
|
||||
operator delete(this_texture);
|
||||
}
|
||||
|
||||
Texture::Texture(const Texture* textures, const size_t& texture_count) {
|
||||
int length = 0;
|
||||
int biggest_y = 0;
|
||||
bool Texture::SizeExceedsMaximum(const Vector2i& s) {
|
||||
|
||||
for (int i = 0; i < texture_count; i++) {
|
||||
if (biggest_y < textures[i].size.y)
|
||||
biggest_y = textures[i].size.y;
|
||||
length += textures[i].size.x;
|
||||
}
|
||||
|
||||
auto* result = new Texture(Vector2i(length, biggest_y));
|
||||
auto render_target = RenderTarget(result);
|
||||
|
||||
int next_x = 0;
|
||||
for (int i = 0; i < texture_count; i++) {
|
||||
RenderTarget::Blit(&textures[i], &render_target, Vector2i(next_x, 0));
|
||||
next_x += textures[i].GetDimensions().x;
|
||||
}
|
||||
auto max_size = Texture::MaxSize();
|
||||
return s.x > max_size.x || s.y > max_size.y;
|
||||
}
|
||||
|
||||
Vector2i Texture::MaxSize() {
|
||||
GLint max_size;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
|
||||
|
||||
return { max_size, max_size };
|
||||
}
|
||||
|
||||
SampleRate Texture::MaxAnisotropySampleRate() {
|
||||
if (!GLAD_GL_ARB_texture_filter_anisotropic)
|
||||
return SampleRate::NONE;
|
||||
|
||||
float anisotropy;
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &anisotropy);
|
||||
|
||||
if (anisotropy == 2)
|
||||
return SampleRate::X2;
|
||||
else if (anisotropy == 4)
|
||||
return SampleRate::X4;
|
||||
else if (anisotropy == 8)
|
||||
return SampleRate::X8;
|
||||
else
|
||||
return SampleRate::X16;
|
||||
}
|
||||
|
||||
SampleRate Texture::GetAnisotropySampleRate() const {
|
||||
return anisotropy;
|
||||
}
|
||||
|
63
src/types/TextureAtlas.cpp
Normal file
63
src/types/TextureAtlas.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include <JGL/types/TextureAtlas.h>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
using namespace JGL;
|
||||
AtlasRegion TextureAtlas::GetRegion(unsigned int region) const {
|
||||
if (region >= regions.size()) {
|
||||
Logger::Error("Requesting region " + std::to_string(region) + "but it's outside of the texture atlas?");
|
||||
return { {0, 0},{0, 0} };
|
||||
}
|
||||
return regions[region];
|
||||
}
|
||||
|
||||
TextureAtlas::TextureAtlas(const Color4** pixels, const Vector2i** sizes, unsigned int texture_count, FilteringMode filtering_mode) {
|
||||
std::vector<Texture> textures(texture_count);
|
||||
|
||||
int x_length = 0; int largest_height = 0;
|
||||
for (unsigned int i = 0; i < texture_count; i++) {
|
||||
textures[i] = Texture(pixels[i], *sizes[i], FilteringMode::NEAREST);
|
||||
x_length += sizes[i]->x;
|
||||
|
||||
if (sizes[i]->y > largest_height)
|
||||
largest_height = sizes[i]->y;
|
||||
}
|
||||
|
||||
int rows = 1;
|
||||
while (x_length > Texture::MaxSize().x)
|
||||
x_length /= 2, rows += 1;
|
||||
|
||||
auto* result = new Texture(Vector2i(x_length, largest_height * rows), filtering_mode);
|
||||
auto* render_target = new RenderTarget(result);
|
||||
|
||||
int current_x = 0; int current_y = 0;
|
||||
for (unsigned int i = 0; i < texture_count; i++) {
|
||||
if (current_x + sizes[i]->x > x_length)
|
||||
current_x = 0, current_y += largest_height;
|
||||
|
||||
RenderTarget::Blit(&textures[i], render_target, Vector2i(current_x, current_y));
|
||||
regions.emplace_back(AtlasRegion({ current_x, current_y }, { sizes[i]->x, sizes[i]->y }));
|
||||
current_x += sizes[i]->x;
|
||||
}
|
||||
|
||||
render_target->RegenerateMipMaps();
|
||||
delete render_target;
|
||||
|
||||
this->texture_handle = result->GetHandle();
|
||||
this->size = result->GetDimensions();
|
||||
this->invert_y = result->Inverted();
|
||||
this->filtering_mode = result->GetFilteringMode();
|
||||
this->wrapping_mode = result->GetWrappingMode();
|
||||
this->anisotropy = result->GetAnisotropySampleRate();
|
||||
this->format = result->GetFormat();
|
||||
|
||||
// Don't call destructor so the v-ram isn't cleared.
|
||||
operator delete(result);
|
||||
}
|
||||
|
||||
TextureAtlas::TextureAtlas(const Color4* pixels, const Vector2i& size, AtlasRegion** regions, unsigned int region_count, FilteringMode filtering_mode, SampleRate anisotropy) : Texture(pixels, size, filtering_mode, anisotropy) {
|
||||
this->regions.resize(region_count);
|
||||
for (unsigned int i = 0; i < region_count; ++i)
|
||||
this->regions[i] = *regions[i];
|
||||
}
|
||||
|
@@ -2,44 +2,39 @@
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <cstring>
|
||||
|
||||
// TODO combine the two load functions.
|
||||
|
||||
void JGL::VRamList::load(const GLfloat* data, const long& size) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
GLint current_array_buffer = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_array_buffer);
|
||||
glGenBuffers(1, &list_handle);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, data, usage_hint);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, current_array_buffer);
|
||||
element_array_buffer = false;
|
||||
num_elements = size / sizeof(GLfloat);
|
||||
byte_count = size;
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
|
||||
void JGL::VRamList::load(const GLuint* data, const long& size) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
GLint current_element_array_buffer = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_element_array_buffer);
|
||||
glGenBuffers(1, &list_handle);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, usage_hint);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_element_array_buffer);
|
||||
element_array_buffer = true;
|
||||
num_elements = size / sizeof(GLuint);
|
||||
byte_count = size;
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
void JGL::VRamList::Erase() {
|
||||
if (list_handle == 0)
|
||||
return;
|
||||
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
GLint current_element_array_buffer = 0;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_element_array_buffer);
|
||||
@@ -55,36 +50,27 @@ void JGL::VRamList::Erase() {
|
||||
glDeleteBuffers(1, &list_handle);
|
||||
list_handle = 0;
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
GLuint JGL::VRamList::GetHandle() const {
|
||||
GLuint JGL::VRamList::Handle() const {
|
||||
return list_handle;
|
||||
}
|
||||
|
||||
bool JGL::VRamList::IsFloatArray() const {
|
||||
return !element_array_buffer;
|
||||
long JGL::VRamList::Length() const {
|
||||
// sizeof(GLfloat) & sizeof(GLuint) are both 4 - Redacted.
|
||||
return byte_count / 4;
|
||||
}
|
||||
|
||||
long JGL::VRamList::GetLength() const {
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
size_t JGL::VRamList::GetDataSize() const {
|
||||
if (element_array_buffer)
|
||||
return sizeof(GLuint) * num_elements;
|
||||
return sizeof(GLfloat) * num_elements;
|
||||
size_t JGL::VRamList::Size() const {
|
||||
return byte_count;
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(void* data, const long& length) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
bool should_resize = (this->num_elements != length);
|
||||
bool should_resize = (this->byte_count != length * 4);
|
||||
if (should_resize) {
|
||||
glDeleteBuffers(1, &list_handle);
|
||||
list_handle = 0;
|
||||
spin_lock = false;
|
||||
element_array_buffer ? load((GLuint*) data, sizeof(GLuint) * length) : load((GLfloat*) data, sizeof(GLfloat) * length);
|
||||
return;
|
||||
}
|
||||
@@ -100,33 +86,22 @@ void JGL::VRamList::SetData(void* data, const long& length) {
|
||||
glGetIntegerv(buffer_binding, ¤t_buffer);
|
||||
glBindBuffer(buffer_type, list_handle);
|
||||
|
||||
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
|
||||
if (!vram)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
memcpy(vram, data, (element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat)) * length);
|
||||
|
||||
if (!glUnmapBuffer(buffer_type))
|
||||
JGL::Logger::Fatal("We couldn't unmap the buffer?");
|
||||
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
|
||||
|
||||
glBufferSubData(buffer_type, 0, length * element_size, data);
|
||||
glBindBuffer(buffer_type, current_buffer);
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
|
||||
while (spin_lock) {}
|
||||
spin_lock = true;
|
||||
|
||||
if (offset + length > num_elements) {
|
||||
JGL::Logger::Warning("Using UpdateData to out-of-bounds write the VRamList? I'll resize it for you, But this is slow.");
|
||||
unsigned long oob_delta = (offset + length) - num_elements;
|
||||
if (offset + length > Length()) {
|
||||
unsigned long oob_delta = (offset + length) - Length();
|
||||
|
||||
if (element_array_buffer) {
|
||||
auto list_data = GetDataUI();
|
||||
list_data.resize(list_data.size() + oob_delta);
|
||||
memcpy(list_data.data() + (offset * sizeof(GLuint)), data, length * sizeof(GLuint));
|
||||
spin_lock = false; // This is going unlock and relock really fast, But this code fixes something considered wrong anyway - Redacted.
|
||||
// This is going unlock and relock really fast, But this code fixes something considered wrong anyway - Redacted.
|
||||
return SetData(list_data.data(), list_data.size());
|
||||
}
|
||||
|
||||
@@ -134,7 +109,6 @@ void JGL::VRamList::UpdateData(void* data, const long& offset, const long& lengt
|
||||
auto list_data = GetDataF();
|
||||
list_data.resize(list_data.size() + oob_delta);
|
||||
memcpy(list_data.data() + (offset * sizeof(GLfloat)), data, length * sizeof(GLfloat));
|
||||
spin_lock = false;
|
||||
return SetData(list_data.data(), list_data.size());
|
||||
}
|
||||
|
||||
@@ -149,23 +123,13 @@ void JGL::VRamList::UpdateData(void* data, const long& offset, const long& lengt
|
||||
glGetIntegerv(buffer_binding, ¤t_buffer);
|
||||
glBindBuffer(buffer_type, list_handle);
|
||||
|
||||
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
|
||||
if (!vram)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
|
||||
memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(vram) + (offset * element_size)), data, length * element_size);
|
||||
|
||||
if (!glUnmapBuffer(buffer_type))
|
||||
JGL::Logger::Fatal("We couldn't unmap the buffer?");
|
||||
|
||||
glBufferSubData(buffer_type, offset * element_size, length * element_size, data);
|
||||
glBindBuffer(buffer_type, current_buffer);
|
||||
|
||||
spin_lock = false;
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
while (spin_lock) {}
|
||||
|
||||
if (element_array_buffer)
|
||||
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
|
||||
@@ -178,12 +142,12 @@ std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
|
||||
|
||||
std::vector<GLfloat> data(num_elements);
|
||||
std::vector<GLfloat> data(byte_count / 4);
|
||||
void* vram = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
|
||||
if (vram == nullptr)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
memcpy(data.data(), vram, num_elements * sizeof(GLfloat));
|
||||
memcpy(data.data(), vram, (byte_count / 4) * sizeof(GLfloat));
|
||||
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, current_buffer);
|
||||
@@ -194,7 +158,6 @@ std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
}
|
||||
|
||||
std::vector<GLuint> JGL::VRamList::GetDataUI() const {
|
||||
while (spin_lock) {}
|
||||
|
||||
if (!element_array_buffer)
|
||||
JGL::Logger::Warning("Getting data as GLuint but the buffer data is GLfloat?");
|
||||
@@ -203,13 +166,13 @@ std::vector<GLuint> JGL::VRamList::GetDataUI() const {
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_buffer);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
|
||||
std::vector<GLuint> data(num_elements);
|
||||
std::vector<GLuint> data(byte_count / 4);
|
||||
|
||||
void* vram = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
|
||||
if (vram == nullptr)
|
||||
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
|
||||
|
||||
memcpy(data.data(), vram, num_elements * sizeof(GLuint));
|
||||
memcpy(data.data(), vram, (byte_count / 4) * sizeof(GLuint));
|
||||
|
||||
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_buffer);
|
||||
@@ -217,26 +180,35 @@ std::vector<GLuint> JGL::VRamList::GetDataUI() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const GLfloat* data, const long& length) {
|
||||
JGL::VRamList::VRamList(const GLfloat* data, const long& length, VRamUsageHint hint) {
|
||||
usage_hint = hint;
|
||||
load(data, (long) sizeof(GLfloat) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const GLuint* data, const long& length) {
|
||||
JGL::VRamList::VRamList(const GLuint* data, const long& length, VRamUsageHint hint) {
|
||||
usage_hint = hint;
|
||||
load(data, (long) sizeof(GLuint) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Vector2* data, const long& length) {
|
||||
JGL::VRamList::VRamList(const Vector2* data, const long& length, VRamUsageHint hint) {
|
||||
usage_hint = hint;
|
||||
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector2) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Vector3* data, const long& length) {
|
||||
JGL::VRamList::VRamList(const Vector3* data, const long& length, VRamUsageHint hint) {
|
||||
usage_hint = hint;
|
||||
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector3) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Vector4* data, const long& length) {
|
||||
JGL::VRamList::VRamList(const Vector4* data, const long& length, VRamUsageHint hint) {
|
||||
usage_hint = hint;
|
||||
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector4) * length);
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const Color4* data, const long& count, VRamUsageHint hint) {
|
||||
usage_hint = hint;
|
||||
load(reinterpret_cast<const GLfloat *>(data), (long) sizeof(GLuint) * count);
|
||||
}
|
||||
void JGL::VRamList::SetData(const GLfloat* data, const long& length) {
|
||||
SetData((void*) data, length);
|
||||
}
|
||||
@@ -261,6 +233,10 @@ void JGL::VRamList::SetData(const Vector2i* data, const long& length) {
|
||||
SetData((void*) data, length * 2);
|
||||
}
|
||||
|
||||
void JGL::VRamList::SetData(const Color4* data, const long& count) {
|
||||
SetData((void*) data, count);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const GLfloat* data, const long& offset, const long& length) {
|
||||
UpdateData((void*) data, offset, length);
|
||||
}
|
||||
@@ -285,13 +261,15 @@ void JGL::VRamList::UpdateData(const Vector2i* data, const long& offset, const l
|
||||
UpdateData((void*) data, offset, length * 2);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const Color4* data, const long &offset, const long &count) {
|
||||
UpdateData((void*) data, offset, count);
|
||||
}
|
||||
|
||||
JGL::VRamList::~VRamList() {
|
||||
Erase();
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
|
||||
while (rhs.spin_lock) {}
|
||||
|
||||
if (rhs.element_array_buffer) {
|
||||
auto data_array = rhs.GetDataUI();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
@@ -300,3 +278,32 @@ JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
|
||||
auto data_array = rhs.GetDataF();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
}
|
||||
|
||||
JGL::VRamList::VRamList(const size_t& byte_count, bool element_array_buffer, VRamUsageHint hint) {
|
||||
this->element_array_buffer = element_array_buffer;
|
||||
this->byte_count = byte_count;
|
||||
|
||||
GLint current_buffer = 0;
|
||||
GLenum buffer = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
|
||||
GLenum buffer_binding = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER_BINDING : GL_ARRAY_BUFFER_BINDING;
|
||||
|
||||
glGetIntegerv(buffer_binding, ¤t_buffer);
|
||||
glGenBuffers(1, &list_handle);
|
||||
glBindBuffer(buffer, list_handle);
|
||||
glBufferData(buffer, byte_count, nullptr, hint);
|
||||
|
||||
glBindBuffer(buffer, current_buffer);
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(const uint8_t* data, const long& offset, const long& count) {
|
||||
GLint current_buffer = 0;
|
||||
GLenum buffer_type = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
|
||||
GLenum buffer_binding = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER_BINDING : GL_ARRAY_BUFFER_BINDING;
|
||||
|
||||
glGetIntegerv(buffer_binding, ¤t_buffer);
|
||||
glBindBuffer(buffer_type, list_handle);
|
||||
|
||||
glBufferSubData(buffer_type, offset, count, data);
|
||||
|
||||
glBindBuffer(buffer_type, current_buffer);
|
||||
}
|
||||
|
Reference in New Issue
Block a user