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
This commit is contained in:
2025-06-06 13:44:47 -04:00
21 changed files with 1343 additions and 435 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

@@ -0,0 +1,30 @@
#ifndef include_shared
#define include_shared
#version 120
vec3 rgb2hsb( in vec3 c ){
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz),
vec4(c.gb, K.xy),
step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r),
vec4(c.r, p.yzx),
step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
d / (q.x + e),
q.x);
}
// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
}
#endif

View File

@@ -1,50 +1,154 @@
#version 120
#ifdef GL_ES
precision mediump float;
#endif
#define J2D_DrawPoint 1
#define J2D_DrawPoints 2
#define J2D_DrawLine 3
#define J2D_DrawLines 4
#define J2D_DrawDottedLine 5
#define J2D_DrawDashedLine 6
#define J2D_DrawGradientLine 7
#define J2D_OutlineRect 8
#define J2D_OutlineRoundedRect 9
#define J2D_OutlineChamferRect 10
#define J2D_FillRect 11
#define J2D_FillGradientRect 12
#define J2D_FillRoundedRect 13
#define J2D_FillChamferRect 14
#define J2D_DrawRenderTarget 15
#define J2D_DrawPartialRenderTarget 16
#define J2D_DrawSprite 17
#define J2D_DrawAlphaMaskSprite 18
#define J2D_DrawPartialSprite 19
#define J2D_DrawMirrorSprite 20
#define J2D_OutlineCircle 21
#define J2D_FillCircle 22
#define J2D_OutlineTriangle 23
#define J2D_FillTriangle 24
#define J2D_FillGradientTriangle 25
#define J2D_DrawCubicBezierCurve 26
#define J2D_OutlinePolygon 27
#define J2D_DrawString 28
#define J2D_DrawArc 29
attribute vec4 gl_Color;
uniform vec2 u_resolution;
uniform float u_time;
uniform int JGL_RENDERING_ROUTINE;
uniform bool JGL_INSTANCED_RENDERING;
vec3 rgb2hsb( in vec3 c ){
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz),
vec4(c.gb, K.xy),
step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r),
vec4(c.r, p.yzx),
step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
d / (q.x + e),
q.x);
// The number of texture units that have been set.
uniform int TEXTURE_UNIT_SET_COUNT;
// The color manually set with glColor4f, glColor4ubv etc.
varying vec4 v_color;
// Texture unit 0 - 7 (8 - 31 will come later).
uniform sampler2D GL_TEXTURE0;
uniform sampler2D GL_TEXTURE1;
uniform sampler2D GL_TEXTURE2;
uniform sampler2D GL_TEXTURE3;
uniform sampler2D GL_TEXTURE4;
uniform sampler2D GL_TEXTURE5;
uniform sampler2D GL_TEXTURE6;
uniform sampler2D GL_TEXTURE7;
// Texture coordinates.
varying vec2 GL_TEXTURE0_COORD;
varying vec2 GL_TEXTURE1_COORD;
varying vec2 GL_TEXTURE2_COORD;
varying vec2 GL_TEXTURE3_COORD;
varying vec2 GL_TEXTURE4_COORD;
varying vec2 GL_TEXTURE5_COORD;
varying vec2 GL_TEXTURE6_COORD;
varying vec2 GL_TEXTURE7_COORD;
void DrawColorOnly() {
gl_FragColor = v_color;
}
// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
void SampleTextureUnits() {
if (JGL_RENDERING_ROUTINE == J2D_DrawString)
gl_FragColor = vec4(v_color.rgb, v_color.a * texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD).a);
// Draw sprite, partial sprite, mirror sprite, render target, partial render target.
else if (TEXTURE_UNIT_SET_COUNT == 1)
gl_FragColor = v_color * texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD);
// Draw alpha masked sprite.
else if (TEXTURE_UNIT_SET_COUNT == 2) {
vec4 color_texture = texture2D(GL_TEXTURE0, GL_TEXTURE0_COORD);
float alpha_mask = texture2D(GL_TEXTURE1, GL_TEXTURE1_COORD).a;
gl_FragColor = vec4(v_color.rgb * color_texture.rgb, v_color.a * alpha_mask);
}
}
void Default() {
if (TEXTURE_UNIT_SET_COUNT == 0) {
DrawColorOnly(); return;
}
SampleTextureUnits();
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 color = vec3(0.0);
// We map x (0.0 - 1.0) to the hue (0.0 - 1.0)
// And the y (0.0 - 1.0) to the brightness
color = hsb2rgb(vec3(st.x,1.0,st.y));
gl_FragColor = vec4(color,1.0);
gl_FragColor = gl_Color;
/* If you want behavior per JGL draw function, Or for specific ones. The order here matters because some JGL functions call others.
if (JGL_RENDERING_ROUTINE == J2D_DrawRenderTarget)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialRenderTarget)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawAlphaMaskSprite)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawMirrorSprite)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawSprite)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawString)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoint)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoints)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawCubicBezierCurve)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawLine)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawLines)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawDottedLine)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawDashedLine)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawGradientLine)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRoundedRect)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillChamferRect)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillRoundedRect)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientRect)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRect)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillRect)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineCircle)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillCircle)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineTriangle)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillTriangle)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientTriangle)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlinePolygon)
Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawArc)
Default();
else { Default(); }
*/
Default();
}

View File

