Compare commits

...

25 Commits

Author SHA1 Message Date
9f9191a9db Temp patch for text size bounds. Needs to be fixed properly.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m13s
2025-06-09 15:54:48 -05:00
2d536cd611 Merged several branches, fixed small error, updated dependency packages.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m14s
2025-06-06 13:02:29 -05:00
40412a300a Merge pull request 'Completed Shaders Task' (#47) from shaders_again into master
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m39s
Reviewed-on: #47
2025-06-06 13:44:47 -04:00
819539247e Merge pull request 'shader_preprocessor' (#43) from shader_preprocessor into shaders_again
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 26m34s
Reviewed-on: #43
2025-06-06 13:38:29 -04:00
ee90e7f95b Fix measure string.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m16s
2025-05-29 22:58:25 -04:00
ad3b451659 BatchFillOutlineRect
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m19s
2025-05-25 16:33:58 -04:00
74ab9d25db BatchFillRoundedRect
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 3m44s
2025-05-18 00:07:58 -04:00
a5424eb370 BatchFillCircle Instanced Rendering.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m51s
Added JGL::ClearScreen as-well to clear fbo 0 at any time.
2025-05-17 17:04:27 -04:00
6f99689add Performance optimization.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-05-12 11:38:28 -04:00
7ea4b8696e cleanup & performance optimization.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-05-11 13:49:07 -04:00
6d37cd93e3 BatchFillRect instanced rendering.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
during shader creation you can now also specify your attributes.
2025-05-09 16:41:29 -04:00
7875b777e5 Demonstrate GLSL custom preprocessor.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-05-09 13:50:18 -05:00
ede11131fe Change gradient rect to accept 4x color4
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-05-06 11:55:01 -04:00
347b9cb278 Performance optimization
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-05-05 11:25:49 -04:00
1a2f7627d3 custom behavior per draw function
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
Add support for doing custom behavior per draw function for JGL.

You must define uniform int J2D_RENDERING_ROUTINE in any shader to be used by JGL even if you're not doing per draw function behavior.
2025-05-04 23:19:49 -04:00
b3fb28be38 Package Maintenance - Update mcolor to 7.1
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m41s
2025-04-22 17:19:00 -04:00
d2497d64a2 Performance Optimization
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m35s
Draw points can accept multiple colors.

Draw points now uses vbos.

Allowed the user to set the usage hint for the VBO.

When changing data in a vbo, the data will be orphaned if the mode is not Fixed.
2025-04-20 04:30:29 -04:00
f7eff123be Fix alpha masking when using shader.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m11s
2025-04-18 12:00:51 -04:00
a1ca7ace77 Flip order of J2D::DrawString argument, so that we can default scale to 1, and add vector2 overload.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m59s
2025-04-17 13:57:03 -04:00
02370c6bfa work on the default shader.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m59s
2025-04-17 13:33:08 -04:00
2f13be9dd8 Merge branch 'shader_preprocessor' into shaders_again
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m56s
2025-04-16 01:44:27 -04:00
4c798ea76a shader with state stack.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m26s
2025-04-16 01:43:00 -04:00
af31b41782 Implement testing GLSL preprocessing and #include support.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m10s
2025-04-16 01:36:39 -04:00
4374b83464 Add Shader::OnCompilationErrorMessag
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m6s
2025-04-15 19:11:07 -05:00
147123b202 Working on the default shader
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m16s
( Need a system for accessing texture units & sampling etc )
2025-04-15 12:18:14 -04:00
21 changed files with 1359 additions and 440 deletions

View File

@@ -17,7 +17,7 @@ include(cmake/CPM.cmake)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-6.2.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_anisotropic.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-17.zip
URL https://git.redacted.cc/josh/jlog/Prerelease-19.zip
)
if (WIN32)

View 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

View File

@@ -1,50 +1,154 @@
#version 120
#ifdef GL_ES
precision mediump float;
#endif
#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
attribute vec4 gl_Color;
uniform vec2 u_resolution;
uniform float u_time;
uniform int JGL_RENDERING_ROUTINE;
uniform bool JGL_INSTANCED_RENDERING;
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);
// 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;
}
// 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);
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 main(){
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 color = vec3(0.0);
void Default() {
if (TEXTURE_UNIT_SET_COUNT == 0) {
DrawColorOnly(); return;
}
SampleTextureUnits();
}
// We map x (0.0 - 1.0) to the hue (0.0 - 1.0)
// And the y (0.0 - 1.0) to the brightness
color = hsb2rgb(vec3(st.x,1.0,st.y));
gl_FragColor = vec4(color,1.0);
gl_FragColor = gl_Color;
void main() {
/* 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();
}

View File

@@ -1,5 +1,155 @@
#version 120
// TODO this will fail if we don't have the extension.
#extension GL_ARB_instanced_arrays : enable
#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 = gl_ModelViewProjectionMatrix * gl_Vertex;
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();
}

View File

@@ -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>
@@ -30,6 +31,7 @@
#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 {
@@ -46,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();
}
@@ -56,6 +60,8 @@ namespace JGL {
[[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(); }
@@ -73,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().
@@ -95,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);
@@ -152,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.
@@ -176,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
@@ -191,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.
@@ -367,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
@@ -387,9 +406,8 @@ namespace JGL::J2D {
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 Color4* colors, const Vector2* positions, const Vector2* sizes, const size_t& rect_count);
void BatchFillCircle(const Color4 *colors, const Vector2* positions, float* radii, unsigned int subdivisions, const size_t& circle_count);
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.

View File

@@ -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;
};

View 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;
};

View File

@@ -5,6 +5,7 @@
#include <fstream>
#include <iostream>
#include "glad/glad.h"
#include <Event.h>
// LearnOpenGL::Shader
// OpenGL Shader Class Wrapper
@@ -21,25 +22,30 @@ namespace JGL {
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(std::filesystem::path vertex_source_path, std::filesystem::path fragment_source_path);
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);
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.
bool Loaded() const;
[[nodiscard]] bool Loaded() const;
/// @return The integer handle that OpenGL links to this shader program.
unsigned int Handle() const;
[[nodiscard]] unsigned int Handle() const;
/// Enable this shader. All rendering performed thereafter will be affected by this shader code.
/// @see UseDefault.
void Use();
static void Use(GLuint shader_program_id);
static void UseDefault();
// TODO: Implement for hot-reloading.
void Reload();
@@ -52,7 +58,7 @@ public:
/// @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.
GLint Attribute(const std::string& name) const;
[[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;
@@ -107,6 +113,9 @@ 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);
};

View File

@@ -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);
};

View File

@@ -15,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
{
@@ -112,8 +112,8 @@ JGL::Font FreeSans;
Texture* image;
Texture* image_mask;
RenderTarget* j2d_render_target;
Shader shader;
float u_time = 0;
Shader* shader;
Vector2 result;
class JGLDemoWindow : public ReWindow::OpenGLWindow
{
@@ -131,14 +131,19 @@ public:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", FilteringMode::MIPMAP_NEAREST, JGL::SampleRate::X16);
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,
SampleRate::NONE, FilteringMode::MIPMAP_TRILINEAR);
SampleRate::NONE, FilteringMode::MIPMAP_NEAREST);
//Texture::MultiplyByAlphaMask(*image, *image_mask);
shader = Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"));
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};
@@ -146,12 +151,9 @@ public:
float pulse = 0;
float sprite_radians = 0;
bool fov_increasing = true;
int blit_pos = 0;
void display() {
Shader::UseDefault();
pulse += 20 * delta_time;
float dt = GetDeltaTime();
@@ -179,9 +181,10 @@ public:
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});
@@ -193,19 +196,20 @@ public:
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
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);
@@ -213,12 +217,13 @@ 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::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::DrawCubicBezierCurve(Colors::Blues::CornflowerBlue,
@@ -235,29 +240,14 @@ public:
J2D::End();
shader.Use();
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(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
J2D::End();
}
void OnRefresh(float elapsed) override {
u_time += elapsed;
shader.SetFloat("u_time", u_time);
auto dimensions = GetSize();
shader.SetVector2("u_resolution", Vector2(dimensions.x, dimensions.y));
fps = GetRefreshRate();
if (IsKeyDown(Keys::RightArrow))
@@ -332,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();

View File

@@ -43,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;
}
}

View File

@@ -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);
}
}

View File

@@ -1,12 +1,48 @@
#include <JGL/JGL.h>
#include <JGL/logger/logger.h>
#include <JGL/types/Instance.h>
#include <J3ML/Algorithm/Bezier.hpp>
#include "internals/internals.h"
void J2D::Begin(RenderTarget* render_target, bool clear_buffers) {
void JGL::ClearScreen(const Color4& clear_color) {
GLuint current_framebuffer = 0;
GLint current_viewport[4] = {0, 0, 0, 0};
GLfloat current_clear_color[4];
glGetIntegerv(GL_VIEWPORT, current_viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, current_clear_color);
current_framebuffer = RenderTarget::GetActiveGLFramebufferHandle();
if (current_framebuffer)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
bool changed_viewport = false;
if (current_viewport[2] != window_size.x || current_viewport[3] != window_size.y)
glViewport(0, 0, window_size.x, window_size.y),
changed_viewport = true;
GLint has_depth = 0;
glGetIntegerv(GL_DEPTH_BITS, &has_depth);
glClearColor(clear_color.RN(), clear_color.GN(), clear_color.BN(), clear_color.AN());
if (has_depth)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(current_clear_color[0], current_clear_color[1], current_clear_color[2], current_clear_color[3]);
if (current_framebuffer)
glBindFramebuffer(GL_FRAMEBUFFER, current_framebuffer);
if (changed_viewport)
glViewport(current_viewport[0], current_viewport[1], current_viewport[2], current_viewport[3]);
}
void J2D::Begin(RenderTarget* render_target, Shader* shader, bool clear_buffers) {
State new_state = default_state;
state_stack.Push(State::SaveState());
state_stack.Push(State::SaveState(current_state));
glMatrixMode(GL_PROJECTION);
glPushMatrix();
@@ -31,13 +67,17 @@ void J2D::Begin(RenderTarget* render_target, bool clear_buffers) {
new_state.viewport[3] = window_size.y;
}
if (shader) {
new_state.current_shader = shader;
new_state.current_shader_handle = shader->Handle();
}
State::RestoreState(new_state);
current_state = new_state;
if (current_state.current_render_target)
RenderTarget::SetActiveGLRenderTarget(*current_state.current_render_target);
if (render_target != nullptr && clear_buffers) {
glClearColor(render_target->GetClearColor().RedChannelNormalized(), render_target->GetClearColor().GreenChannelNormalized(), render_target->GetClearColor().BlueChannelNormalized(), render_target->GetClearColor().AlphaChannelNormalized());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -86,7 +126,15 @@ void J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float radiu
glPointSize(radius);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), coordinates.ptr());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawPoint);
glDrawArrays(GL_POINTS, 0, 1);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -102,7 +150,15 @@ void J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, floa
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawLine);
glDrawArrays(GL_LINES, 0, 2);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -117,7 +173,15 @@ void J2D::DrawLines(const Color4& color, const Vector2* points, const size_t& po
glLineWidth(thickness);
glColor3ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), points);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawLines);
glDrawArrays(GL_LINE_STRIP, 0, point_count);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -134,7 +198,13 @@ void J2D::DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B
for (unsigned int i = 0; i < point_count; ++i)
points[i] = A + direction * (i * spacing);
return J2D::DrawPoints(color, points.data(), points.size(), thickness);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawDottedLine);
J2D::DrawPoints(color, points.data(), points.size(), thickness);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
}
void J2D::DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float thickness) {
@@ -151,6 +221,10 @@ void J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B
Logger::Error("Drawing a dashed line that would have no dashes?");
Vector2 A_current, B_current;
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawDashedLine);
for (unsigned int i = 0; i < dash_count; i++) {
A_current = A + direction * (i * length_of_dash_and_gap);
B_current = A_current + (direction * dash_length);
@@ -164,6 +238,9 @@ void J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B
B_current = A_current + direction * std::min(dash_length, distance_left);
J2D::DrawLine(color, A_current, B_current, thickness);
}
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
}
void J2D::DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float dash_length, float thickness) {
@@ -182,7 +259,15 @@ void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vec
glLineWidth(thickness);
glColorPointer(4,GL_FLOAT,sizeof(Color4), colors);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawGradientLine);
glDrawArrays(GL_LINES, 0, 2);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glDisableClientState(GL_COLOR_ARRAY);
glColor4fv(default_state.draw_color);
}
@@ -192,90 +277,204 @@ void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float
}
void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
Instance2D rect(color, pos, size);
J2D::BatchOutlineRect(&rect, thickness, 1);
}
void J2D::BatchOutlineRect(const Instance2D* instances, float thickness, const size_t& instance_count) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
if (instance_count <= 0)
return;
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineRect);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->Handle());
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINE_LOOP, 0, 4);
if (instance_count == 1 || !supports_instanced || !current_state.current_shader) {
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
for (size_t i = 0; i < instance_count; i++) {
glPushMatrix();
glColor4ubv(instances[i].color.ptr());
glTranslatef(instances[i].position.x, instances[i].position.y, 0);
glScalef(instances[i].size.x, instances[i].size.y, 1);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else {
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", true);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
glVertexAttribDivisorARB(0, 0);
VRamList instance_buffer((GLfloat*) instances, instance_count * (sizeof(Instance2D) / sizeof(GLfloat)), Stream);
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer.Handle());
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, position));
glVertexAttribDivisorARB(1, 1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, size));
glVertexAttribDivisorARB(2, 1);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, color));
glVertexAttribDivisorARB(3, 1);
glDrawArraysInstancedARB(GL_LINE_LOOP, 0, 4, instance_count);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", false);
}
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
BatchFillRect(&color, &pos, &size, 1);
Instance2D rect(color, pos, size);
BatchFillRect(&rect, 1);
}
void J2D::BatchFillRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, const size_t& rect_count) {
void J2D::BatchFillRect(const Instance2D* instances, const size_t& instance_count) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
if (rect_count <= 0)
if (instance_count <= 0)
return;
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->GetHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillRect);
for (size_t i = 0; i < rect_count; i++) {
glPushMatrix();
glColor4ubv(colors[i].ptr());
glTranslatef(positions[i].x, positions[i].y + sizes[i].y, 0);
glScalef(sizes[i].x, sizes[i].y, 1);
glDrawArrays(GL_QUADS, 0, 4);
glPopMatrix();
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->Handle());
if (instance_count == 1 || !supports_instanced || !current_state.current_shader) {
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
for (size_t i = 0; i < instance_count; i++) {
glPushMatrix();
glColor4ubv(instances[i].color.ptr());
glTranslatef(instances[i].position.x, instances[i].position.y, 0);
glScalef(instances[i].size.x, instances[i].size.y, 1);
glDrawArrays(GL_QUADS, 0, 4);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
else {
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", true);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
glVertexAttribDivisorARB(0, 0);
VRamList instance_buffer((GLfloat*) instances, instance_count * (sizeof(Instance2D) / sizeof(GLfloat)), Stream);
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer.Handle());
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, position));
glVertexAttribDivisorARB(1, 1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, size));
glVertexAttribDivisorARB(2, 1);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, color));
glVertexAttribDivisorARB(3, 1);
glDrawArraysInstancedARB(GL_QUADS, 0, 4, instance_count);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", false);
}
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
void J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size) {
void J2D::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) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
std::vector<GLfloat> colors{};
if (gradient == Direction::Horizontal)
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(), color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized()};
else if (gradient == Direction::Vertical)
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(),
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(), color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized()};
else if (gradient == Direction::Diagonal_SWNE)
colors = {(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f, (color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f,
color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), (color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f,
(color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f, color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized()};
else if (gradient == Direction::Diagonal_NWSE)
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f,
(color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f, color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(),
(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f, (color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f,(color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f};
std::vector<GLfloat> colors {
top_left_color.RN(), top_left_color.GN(), top_left_color.BN(), top_left_color.AN(),
bottom_left_color.RN(), bottom_left_color.GN(), bottom_left_color.BN(), bottom_left_color.AN(),
bottom_right_color.RN(), bottom_right_color.GN(), bottom_right_color.BN(), bottom_right_color.AN(),
top_right_color.RN(), top_right_color.GN(), top_right_color.BN(), top_right_color.AN()
};
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glColorPointer(4, GL_FLOAT, 0, colors.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillGradientRect);
glDrawArrays(GL_QUADS, 0, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glDisableClientState(GL_COLOR_ARRAY);
glColor4fv(default_state.draw_color);
}
void J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, unsigned int subdivisions) {
std::array<Color4, 4> colors = { color, color, color, color };
std::array<Vector2, 2> rect_positions = { Vector2(pos.x + radius, pos.y), {pos.x, pos.y + radius} };
std::array<Vector2, 2> rect_sizes = { Vector2(size.x - 2 * radius, size.y), {size.x, size.y - 2 * radius} };
std::array<float, 4> circle_radii = { radius, radius, radius, radius };
std::array<Vector2, 4> circle_positions
{
Vector2(pos.x + radius, pos.y + radius), {pos.x + size.x - radius, pos.y + radius},
{pos.x + radius, pos.y + size.y - radius}, {pos.x + size.x - radius, pos.y + size.y - radius}
};
void J2D::BatchFillRoundedRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, float radius, unsigned int subdivisions, const size_t& count) {
std::vector<Instance2D> rect_instances(count * 2);
std::vector<Instance2D> circle_instances(count * 4);
J2D::BatchFillRect(colors.data(), rect_positions.data(), rect_sizes.data(), 2);
J2D::BatchFillCircle(colors.data(), circle_positions.data(), circle_radii.data(), subdivisions, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillRoundedRect);
for (unsigned int i = 0; i < count; i++) {
unsigned int rect_i = i * 2;
unsigned int circle_i = i * 4;
rect_instances[rect_i] = Instance2D(colors[i], Vector2(positions[i].x + radius, positions[i].y), Vector2(sizes[i].x - 2 * radius, sizes[i].y));
rect_instances[rect_i + 1] = Instance2D(colors[i], Vector2(positions[i].x, positions[i].y + radius), Vector2(sizes[i].x, sizes[i].y - 2 * radius));
circle_instances[circle_i] = Instance2D(colors[i], Vector2(positions[i].x + radius, positions[i].y + radius), Vector2::One, Vector2(radius, radius));
circle_instances[circle_i + 1] = Instance2D(colors[i], Vector2(positions[i].x + sizes[i].x - radius, positions[i].y + radius), Vector2::One, Vector2(radius, radius));
circle_instances[circle_i + 2] = Instance2D(colors[i], Vector2(positions[i].x + radius, positions[i].y + sizes[i].y - radius), Vector2::One, Vector2(radius, radius));
circle_instances[circle_i + 3] = Instance2D(colors[i], Vector2(positions[i].x + sizes[i].x - radius, positions[i].y + sizes[i].y - radius), Vector2::One, Vector2(radius, radius));
}
J2D::BatchFillRect(rect_instances.data(), rect_instances.size());
J2D::BatchFillCircle(circle_instances.data(), subdivisions, circle_instances.size());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
}
void J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, unsigned int subdivisions) {
J2D::BatchFillRoundedRect(&color, &pos, &size, radius, subdivisions, 1);
}
void J2D::DrawSprite(const Texture* texture, float positionX, float positionY, float rad_rotation,
@@ -347,8 +546,15 @@ void J2D::DrawSprite(const RenderTarget& rt, const Vector2& position, float rad_
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
auto r_position = Vector2(Math::Floor(position.x), Math::Floor(position.y));
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawRenderTarget);
J2D::DrawPartialSprite(*rt.GetTexture(), r_position, {0, 0}, Vector2(rt.GetDimensions()), rad_rotation, origin, scale, color, d);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
if (rt.OwnsTexture())
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
@@ -423,9 +629,23 @@ void J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, const Ve
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 2),
current_state.current_shader->SetInt("GL_TEXTURE1", 1);
// Draw.
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawAlphaMaskSprite);
glDrawArrays(GL_QUADS, 0, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
if (current_state.current_shader)
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 0),
current_state.current_shader->SetInt("GL_TEXTURE1", 0);
// Reset Texture 1.
glBindTexture(GL_TEXTURE_2D, 0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -482,8 +702,14 @@ void J2D::DrawPartialRenderTarget(const RenderTarget& rt, const Vector2& positio
auto r_position = Vector2(Math::Floor(position.x), Math::Floor(position.y));
auto r_sub_texture_position = Vector2(Math::Floor(sub_texture_position.x), Math::Floor(sub_texture_position.y));
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawPartialRenderTarget);
J2D::DrawPartialSprite(*rt.GetTexture(), r_position, r_sub_texture_position, sub_texture_size, rad_rotation, origin, scale, color, d);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
if (rt.OwnsTexture())
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
@@ -507,9 +733,6 @@ void J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotat
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
// TODO: Kind of a mess, refactor to be more sensible later.
// Factors in scaling and origin correctly.
// i.e. to render at 2x size, from the center, at coords XY, use {2, 2} scale, and {0.5, 0.5} offset.
const Vector2 offset = origin * size;
Vector2 pos2 = pos;
Vector2 scaled_size = scale * size;
@@ -547,7 +770,17 @@ void J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotat
glBindTexture(GL_TEXTURE_2D, texture.GetHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawSprite),
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 1);
glDrawArrays(GL_QUADS, 0, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0),
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 0);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(default_state.draw_color);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -636,7 +869,17 @@ void J2D::DrawPartialSprite(const Texture& texture, const Vector2& position, con
glBindTexture(GL_TEXTURE_2D, texture.GetHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawPartialSprite),
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 1);
glDrawArrays(GL_QUADS, 0, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0),
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 0);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(default_state.draw_color);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -718,8 +961,17 @@ void J2D::DrawMirrorSprite(const Texture& texture, const Vector2& position, Dire
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawMirrorSprite),
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 1);
glDrawArrays(GL_QUADS, 0, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0),
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 0);
//Reset the wrapping mode.
if (texture.GetWrappingMode() == WrappingMode::CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE),
@@ -760,19 +1012,28 @@ void J2D::OutlineCircle(const Color4& color, const Vector2& center, float radius
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineCircle);
glDrawArrays(GL_LINE_LOOP, 0, (int) vertices.size());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
void J2D::FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions) {
BatchFillCircle(&color, &center, &radius, subdivisions, 1);
Instance2D circle(color, center, Vector2(1, 1), Vector2(radius, radius));
BatchFillCircle(&circle, subdivisions, 1);
}
void J2D::BatchFillCircle(const Color4* colors, const Vector2* positions, float* radii, unsigned int subdivisions, const size_t& circle_count) {
void J2D::BatchFillCircle(const JGL::Instance2D* instances, float subdivisions, const size_t &instance_count) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
if (circle_count <= 0)
if (instance_count <= 0)
return;
GLfloat angle, x, y;
@@ -793,15 +1054,64 @@ void J2D::BatchFillCircle(const Color4* colors, const Vector2* positions, float*
i++;
}
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
for (size_t j = 0; j < circle_count; j++) {
glPushMatrix();
glColor4ubv(colors[j].ptr());
glTranslatef(positions[j].x, positions[j].y, 0);
glScalef(radii[j], radii[j], 0);
auto vertex_buffer = VRamList(vertices.data(), vertices.size(), Stream);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer.Handle());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillCircle);
if (instance_count == 1 || !supports_instanced || !current_state.current_shader) {
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
for (size_t j = 0; j < instance_count; j++) {
glPushMatrix();
glColor4ubv(instances[j].color.ptr());
glTranslatef(instances[j].position.x, instances[j].position.y, 0);
glScalef(instances[j].scale.x, instances[j].scale.y, 0);
glDrawArrays(GL_TRIANGLE_FAN, 0, (int) vertices.size());
glPopMatrix();
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else {
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", true);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
glVertexAttribDivisorARB(0, 0);
VRamList instance_buffer((GLfloat*) instances, instance_count * (sizeof(Instance2D) / sizeof(GLfloat)), Stream);
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer.Handle());
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, position));
glVertexAttribDivisorARB(1, 1);
glEnableVertexAttribArray(2);
// Swapped scale with size in this path because we always render a unit circle scaled up to the given size.
// TODO implement scaling attribute in vertex shader.
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, scale));
glVertexAttribDivisorARB(2, 1);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, color));
glVertexAttribDivisorARB(3, 1);
glDrawArraysInstancedARB(GL_TRIANGLE_FAN, 0, vertices.size(), instance_count);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", false);
}
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -814,7 +1124,15 @@ void J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float thic
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineTriangle);
glDrawArrays(GL_LINE_LOOP, 0, 3);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -826,7 +1144,15 @@ void J2D::FillTriangle(const Color4& color, const Triangle2D& tri) {
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillTriangle);
glDrawArrays(GL_TRIANGLES, 0, 3);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -842,7 +1168,15 @@ void J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, con
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(Color4), colors);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillGradientTriangle);
glDrawArrays(GL_TRIANGLES, 0, 3);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glDisableClientState(GL_COLOR_ARRAY);
glColor4fv(default_state.draw_color);
}
@@ -864,7 +1198,14 @@ void J2D::DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, con
}
vertices[2 * subdivisions] = last;
vertices[2 * subdivisions + 1] = first;
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawCubicBezierCurve);
DrawLines(color, vertices.data(), vertices.size(), thickness);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
}
void J2D::OutlinePolygon(const Color4& color, const Vector2* points, int points_size, float thickness) {
@@ -877,7 +1218,15 @@ void J2D::OutlinePolygon(const Color4& color, const Vector2* points, int points_
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), points);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlinePolygon);
glDrawArrays(GL_LINE_LOOP, 0, points_size);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -915,7 +1264,15 @@ void J2D::DrawArc(const Color4& color, const Vector2& center, float radius, floa
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawArc);
glDrawArrays(GL_LINE_STRIP, 0, (int) vertices.size());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
@@ -969,6 +1326,9 @@ void J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vect
unsigned int subdivisions = 9;
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineRoundedRect);
J2D::DrawArc(color, anchor_tl, radius, Math::Pi, 3.01f*Math::Pi/2.f, subdivisions, thickness);
J2D::DrawLine(color, anchor_topleft_top, anchor_topright_top, thickness);
J2D::DrawArc(color, anchor_tr, radius, 3.f*Math::Pi/2.f, 2.02*Math::Pi, subdivisions, thickness);
@@ -977,13 +1337,22 @@ void J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vect
J2D::DrawLine(color, anchor_bottomright_bottom, anchor_bottomleft_bottom, thickness);
J2D::DrawArc(color, anchor_bl, radius, Math::Pi/2, Math::Pi*1.01f, subdivisions, thickness);
J2D::DrawLine(color, anchor_bottomleft_left, anchor_topleft_left, thickness);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
//J2D::End();
}
void J2D::FillChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius) {
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillChamferRect);
FillRoundedRect(color, pos, size, radius, 4);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
}
void J2D::OutlineChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, float thickness) {
@@ -1000,15 +1369,59 @@ void J2D::OutlineChamferRect(const Color4& color, const Vector2& pos, const Vect
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineChamferRect);
glDrawArrays(GL_LINE_LOOP, 0, 8);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glColor4fv(default_state.draw_color);
}
void J2D::DrawPoints(const Color4& color, const Vector2* points, int num_points, float radius) {
void J2D::DrawPoints(const Color4* colors, const Vector2* points, int point_count, float radius) {
ShapeCache::draw_points_colors->SetData(colors, point_count);
ShapeCache::draw_points_positions->SetData(points, point_count);
glPointSize(radius);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::draw_points_colors->Handle());
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Color4), nullptr);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::draw_points_positions->Handle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawPoints);
glDrawArrays(GL_POINTS, 0, point_count);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glDisableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColor4fv(default_state.draw_color);
}
void J2D::DrawPoints(const Color4& color, const Vector2* points, int point_count, float radius) {
ShapeCache::draw_points_positions->SetData(points, point_count);
glPointSize(radius);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), points);
glDrawArrays(GL_POINTS, 0, num_points);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::draw_points_positions->Handle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawPoints);
glDrawArrays(GL_POINTS, 0, point_count);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColor4fv(default_state.draw_color);
}
@@ -1044,7 +1457,19 @@ void J2D::OutlineEllipse(const Color4& color, const Vector2& position, float rad
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
/*
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineElipse);
*/
glDrawArrays(GL_LINE_LOOP, 0, (int) vertices.size());
/*
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
*/
glColor4fv(default_state.draw_color);
}
@@ -1072,7 +1497,18 @@ void J2D::FillEllipse(const Color4& color, const Vector2& position, float radius
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
/*
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_OutlineElipse);
*/
glDrawArrays(GL_TRIANGLE_FAN, 0, (int) vertices.size());
/*
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
*/
glColor4fv(default_state.draw_color);
}
@@ -1083,3 +1519,8 @@ void J2D::DrawSprite(const TextureAtlas* texture_atlas, const AtlasRegion& atlas
void J2D::DrawSprite(const TextureAtlas& texture_atlas, const AtlasRegion& atlas_region, const Vector2& position, float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color) {
J2D::DrawSprite(&texture_atlas, atlas_region, position, rad_rotation, origin, scale, color);
}
void J2D::DrawString(const Color4 &color, const std::string &text, const Vector2 &pos, u32 size, float scale,
const Font &font) {
DrawString(color, text, pos.x, pos.y, size, scale, font);
}

View File

@@ -236,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.
@@ -245,10 +246,10 @@ 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);
@@ -371,9 +372,9 @@ void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const
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->GetHandle());
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;
@@ -381,7 +382,7 @@ 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);
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->GetLength(), GL_UNSIGNED_INT, nullptr);
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->Length(), GL_UNSIGNED_INT, nullptr);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -396,9 +397,9 @@ 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) {
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);
@@ -407,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);
}
@@ -486,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++) {
@@ -495,7 +496,7 @@ 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);
@@ -566,13 +567,13 @@ void JGL::J3D::DrawVertexArray(const Color4& color, const VertexArray& vertex_ar
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);

