Compare commits

...

8 Commits

Author SHA1 Message Date
7498390180 Add the ability to use mipmaps with RenderTargets.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 50s
2025-02-11 18:48:15 -05:00
4ac28a2c10 Fixed a regression that causes MSAA to not work.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m14s
2025-02-11 16:25:59 -05:00
61c1c3245c Fixed a case where resizing the render target was no good
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m16s
2025-02-07 01:56:34 -05:00
cb9fe4e5c9 Update J2D.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m26s
Dramatically improve the speed of J2D::DrawCubicBezierCurve
2025-02-06 12:01:49 -05:00
c7e7aa6fb5 Batch FillRect & Batch FillCircle.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
2025-02-06 11:43:03 -05:00
1261321992 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m11s
2025-02-06 10:26:35 -05:00
6d1ddad428 Add a way to query the max texture size. 2025-02-06 10:26:34 -05:00
eae3c794fa Update README.md
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m46s
Added extended J2D member functions. (TODO: Document new usability of J2D contexts)
2025-02-04 15:51:52 -05:00
10 changed files with 279 additions and 192 deletions

View File

@@ -19,12 +19,17 @@ Yet Another C++ Rendering Toolkit
### J2D
* DrawPoint
* DrawLine / DrawGradientLine
* DrawLine / DrawGradientLine / DrawDottedLine / DrawDashedLine / DrawLines
* DrawSprite / DrawPartialSprite
* OutlineRect / FillRect / FillGradientRect / FillRoundedRect
* DrawRenderTarget / DrawPartialRenderTarget
* OutlineRect / OutlineRoundedRect / OutlineChamferRect
* FillRect / FillGradientRect / FillRoundedRect / FillChamferRect
* OutlineCircle / FillCircle
* OutlineTriangle / FillTriangle
* OutlineTriangle / FillTriangle / FillGradientTriangle
* DrawString
* DrawCubicBezierCurve
* DrawArc
* OutlineEllipse / FillEllipse
### J3D
* DrawLine

View File

@@ -381,6 +381,10 @@ namespace JGL::J2D {
void FillPolygon(const Color4& color, const std::vector<Vector2>& points);
void OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness = 1, int subdivisions = 8);
void FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions = 8);
void BatchFillRect(const 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);
}
/// Drawing functions for 3D objects.

View File