@@ -1,5 +1,155 @@
#version 120
// TODO this will fail if we don't have the extension.
#extension GL_ARB_instanced_arrays : enable
#define J2D_DrawPoint 1
#define J2D_DrawPoints 2
#define J2D_DrawLine 3
#define J2D_DrawLines 4
#define J2D_DrawDottedLine 5
#define J2D_DrawDashedLine 6
#define J2D_DrawGradientLine 7
#define J2D_OutlineRect 8
#define J2D_OutlineRoundedRect 9
#define J2D_OutlineChamferRect 10
#define J2D_FillRect 11
#define J2D_FillGradientRect 12
#define J2D_FillRoundedRect 13
#define J2D_FillChamferRect 14
#define J2D_DrawRenderTarget 15
#define J2D_DrawPartialRenderTarget 16
#define J2D_DrawSprite 17
#define J2D_DrawAlphaMaskSprite 18
#define J2D_DrawPartialSprite 19
#define J2D_DrawMirrorSprite 20
#define J2D_OutlineCircle 21
#define J2D_FillCircle 22
#define J2D_OutlineTriangle 23
#define J2D_FillTriangle 24
#define J2D_FillGradientTriangle 25
#define J2D_DrawCubicBezierCurve 26
#define J2D_OutlinePolygon 27
#define J2D_DrawString 28
#define J2D_DrawArc 29
uniform int JGL_RENDERING_ROUTINE;
uniform bool JGL_INSTANCED_RENDERING;
// The color manually set with glColor4f, glColor4ubv etc etc.
varying vec4 v_color;
// Local space vertices for instanced rendering.
attribute vec2 a_vertex_position; // 0
// The position at which to render the instance.
attribute vec2 a_instance_position; // 1
// The scale of the instance.
attribute vec2 a_instance_size; // 2
// The color of the instance.
attribute vec4 a_instance_color; // 3
// The texture coordinates in each texture unit.
varying vec2 GL_TEXTURE0_COORD;
varying vec2 GL_TEXTURE1_COORD;
varying vec2 GL_TEXTURE2_COORD;
varying vec2 GL_TEXTURE3_COORD;
varying vec2 GL_TEXTURE4_COORD;
varying vec2 GL_TEXTURE5_COORD;
varying vec2 GL_TEXTURE6_COORD;
varying vec2 GL_TEXTURE7_COORD;
vec4 Default() {
v_color = gl_Color;
return gl_ModelViewProjectionMatrix * gl_Vertex;
}
vec4 DefaultInstanced() {
v_color = a_instance_color;
vec2 scaled = a_vertex_position * a_instance_size;
vec2 world_pos = scaled + a_instance_position;
return gl_ModelViewProjectionMatrix * vec4(world_pos, 0.0, 1.0);
}
#include "shared.glsl"
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
GL_TEXTURE0_COORD = gl_MultiTexCoord0.xy;
GL_TEXTURE1_COORD = gl_MultiTexCoord1.xy;
GL_TEXTURE2_COORD = gl_MultiTexCoord2.xy;
GL_TEXTURE3_COORD = gl_MultiTexCoord3.xy;
GL_TEXTURE4_COORD = gl_MultiTexCoord4.xy;
GL_TEXTURE5_COORD = gl_MultiTexCoord5.xy;
GL_TEXTURE6_COORD = gl_MultiTexCoord6.xy;
GL_TEXTURE7_COORD = gl_MultiTexCoord7.xy;
/* If you want behavior per JGL draw function, Or for specific ones. The order here matters because some JGL functions call others.
if (JGL_RENDERING_ROUTINE == J2D_DrawRenderTarget)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialRenderTarget)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawAlphaMaskSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawMirrorSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPartialSprite)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawString)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoint)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawPoints)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawCubicBezierCurve)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawLines)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawDottedLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawDashedLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawGradientLine)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRoundedRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillChamferRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillRoundedRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillRect)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineCircle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillCircle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlineTriangle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillTriangle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_FillGradientTriangle)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_OutlinePolygon)
gl_Position = Default();
else if (JGL_RENDERING_ROUTINE == J2D_DrawArc)
gl_Position = Default();
else { gl_Position = Default(); }
*/
if (JGL_INSTANCED_RENDERING)
gl_Position = DefaultInstanced();
else
gl_Position = Default();
}

View File