View File

@@ -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,7 +159,17 @@ 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(default_state.draw_color);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -238,8 +251,18 @@ 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);

View File

@@ -133,7 +133,7 @@ JGL::State* JGL::StateStack::PreviousState() {
return &states.back();
}
JGL::State JGL::State::SaveState() {
JGL::State JGL::State::SaveState(const State& state) {
State result;
result.depth_test = glIsEnabled(GL_DEPTH_TEST);
@@ -152,6 +152,8 @@ JGL::State JGL::State::SaveState() {
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]);
@@ -184,7 +186,6 @@ void JGL::State::RestoreState(const State& state) {
else
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
glClientActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
@@ -203,10 +204,14 @@ void JGL::State::RestoreState(const State& state) {
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]);
}

View File

@@ -6,13 +6,47 @@
#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 {
class State;
class StateStack;
enum RENDERING_ROUTINE_ID : int32_t;
}
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,
};
class JGL::State {
public:
@@ -23,6 +57,8 @@ public:
GLint blend_func[2];
GLuint current_fbo = 0;
RenderTarget* current_render_target = nullptr;
GLint current_shader_handle = 0;
Shader* current_shader = nullptr;
bool texture_2D = false;
bool texture_coordinate_array = false;
@@ -38,7 +74,7 @@ public:
// List of all lights in the scene.
std::vector<const LightBase*> optional_lights{};
public:
static State SaveState();
static State SaveState(const State& state);
static void RestoreState(const State& state);
};
@@ -60,6 +96,7 @@ namespace JGL {
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 {
@@ -70,7 +107,7 @@ namespace JGL::J2D {
{1, 1, 1, 1},
{0, 0, 0, 0},
{GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
0, nullptr, false, false,
0, nullptr, 0, nullptr, false, false,
false, false, true, true,
true, false, 0,
{}, {}

View File

@@ -108,61 +108,36 @@ 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()) {
// This edit technically "works" by solving the immediate problem of text-bounds returning incorrectly,
// But I am **sure** this is not how it should be implemented, I will leave that to Will to fix.
if (f->getFontIndex() == this->index && f->getFontSize() == ptSize) {
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;
}

View File

@@ -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) {

View File

@@ -3,102 +3,122 @@
#include <glad/glad.h>
namespace JGL {
Shader::Shader(std::filesystem::path vertex_source_path, std::filesystem::path fragment_source_path) {
std::string vertex_code;
std::string fragment_code;
std::string geometry_code; // Currently unused, might be supported later.
std::string compute_code; // Currently unused, might be supported later.
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
std::ifstream cShaderFile;
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);
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
cShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// Open Files
vShaderFile.open(vertex_source_path);
fShaderFile.open(fragment_source_path);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertex_code = vShaderStream.str();
fragment_code = fShaderStream.str();
if (false) {
gShaderFile.open("");
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometry_code = gShaderStream.str();
if (stack_top) {
already_included.emplace_back(filepath.string());
}
} catch (std::ifstream::failure& e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
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;
}
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, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
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("\\/");
// if geometry shader is given, compile geometry shader.
unsigned int geometry;
if (false) {
// const char* gShaderCode = geometry_code.c_str();
// geometry = glCreateShader(GL_GEOMETRY_SHADER);
// glShaderSource(geometry, 1 &gShaderCode, NULL);
// glCompileShader(geometry);
// checkCompileErrors(geometry, "GEOMETRY");
// 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);
// shader Program
id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
if (false)
glAttachShader(id, geometry);
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);
if (false)
glDeleteShader(geometry);
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) {
@@ -108,14 +128,14 @@ namespace JGL {
if (type != "PROGRAM") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of " << type << "\n" << infoLog << std::endl;
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, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of " << type << "\n" << infoLog << std::endl;
glGetProgramInfoLog(shader, 1024, nullptr, infoLog);
OnCompilationErrorMessage.Invoke(std::format("COMPILATION_ERROR: {}", type), infoLog);
}
}
@@ -124,14 +144,23 @@ namespace JGL {
}
GLint Shader::Uniform(const std::string &name) const {
return glGetUniformLocation(id, name.c_str());
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) {
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();
@@ -140,60 +169,37 @@ namespace JGL {
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glShaderSource(fragment, 1, &fShaderCode, nullptr);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader.
unsigned int geometry;
if (false) {
// const char* gShaderCode = geometry_code.c_str();
// geometry = glCreateShader(GL_GEOMETRY_SHADER);
// glShaderSource(geometry, 1 &gShaderCode, NULL);
// glCompileShader(geometry);
// checkCompileErrors(geometry, "GEOMETRY");
}
// 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);
if (false)
glAttachShader(id, geometry);
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);
if (false)
glDeleteShader(geometry);
}
void Shader::Use() {
glUseProgram(id);
}
bool Shader::Loaded() const { return id != 0; }
unsigned int Shader::Handle() const { return id;}
void Shader::UseDefault() {
glUseProgram(0);
}
void Shader::Use(GLuint shader_program_id) {
glUseProgram(shader_program_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); }
@@ -229,4 +235,35 @@ namespace JGL {
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);
}
}

View File

@@ -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, &current_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, &current_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, &current_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, &current_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, &current_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, &current_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, &current_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, &current_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, &current_buffer);
glBindBuffer(buffer_type, list_handle);
glBufferSubData(buffer_type, offset, count, data);
glBindBuffer(buffer_type, current_buffer);
}