@@ -41,6 +41,24 @@ namespace JGL {
MSAA_8X = 3
};
enum class FilteringMode : u8 {
NEAREST = 0, // Fastest for 2D, Sometimes causes graphical issues.
BILINEAR = 1, // Fast and pretty, The best for 2D.
MIPMAP_NEAREST = 2, // Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues. Uses more vram.
MIPMAP_BILINEAR = 3, // Bilinear with mipmaps, Fast and pretty. Uses more vram.
MIPMAP_TRILINEAR = 4 // The prettiest. Still decent speed. Uses more vram.
};
enum class WrappingMode : u8 {
REPEAT = 0,
MIRRORED_REPEAT = 1,
CLAMP_TO_EDGE = 2,
CLAMP_TO_BORDER = 3 // Effectively the same as clamp_to_edge
};
enum class ColorFormat : bool { RGB = false, RGBA = true };
static std::string to_string(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
switch (sample_rate) {
case MSAA_SAMPLE_RATE::MSAA_NONE:

View File

@@ -47,6 +47,7 @@ public:
/// If you're using MSAA and not using J2D || J3D Begin & End you must do this.
void MSAABlit() const;
void RegenerateMipMaps();
/// Copy one Render Target onto another. Will break if they're not the same size.
// TODO support different sizes. If the destination is too small fix it for them but log a warning.
static void Blit(const RenderTarget& source, RenderTarget* destination, const Vector2i& position = {0, 0});
@@ -91,10 +92,11 @@ public:
/// @returns The color that should be used to clear this Render Target.
[[nodiscard]] Color4 GetClearColor() const;
/// @returns The color information for this Render Target.
/// @note Both the CPU & GPU cannot do anything while this takes place. It's very slow.
/// @note The CPU thread this is called from & the GPU cannot do anything while this takes place. It's very slow.
[[nodiscard]] std::vector<GLfloat> GetPixels() const;
[[nodiscard]] static Vector2i MaximumSize();
public:
/// Create a Render Target from a Render Target that already exists.
/** @note Render Targets that are copies of another will copy the Texture.
@@ -113,7 +115,8 @@ public:
/// @param clear_color The color to be used if you want to clear the Render Target.
/// @param use_depth Whether or not this Render Target will have depth information.
/// @param sample_rate The MSAA sample rate this Render Target will use.
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false,
MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE, FilteringMode filteirng_mode = FilteringMode::NEAREST);
/// Deletes this Render Target.
/** @note If this Render Target was made with a Texture that already existed

View File

@@ -4,30 +4,13 @@
#include <J3ML/LinearAlgebra/Vector2i.hpp>
#include <Color3.hpp>
#include <Color4.hpp>
#include <JGL/types/Enums.h>
namespace JGL {
using J3ML::LinearAlgebra::Vector2i;
enum class FilteringMode : u8 {
NEAREST = 0, // Fastest for 2D, Sometimes causes graphical issues.
BILINEAR = 1, // Fast and pretty, The best for 2D.
MIPMAP_NEAREST = 2, // Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues. Uses more vram.
MIPMAP_BILINEAR = 3, // Bilinear with mipmaps, Fast and pretty. Uses more vram.
MIPMAP_TRILINEAR = 4 // The prettiest. Still decent speed. Uses more vram.
};
enum class WrappingMode : u8 {
REPEAT = 0,
MIRRORED_REPEAT = 1,
CLAMP_TO_EDGE = 2,
CLAMP_TO_BORDER = 3 // Effectively the same as clamp_to_edge
};
enum class ColorFormat : bool { RGB = false, RGBA = true };
class Texture;
}
/// TODO handle the case of a texture being loaded that exceeds the max texture size.
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
class JGL::Texture {
protected:
@@ -40,6 +23,7 @@ protected:
void load(const unsigned char* pixels);
std::vector<unsigned char> png(const std::filesystem::path& file);
std::vector<unsigned char> bmp(const std::filesystem::path& file);
[[nodiscard]] bool SizeExceedsMaximum(const Vector2i& size);
public:
/// @returns A handle used to identify this texture.
[[nodiscard]] unsigned int GetHandle() const;
@@ -56,6 +40,9 @@ public:
/// @returns The raw pixels this texture is made up of.
/// @note This will read-back from the GPU. Slow.
[[nodiscard]] std::vector<Color4> GetPixelData() const;
/// @returns The biggest size for a texture on this system.
/// @note on modern systems this is *usually* ridiculous.
[[nodiscard]] static Vector2i MaximumSize();
public:
/// Load a texture from a file,
explicit Texture(const std::filesystem::path& file, FilteringMode filtering_mode = FilteringMode::BILINEAR, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE, bool invert_y = true);
@@ -68,7 +55,7 @@ public:
Texture(const Texture* textures, const size_t& texture_count);
/// Initialize a texture filled with trash data.
/// @see RenderTarget
explicit Texture(const Vector2i& size);
explicit Texture(const Vector2i& size, FilteringMode filtering_mode = FilteringMode::NEAREST);
Texture(const Texture& rhs);
~Texture();

View File

@@ -130,7 +130,8 @@ public:
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", FilteringMode::BILINEAR);
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_NONE);
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false,
MSAA_SAMPLE_RATE::MSAA_8X, FilteringMode::MIPMAP_TRILINEAR);
//Texture::MultiplyByAlphaMask(*image, *image_mask);
}

View File

@@ -4,8 +4,8 @@
#include "internals/internals.h"
void JGL::J2D::Begin(RenderTarget* render_target, bool clear_buffers) {
State current_state = default_state;
void J2D::Begin(RenderTarget* render_target, bool clear_buffers) {
State new_state = default_state;
state_stack.Push(State::SaveState());
glMatrixMode(GL_PROJECTION);
@@ -16,34 +16,51 @@ void JGL::J2D::Begin(RenderTarget* render_target, bool clear_buffers) {
if (!render_target->GetTexture()->Inverted())
Logger::Warning("You're rendering onto a texture that is upside-down. Your draw commands won't work how you'd expect.");
current_state.current_fbo = render_target->GetGLFramebufferObjectHandle();
current_state.viewport[2] = render_target->GetDimensions().x;
current_state.viewport[3] = render_target->GetDimensions().y;
new_state.current_fbo = render_target->GetGLFramebufferObjectHandle();
new_state.viewport[2] = render_target->GetDimensions().x;
new_state.viewport[3] = render_target->GetDimensions().y;
current_state.clear_color[0] = render_target->GetClearColor().RN();
current_state.clear_color[1] = render_target->GetClearColor().GN();
current_state.clear_color[2] = render_target->GetClearColor().BN();
current_state.clear_color[3] = render_target->GetClearColor().AN();
new_state.clear_color[0] = render_target->GetClearColor().RN();
new_state.clear_color[1] = render_target->GetClearColor().GN();
new_state.clear_color[2] = render_target->GetClearColor().BN();
new_state.clear_color[3] = render_target->GetClearColor().AN();
new_state.current_render_target = render_target;
}
else {
current_state.viewport[2] = window_size.x;
current_state.viewport[3] = window_size.y;
new_state.viewport[2] = window_size.x;
new_state.viewport[3] = window_size.y;
}
State::RestoreState(current_state);
State::RestoreState(new_state);
current_state = new_state;
if (current_state.current_render_target)
JGL::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);
}
glOrtho(0, current_state.viewport[2], current_state.viewport[3], 0, -1, 1);
glOrtho(0, new_state.viewport[2], new_state.viewport[3], 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}
void JGL::J2D::End() {
void J2D::End() {
if (current_state.current_render_target) {
current_state.current_render_target->MSAABlit();
FilteringMode filtering_mode = current_state.current_render_target->GetTexture()->GetFilteringMode();
if (filtering_mode == FilteringMode::MIPMAP_NEAREST ||
filtering_mode == FilteringMode::MIPMAP_BILINEAR ||
filtering_mode == FilteringMode::MIPMAP_TRILINEAR)
current_state.current_render_target->RegenerateMipMaps();
}
//Change back to the previous projection.
glPopMatrix();
glMatrixMode(GL_PROJECTION);
@@ -55,10 +72,14 @@ void JGL::J2D::End() {
Logger::Fatal("Calling J2D::End before J2D::Begin.");
State::RestoreState(*previous_state);
if (previous_state->current_render_target)
JGL::RenderTarget::SetActiveGLRenderTarget(*current_state.current_render_target);
current_state = *previous_state;
state_stack.Pop();
}
void JGL::J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float radius) {
void J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float radius) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -69,11 +90,11 @@ void JGL::J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float
glColor4fv(default_state.draw_color);
}
void JGL::J2D::DrawPoint(const Color4& color, float x, float y, float radius) {
void J2D::DrawPoint(const Color4& color, float x, float y, float radius) {
DrawPoint(color, {x, y}, radius);
}
void JGL::J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness) {
void J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
@@ -85,8 +106,8 @@ void JGL::J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B,
glColor4fv(default_state.draw_color);
}
void JGL::J2D::DrawLine(const Color4& color, float x, float y, float w, float h, float thickness) {
JGL::J2D::DrawLine(color, {x, y}, {w, h}, thickness);
void J2D::DrawLine(const Color4& color, float x, float y, float w, float h, float thickness) {
J2D::DrawLine(color, {x, y}, {w, h}, thickness);
}
void J2D::DrawLines(const Color4& color, const Vector2* points, const size_t& point_count, float thickness) {
@@ -100,7 +121,7 @@ void J2D::DrawLines(const Color4& color, const Vector2* points, const size_t& po
glColor4fv(default_state.draw_color);
}
void JGL::J2D::DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing, float thickness) {
void J2D::DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing, float thickness) {
float distance = Vector2::Distance(A, B);
Vector2 direction = (B - A).Normalized();
@@ -113,14 +134,14 @@ void JGL::J2D::DrawDottedLine(const Color4& color, const Vector2& A, const Vecto
for (unsigned int i = 0; i < point_count; ++i)
points[i] = A + direction * (i * spacing);
return JGL::J2D::DrawPoints(color, points.data(), points.size(), thickness);
return J2D::DrawPoints(color, points.data(), points.size(), thickness);
}
void JGL::J2D::DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float thickness) {
return JGL::J2D::DrawDottedLine(color, {x1, y1}, {x2, y2}, spacing, thickness);
void J2D::DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float thickness) {
return J2D::DrawDottedLine(color, {x1, y1}, {x2, y2}, spacing, thickness);
}
void JGL::J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing, float dash_length, float thickness) {
void J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing, float dash_length, float thickness) {
float distance = Vector2::Distance(A, B);
Vector2 direction = (B - A).Normalized();
float length_of_dash_and_gap = dash_length + spacing;
@@ -133,7 +154,7 @@ void JGL::J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vecto
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);
JGL::J2D::DrawLine(color, A_current, B_current, thickness);
J2D::DrawLine(color, A_current, B_current, thickness);
}
// For the little piece at the end.
@@ -141,15 +162,15 @@ void JGL::J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vecto
if (distance_left > 0) {
A_current = A + direction * (dash_count * length_of_dash_and_gap);
B_current = A_current + direction * std::min(dash_length, distance_left);
JGL::J2D::DrawLine(color, A_current, B_current, thickness);
J2D::DrawLine(color, A_current, B_current, thickness);
}
}
void JGL::J2D::DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float dash_length, float thickness) {
return JGL::J2D::DrawDashedLine(color, {x1, y1}, {x2, y2}, spacing, dash_length, thickness);
void J2D::DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float dash_length, float thickness) {
return J2D::DrawDashedLine(color, {x1, y1}, {x2, y2}, spacing, dash_length, thickness);
}
void JGL::J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -167,10 +188,10 @@ void JGL::J2D::DrawGradientLine(const Color4& color1, const Color4& color2, cons
}
void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float y, float w, float h, float thickness) {
JGL::J2D::DrawGradientLine(color1, color2, {x, y}, {w, h}, thickness);
J2D::DrawGradientLine(color1, color2, {x, y}, {w, h}, thickness);
}
void JGL::J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -183,24 +204,33 @@ void JGL::J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
BatchFillRect(&color, &pos, &size, 1);
}
void J2D::BatchFillRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, const size_t& rect_count) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
glColor4ubv(color.ptr());
if (rect_count <= 0)
return;
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->GetHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
glPushMatrix();
glTranslatef(pos.x, pos.y + size.y, 0);
glScalef(size.x, size.y, 1);
glDrawArrays(GL_QUADS, 0, 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glPopMatrix();
for (size_t i = 0; i < rect_count; i++) {
glPushMatrix();
glColor4ubv(colors[i].ptr());
glTranslatef(positions[i].x, positions[i].y + sizes[i].y, 0);
glScalef(sizes[i].x, sizes[i].y, 1);
glDrawArrays(GL_QUADS, 0, 4);
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size) {
void J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -233,38 +263,40 @@ void JGL::J2D::FillGradientRect(const Color4& color1, const Color4& color2, cons
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, unsigned int subdivisions) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
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}
};
JGL::J2D::FillRect(color, {pos.x + radius, pos.y}, {size.x - 2 * radius, size.y});
JGL::J2D::FillRect(color, {pos.x, pos.y + radius}, {size.x, size.y - 2 * radius});
JGL::J2D::FillCircle(color, {pos.x + radius, pos.y + radius}, radius, subdivisions);
JGL::J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + radius}, radius, subdivisions);
JGL::J2D::FillCircle(color, {pos.x + radius, pos.y + size.y - radius}, radius, subdivisions);
JGL::J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + size.y - radius}, radius, subdivisions);
J2D::BatchFillRect(colors.data(), rect_positions.data(), rect_sizes.data(), 2);
J2D::BatchFillCircle(colors.data(), circle_positions.data(), circle_radii.data(), subdivisions, 4);
}
void JGL::J2D::DrawSprite(const Texture* texture, float positionX, float positionY, float rad_rotation,
void J2D::DrawSprite(const Texture* texture, float positionX, float positionY, float rad_rotation,
float originX, float originY,float scaleX, float scaleY,
const Color4& color, Direction inversion) {
DrawSprite(*texture, {positionX, positionY}, rad_rotation, {originX, originY}, {scaleX, scaleY}, color, inversion);
}
void JGL::J2D::DrawSprite(const Texture* texture, const Vector2& position, float rad_rotation, const Vector2& origin,
void J2D::DrawSprite(const Texture* texture, const Vector2& position, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
DrawSprite(*texture, position, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawPartialSprite(const Texture* texture, const Vector2& position, const Vector2& sub_texture_position,
void J2D::DrawPartialSprite(const Texture* texture, const Vector2& position, const Vector2& sub_texture_position,
const Vector2& sub_texture_size, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
DrawPartialSprite(*texture, position, sub_texture_position, sub_texture_size, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawPartialSprite(const Texture* texture, float positionX, float positionY, float sub_texture_positionX,
void J2D::DrawPartialSprite(const Texture* texture, float positionX, float positionY, float sub_texture_positionX,
float sub_texture_positionY, unsigned int sub_texture_sizeX,
unsigned int sub_texture_sizeY, float rad_rotation, float originX, float originY,
float scaleX, float scaleY, const Color4& color, Direction inversion) {
@@ -272,27 +304,27 @@ void JGL::J2D::DrawPartialSprite(const Texture* texture, float positionX, float
rad_rotation, {originX, originY}, {scaleX, scaleY}, color, inversion);
}
void JGL::J2D::DrawMirrorSprite(const Texture* texture, const Vector2& position, Direction mirror_axis, float rad_rotation,
void J2D::DrawMirrorSprite(const Texture* texture, const Vector2& position, Direction mirror_axis, float rad_rotation,
const Vector2& origin, const Vector2& scale, const Color4& color) {
DrawMirrorSprite(*texture, position, mirror_axis, rad_rotation, origin, scale, color);
}
void JGL::J2D::DrawSprite(const RenderTarget* render_target, const Vector2& position, float rad_rotation,
void J2D::DrawSprite(const RenderTarget* render_target, const Vector2& position, float rad_rotation,
const Vector2& origin, const Vector2& scale, const Color4& color, Direction inversion) {
DrawSprite(*render_target, position, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawRenderTarget(const RenderTarget* render_target, const Vector2& position, float rad_rotation,
void J2D::DrawRenderTarget(const RenderTarget* render_target, const Vector2& position, float rad_rotation,
const Vector2& origin, const Vector2& scale, const Color4& color, Direction inversion) {
DrawSprite(*render_target, position, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawRenderTarget(const RenderTarget& render_target, const Vector2& position, float rad_rotation,
void J2D::DrawRenderTarget(const RenderTarget& render_target, const Vector2& position, float rad_rotation,
const Vector2& origin, const Vector2& scale, const Color4& color, Direction inversion) {
DrawSprite(render_target, position, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawSprite(const JGL::RenderTarget& rt, const Vector2& position, float rad_rotation, const Vector2& origin,
void J2D::DrawSprite(const RenderTarget& rt, const Vector2& position, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
//Correct for the render-target being upside-down.
@@ -315,14 +347,14 @@ void JGL::J2D::DrawSprite(const JGL::RenderTarget& rt, const Vector2& position,
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
auto r_position = Vector2(Math::Floor(position.x), Math::Floor(position.y));
JGL::J2D::DrawPartialSprite(*rt.GetTexture(), r_position, {0, 0}, Vector2(rt.GetDimensions()), rad_rotation, origin, scale, color, d);
J2D::DrawPartialSprite(*rt.GetTexture(), r_position, {0, 0}, Vector2(rt.GetDimensions()), rad_rotation, origin, scale, color, d);
if (rt.OwnsTexture())
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void JGL::J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, const Vector2& position, float rad_rotation,
const Vector2& origin, const Vector2& scale,const Color4& color, JGL::Direction inversion) {
void J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, const Vector2& position, float rad_rotation,
const Vector2& origin, const Vector2& scale,const Color4& color, Direction inversion) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -409,23 +441,23 @@ void JGL::J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, con
glColor4fv(default_state.draw_color);
}
void JGL::J2D::DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation,
void J2D::DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation,
const Vector2& origin, const Vector2& scale,const Color4& color, Direction inversion) {
DrawSprite(*texture, *alpha_mask, position, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation,
void J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation,
float originX, float originY,float scaleX, float scaleY,const Color4& color, Direction inversion) {
DrawSprite(texture, alpha_mask, {positionX, positionY}, rad_rotation, {originX, originY}, {scaleX, scaleY}, color, inversion);
}
void JGL::J2D::DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation,
void J2D::DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation,
float originX, float originY,float scaleX, float scaleY,const Color4& color, Direction inversion) {
DrawSprite(*texture, *alpha_mask, {positionX, positionY}, rad_rotation, {originX, originY}, {scaleX, scaleY}, color, inversion);
}
void JGL::J2D::DrawPartialRenderTarget(const JGL::RenderTarget& rt, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size,
float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color, JGL::Direction inversion) {
void J2D::DrawPartialRenderTarget(const RenderTarget& rt, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size,
float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color, Direction inversion) {
//Correct for the render-target being upside-down.
Direction d{};
@@ -450,18 +482,18 @@ void JGL::J2D::DrawPartialRenderTarget(const JGL::RenderTarget& rt, const Vector
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));
JGL::J2D::DrawPartialSprite(*rt.GetTexture(), r_position, r_sub_texture_position, sub_texture_size, rad_rotation, origin, scale, color, d);
J2D::DrawPartialSprite(*rt.GetTexture(), r_position, r_sub_texture_position, sub_texture_size, rad_rotation, origin, scale, color, d);
if (rt.OwnsTexture())
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void JGL::J2D::DrawPartialRenderTarget(const JGL::RenderTarget* rt, const Vector2& position,const Vector2& sub_texture_position,const Vector2& sub_texture_size, float rad_rotation,
void J2D::DrawPartialRenderTarget(const RenderTarget* rt, const Vector2& position,const Vector2& sub_texture_position,const Vector2& sub_texture_size, float rad_rotation,
const Vector2& origin, const Vector2& scale, const Color4& color, Direction inversion) {
DrawPartialRenderTarget(*rt, position, sub_texture_position, sub_texture_size, rad_rotation, origin, scale, color, inversion);
}
void JGL::J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotation, const Vector2& origin,
void J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -523,7 +555,7 @@ void JGL::J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_
}
void JGL::J2D::DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation, float originX,
void J2D::DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation, float originX,
float originY, float scaleX, float scaleY, const Color4& color, Direction inversion) {
DrawSprite(texture,
{positionX, positionY},
@@ -533,7 +565,7 @@ void JGL::J2D::DrawSprite(const Texture& texture, float positionX, float positio
color, inversion);
}
void JGL::J2D::DrawPartialSprite(const Texture& texture, const Vector2& position, const Vector2& sub_texture_position,
void J2D::DrawPartialSprite(const Texture& texture, const Vector2& position, const Vector2& sub_texture_position,
const Vector2& sub_texture_size, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
if (!state_stack.Size())
@@ -611,22 +643,22 @@ void JGL::J2D::DrawPartialSprite(const Texture& texture, const Vector2& position
glDisable(GL_TEXTURE_2D);
}
void JGL::J2D::DrawPartialSprite(const JGL::Texture& texture, float positionX, float positionY, float sub_texture_positionX,
void J2D::DrawPartialSprite(const Texture& texture, float positionX, float positionY, float sub_texture_positionX,
float sub_texture_positionY, unsigned int sub_texture_sizeX,
unsigned int sub_texture_sizeY, float originX, float originY, float rad_rotation,
float scaleX, float scaleY, const Color4& color, JGL::Direction inversion) {
float scaleX, float scaleY, const Color4& color, Direction inversion) {
JGL::J2D::DrawPartialSprite(texture, {positionX, positionY}, {sub_texture_positionX, sub_texture_positionY},
J2D::DrawPartialSprite(texture, {positionX, positionY}, {sub_texture_positionX, sub_texture_positionY},
{(float) sub_texture_sizeX, (float) sub_texture_sizeY}, rad_rotation, {originX, originY},
{scaleX, scaleY}, color, inversion);
}
void JGL::J2D::DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis, float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color) {
void J2D::DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis, float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
if (mirror_axis == Direction::None)
Logger::Warning("Drawing non-mirrored sprite with JGL::J2D::DrawMirrorSprite?");
Logger::Warning("Drawing non-mirrored sprite with J2D::DrawMirrorSprite?");
glBindTexture(GL_TEXTURE_2D, texture.GetHandle());
Vector2 size = Vector2(texture.GetDimensions());
@@ -705,7 +737,7 @@ void JGL::J2D::DrawMirrorSprite(const Texture& texture, const Vector2& position,
glDisable(GL_TEXTURE_2D);
}
void JGL::J2D::OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
void J2D::OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -732,10 +764,17 @@ void JGL::J2D::OutlineCircle(const Color4& color, const Vector2& center, float r
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions) {
void J2D::FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions) {
BatchFillCircle(&color, &center, &radius, subdivisions, 1);
}
void J2D::BatchFillCircle(const Color4* colors, const Vector2* positions, float* radii, unsigned int subdivisions, const size_t& circle_count) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
if (circle_count <= 0)
return;
GLfloat angle, x, y;
float step = (2.f * Math::Pi) / (float) subdivisions;
std::vector<Vector2> vertices(subdivisions);
@@ -745,8 +784,8 @@ void JGL::J2D::FillCircle(const Color4& color, const Vector2& center, float radi
* wait around for the container to resize. This gets rid of it for what we can guarantee. */
int i = 0;
for (angle = 0.0f; angle < (2.f * Math::Pi); angle += step) {
x = radius * std::sin(angle) + center.x;
y = radius * std::cos(angle) + center.y;
x = std::sin(angle);
y = std::cos(angle);
if (i < subdivisions)
vertices[i] = {x, y};
else
@@ -754,13 +793,19 @@ void JGL::J2D::FillCircle(const Color4& color, const Vector2& center, float radi
i++;
}
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glDrawArrays(GL_TRIANGLE_FAN, 0, (int) vertices.size());
for (size_t j = 0; j < circle_count; j++) {
glPushMatrix();
glColor4ubv(colors[j].ptr());
glTranslatef(positions[j].x, positions[j].y, 0);
glScalef(radii[j], radii[j], 0);
glDrawArrays(GL_TRIANGLE_FAN, 0, (int) vertices.size());
glPopMatrix();
}
glColor4fv(default_state.draw_color);
}
void JGL::J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness) {
void J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -773,7 +818,7 @@ void JGL::J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillTriangle(const Color4& color, const Triangle2D& tri) {
void J2D::FillTriangle(const Color4& color, const Triangle2D& tri) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -785,7 +830,7 @@ void JGL::J2D::FillTriangle(const Color4& color, const Triangle2D& tri) {
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri) {
void J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -802,31 +847,32 @@ void JGL::J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color
glColor4fv(default_state.draw_color);
}
//TODO render all in once pass with GL_LINE_LOOP instead of separate lines.
void JGL::J2D::DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
void J2D::DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
int subdivisions, float thickness) {
Vector2 last = controlA;
const Vector2& first = controlB;
for (int i = 0; i < subdivisions; ++i)
{
std::vector<Vector2> vertices(2 * subdivisions + 2);
for (int i = 0; i < subdivisions; ++i) {
float alpha = (float) i / (float) subdivisions;
Vector2 step = J3ML::Algorithm::Bezier(alpha, controlA, pointA, pointB, controlB);
DrawLine(color, last, step, thickness);
vertices[2 * i] = last;
vertices[2 * i + 1] = step;
last = step;
}
// Have to manually draw the last segment of the curve.
DrawLine(color, last, first, thickness);
vertices[2 * subdivisions] = last;
vertices[2 * subdivisions + 1] = first;
DrawLines(color, vertices.data(), vertices.size(), thickness);
}
void JGL::J2D::OutlinePolygon(const Color4& color, const Vector2* points, int points_size, float thickness) {
void J2D::OutlinePolygon(const Color4& color, const Vector2* points, int points_size, float thickness) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
if (points[0] != points[points_size -1])
throw std::runtime_error("JGL::J2D::OutlinePolygon: The first point and the last point must connect.");
throw std::runtime_error("J2D::OutlinePolygon: The first point and the last point must connect.");
glLineWidth(thickness);
glColor4ubv(color.ptr());
@@ -835,12 +881,12 @@ void JGL::J2D::OutlinePolygon(const Color4& color, const Vector2* points, int po
glColor4fv(default_state.draw_color);
}
void JGL::J2D::DrawGradientLine(const Color4& color_a, const Color4& color_b, float x, float y, float w, float h,
void J2D::DrawGradientLine(const Color4& color_a, const Color4& color_b, float x, float y, float w, float h,
float thickness) {
DrawGradientLine(color_a, color_b, {x, y}, {w, h}, thickness);
}
void JGL::J2D::DrawArc(const Color4& color, const Vector2& center, float radius, float arc_begin, float arc_end, unsigned int subdivisions, float thickness)
void J2D::DrawArc(const Color4& color, const Vector2& center, float radius, float arc_begin, float arc_end, unsigned int subdivisions, float thickness)
{
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -873,7 +919,7 @@ void JGL::J2D::DrawArc(const Color4& color, const Vector2& center, float radius,
glColor4fv(default_state.draw_color);
}
void JGL::J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, float thickness)
void J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, float thickness)
{
// A rounded rectangle of size 2a x 2b with rounding radius r is given by
// f(x; a, r) + f(y; b, r) = 1
@@ -888,7 +934,6 @@ void JGL::J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const
// TODO: Calculate vertices for top-left quarter-circle.
Vector2 tl = pos;
Vector2 tr = pos + Vector2(size.x, 0);
Vector2 br = pos + size;
Vector2 bl = pos + Vector2(0, size.y);
@@ -899,10 +944,10 @@ void JGL::J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const
Vector2 anchor_br = pos + size - Vector2(radius, radius);
Vector2 anchor_bl = pos + Vector2(radius, size.y - radius);
//JGL::J2D::Begin();
//JGL::J2D::DrawPoints(Colors::Red, {tl, tr, br, bl}, 2);
//JGL::J2D::DrawPoints(Colors::Blue, {anchor_tl, anchor_tr, anchor_br, anchor_bl}, 2);
//JGL::J2D::End();
//J2D::Begin();
//J2D::DrawPoints(Colors::Red, {tl, tr, br, bl}, 2);
//J2D::DrawPoints(Colors::Blue, {anchor_tl, anchor_tr, anchor_br, anchor_bl}, 2);
//J2D::End();
Vector2 anchor_topleft_top = pos + Vector2(radius, 0);
Vector2 anchor_topright_top = pos + Vector2(size.x - radius, 0);
@@ -916,7 +961,7 @@ void JGL::J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const
Vector2 anchor_bottomleft_left = pos + Vector2(0, size.y - radius);
Vector2 anchor_topleft_left = pos + Vector2(0, radius);
//JGL::J2D::Begin();
//J2D::Begin();
// The 3.01f, etc is a tiny-bit of overshoot to compensate for the fact that
// this is not being plotted as a continuous line-loop.
@@ -924,25 +969,24 @@ void JGL::J2D::OutlineRoundedRect(const Color4& color, const Vector2& pos, const
unsigned int subdivisions = 9;
JGL::J2D::DrawArc(color, anchor_tl, radius, Math::Pi, 3.01f*Math::Pi/2.f, subdivisions, thickness);
JGL::J2D::DrawLine(color, anchor_topleft_top, anchor_topright_top, thickness);
JGL::J2D::DrawArc(color, anchor_tr, radius, 3.f*Math::Pi/2.f, 2.02*Math::Pi, subdivisions, thickness);
JGL::J2D::DrawLine(color, anchor_topright_right, anchor_bottomright_right, thickness);
JGL::J2D::DrawArc(color, anchor_br, radius, 0.0f, 1.01f*Math::Pi/2, subdivisions, thickness);
JGL::J2D::DrawLine(color, anchor_bottomright_bottom, anchor_bottomleft_bottom, thickness);
JGL::J2D::DrawArc(color, anchor_bl, radius, Math::Pi/2, Math::Pi*1.01f, subdivisions, thickness);
JGL::J2D::DrawLine(color, anchor_bottomleft_left, anchor_topleft_left, thickness);
//JGL::J2D::End();
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);
J2D::DrawLine(color, anchor_topright_right, anchor_bottomright_right, thickness);
J2D::DrawArc(color, anchor_br, radius, 0.0f, 1.01f*Math::Pi/2, subdivisions, thickness);
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);
//J2D::End();
}
void JGL::J2D::FillChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius) {
void J2D::FillChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius) {
FillRoundedRect(color, pos, size, radius, 4);
}
void JGL::J2D::OutlineChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius,
float thickness) {
void J2D::OutlineChamferRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, float thickness) {
Vector2 anchor_topleft_top = pos + Vector2(radius, 0);
Vector2 anchor_topright_top = pos + Vector2(size.x - radius, 0);
Vector2 anchor_topright_right = pos + Vector2(size.x, radius);
@@ -960,7 +1004,7 @@ void JGL::J2D::OutlineChamferRect(const Color4& color, const Vector2& pos, const
glColor4fv(default_state.draw_color);
}
void JGL::J2D::DrawPoints(const Color4& color, const Vector2* points, int num_points, float radius) {
void J2D::DrawPoints(const Color4& color, const Vector2* points, int num_points, float radius) {
glPointSize(radius);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), points);
@@ -968,16 +1012,16 @@ void JGL::J2D::DrawPoints(const Color4& color, const Vector2* points, int num_po
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC) {
void J2D::FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC) {
FillTriangle(color, {triA, triB, triC});
}
void JGL::J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Vector2& tri_a,
void J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Vector2& tri_a,
const Vector2& tri_b, const Vector2& tri_c) {
FillGradientTriangle(a_color, b_color, c_color, {tri_a, tri_b, tri_c});
}
void JGL::J2D::OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness,
void J2D::OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness,
int subdivisions) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");
@@ -1004,7 +1048,7 @@ void JGL::J2D::OutlineEllipse(const Color4& color, const Vector2& position, floa
glColor4fv(default_state.draw_color);
}
void JGL::J2D::FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions) {
void J2D::FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions) {
if (!state_stack.Size())
Logger::Error("Drawing J2D element before J2D begin.");

View File

@@ -20,6 +20,7 @@ public:
GLint viewport[4] = {0, 0, 0, 0};
GLint blend_func[2];
GLuint current_fbo = 0;
RenderTarget* current_render_target = nullptr;
bool texture_2D = false;
bool texture_coordinate_array = false;
@@ -57,7 +58,6 @@ 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 State current_state;
}
namespace JGL::J2D {
@@ -67,11 +67,13 @@ namespace JGL::J2D {
{1, 1, 1, 1},
{0, 0, 0, 0},
{GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
0, false, false,
0, nullptr, false, false,
false, false, true, true,
true, false, 0,
{}, {}
};
inline State current_state;
}
namespace JGL::J3D {

View File

@@ -76,7 +76,7 @@ JGL::RenderTarget::RenderTarget(const JGL::Texture* texture, const Color4& clear
texture_created_by_us = false;
}
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate, FilteringMode filtering_mode) {
if (size.x < 1 || size.y < 1)
Logger::Fatal("Creating a render target where the color attachment is empty?");
@@ -85,7 +85,7 @@ JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color,
glGetIntegerv(GL_VIEWPORT, viewport);
//Textures behave strangely if they're not square aaaaaaaaaaaaa.
texture = new Texture(size);
texture = new Texture(size, filtering_mode);
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glViewport(0,0, size.x, size.y);
@@ -140,30 +140,10 @@ void JGL::RenderTarget::Resize(const Vector2i& new_size) {
glGetIntegerv(GL_VIEWPORT, old_viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
/* If what was previously not part of the renderable area is big enough
* to just set the new size. */
if (new_size.x <= texture->GetDimensions().x && new_size.y <= texture->GetDimensions().y) {
size = new_size;
// Clear.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
auto cc = GetClearColor();
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
glViewport(0,0, size.x, size.y);
glClear(GL_COLOR_BUFFER_BIT);
if (using_depth)
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
return;
}
//If we have to remake the texture.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
// Erase it.
delete texture;
@@ -240,20 +220,19 @@ bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
glGetIntegerv(GL_RENDERBUFFER_BINDING, &current_renderbuffer);
glGenRenderbuffers(1, &msaa_render_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, msaa_render_buffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, JGL::to_int(sample_rate), GL_RGBA, size.x, size.y);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, to_int(sample_rate), GL_RGBA, size.x, size.y);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa_render_buffer);
if (using_depth) {
glGenRenderbuffers(1, &msaa_depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, msaa_depth_buffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, JGL::to_int(sample_rate), GL_DEPTH_COMPONENT, size.x, size.y);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, to_int(sample_rate), GL_DEPTH_COMPONENT, size.x, size.y);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaa_depth_buffer);
}
bool failure = false;
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
failure = true,
Logger::Fatal("A new MSAA " + std::to_string(to_int(sample_rate)) + "x framebuffer couldn't be allocated.");
failure = true, Logger::Fatal("A new " + to_string(sample_rate) + " framebuffer couldn't be allocated.");
glBindRenderbuffer(GL_RENDERBUFFER, current_renderbuffer);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
@@ -283,19 +262,6 @@ void JGL::RenderTarget::MSAABlit() const {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
}
// Fixes using render targets on a texture that has mipmaps.
if (GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_NEAREST
|| GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_BILINEAR ||
GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_TRILINEAR) {
GLint current_texture = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
glBindTexture(GL_TEXTURE_2D, GetTexture()->GetHandle());
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, current_texture);
}
}
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination, const Vector2i& position) {
@@ -381,3 +347,22 @@ JGL::RenderTarget::RenderTarget(const JGL::RenderTarget& rhs) {
operator delete(this_render_target);
}
Vector2i JGL::RenderTarget::MaximumSize() {
return Texture::MaximumSize();
}
void JGL::RenderTarget::RegenerateMipMaps() {
// Fixes using render targets on a texture that has mipmaps.
if (GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_NEAREST
|| GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_BILINEAR ||
GetTexture()->GetFilteringMode() == FilteringMode::MIPMAP_TRILINEAR) {
GLint current_texture = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
glBindTexture(GL_TEXTURE_2D, GetTexture()->GetHandle());
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, current_texture);
}
}

