Render Target for J2D
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m10s

This commit is contained in:
2024-09-13 13:24:20 -04:00
parent 9e3e0c949f
commit 881d031f3c
8 changed files with 158 additions and 69 deletions

View File

@@ -80,16 +80,16 @@ endif()
set_target_properties(JGL PROPERTIES LINKER_LANGUAGE CXX)
#Don't expose this one because it's only to be used in the demo program.
include_directories(${ReTexture_SOURCE_DIR}/include)
#Don't expose these ones.
include_directories(${ReWindow_SOURCE_DIR}/include)
target_include_directories(JGL PUBLIC
${PROJECT_SOURCE_DIR}/include
${OPENGL_INCLUDE_DIRS}
${ReTexture_SOURCE_DIR}/include
${mcolor_SOURCE_DIR}/include
${J3ML_SOURCE_DIR}/include
${Event_SOURCE_DIR}/include
${ReWindow_SOURCE_DIR}/include
${glad_SOURCE_DIR}/include
${jlog_SOURCE_DIR}/include
)
@@ -100,13 +100,13 @@ add_executable(JGL_Demo main.cpp)
if (UNIX AND NOT APPLE)
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(JGL PRIVATE ${FREETYPE_LIBRARIES})
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML ReWindowLibrary glad jlog Event ReTexture)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog Event ReTexture)
endif()
if (WIN32)
target_include_directories(JGL PRIVATE ${freetype_SOURCE_DIR}/include)
target_link_libraries(JGL PRIVATE freetype)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML ReWindowLibrary glad jlog Event ReTexture)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog Event ReTexture)
endif()
target_link_libraries(JGL_Demo PUBLIC JGL)
target_link_libraries(JGL_Demo PUBLIC JGL ReWindowLibrary)

View File

