Compare commits

...

34 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
2a2410e9bf Merge pull request 'Shader Implementation' (#42) from shaders_again into master
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m29s
Reviewed-on: #42
2025-04-15 01:21:42 -04:00
fdabbe866f Implement doxygen annotation for Shader class.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m55s
2025-04-14 22:12:28 -04:00
dac830fc7c Implement ineffectual shader for basis testing.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m44s
2025-04-14 21:45:42 -04:00
019b4aa5ae Implement Shader::UseDefault()
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-04-14 21:44:33 -04:00
3a293a2e0c Even Epicer
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m56s
2025-04-14 21:37:27 -04:00
73de143ec5 Epic Color Transition Fragment Shader
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-04-14 21:36:08 -04:00
5068b4660e Josh Attempts Shaders
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 3m24s
2025-04-14 21:28:06 -04:00
fd656cd543 Upgrade mcolor version.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 3m11s
2025-02-26 15:19:46 -05:00
291b3f3778 Fix the wireframe AABB not rendering correctly.
Some checks are pending
Run ReCI Build Test / Explore-Gitea-Actions (push) Waiting to run
2025-02-23 22:04:20 -05:00
21 changed files with 1594 additions and 262 deletions

View File

@@ -17,7 +17,7 @@ include(cmake/CPM.cmake)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
URL https://git.redacted.cc/maxine/mcolor/archive/Release-1.zip
)
CPMAddPackage(
@@ -27,17 +27,17 @@ CPMAddPackage(
CPMAddPackage(
NAME ReWindow
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-32.zip
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-34.zip
)
CPMAddPackage(
NAME GLAD
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo_depthtexture_shadow_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,5 +1,154 @@
#version 120
void main() {
gl_FragColor = vec4(1, 1, 1, 1);
#define J2D_DrawPoint 1
#define J2D_DrawPoints 2
#define J2D_DrawLine 3
#define J2D_DrawLines 4
#define J2D_DrawDottedLine 5
#define J2D_DrawDashedLine 6
#define J2D_DrawGradientLine 7
#define J2D_OutlineRect 8
#define J2D_OutlineRoundedRect 9
#define J2D_OutlineChamferRect 10
#define J2D_FillRect 11
#define J2D_FillGradientRect 12
#define J2D_FillRoundedRect 13
#define J2D_FillChamferRect 14
#define J2D_DrawRenderTarget 15
#define J2D_DrawPartialRenderTarget 16
#define J2D_DrawSprite 17
#define J2D_DrawAlphaMaskSprite 18
#define J2D_DrawPartialSprite 19
#define J2D_DrawMirrorSprite 20
#define J2D_OutlineCircle 21
#define J2D_FillCircle 22
#define J2D_OutlineTriangle 23
#define J2D_FillTriangle 24
#define J2D_FillGradientTriangle 25
#define J2D_DrawCubicBezierCurve 26
#define J2D_OutlinePolygon 27
#define J2D_DrawString 28
#define J2D_DrawArc 29
uniform int JGL_RENDERING_ROUTINE;
uniform bool JGL_INSTANCED_RENDERING;
// The number of texture units that have been set.
uniform int TEXTURE_UNIT_SET_COUNT;
// The color manually set with glColor4f, glColor4ubv etc.
varying vec4 v_color;
// Texture unit 0 - 7 (8 - 31 will come later).
uniform sampler2D GL_TEXTURE0;
uniform sampler2D GL_TEXTURE1;
uniform sampler2D GL_TEXTURE2;
uniform sampler2D GL_TEXTURE3;
uniform sampler2D GL_TEXTURE4;
uniform sampler2D GL_TEXTURE5;
uniform sampler2D GL_TEXTURE6;
uniform sampler2D GL_TEXTURE7;
// Texture coordinates.
varying vec2 GL_TEXTURE0_COORD;
varying vec2 GL_TEXTURE1_COORD;
varying vec2 GL_TEXTURE2_COORD;
varying vec2 GL_TEXTURE3_COORD;
varying vec2 GL_TEXTURE4_COORD;
varying vec2 GL_TEXTURE5_COORD;
varying vec2 GL_TEXTURE6_COORD;
varying vec2 GL_TEXTURE7_COORD;
void DrawColorOnly() {
gl_FragColor = v_color;
}
void SampleTextureUnits() {
if (JGL_RENDERING_ROUTINE == J2D_DrawString)
gl_FragColor = vec4(v_color.rgb, v_color.a * texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD).a);
// Draw sprite, partial sprite, mirror sprite, render target, partial render target.
else if (TEXTURE_UNIT_SET_COUNT == 1)
gl_FragColor = v_color * texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD);
// Draw alpha masked sprite.
else if (TEXTURE_UNIT_SET_COUNT == 2) {
vec4 color_texture = texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD);
float alpha_mask = texture2D(GL_TEXTURE1, GL_TEXTURE1_COORD).a;
gl_FragColor = vec4(v_color.rgb * color_texture.rgb, v_color.a * alpha_mask);
}
}
void Default() {
if (TEXTURE_UNIT_SET_COUNT == 0) {
DrawColorOnly(); return;
}
SampleTextureUnits();
}
void main() {
/* 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,7 +1,155 @@
#version 120
// TODO this will fail if we don't have the extension.
#extension GL_ARB_instanced_arrays : enable
attribute vec2 position;
#define J2D_DrawPoint 1
#define J2D_DrawPoints 2
#define J2D_DrawLine 3
#define J2D_DrawLines 4
#define J2D_DrawDottedLine 5
#define J2D_DrawDashedLine 6
#define J2D_DrawGradientLine 7
#define J2D_OutlineRect 8
#define J2D_OutlineRoundedRect 9
#define J2D_OutlineChamferRect 10
#define J2D_FillRect 11
#define J2D_FillGradientRect 12
#define J2D_FillRoundedRect 13
#define J2D_FillChamferRect 14
#define J2D_DrawRenderTarget 15
#define J2D_DrawPartialRenderTarget 16
#define J2D_DrawSprite 17
#define J2D_DrawAlphaMaskSprite 18
#define J2D_DrawPartialSprite 19
#define J2D_DrawMirrorSprite 20
#define J2D_OutlineCircle 21
#define J2D_FillCircle 22
#define J2D_OutlineTriangle 23
#define J2D_FillTriangle 24
#define J2D_FillGradientTriangle 25
#define J2D_DrawCubicBezierCurve 26
#define J2D_OutlinePolygon 27
#define J2D_DrawString 28
#define J2D_DrawArc 29
uniform int JGL_RENDERING_ROUTINE;
uniform bool JGL_INSTANCED_RENDERING;
// The color manually set with glColor4f, glColor4ubv etc etc.
varying vec4 v_color;
// Local space vertices for instanced rendering.
attribute vec2 a_vertex_position; // 0
// The position at which to render the instance.
attribute vec2 a_instance_position; // 1
// The scale of the instance.
attribute vec2 a_instance_size; // 2
// The color of the instance.
attribute vec4 a_instance_color; // 3
// The texture coordinates in each texture unit.
varying vec2 GL_TEXTURE0_COORD;
varying vec2 GL_TEXTURE1_COORD;
varying vec2 GL_TEXTURE2_COORD;
varying vec2 GL_TEXTURE3_COORD;
varying vec2 GL_TEXTURE4_COORD;
varying vec2 GL_TEXTURE5_COORD;
varying vec2 GL_TEXTURE6_COORD;
varying vec2 GL_TEXTURE7_COORD;
vec4 Default() {
v_color = gl_Color;
return gl_ModelViewProjectionMatrix * gl_Vertex;
}
vec4 DefaultInstanced() {
v_color = a_instance_color;
vec2 scaled = a_vertex_position * a_instance_size;
vec2 world_pos = scaled + a_instance_position;
return gl_ModelViewProjectionMatrix * vec4(world_pos, 0.0, 1.0);
}
#include "shared.glsl"
void main() {
gl_Position = vec4(position.x, position.y, 1.0, 1.0);
GL_TEXTURE0_COORD = gl_MultiTexCoord0.xy;
GL_TEXTURE1_COORD = gl_MultiTexCoord1.xy;
GL_TEXTURE2_COORD = gl_MultiTexCoord2.xy;
GL_TEXTURE3_COORD = gl_MultiTexCoord3.xy;
GL_TEXTURE4_COORD = gl_MultiTexCoord4.xy;
GL_TEXTURE5_COORD = gl_MultiTexCoord5.xy;
GL_TEXTURE6_COORD = gl_MultiTexCoord6.xy;
GL_TEXTURE7_COORD = gl_MultiTexCoord7.xy;
/* If you want behavior per JGL draw function, Or for specific ones. The order here matters because some JGL functions call others.
if (JGL_RENDERING_ROUTINE == J2D_DrawRenderTarget)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialRenderTarget)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawAlphaMaskSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawMirrorSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawString)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoint)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoints)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawCubicBezierCurve)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawLines)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawDottedLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawDashedLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawGradientLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRoundedRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillChamferRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillRoundedRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineCircle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillCircle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineTriangle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillTriangle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientTriangle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlinePolygon)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawArc)
gl_Position = Default();
else { gl_Position = Default(); }
*/
if (JGL_INSTANCED_RENDERING)
gl_Position = DefaultInstanced();
else
gl_Position = Default();
}

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().
@@ -93,6 +99,13 @@ namespace JGL::J2D {
void DrawPoint(const Color4& color, const Vector2& coordinates, float radius = 1.f);
void DrawPoint(const Color4& color, float x, float y, 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 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
@@ -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;
};

121
include/JGL/types/Shader.h Normal file
View File

@@ -0,0 +1,121 @@
#pragma once
#include <filesystem>
#include <J3ML/LinearAlgebra.hpp>
#include <fstream>
#include <iostream>
#include "glad/glad.h"
#include <Event.h>
// LearnOpenGL::Shader
// OpenGL Shader Class Wrapper
// Updated by dawsh
// https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/shader.h
namespace JGL {
using namespace J3ML::LinearAlgebra;
class Shader;
}
/// TODO: Eventually support Hot-reloading shaders like in shadertoy. Should help tremendously with debugging.
class JGL::Shader {
public:
static inline Event<std::string, std::string> OnCompilationErrorMessage;
static bool HasFile(const std::filesystem::path& path)
{
return std::filesystem::exists(path);
}
static std::string ReadFile(const std::filesystem::path& path);
/// The default constructor does not initialize any member values.
Shader() = default;
/// Creates a shader by compiling a vertex and fragment program from the sources in the respective filesystem paths.
Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
/// Creates a shader by compiling a vertex and fragment program from the respective GLSL source-strings.
Shader(const std::string& vertex_code, const std::string& fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
/// @return True if the shader program successfully loaded and compiled.
[[nodiscard]] bool Loaded() const;
/// @return The integer handle that OpenGL links to this shader program.
[[nodiscard]] unsigned int Handle() const;
/// Enable this shader. All rendering performed thereafter will be affected by this shader code.
/// @see UseDefault.
// TODO: Implement for hot-reloading.
void Reload();
// TODO: Implement for hot-reloading.
void Unload();
/// @return The Uniform variable linked to the specified name.
/// A Uniform is global a variable that is unique per shader program object, and can be accessed from any shader at any stage in the shader program.
GLint Uniform(const std::string& name) const;
/// @return The Attribute variable linked to the specified name.
/// Attributes differ from Uniforms in that their value is different for each instance of the shader-program as it is running.
[[nodiscard]] GLint Attribute(const std::string& name) const;
/// Sets a `uniform bool name = value` in the shader program.
void SetBool (const std::string& name, bool value) const;
/// Sets a `uniform int name = value` in the shader program.
void SetInt (const std::string& name, int value) const;
/// Sets a `uniform float name = value` in the shader program.
void SetFloat(const std::string& name, float value) const;
/// Sets a `uniform vec2 name = value` in the shader program.
/// @note GLSL has builtin vec2, while we implement a Vector2 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector2.
void SetVector2(const std::string& name, const Vector2& value) const;
/// Sets a `uniform vec2 name = value` in the shader program.
/// @note GLSL has builtin vec2, while we implement a Vector2 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector2.
void SetVector2(const std::string& name, float x, float y) const;
/// Sets a `uniform vec3 name = value` in the shader program.
/// @note GLSL has builtin vec3, while we implement a Vector3 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector3.
void SetVector3(const std::string& name, const Vector3& value) const;
/// Sets a `uniform vec3 name = value` in the shader program.
/// @note GLSL has builtin vec3, while we implement a Vector3 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector3.
void SetVector3(const std::string& name, float x, float y, float z) const;
/// Sets a `uniform vec4 name = value` in the shader program.
/// @note GLSL has builtin vec4, while we implement aVector4 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector4.
void SetVector4(const std::string& name, const Vector4& value) const;
/// Sets a `uniform vec4 name = value` in the shader program.
/// @note GLSL has builtin vec4, while we implement a Vector4 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Vector4.
void SetVector4(const std::string& name, float x, float y, float z, float w) const;
/// Sets a `uniform mat2 name = value` in the shader program.
/// @note GLSL has builtin mat2, while we implement a Matrix2x2 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Matrix2x2
void SetMatrix2x2(const std::string& name, const Matrix2x2& value) const;
/// Sets a `uniform mat3 name = value` in the shader program.
/// @note GLSL has builtin mat3, while we implement a Matrix3x3 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Matrix3x3
void SetMatrix3x3(const std::string& name, const Matrix3x3& value) const;
/// Sets a `uniform mat4 name = value` in the shader program.
/// @note GLSL has builtin mat4, while we implement a Matrix4x4 type. Please be aware there may be differences in implementation between them!
/// @see class J3ML::LinearAlgebra::Matrix4x4
void SetMatrix4x4(const std::string& name, const Matrix4x4& value) const;
// TODO: Implement Uniform-Setters for GLSL types that do not have a J3ML corollary (dmat3x4, dvec4, etc).
protected:
private:
unsigned int id = 0;
std::string vertexPath;
std::string vertexSource;
std::string fragmentSource;
std::string fragmentPath;
mutable std::unordered_map<std::string, GLint> uniform_location_cache;
static void checkCompileErrors(GLuint shader, const std::string& type);
};

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

@@ -7,6 +7,7 @@
#include <J3ML/Geometry/AABB.hpp>
#include <ReWindow/Logger.h>
#include <JGL/types/VertexArray.h>
#include <JGL/types/Shader.h>
using J3ML::LinearAlgebra::Vector2;
using namespace JGL::Fonts;
@@ -14,7 +15,7 @@ using namespace JGL;
using JGL::Font;
float fps = 0.0f;
std::vector<Instance2D> rect_instances;
/// A draggable 2D point that highlights when moused over and when clicked.
class Gizmo
{
@@ -111,6 +112,8 @@ JGL::Font FreeSans;
Texture* image;
Texture* image_mask;
RenderTarget* j2d_render_target;
Shader* shader;
Vector2 result;
class JGLDemoWindow : public ReWindow::OpenGLWindow
{
@@ -128,23 +131,30 @@ 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 = new Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"),
{{"a_vertex_position", 0}, {"a_instance_position", 1}, {"a_instance_size", 2}, {"a_instance_color", 3}});
result = Jupiteroid.MeasureString("The quick black fox jumps over the lazy dog.", 16);
for (unsigned int i = 0; i < 100; i++)
rect_instances.emplace_back(Colors::Red, Vector2(420, 420), Vector2(20, 20));
}
EulerAngleXYZ textAngle = {0,0,0};
float fov = 90;
u8 pulse = 0;
float pulse = 0;
float sprite_radians = 0;
bool fov_increasing = true;
int blit_pos = 0;
void display() {
pulse++;
pulse += 20 * delta_time;
float dt = GetDeltaTime();
JGL::Update({ GetSize().x, GetSize().y });
@@ -166,38 +176,40 @@ public:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera->render();
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
/* if rendering to screen space directly. */
auto test_light = PointLight({2,1,2}, {pulse,pulse,pulse, 255}, {pulse, pulse, pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
auto test_light = PointLight({2,1,2}, {(u8) pulse,(u8) pulse,(u8) pulse, 255}, {(u8) pulse, (u8) pulse, (u8) pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
// If a 3D object has transparency. The things you'd like to see through it must be drawn before.
J3D::Begin();
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
Sphere sphere = {{0,0, 0.5f}, 0.2125};
Sphere sphere = {{1,0, 0.5f}, 0.2125};
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 8, 8, true);
J3D::RequiredLight(&test_light);
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
J3D::WireframeAABB(Colors::Gray, {0,0,0.5f}, {0.11f, 0.06f, 0.11f});
AABB boxes[1] = {{Vector3(-0.2125, -0.2125,0.28750), Vector3(0.2125,0.2125,0.7125)}};
J3D::BatchWireframeAABB(Colors::Yellow, boxes, 1, 1);
J3D::WireframeAABB(Colors::Yellow, {0.5, 0, 0.5}, {0.125, 0.125, 0.125}, 1);
J3D::End();
J2D::Begin(j2d_render_target, true);
//JGL::ClearScreen(Colors::Red);
J2D::Begin(j2d_render_target, shader, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::BatchFillRect(rect_instances.data(), rect_instances.size());
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawPartialSprite(image, Vector2(225, 300), Vector2(image->GetDimensions()) * 0.25, Vector2(image->GetDimensions()) * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
J2D::FillGradientRect(Colors::Red, Colors::Green, Colors::Blue, Colors::White, {100,52}, {100,100});
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
auto box = JGL::Fonts::Jupiteroid.MeasureString("Hello g", 16);
J2D::FillChamferRect(Colors::Reds::LightSalmon, {150, 400}, {64, 64}, 5);
J2D::OutlineRoundedRect(Colors::Reds::LightCoral, {250, 350}, {128, 128}, 10, 2);
@@ -205,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,
@@ -224,17 +237,17 @@ public:
b.Draw();
c.Draw();
d.Draw();
J2D::End();
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 {
fps = GetRefreshRate();
if (IsKeyDown(Keys::RightArrow))
@@ -309,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);
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());
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillRect);
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 < rect_count; i++) {
for (size_t i = 0; i < instance_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);
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);
}
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++) {
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(colors[j].ptr());
glTranslatef(positions[j].x, positions[j].y, 0);
glScalef(radii[j], radii[j], 0);
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();
}
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

@@ -48,7 +48,7 @@ void JGL::J3D::Begin(bool two_pass) {
auto aspect = (float) window_size.x / (float) window_size.y;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
glLoadMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
glMatrixMode(GL_MODELVIEW);
//Get what the draw color was before we did anything.
@@ -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,8 +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->Handle());
for (size_t i = 0; i < box_count; i++) {
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
@@ -380,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);
glDrawArrays(GL_LINES, 0, ShapeCache::cube_vertex_data->GetLength());
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->Length(), GL_UNSIGNED_INT, nullptr);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -395,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);
@@ -406,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);
}
@@ -485,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++) {
@@ -494,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);
@@ -565,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,21 +6,59 @@
#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:
//Matrix4x4 transformation = Matrix4x4::Identity;
GLfloat clear_color[4] = {0, 0, 0, 1};
GLfloat draw_color[4] = {1, 1, 1, 1};
GLint viewport[4] = {0, 0, 0, 0};
GLint blend_func[2];
GLuint current_fbo = 0;
RenderTarget* current_render_target = nullptr;
GLint current_shader_handle = 0;
Shader* current_shader = nullptr;
bool texture_2D = false;
bool texture_coordinate_array = false;
@@ -36,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);
};
@@ -58,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 {
@@ -68,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

@@ -109,60 +109,35 @@ namespace JGL {
}
Vector2 Font::MeasureString(const std::string& text, unsigned int ptSize) {
Vector2 extents = Vector2(0,0);
bool font_of_size_in_cache = false;
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 (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);
if (f->getFontIndex() == this->index && f->getFontSize() == 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);
auto glyph = f->getGlyph(c);
extents.x += glyph->advanceX;
extents.y = glyph->ascent + glyph->descent;
}
return extents;
}
}
// No cache
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
for (const char& c : text) {
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) {

269
src/types/Shader.cpp Normal file
View File

@@ -0,0 +1,269 @@
#include <JGL/types/Shader.h>
#include <glad/glad.h>
namespace JGL {
class ShaderPreprocessor {
public:
std::string include_keyword = "#include";
ShaderPreprocessor() {}
std::string LoadShaderFile(const std::filesystem::path& filepath)
{
// if size is 0, it indicates, that we are at the top of the recursive load stack
bool stack_top = (already_included.size() == 0);
if (stack_top) {
already_included.emplace_back(filepath.string());
}
std::string ret_data = "";
std::ifstream file(filepath);
if (!file.good())
{
std::cout << "ERROR [ ShaderLoader::load_shader ]: Failed to start fstream, check if '" << filepath << "' exists\n";
return ret_data;
}
if (file.is_open()) {
std::string line;
while (getline(file, line)) {
if (line.find(include_keyword) == 0)
{
// Get path between double quotes
std::string rel_include_path = extract_first_between(line.substr(include_keyword.length()), '"', '"');
// Modify path according to os
// TODO: Use std::filesystem dummy...
// later, let me get this stolen code to work first.
#ifdef _WIN32
std::replace(rel_include_path.begin(), rel_include_path.end(), '/', '\\');
#elif __linux__
std::replace(rel_include_path.begin(), rel_include_path.end(), '\\', '/');
#endif
std::string full_include_path = extract_path(filepath.string()) + rel_include_path;
// Avoid including self
if (filepath == full_include_path) {
std::cout << "WARNING [ ShaderLoader::load_shader ]: '"<< filepath <<"' tried to include itself\n";
continue;
} else {
bool include_flag = true;
// check if the current file is already included
for (const auto& file_to_check : already_included) {
// Avoid duplicate includes
if (file_to_check == full_include_path) {
include_flag = false;
break;
}
}
// If not yet included, push path to include vector and replace line with file contents
if (include_flag) {
already_included.push_back(full_include_path);
// Repeat recursively.
ret_data += LoadShaderFile(full_include_path) + '\n';
}
}
} else {
ret_data += line + "\n";
}
}
file.close();
} else {
std::cout << "ERROR [ ShaderLoader::load_shader ]: Unable to open file '" << filepath << "'\n";
}
// We are back to the first call
if (stack_top) {
already_included.clear();
}
return ret_data;
}
std::string PreprocessShaderSource(const std::string& source);
private:
std::vector<std::string> already_included;
/// Helper function that strips filename from a path, basically getting the path to the directory containing the file.
std::string extract_path(const std::string& path)
{
// find the position of the last directory separator.
std::size_t pos = path.find_last_of("\\/");
// strip fname from path
if (pos != std::string::npos) {
return path.substr(0, pos+1);
}
return "";
}
std::string extract_first_between(const std::string& input, char start_symbol, char end_symbol)
{
size_t start_index = input.find(start_symbol);
size_t end_index = input.find(end_symbol, start_index+1);
std::string extracted = "";
if (start_index != std::string::npos && end_index != std::string::npos) {
extracted = input.substr(start_index + 1, end_index - start_index - 1);
} else {
std::cout << "ERROR [ ShaderLoader::extract_first_between ]: Start '" << start_symbol << "' or end symbol '" << end_symbol << "' not found" << std::endl;
}
return extracted;
}
};
Shader::Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path, const std::vector<std::pair<std::string, GLint>>& attribute_bindings) :
Shader(ReadFile(vertex_source_path), ReadFile(fragment_source_path), attribute_bindings) {
vertexPath = vertex_source_path.string();
fragmentPath = fragment_source_path.string();
}
void Shader::checkCompileErrors(GLuint shader, const std::string& type) {
GLint success;
GLchar infoLog[1024];
if (type != "PROGRAM") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, nullptr, infoLog);
OnCompilationErrorMessage.Invoke( std::format("COMPILATION_ERROR: {}", type), infoLog);
}
} else {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader, 1024, nullptr, infoLog);
OnCompilationErrorMessage.Invoke(std::format("COMPILATION_ERROR: {}", type), infoLog);
}
}
if (success)
std::cout << "Shader compiled successfully" << std::endl;
}
GLint Shader::Uniform(const std::string &name) const {
auto it = uniform_location_cache.find(name);
if (it == uniform_location_cache.end()) {
auto location = glGetUniformLocation(id, name.c_str());
uniform_location_cache[name] = location;
return location;
}
return it->second;
}
GLint Shader::Attribute(const std::string &name) const {
return glGetAttribLocation(id, name.c_str());
}
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings) {
vertexSource = vertex_code;
fragmentSource = fragment_code;
const char* vShaderCode = vertex_code.c_str();
const char* fShaderCode = fragment_code.c_str();
// 2. Compile shaders.
unsigned int vertex, fragment;
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, nullptr);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
id = glCreateProgram();
// bind attribute locations.
for (auto& a: attribute_bindings)
glBindAttribLocation(id, a.second, a.first.c_str());
glAttachShader(id, vertex);
glAttachShader(id, fragment);
glLinkProgram(id);
checkCompileErrors(id, "PROGRAM");
// delete the shaders as they're linked into our program now and are no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
bool Shader::Loaded() const { return id != 0; }
unsigned int Shader::Handle() const { return id;}
void Shader::SetBool(const std::string &name, bool value) const { glUniform1i(Uniform(name), (int)value); }
void Shader::SetInt(const std::string &name, int value) const { glUniform1i(Uniform(name), value); }
void Shader::SetFloat(const std::string &name, float value) const { glUniform1f(Uniform(name), value); }
void Shader::SetVector2(const std::string &name, const Vector2 &value) const { glUniform2f(Uniform(name), value.x, value.y); }
void Shader::SetVector2(const std::string &name, float x, float y) const { glUniform2f(Uniform(name), x, y); }
void Shader::SetVector3(const std::string &name, const Vector3 &value) const { glUniform3f(Uniform(name), value.x, value.y, value.z); }
void Shader::SetVector3(const std::string &name, float x, float y, float z) const { glUniform3f(Uniform(name), x, y, z); }
void Shader::SetVector4(const std::string &name, const Vector4 &value) const { glUniform4f(Uniform(name), value.x, value.y, value.z, value.w); }
void Shader::SetVector4(const std::string &name, float x, float y, float z, float w) const { glUniform4f(Uniform(name), x, y, z, w); }
void Shader::SetMatrix2x2(const std::string &name, const Matrix2x2 &value) const {
/// TODO: Verify if glsl expects row-major or col-major!!
bool transpose = false;
glUniformMatrix2fv(Uniform(name), 4, transpose, value.ptr());
}
void Shader::SetMatrix3x3(const std::string &name, const Matrix3x3 &value) const {
/// TODO: Verify if glsl expects row-major or col-major!!
bool transpose = false;
glUniformMatrix3fv(Uniform(name), 9, transpose, value.ptr());
}
void Shader::SetMatrix4x4(const std::string &name, const Matrix4x4 &value) const {
/// TODO: Verify if glsl expects row-major or col-major!!
bool transpose = false;
glUniformMatrix4fv(Uniform(name), 16, transpose, value.ptr());
}
std::string Shader::ReadFile(const std::filesystem::path &path) {
/*std::string contents;
std::ifstream file;
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// Open Files
file.open(path);
std::stringstream stream;
// Read file's buffer contents into streams
stream << file.rdbuf();
// close file handlers
file.close();
// convert stream into string
contents = stream.str();
return contents;
} catch (std::ifstream::failure& e) {
std::cout << "ERROR::FILE_READ_FAILURE: " << e.what() << std::endl;
return "";
}*/
ShaderPreprocessor processor;
return processor.LoadShaderFile(path);
}
}

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