@@ -16,6 +16,7 @@
#include <Color4.hpp>
#include <JGL/types/Texture.h>
#include <JGL/types/Enums.h>
#include <JGL/types/Instance.h>
#include <JGL/types/FontCache.h>
#include <JGL/types/Font.h>
#include <JGL/types/RenderTarget.h>
@@ -30,6 +31,7 @@
#include <JGL/types/VRamList.h>
#include <JGL/types/VertexArray.h>
#include <JGL/types/TextureAtlas.h>
#include <JGL/types/Shader.h>
// Fonts that are included by default.
namespace JGL::Fonts {
@@ -46,6 +48,8 @@ namespace JGL::ShapeCache {
// Facing straight out.
inline VRamList* j2d_default_normal_data = nullptr;
inline VRamList* square_origin_topleft_vertex_data = nullptr;
inline VRamList* draw_points_positions = nullptr;
inline VRamList* draw_points_colors = nullptr;
void Init();
}
@@ -56,6 +60,8 @@ namespace JGL {
[[nodiscard]] bool Init(const Vector2i& window_size, float fovY, float far_plane);
void Update(const Vector2i& window_size);
/// Clear the default framebuffer for the OpenGL context (0).
void ClearScreen(const Color4& clear_color);
inline void PurgeFontCache() { JGL::fontCache.purgeCache(); }
@@ -73,7 +79,7 @@ namespace JGL::J2D {
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 3D content in between our calls.
/// @param render_target
/// @param clear_buffers
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
void Begin(RenderTarget* render_target = nullptr, Shader* shader = nullptr, bool clear_buffers = false);
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @see Begin().
@@ -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;
};

View File

@@ -24,25 +24,28 @@ class JGL::Shader {
public:
static inline Event<std::string, std::string> OnCompilationErrorMessage;
static bool HasFile(const std::filesystem::path& path)
{
return std::filesystem::exists(path);
}
static std::string ReadFile(const std::filesystem::path& path);
/// The default constructor does not initialize any member values.
Shader() = default;
/// Creates a shader by compiling a vertex and fragment program from the sources in the respective filesystem paths.
Shader(std::filesystem::path vertex_source_path, std::filesystem::path fragment_source_path);
Shader(const std::filesystem::path& vertex_source_path, const std::filesystem::path& fragment_source_path, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
/// Creates a shader by compiling a vertex and fragment program from the respective GLSL source-strings.
Shader(const std::string& vertex_code, const std::string& fragment_code);
Shader(const std::string& vertex_code, const std::string& fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings = {});
/// @return True if the shader program successfully loaded and compiled.
bool Loaded() const;
[[nodiscard]] bool Loaded() const;
/// @return The integer handle that OpenGL links to this shader program.
unsigned int Handle() const;
[[nodiscard]] unsigned int Handle() const;
/// Enable this shader. All rendering performed thereafter will be affected by this shader code.
/// @see UseDefault.
void Use();
static void Use(GLuint shader_program_id);
static void UseDefault();
// TODO: Implement for hot-reloading.
void Reload();
@@ -55,7 +58,7 @@ public:
/// @return The Attribute variable linked to the specified name.
/// Attributes differ from Uniforms in that their value is different for each instance of the shader-program as it is running.
GLint Attribute(const std::string& name) const;
[[nodiscard]] GLint Attribute(const std::string& name) const;
/// Sets a `uniform bool name = value` in the shader program.
void SetBool (const std::string& name, bool value) const;
@@ -110,6 +113,9 @@ protected:
private:
unsigned int id = 0;
std::string vertexPath;
std::string vertexSource;
std::string fragmentSource;
std::string fragmentPath;
mutable std::unordered_map<std::string, GLint> uniform_location_cache;
static void checkCompileErrors(GLuint shader, const std::string& type);
};

View File

@@ -5,52 +5,68 @@
#include <J3ML/LinearAlgebra/Vector2i.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/LinearAlgebra/Vector4.hpp>
#include <Color4.hpp>
namespace JGL {
class VRamList;
/// A hint for OpenGL on how the VBO is to be used.
enum VRamUsageHint : GLenum {
// Never updated after creation.
Fixed = GL_STATIC_DRAW,
// Modified occasionally.
Dynamic = GL_DYNAMIC_DRAW,
// Constantly modified and used one or a few times.
Stream = GL_STREAM_DRAW
};
}
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in VRam.
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in V-ram.
class JGL::VRamList {
private:
VRamUsageHint usage_hint = Fixed;
GLuint list_handle = 0;
long num_elements = 0;
long byte_count = 0;
bool element_array_buffer = false;
/// "Spin Locking" fix for multi-threading.
bool spin_lock = false;
// TODO mutex lock.
void load(const GLfloat* data, const long& size);
void load(const GLuint* data, const long& size);
void SetData(void* data, const long& count);
void UpdateData(void* data, const long& offset, const long& count);
void Erase();
public:
VRamList(const GLuint* data, const long& count);
VRamList(const GLfloat* data, const long& count);
VRamList(const Vector2* data, const long& count);
VRamList(const Vector3* data, const long& count);
VRamList(const Vector4* data, const long& count);
VRamList(const GLuint* data, const long& count, VRamUsageHint hint = Fixed);
VRamList(const GLfloat* data, const long& count, VRamUsageHint hint = Fixed);
VRamList(const Vector2* data, const long& count, VRamUsageHint hint = Fixed);
VRamList(const Vector3* data, const long& count, VRamUsageHint hint = Fixed);
VRamList(const Vector4* data, const long& count, VRamUsageHint hint = Fixed);
VRamList(const Color4* data, const long& count, VRamUsageHint hint = Fixed);
/// Allocate an empty VBO
/// @param byte_count the size of the buffer in bytes.
/// @param element_array_buffer if applicable, whether the buffer is to be used for GLuint indices.
/// @param hint A hint to the graphics driver for what the buffer is to be used for.
VRamList(const size_t& byte_count, bool element_array_buffer, VRamUsageHint hint = Fixed);
~VRamList();
/** Copying around the VBO data to a new VBO like this is slow.
* Pass to function by const reference or pointer always. */
VRamList(const VRamList& rhs);
VRamList() : list_handle(0), num_elements(0), element_array_buffer(false), spin_lock(false) {}
VRamList() : list_handle(0), byte_count(0), element_array_buffer(false) {}
public:
[[nodiscard]] GLuint GetHandle() const;
[[nodiscard]] GLuint Handle() const;
/// Returns the number of elements in the list.
[[nodiscard]] long GetLength() const;
[[nodiscard]] long Length() const;
/// Returns the size of the data in bytes.
[[nodiscard]] size_t GetDataSize() const;
[[nodiscard]] size_t Size() const;
/** Get VBO data back from the GPU. This is *bad* because the CPU is going to wait
* for the transfer to finish. Has limited use other than testing. */
[[nodiscard]] std::vector<GLfloat> GetDataF() const;
[[nodiscard]] std::vector<GLuint> GetDataUI() const;
[[nodiscard]] bool IsFloatArray() const;
/** Replace the data of an existing VBO in it's entirety. Must be same type. */
void SetData(const GLfloat* data, const long& count);
void SetData(const Vector2* data, const long& count);
void SetData(const Vector3* data, const long& count);
void SetData(const Vector4* data, const long& count);
void SetData(const Color4* data, const long& count);
void SetData(const GLuint* data, const long& count);
void SetData(const Vector2i* data, const long& count);
@@ -58,11 +74,17 @@ public:
/** Update only a portion of the data in a VBO. Must be same type.
* "offset" refers the number of Typename T into the buffer the data you want to change is.
* For ex, offset 0 and length of 1 overwrites the first value. Offset 1 the second etc */
// TODO provide a bool to specify whether the current buffer should be orphaned.
void UpdateData(const GLfloat* data, const long& offset, const long& count);
void UpdateData(const Vector2* data, const long& offset, const long& count);
void UpdateData(const Vector3* data, const long& offset, const long& count);
void UpdateData(const Vector4* data, const long& offset, const long& count);
void UpdateData(const Color4* data, const long& offset, const long& count);
void UpdateData(const GLuint* data, const long& offset, const long& count);
void UpdateData(const Vector2i* data, const long& offset, const long& count);
// Update only a portion of the data in a VBO using bytes.
// TODO This version of the function has no protection for out of bounds writes.
void UpdateData(const uint8_t* data, const long& offset, const long& count);
};

View File

@@ -15,7 +15,7 @@ using namespace JGL;
using JGL::Font;
float fps = 0.0f;
std::vector<Instance2D> rect_instances;
/// A draggable 2D point that highlights when moused over and when clicked.
class Gizmo
{
@@ -112,8 +112,8 @@ JGL::Font FreeSans;
Texture* image;
Texture* image_mask;
RenderTarget* j2d_render_target;
Shader shader;
float u_time = 0;
Shader* shader;
Vector2 result;
class JGLDemoWindow : public ReWindow::OpenGLWindow
{
@@ -131,14 +131,19 @@ public:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", FilteringMode::MIPMAP_NEAREST, JGL::SampleRate::X16);
image = new Texture("assets/sprites/Re3D.png", FilteringMode::MIPMAP_NEAREST);
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false,
SampleRate::NONE, FilteringMode::MIPMAP_TRILINEAR);
SampleRate::NONE, FilteringMode::MIPMAP_NEAREST);
//Texture::MultiplyByAlphaMask(*image, *image_mask);
shader = Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"));
shader = new Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"),
{{"a_vertex_position", 0}, {"a_instance_position", 1}, {"a_instance_size", 2}, {"a_instance_color", 3}});
result = Jupiteroid.MeasureString("The quick black fox jumps over the lazy dog.", 16);
for (unsigned int i = 0; i < 100; i++)
rect_instances.emplace_back(Colors::Red, Vector2(420, 420), Vector2(20, 20));
}
EulerAngleXYZ textAngle = {0,0,0};
@@ -146,12 +151,9 @@ public:
float pulse = 0;
float sprite_radians = 0;
bool fov_increasing = true;
int blit_pos = 0;
void display() {
Shader::UseDefault();
pulse += 20 * delta_time;
float dt = GetDeltaTime();
@@ -179,9 +181,10 @@ public:
camera->render();
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
/* if rendering to screen space directly. */
auto test_light = PointLight({2,1,2}, {pulse,pulse,pulse, 255}, {pulse, pulse, pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
auto test_light = PointLight({2,1,2}, {(u8) pulse,(u8) pulse,(u8) pulse, 255}, {(u8) pulse, (u8) pulse, (u8) pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
// If a 3D object has transparency. The things you'd like to see through it must be drawn before.
J3D::Begin();
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
@@ -193,19 +196,20 @@ public:
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
J3D::WireframeAABB(Colors::Yellow, {0.5, 0, 0.5}, {0.125, 0.125, 0.125}, 1);
J3D::End();
J2D::Begin(j2d_render_target, true);
//JGL::ClearScreen(Colors::Red);
J2D::Begin(j2d_render_target, shader, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::BatchFillRect(rect_instances.data(), rect_instances.size());
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
J2D::DrawPartialSprite(image, Vector2(225, 300), Vector2(image->GetDimensions()) * 0.25, Vector2(image->GetDimensions()) * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
J2D::FillGradientRect(Colors::Red, Colors::Green, Colors::Blue, Colors::White, {100,52}, {100,100});
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
auto box = JGL::Fonts::Jupiteroid.MeasureString("Hello g", 16);
J2D::FillChamferRect(Colors::Reds::LightSalmon, {150, 400}, {64, 64}, 5);
J2D::OutlineRoundedRect(Colors::Reds::LightCoral, {250, 350}, {128, 128}, 10, 2);
@@ -213,12 +217,13 @@ public:
J2D::FillGradientTriangle(Color4(Colors::Red), Color4(Colors::Green), Color4(Colors::Blue), {{0, 275}, {0, 375}, {100, 375}});
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
J2D::DrawGradientLine(Colors::Red, Colors::Blue, {105, 375}, {200, 275}, 2);
auto result = Jupiteroid.MeasureString("Jupiteroid Font", 16);
J2D::DrawString(Colors::Green, "The quick black fox jumps over the lazy dog.", 0, 20, 1, 16);
J2D::OutlineRect(Colors::Red, {0, 20}, result, 1);
J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
//J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
//J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
//J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
//J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
std::array<Vector2, 5> polygon = {Vector2(200, 400), {220, 420}, {220, 430}, {230, 410}, {200, 400}};
J2D::OutlinePolygon(Colors::White, polygon.data(), polygon.size());
J2D::DrawCubicBezierCurve(Colors::Blues::CornflowerBlue,
@@ -235,29 +240,14 @@ public:
J2D::End();
shader.Use();
J2D::Begin();
J2D::Begin(nullptr, nullptr, true);
J2D::DrawRenderTarget(j2d_render_target, {0, 0});
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
//J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
J2D::End();
}
void OnRefresh(float elapsed) override {
u_time += elapsed;
shader.SetFloat("u_time", u_time);
auto dimensions = GetSize();
shader.SetVector2("u_resolution", Vector2(dimensions.x, dimensions.y));
fps = GetRefreshRate();
if (IsKeyDown(Keys::RightArrow))

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

@@ -236,8 +236,9 @@ void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spher
glLineWidth(thickness);
glColor4ubv(color.ptr());
// TODO allocate once.
VRamList vertex_data(vertices.data(), vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.Handle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
// Render each sphere in the batch at their given position and radius.
@@ -245,10 +246,10 @@ void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spher
glPushMatrix();
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.Length());
if (draw_stacks)
glRotatef(90, 0, 1, 0),
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.Length());
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -371,9 +372,9 @@ void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const
glColor4ubv(color.ptr());
glLineWidth(thickness);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->Handle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->Handle());
for (size_t i = 0; i < box_count; i++) {
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
@@ -381,7 +382,7 @@ void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const
glPushMatrix();
glTranslatef(center.x, center.y, center.z);
glScalef(delta.x, delta.y, delta.z);
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->GetLength(), GL_UNSIGNED_INT, nullptr);
glDrawElements(GL_LINE_LOOP, ShapeCache::cube_index_data->Length(), GL_UNSIGNED_INT, nullptr);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -396,9 +397,9 @@ void JGL::J3D::WireframeAABB(const Color4& color, const Vector3& pos, const Vect
void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count) {
glColor4ubv(color.ptr());
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->Handle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->Handle());
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
@@ -407,7 +408,7 @@ void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_
if (UsingLighting()) {
using_lights = true;
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->GetHandle());
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->Handle());
glNormalPointer(GL_FLOAT, sizeof(float), nullptr);
}
@@ -486,8 +487,8 @@ void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const
VRamList index_data(indices.data(), indices.size());
glColor4ubv(color.ptr());
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.GetHandle());
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.Handle());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.Handle());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
for (size_t i = 0; i < sphere_count; i++) {
@@ -495,7 +496,7 @@ void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
glDrawElements(GL_TRIANGLES, index_data.GetLength(), GL_UNSIGNED_INT, nullptr);
glDrawElements(GL_TRIANGLES, index_data.Length(), GL_UNSIGNED_INT, nullptr);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -566,13 +567,13 @@ void JGL::J3D::DrawVertexArray(const Color4& color, const VertexArray& vertex_ar
glColor4ubv(color.ptr());
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->GetHandle());
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->Handle());
glVertexPointer(3, GL_FLOAT, 0, nullptr);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
//glScalef(1,1,1);
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->GetLength());
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->Length());
glPopMatrix();
//glDrawElements(GL_LINES, vertex_array.GetIndices()->GetLength(), GL_UNSIGNED_INT, nullptr);