@@ -18,6 +18,7 @@
#include <JGL/types/Enums.h>
#include <JGL/types/FontCache.h>
#include <JGL/types/Font.h>
#include <JGL/types/RenderTarget.h>
#include <J3ML/LinearAlgebra.hpp>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
@@ -41,7 +42,7 @@ namespace JGL {
/// @note This call may not strictly be necessary on some setups, but is provided to keep the API constant.
/// It is recommended to always open a JGL 2D context to render your content, then close when completed.
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 3D content in between our calls.
void Begin();
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @see Begin().
void End();
@@ -76,6 +77,8 @@ namespace JGL {
/// Draws a filled rectangle with rounded corners on the screen.
void FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
void DrawRenderTargetAsSprite(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
/// @param texture
/// @param position

View File

@@ -10,16 +10,26 @@ namespace JGL {
class JGL::RenderTarget {
private:
Color4 background_color = {0,0,0,0};
Color4 clear_color{0,0,0,0};
bool using_depth = false;
GLuint framebuffer_object = 0;
GLuint depth_buffer = 0;
Texture texture;
Texture* texture = nullptr;
public:
static GLuint GetActiveGLRenderTargetHandle();
static GLuint GetActiveGLFramebufferHandle();
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
public:
[[nodiscard]] Texture GetGLTexture();
[[nodiscard]] GLuint GetGLTextureHandle();
[[nodiscard]] GLuint GetGLFramebufferObjectHandle();
[[nodiscard]] GLuint GetGLDepthBufferHandle();
[[nodiscard]] Vector2 GetDimensions() const;
[[nodiscard]] Texture* GetJGLTexture() const;
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
[[nodiscard]] Color4 GetClearColor() const;
public:
/// Create a render target for a texture that already exists. For decals.
explicit RenderTarget(const Texture& texture, const Color4& clear_color = Colors::Black, bool use_depth = false);
/// Create a Render Target with a brand new texture. Want to render JGL elements onto a texture and display it as a sprite?
explicit RenderTarget(unsigned int size, const Color4& clear_color = Colors::Black, bool use_depth = false);
void Erase();
};

View File

@@ -40,8 +40,6 @@ namespace JGL {
/* Initialize a texture filled with trash data
this is primarily for the RenderTarget */
explicit Texture(const Vector2& size);
/* Initialize a texture that is a single color */
Texture(const Color4& color, const Vector2& size);
Texture() = default;
public:
[[nodiscard]] GLuint GetGLTextureHandle() const;

View File

@@ -4,9 +4,6 @@
#include <Colors.hpp>
#include <chrono>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <JGL/types/Font.h>
#include <JGL/Logger.h>
#include <ReTexture/Texture.h>
using J3ML::LinearAlgebra::Vector2;
using namespace JGL;
@@ -51,8 +48,6 @@ public:
}
};
Texture* image;
class Camera {
public:
Vector3 position = {0,0,0};
@@ -96,6 +91,9 @@ Gizmo b({200, 250});
Gizmo c({350, 300});
Gizmo d({450, 250});
Texture* image;
RenderTarget* j2d_render_target;
class JGLDemoWindow : public ReWindow::RWindow
{
public:
@@ -114,6 +112,7 @@ public:
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
j2d_render_target = new RenderTarget(1280, {0,0,0,0});
}
Vector3 textAngle = {0,0,0};
@@ -156,9 +155,9 @@ public:
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
J3D::End();
J2D::Begin();
J2D::Begin(j2d_render_target, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::DrawSprite(*image, {300, 300}, 0, {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, {225, 300}, image->GetDimensions() * 0.25, image->GetDimensions() * 0.75, sprite_radians, {0.5, 0.5});
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
@@ -193,6 +192,11 @@ public:
d.Draw();
J2D::End();
//Draw the Render Target that we just drew all that stuff onto.
J2D::Begin();
J2D::DrawRenderTargetAsSprite(*j2d_render_target, {0, 0});
J2D::End();
if (framerate_measurement) {
frames++;
std::chrono::system_clock::time_point stop = std::chrono::high_resolution_clock::now();

View File

@@ -7,8 +7,13 @@
#include <jlog/Logger.hpp>
#include <J3ML/Algorithm/Bezier.hpp>
JGL::RenderTarget* render_target = nullptr;
GLfloat oldColor[4] = {0, 0, 0, 1};
GLfloat baseColor[4] = {1, 1, 1, 1};
GLuint current_fbo = 0;
GLint viewport[4] = {0, 0, 0, 0};
bool inJ2D = false;
bool inJ3D = false;
bool wasTexture2DEnabled = false;
@@ -30,12 +35,25 @@ namespace JGL {
}
#pragma region J2D
void J2D::Begin() {
void J2D::Begin(RenderTarget* rt, bool clear_buffers) {
GLfloat old_clear_color[4];
if (rt != nullptr) {
render_target = rt;
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
glGetIntegerv(GL_VIEWPORT, viewport);
current_fbo = JGL::RenderTarget::GetActiveGLFramebufferHandle();
JGL::RenderTarget::SetActiveGLRenderTarget(*rt);
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glViewport(0, 0, (int) wS.x, (int) wS.y);
glOrtho(0, wS.x, wS.y, 0, -1, 1);
if (rt == nullptr)
glViewport(0, 0, (int) wS.x, (int) wS.y),
glOrtho(0, wS.x, wS.y, 0, -1, 1);
else
glOrtho(0, rt->GetDimensions().x, rt->GetDimensions().y, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
@@ -97,6 +115,12 @@ namespace JGL {
if (!inJ3D)
inJ2D = true;
else { jlog::Error("Attempt to Begin J2D inside of J3D context."); }
if (rt != nullptr && clear_buffers) {
glClearColor(rt->GetClearColor().R(), rt->GetClearColor().G(), rt->GetClearColor().B(), rt->GetClearColor().A());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
}
}
void J2D::End() {
@@ -132,6 +156,11 @@ namespace JGL {
//Put the draw color back how it was before.
glColor4fv(oldColor);
if (render_target != nullptr) {
render_target = nullptr;
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
inJ2D = false;
}
@@ -259,6 +288,24 @@ namespace JGL {
J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + size.y - radius}, radius, subdivisions);
}
void
J2D::DrawRenderTargetAsSprite(const JGL::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.
Direction d{};
if (inversion == Direction::None)
d = Direction::Vertical;
else if (inversion == Direction::Horizontal)
d = Direction::Horizontal | Direction::Vertical;
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical)
d = Direction::Horizontal;
//Change the blending mode such that the alpha doesn't get multiplied again.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
J2D::DrawSprite(*rt.GetJGLTexture(), position, rad_rotation, origin, scale, color, d);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
if (!inJ2D)

View File

@@ -1,22 +1,24 @@
#include <JGL/types/RenderTarget.h>
#include <jlog/Logger.hpp>
#include <stdexcept>
JGL::Texture JGL::RenderTarget::GetGLTexture() {
JGL::Texture* JGL::RenderTarget::GetJGLTexture() const {
return texture;
}
GLuint JGL::RenderTarget::GetGLTextureHandle() {
return texture.GetGLTextureHandle();
GLuint JGL::RenderTarget::GetGLTextureHandle() const {
return texture->GetGLTextureHandle();
}
GLuint JGL::RenderTarget::GetGLFramebufferObjectHandle() {
GLuint JGL::RenderTarget::GetGLFramebufferObjectHandle() const {
return framebuffer_object;
}
GLuint JGL::RenderTarget::GetGLDepthBufferHandle() {
GLuint JGL::RenderTarget::GetGLDepthBufferHandle() const {
return depth_buffer;
}
GLuint JGL::RenderTarget::GetActiveGLRenderTargetHandle() {
GLuint JGL::RenderTarget::GetActiveGLFramebufferHandle() {
GLuint fbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &fbo);
return fbo;
@@ -24,5 +26,62 @@ GLuint JGL::RenderTarget::GetActiveGLRenderTargetHandle() {
void JGL::RenderTarget::SetActiveGLRenderTarget(const RenderTarget& render_target) {
RenderTarget rt = render_target;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, rt.GetGLFramebufferObjectHandle());
glBindFramebuffer(GL_FRAMEBUFFER, rt.GetGLFramebufferObjectHandle());
glViewport(0,0, render_target.GetJGLTexture()->GetDimensions().x, render_target.GetJGLTexture()->GetDimensions().x);
}
Vector2 JGL::RenderTarget::GetDimensions() const {
return texture->GetDimensions();
}
void JGL::RenderTarget::Erase() {
if (GetActiveGLFramebufferHandle() == framebuffer_object)
jlog::Warning("Deleting the framebuffer that's currently in use?");
texture->Erase();
if (using_depth)
glDeleteRenderbuffers(1, &depth_buffer);
glDeleteFramebuffers(1, &framebuffer_object);
}
Color4 JGL::RenderTarget::GetClearColor() const {
return clear_color;
}
JGL::RenderTarget::RenderTarget(const unsigned int size, const Color4& clear_color, bool use_depth) {
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, viewport);
texture = new Texture(Vector2(size, size));
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glViewport(0,0, size, size);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
if (use_depth) {
GLuint depthBuffer;
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size, size);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
glClear(GL_DEPTH_BUFFER_BIT);
using_depth = true;
}
GLfloat old_clear_color[4];
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
glClearColor(clear_color.RedChannelNormalized(), clear_color.GreenChannelNormalized(), clear_color.BlueChannelNormalized(), clear_color.AlphaChannelNormalized());
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("Error " + std::to_string(status) + "while generating framebuffer");
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
this->clear_color = clear_color;
}

View File

@@ -33,47 +33,15 @@ namespace JGL
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
Texture::Texture(const Color4& color, const Vector2& size) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
glGenTextures(1, &texture_handle);
glBindTexture(GL_TEXTURE_2D, texture_handle);
//Bilinear
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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);
auto* pixel_data = new std::vector<Color4>(size.x * size.y);
for (unsigned int i = 0; i < (unsigned int) (size.x * size.y); i++)
pixel_data->at(i) = color;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int) size.x, (int) size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data->data());
delete pixel_data;
texture_format = TextureFormat::RGBA;
texture_size = size;
texture_filtering_mode = TextureFilteringMode::BILINEAR;
texture_wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE;
texture_flags = TextureFlag::NONE;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
Texture::Texture(const Vector2& size) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
glGenTextures(1, &texture_handle);
glBindTexture(GL_TEXTURE_2D, texture_handle);
//Bilinear
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//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);
@@ -82,7 +50,7 @@ namespace JGL
texture_format = TextureFormat::RGBA;
texture_size = size;
texture_filtering_mode = TextureFilteringMode::BILINEAR;
texture_filtering_mode = TextureFilteringMode::NEAREST;
texture_wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE;
texture_flags = TextureFlag::NONE;