View File

@@ -98,7 +98,9 @@ std::vector<unsigned char> Texture::bmp(const std::filesystem::path& file) {
return result;
}
Texture::Texture(const Vector2i& size) : invert_y(true), format(ColorFormat::RGBA), size(size), filtering_mode(FilteringMode::NEAREST), wrapping_mode(WrappingMode::CLAMP_TO_EDGE) {
Texture::Texture(const Vector2i& size, FilteringMode filtering_mode) : invert_y(true), format(ColorFormat::RGBA), size(size), filtering_mode(filtering_mode), wrapping_mode(WrappingMode::CLAMP_TO_EDGE) {
if (SizeExceedsMaximum(size))
Logger::Error("Creating a texture where the size is bigger than the maximum for this system.");
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
@@ -107,6 +109,27 @@ Texture::Texture(const Vector2i& size) : invert_y(true), format(ColorFormat::RGB
//NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (filtering_mode == FilteringMode::NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
else if (filtering_mode == FilteringMode::BILINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (filtering_mode == FilteringMode::MIPMAP_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
else if (filtering_mode == FilteringMode::MIPMAP_BILINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
else if (filtering_mode == FilteringMode::MIPMAP_TRILINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//Clamp
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -114,8 +137,10 @@ Texture::Texture(const Vector2i& size) : invert_y(true), format(ColorFormat::RGB
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
void Texture::load(const unsigned char* pixels) {
if (SizeExceedsMaximum(size))
Logger::Error("Creating a texture where the size is bigger than the maximum for this system.");
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
@@ -272,3 +297,16 @@ Texture::Texture(const Texture* textures, const size_t& texture_count) {
next_x += textures[i].GetDimensions().x;
}
}
bool Texture::SizeExceedsMaximum(const Vector2i& s) {
auto max_size = Texture::MaximumSize();
return s.x > max_size.x || s.y > max_size.y;
}
Vector2i Texture::MaximumSize() {
GLint max_size;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
return { max_size, max_size };
}