View File

@@ -86,7 +86,10 @@ namespace JGL {
u1, v0
};
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
float ascent = font.face->size->metrics.ascender / 64.0f;
float descent = -font.face->size->metrics.descender / 64.0f;
cachedFont->appendGlyph(new CachedGlyph((char) charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6), ascent, descent));
xoffset += g->bitmap.width;
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
@@ -95,7 +98,7 @@ namespace JGL {
return cachedFont;
}
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, u32 size, float scale, const Font& font) {
// Offset by height to render at "correct" location.
y += size;
@@ -134,7 +137,7 @@ namespace JGL {
continue;
x2 = x + glyph->x2offset * scale;
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
y2 = y - glyph->y2offset * scale;
w = glyph->w * scale;
h = glyph->h * scale;
x += glyph->advanceX * scale;
@@ -156,7 +159,17 @@ namespace JGL {
}
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
if (current_state.current_shader)
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 1),
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawString);
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
if (current_state.current_shader)
current_state.current_shader->SetInt("TEXTURE_UNIT_SET_COUNT", 0),
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(default_state.draw_color);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -238,8 +251,18 @@ namespace JGL {
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
/*
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_DrawString);
*/
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
/*
if (current_state.current_shader)
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", 0);
*/
if (!draw_back_face)
glDisable(GL_CULL_FACE);

View File

@@ -133,7 +133,7 @@ JGL::State* JGL::StateStack::PreviousState() {
return &states.back();
}
JGL::State JGL::State::SaveState() {
JGL::State JGL::State::SaveState(const State& state) {
State result;
result.depth_test = glIsEnabled(GL_DEPTH_TEST);
@@ -152,6 +152,8 @@ JGL::State JGL::State::SaveState() {
glGetFloatv(GL_CURRENT_COLOR, result.draw_color);
glGetIntegerv(GL_VIEWPORT, result.viewport);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&result.current_fbo);
glGetIntegerv(GL_CURRENT_PROGRAM, &result.current_shader_handle);
result.current_shader = state.current_shader;
glGetIntegerv(GL_BLEND_SRC, &result.blend_func[0]);
glGetIntegerv(GL_BLEND_DST, &result.blend_func[1]);
@@ -184,7 +186,6 @@ void JGL::State::RestoreState(const State& state) {
else
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
glClientActiveTexture(GL_TEXTURE0 + state.selected_texture_unit);
@@ -203,10 +204,14 @@ void JGL::State::RestoreState(const State& state) {
else
glDisableClientState(GL_COLOR_ARRAY);
if (state.current_shader)
glUseProgram(state.current_shader->Handle());
else
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, state.current_fbo);
glViewport(state.viewport[0], state.viewport[1], state.viewport[2], state.viewport[3]);
glClearColor(state.clear_color[0], state.clear_color[1], state.clear_color[2], state.clear_color[3]);
glColor4f(state.draw_color[0], state.draw_color[1], state.draw_color[2], state.draw_color[3]);
glBlendFunc(state.blend_func[0], state.blend_func[1]);
}

View File

@@ -6,13 +6,47 @@
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <JGL/types/RenderTarget.h>
#include <JGL/types/Light.h>
#include <JGL/types/Shader.h>
#include <JGL/logger/logger.h>
namespace JGL {
class State;
class StateStack;
enum RENDERING_ROUTINE_ID : int32_t;
}
enum JGL::RENDERING_ROUTINE_ID : int32_t {
J2D_DrawPoint = 1,
J2D_DrawPoints = 2,
J2D_DrawLine = 3,
J2D_DrawLines = 4,
J2D_DrawDottedLine = 5,
J2D_DrawDashedLine = 6,
J2D_DrawGradientLine = 7,
J2D_OutlineRect = 8,
J2D_OutlineRoundedRect = 9,
J2D_OutlineChamferRect = 10,
J2D_FillRect = 11,
J2D_FillGradientRect = 12,
J2D_FillRoundedRect = 13,
J2D_FillChamferRect = 14,
J2D_DrawRenderTarget = 15,
J2D_DrawPartialRenderTarget = 16,
J2D_DrawSprite = 17,
J2D_DrawAlphaMaskSprite = 18,
J2D_DrawPartialSprite = 19,
J2D_DrawMirrorSprite = 20,
J2D_OutlineCircle = 21,
J2D_FillCircle = 22,
J2D_OutlineTriangle = 23,
J2D_FillTriangle = 24,
J2D_FillGradientTriangle = 25,
J2D_DrawCubicBezierCurve = 26,
J2D_OutlinePolygon = 27,
J2D_DrawString = 28,
J2D_DrawArc = 29,
};
class JGL::State {
public:
@@ -23,6 +57,8 @@ public:
GLint blend_func[2];
GLuint current_fbo = 0;
RenderTarget* current_render_target = nullptr;
GLint current_shader_handle = 0;
Shader* current_shader = nullptr;
bool texture_2D = false;
bool texture_coordinate_array = false;
@@ -38,7 +74,7 @@ public:
// List of all lights in the scene.
std::vector<const LightBase*> optional_lights{};
public:
static State SaveState();
static State SaveState(const State& state);
static void RestoreState(const State& state);
};
@@ -60,6 +96,7 @@ namespace JGL {
std::vector<Vector3> TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count);
inline StateStack state_stack;
inline Vector2i window_size;
inline bool supports_instanced = true;
}
namespace JGL::J2D {
@@ -70,7 +107,7 @@ namespace JGL::J2D {
{1, 1, 1, 1},
{0, 0, 0, 0},
{GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
0, nullptr, false, false,
0, nullptr, 0, nullptr, false, false,
false, false, true, true,
true, false, 0,
{}, {}

View File

@@ -109,60 +109,31 @@ 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()) {
if (f->getFontIndex() == this->index) {
for (const char &c: text) {
auto glyph = f->getGlyph(c);
extents.x += glyph->advanceX;
extents.y = glyph->ascent + glyph->descent;
}
}
if (font_of_size_in_cache) {
CachedFont* font;
for (auto* f: fontCache.getFonts())
if (f->getFontSize() == ptSize)
font = f;
for (const char& c : text)
extents.x += font->getGlyph(c)->advanceX;
extents.y = ptSize;
return extents;
}
}
jlog::Warning("Measuring a font size that is not cached, Defaulting to Jupiteroid.");
FT_Set_Pixel_Sizes(Fonts::Jupiteroid.face, ptSize, ptSize);
// No cache
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
for (const char& c : text) {
// TODO: Fix segfault
//FT_GlyphSlot slot = Fonts::Jupiteroid.face->glyph;
//auto glyph_index = FT_Get_Char_Index(Fonts::Jupiteroid.face, c);
FT_GlyphSlot slot = face->glyph;
auto glyph_index = FT_Get_Char_Index(this->face, c);
//auto error = FT_Load_Glyph(Fonts::Jupiteroid.face, glyph_index, FT_LOAD_DEFAULT);
auto error = FT_Load_Glyph(this->face, glyph_index, FT_LOAD_DEFAULT);
if (error)
continue;
Vector2 advance = {static_cast<float>(slot->advance.x >> 6),
static_cast<float>(slot->advance.y >> 6)};
extents += advance;
// Gives smaller results than we'd want.
if (extents.y < slot->metrics.height / 64)
extents.y = slot->metrics.height / 64;
// Just fucking hardcode it, we know the glyph height is roughly always the ptSize anyway.
if (extents.y < ptSize)
extents.y = ptSize;
extents.x += static_cast<float>(slot->advance.x >> 6);
extents.y = (face->size->metrics.ascender / 64.0f) + (-face->size->metrics.descender / 64.0f);
}
return extents;
}

View File

@@ -10,7 +10,7 @@ std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
return texcoords;
}
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY, float asc, float desc) {
character = c;
this->x2offset = x2offset;
this->y2offset = y2offset;
@@ -19,6 +19,8 @@ CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offs
this->advanceX = advanceX;
this->advanceY = advanceY;
this->texcoords = texcoords;
this->ascent = asc;
this->descent = desc;
}
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {

View File

@@ -3,102 +3,122 @@
#include <glad/glad.h>
namespace JGL {
Shader::Shader(std::filesystem::path vertex_source_path, std::filesystem::path fragment_source_path) {
std::string vertex_code;
std::string fragment_code;
std::string geometry_code; // Currently unused, might be supported later.
std::string compute_code; // Currently unused, might be supported later.
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
std::ifstream cShaderFile;
class ShaderPreprocessor {
public:
std::string include_keyword = "#include";
ShaderPreprocessor() {}
std::string LoadShaderFile(const std::filesystem::path& filepath)
{
// if size is 0, it indicates, that we are at the top of the recursive load stack
bool stack_top = (already_included.size() == 0);
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
cShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// Open Files
vShaderFile.open(vertex_source_path);
fShaderFile.open(fragment_source_path);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertex_code = vShaderStream.str();
fragment_code = fShaderStream.str();
if (false) {
gShaderFile.open("");
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometry_code = gShaderStream.str();
}
} catch (std::ifstream::failure& e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
if (stack_top) {
already_included.emplace_back(filepath);
}
const char* vShaderCode = vertex_code.c_str();
const char* fShaderCode = fragment_code.c_str();
std::string ret_data = "";
std::ifstream file(filepath);
// 2. Compile shaders.
unsigned int vertex, fragment;
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader.
unsigned int geometry;
if (false) {
// const char* gShaderCode = geometry_code.c_str();
// geometry = glCreateShader(GL_GEOMETRY_SHADER);
// glShaderSource(geometry, 1 &gShaderCode, NULL);
// glCompileShader(geometry);
// checkCompileErrors(geometry, "GEOMETRY");
if (!file.good())
{
std::cout << "ERROR [ ShaderLoader::load_shader ]: Failed to start fstream, check if '" << filepath << "' exists\n";
return ret_data;
}
// shader Program
id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
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()), '"', '"');
if (false)
glAttachShader(id, geometry);
// 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) + rel_include_path;
glLinkProgram(id);
checkCompileErrors(id, "PROGRAM");
// 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;
}
}
// delete the shaders as they're linked into our program now and are no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
if (false)
glDeleteShader(geometry);
// 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;
fragmentPath = fragment_source_path;
}
void Shader::checkCompileErrors(GLuint shader, const std::string& type) {
@@ -108,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);
}
}
@@ -124,14 +144,23 @@ namespace JGL {
}
GLint Shader::Uniform(const std::string &name) const {
return glGetUniformLocation(id, name.c_str());
auto it = uniform_location_cache.find(name);
if (it == uniform_location_cache.end()) {
auto location = glGetUniformLocation(id, name.c_str());
uniform_location_cache[name] = location;
return location;
}
return it->second;
}
GLint Shader::Attribute(const std::string &name) const {
return glGetAttribLocation(id, name.c_str());
}
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code) {
Shader::Shader(const std::string &vertex_code, const std::string &fragment_code, const std::vector<std::pair<std::string, GLint>>& attribute_bindings) {
vertexSource = vertex_code;
fragmentSource = fragment_code;
const char* vShaderCode = vertex_code.c_str();
const char* fShaderCode = fragment_code.c_str();
@@ -140,60 +169,37 @@ namespace JGL {
// vertex shader.
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glShaderSource(fragment, 1, &fShaderCode, nullptr);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader.
unsigned int geometry;
if (false) {
// const char* gShaderCode = geometry_code.c_str();
// geometry = glCreateShader(GL_GEOMETRY_SHADER);
// glShaderSource(geometry, 1 &gShaderCode, NULL);
// glCompileShader(geometry);
// checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
id = glCreateProgram();
// bind attribute locations.
for (auto& a: attribute_bindings)
glBindAttribLocation(id, a.second, a.first.c_str());
glAttachShader(id, vertex);
glAttachShader(id, fragment);
if (false)
glAttachShader(id, geometry);
glLinkProgram(id);
checkCompileErrors(id, "PROGRAM");
// delete the shaders as they're linked into our program now and are no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
if (false)
glDeleteShader(geometry);
}
void Shader::Use() {
glUseProgram(id);
}
bool Shader::Loaded() const { return id != 0; }
unsigned int Shader::Handle() const { return id;}
void Shader::UseDefault() {
glUseProgram(0);
}
void Shader::Use(GLuint shader_program_id) {
glUseProgram(shader_program_id);
}
void Shader::SetBool(const std::string &name, bool value) const { glUniform1i(Uniform(name), (int)value); }
void Shader::SetInt(const std::string &name, int value) const { glUniform1i(Uniform(name), value); }
@@ -229,4 +235,35 @@ namespace JGL {
bool transpose = false;
glUniformMatrix4fv(Uniform(name), 16, transpose, value.ptr());
}
std::string Shader::ReadFile(const std::filesystem::path &path) {
/*std::string contents;
std::ifstream file;
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// Open Files
file.open(path);
std::stringstream stream;
// Read file's buffer contents into streams
stream << file.rdbuf();
// close file handlers
file.close();
// convert stream into string
contents = stream.str();
return contents;
} catch (std::ifstream::failure& e) {
std::cout << "ERROR::FILE_READ_FAILURE: " << e.what() << std::endl;
return "";
}*/
ShaderPreprocessor processor;
return processor.LoadShaderFile(path);
}
}

View File

@@ -2,44 +2,39 @@
#include <JGL/logger/logger.h>
#include <cstring>
// TODO combine the two load functions.
void JGL::VRamList::load(const GLfloat* data, const long& size) {
while (spin_lock) {}
spin_lock = true;
GLint current_array_buffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_array_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, size, data, usage_hint);
glBindBuffer(GL_ARRAY_BUFFER, current_array_buffer);
element_array_buffer = false;
num_elements = size / sizeof(GLfloat);
byte_count = size;
spin_lock = false;
}
void JGL::VRamList::load(const GLuint* data, const long& size) {
while (spin_lock) {}
spin_lock = true;
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, usage_hint);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_element_array_buffer);
element_array_buffer = true;
num_elements = size / sizeof(GLuint);
byte_count = size;
spin_lock = false;
}
void JGL::VRamList::Erase() {
if (list_handle == 0)
return;
while (spin_lock) {}
spin_lock = true;
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
@@ -55,36 +50,27 @@ void JGL::VRamList::Erase() {
glDeleteBuffers(1, &list_handle);
list_handle = 0;
spin_lock = false;
}
GLuint JGL::VRamList::GetHandle() const {
GLuint JGL::VRamList::Handle() const {
return list_handle;
}
bool JGL::VRamList::IsFloatArray() const {
return !element_array_buffer;
long JGL::VRamList::Length() const {
// sizeof(GLfloat) & sizeof(GLuint) are both 4 - Redacted.
return byte_count / 4;
}
long JGL::VRamList::GetLength() const {
return num_elements;
}
size_t JGL::VRamList::GetDataSize() const {
if (element_array_buffer)
return sizeof(GLuint) * num_elements;
return sizeof(GLfloat) * num_elements;
size_t JGL::VRamList::Size() const {
return byte_count;
}
void JGL::VRamList::SetData(void* data, const long& length) {
while (spin_lock) {}
spin_lock = true;
bool should_resize = (this->num_elements != length);
bool should_resize = (this->byte_count != length * 4);
if (should_resize) {
glDeleteBuffers(1, &list_handle);
list_handle = 0;
spin_lock = false;
element_array_buffer ? load((GLuint*) data, sizeof(GLuint) * length) : load((GLfloat*) data, sizeof(GLfloat) * length);
return;
}
@@ -100,33 +86,22 @@ void JGL::VRamList::SetData(void* data, const long& length) {
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (!vram)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(vram, data, (element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat)) * length);
if (!glUnmapBuffer(buffer_type))
JGL::Logger::Fatal("We couldn't unmap the buffer?");
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
glBufferSubData(buffer_type, 0, length * element_size, data);
glBindBuffer(buffer_type, current_buffer);
spin_lock = false;
}
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
while (spin_lock) {}
spin_lock = true;
if (offset + length > num_elements) {
JGL::Logger::Warning("Using UpdateData to out-of-bounds write the VRamList? I'll resize it for you, But this is slow.");
unsigned long oob_delta = (offset + length) - num_elements;
if (offset + length > Length()) {
unsigned long oob_delta = (offset + length) - Length();
if (element_array_buffer) {
auto list_data = GetDataUI();
list_data.resize(list_data.size() + oob_delta);
memcpy(list_data.data() + (offset * sizeof(GLuint)), data, length * sizeof(GLuint));
spin_lock = false; // This is going unlock and relock really fast, But this code fixes something considered wrong anyway - Redacted.
// This is going unlock and relock really fast, But this code fixes something considered wrong anyway - Redacted.
return SetData(list_data.data(), list_data.size());
}
@@ -134,7 +109,6 @@ void JGL::VRamList::UpdateData(void* data, const long& offset, const long& lengt
auto list_data = GetDataF();
list_data.resize(list_data.size() + oob_delta);
memcpy(list_data.data() + (offset * sizeof(GLfloat)), data, length * sizeof(GLfloat));
spin_lock = false;
return SetData(list_data.data(), list_data.size());
}
@@ -149,23 +123,13 @@ void JGL::VRamList::UpdateData(void* data, const long& offset, const long& lengt
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (!vram)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(vram) + (offset * element_size)), data, length * element_size);
if (!glUnmapBuffer(buffer_type))
JGL::Logger::Fatal("We couldn't unmap the buffer?");
glBufferSubData(buffer_type, offset * element_size, length * element_size, data);
glBindBuffer(buffer_type, current_buffer);
spin_lock = false;
}
std::vector<GLfloat> JGL::VRamList::GetDataF() const {
while (spin_lock) {}
if (element_array_buffer)
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
@@ -178,12 +142,12 @@ std::vector<GLfloat> JGL::VRamList::GetDataF() const {
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_buffer);
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
std::vector<GLfloat> data(num_elements);
std::vector<GLfloat> data(byte_count / 4);
void* vram = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
if (vram == nullptr)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(data.data(), vram, num_elements * sizeof(GLfloat));
memcpy(data.data(), vram, (byte_count / 4) * sizeof(GLfloat));
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, current_buffer);
@@ -194,7 +158,6 @@ std::vector<GLfloat> JGL::VRamList::GetDataF() const {
}
std::vector<GLuint> JGL::VRamList::GetDataUI() const {
while (spin_lock) {}
if (!element_array_buffer)
JGL::Logger::Warning("Getting data as GLuint but the buffer data is GLfloat?");
@@ -203,13 +166,13 @@ std::vector<GLuint> JGL::VRamList::GetDataUI() const {
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
std::vector<GLuint> data(num_elements);
std::vector<GLuint> data(byte_count / 4);
void* vram = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
if (vram == nullptr)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(data.data(), vram, num_elements * sizeof(GLuint));
memcpy(data.data(), vram, (byte_count / 4) * sizeof(GLuint));
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_buffer);
@@ -217,26 +180,35 @@ std::vector<GLuint> JGL::VRamList::GetDataUI() const {
return data;
}
JGL::VRamList::VRamList(const GLfloat* data, const long& length) {
JGL::VRamList::VRamList(const GLfloat* data, const long& length, VRamUsageHint hint) {
usage_hint = hint;
load(data, (long) sizeof(GLfloat) * length);
}
JGL::VRamList::VRamList(const GLuint* data, const long& length) {
JGL::VRamList::VRamList(const GLuint* data, const long& length, VRamUsageHint hint) {
usage_hint = hint;
load(data, (long) sizeof(GLuint) * length);
}
JGL::VRamList::VRamList(const Vector2* data, const long& length) {
JGL::VRamList::VRamList(const Vector2* data, const long& length, VRamUsageHint hint) {
usage_hint = hint;
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector2) * length);
}
JGL::VRamList::VRamList(const Vector3* data, const long& length) {
JGL::VRamList::VRamList(const Vector3* data, const long& length, VRamUsageHint hint) {
usage_hint = hint;
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector3) * length);
}
JGL::VRamList::VRamList(const Vector4* data, const long& length) {
JGL::VRamList::VRamList(const Vector4* data, const long& length, VRamUsageHint hint) {
usage_hint = hint;
load(reinterpret_cast<const GLfloat*>(data), (long) sizeof(Vector4) * length);
}
JGL::VRamList::VRamList(const Color4* data, const long& count, VRamUsageHint hint) {
usage_hint = hint;
load(reinterpret_cast<const GLfloat *>(data), (long) sizeof(GLuint) * count);
}
void JGL::VRamList::SetData(const GLfloat* data, const long& length) {
SetData((void*) data, length);
}
@@ -261,6 +233,10 @@ void JGL::VRamList::SetData(const Vector2i* data, const long& length) {
SetData((void*) data, length * 2);
}
void JGL::VRamList::SetData(const Color4* data, const long& count) {
SetData((void*) data, count);
}
void JGL::VRamList::UpdateData(const GLfloat* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length);
}
@@ -285,13 +261,15 @@ void JGL::VRamList::UpdateData(const Vector2i* data, const long& offset, const l
UpdateData((void*) data, offset, length * 2);
}
void JGL::VRamList::UpdateData(const Color4* data, const long &offset, const long &count) {
UpdateData((void*) data, offset, count);
}
JGL::VRamList::~VRamList() {
Erase();
}
JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
while (rhs.spin_lock) {}
if (rhs.element_array_buffer) {
auto data_array = rhs.GetDataUI();
this->load(data_array.data(), data_array.size());
@@ -300,3 +278,32 @@ JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
auto data_array = rhs.GetDataF();
this->load(data_array.data(), data_array.size());
}
JGL::VRamList::VRamList(const size_t& byte_count, bool element_array_buffer, VRamUsageHint hint) {
this->element_array_buffer = element_array_buffer;
this->byte_count = byte_count;
GLint current_buffer = 0;
GLenum buffer = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
GLenum buffer_binding = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER_BINDING : GL_ARRAY_BUFFER_BINDING;
glGetIntegerv(buffer_binding, &current_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(buffer, list_handle);
glBufferData(buffer, byte_count, nullptr, hint);
glBindBuffer(buffer, current_buffer);
}
void JGL::VRamList::UpdateData(const uint8_t* data, const long& offset, const long& count) {
GLint current_buffer = 0;
GLenum buffer_type = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
GLenum buffer_binding = element_array_buffer ? GL_ELEMENT_ARRAY_BUFFER_BINDING : GL_ARRAY_BUFFER_BINDING;
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
glBufferSubData(buffer_type, offset, count, data);
glBindBuffer(buffer_type, current_buffer);
}