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.
This commit is contained in:
2025-05-09 16:41:29 -04:00
parent 7875b777e5
commit 6d37cd93e3
10 changed files with 188 additions and 60 deletions

View File

@@ -32,7 +32,7 @@ CPMAddPackage(
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(

View File

@@ -1,31 +0,0 @@
#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;

View File

@@ -1,6 +1,38 @@
#version 120
#include "jgl.glsl"
#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;

View File

@@ -1,10 +1,55 @@
#version 120
// TODO this will fail if we don't have the extension.
#extension GL_ARB_instanced_arrays : enable
#include "jgl.glsl"
#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;
@@ -16,11 +61,11 @@ varying vec2 GL_TEXTURE6_COORD;
varying vec2 GL_TEXTURE7_COORD;
vec4 Default() {
v_color = gl_Color;
return gl_ModelViewProjectionMatrix * gl_Vertex;
}
void main() {
v_color = gl_Color;
GL_TEXTURE0_COORD = gl_MultiTexCoord0.xy;
GL_TEXTURE1_COORD = gl_MultiTexCoord1.xy;
GL_TEXTURE2_COORD = gl_MultiTexCoord2.xy;
@@ -30,6 +75,8 @@ void main() {
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();
@@ -92,5 +139,13 @@ void main() {
else { gl_Position = Default(); }
*/
gl_Position = Default();
if (JGL_RENDERING_ROUTINE == J2D_FillRect) {
if (!JGL_INSTANCED_RENDERING) { gl_Position = Default(); return; }
vec2 scaled = a_vertex_position * a_instance_size;
vec2 world_pos = scaled + a_instance_position;
gl_Position = gl_ModelViewProjectionMatrix * vec4(world_pos, 0.0, 1.0);
v_color = a_instance_color;
}
else { gl_Position = Default(); }
}

View File

@@ -35,10 +35,10 @@ public:
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);
Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
/// Creates a shader by compiling a vertex and fragment program from the respective GLSL source-strings.
Shader(const std::string& vertex_code, const std::string& fragment_code);
Shader(const std::string& vertex_code, const std::string& fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
/// @return True if the shader program successfully loaded and compiled.
[[nodiscard]] bool Loaded() const;

View File

@@ -15,7 +15,9 @@ using namespace JGL;
using JGL::Font;
float fps = 0.0f;
std::vector<Vector2> rect_pos;
std::vector<Vector2> rect_size;
std::vector<Color4> rect_colors;
/// A draggable 2D point that highlights when moused over and when clicked.
class Gizmo
{
@@ -137,7 +139,14 @@ public:
//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"));
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}});
for (unsigned int i = 0; i < 100; i++) {
rect_pos.emplace_back(420, 420);
rect_size.emplace_back(20, 20);
rect_colors.emplace_back(Colors::Red);
}
}
EulerAngleXYZ textAngle = {0,0,0};
@@ -178,6 +187,7 @@ public:
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});
@@ -192,6 +202,7 @@ public:
J2D::Begin(j2d_render_target, shader, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::BatchFillRect(rect_colors.data(), rect_pos.data(), rect_size.data(), rect_pos.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);
@@ -235,7 +246,6 @@ public:
J2D::DrawRenderTarget(j2d_render_target, {0, 0});
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
J2D::End();
}
void OnRefresh(float elapsed) override {

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

@@ -272,25 +272,68 @@ void J2D::BatchFillRect(const Color4* colors, const Vector2* positions, const Ve
if (rect_count <= 0)
return;
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->GetHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillRect);
for (size_t i = 0; i < rect_count; i++) {
glPushMatrix();
glColor4ubv(colors[i].ptr());
glTranslatef(positions[i].x, positions[i].y + sizes[i].y, 0);
glScalef(sizes[i].x, sizes[i].y, 1);
glDrawArrays(GL_QUADS, 0, 4);
glPopMatrix();
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->GetHandle());
if (rect_count == 1 || !supports_instanced || !current_state.current_shader) {
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
for (size_t i = 0; i < rect_count; i++) {
glPushMatrix();
glColor4ubv(colors[i].ptr());
glTranslatef(positions[i].x, positions[i].y + sizes[i].y, 0);
glScalef(sizes[i].x, sizes[i].y, 1);
glDrawArrays(GL_QUADS, 0, 4);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else {
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", true);
std::vector<Instance> instances;
instances.reserve(rect_count);
for (size_t i = 0; i < rect_count; ++i)
instances.emplace_back(Vector2(positions[i].x, positions[i].y + sizes[i].y), sizes[i], colors[i]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
glVertexAttribDivisorARB(0, 0);
// count * 5 because 4x float & 4x uint8_t = sizeof(float).
VRamList instance_buffer((GLfloat*) instances.data(), instances.size() * 5, VRamUsageHint::Stream);
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer.GetHandle());
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Instance), (GLvoid*) offsetof(Instance, position));
glVertexAttribDivisorARB(1, 1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Instance), (GLvoid*) offsetof(Instance, size));
glVertexAttribDivisorARB(2, 1);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Instance), (GLvoid*) offsetof(Instance, color));
glVertexAttribDivisorARB(3, 1);
glDrawArraysInstancedARB(GL_QUADS, 0, 4, rect_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);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColor4fv(default_state.draw_color);
}

View File

@@ -96,6 +96,17 @@ 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;
struct Instance {
public:
Vector2 position;
Vector2 size;
Color4 color;
public:
Instance(const Vector2& position, const Vector2& size, const Color4& color) : position(position), size(size), color(color) {}
~Instance() = default;
};
}
namespace JGL::J2D {

View File

@@ -115,8 +115,8 @@ namespace JGL {
}
};
Shader::Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path) :
Shader(ReadFile(vertex_source_path), ReadFile(fragment_source_path)) {
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;
fragmentPath = fragment_source_path;
}
@@ -128,13 +128,13 @@ namespace JGL {
if (type != "PROGRAM") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
glGetShaderInfoLog(shader, 1024, nullptr, infoLog);
OnCompilationErrorMessage.Invoke( std::format("COMPILATION_ERROR: {}", type), infoLog);
}
} else {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
glGetProgramInfoLog(shader, 1024, nullptr, infoLog);
OnCompilationErrorMessage.Invoke(std::format("COMPILATION_ERROR: {}", type), infoLog);
}
}
@@ -157,7 +157,7 @@ namespace JGL {
return glGetAttribLocation(id, name.c_str());
}
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code) {
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings) {
vertexSource = vertex_code;
fragmentSource = fragment_code;
@@ -169,21 +169,25 @@ namespace JGL {
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glShaderSource(fragment, 1, &fShaderCode, nullptr);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// 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");