Ability to resize render targets.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s

This commit is contained in:
2024-10-06 00:01:06 -04:00
parent b4c29315f4
commit 5f367efc28
7 changed files with 148 additions and 48 deletions

View File

@@ -8,18 +8,29 @@ namespace JGL {
class RenderTarget;
}
//TODO copy constructor for this. Copying this as it is and then that copy going out of scope will crash the program as it sits.
class JGL::RenderTarget {
private:
Color4 clear_color{0,0,0,0};
/// "Size" in this sense is the "Renderable Area" because OpenGL textures behave strangely if they're not square.
Vector2 size{0, 0};
bool using_depth = false;
bool texture_created_by_us = false;
GLuint framebuffer_object = 0;
GLuint depth_buffer = 0;
Texture* texture = nullptr;
void Erase();
public:
static GLuint GetActiveGLFramebufferHandle();
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
/** Change the size of the renderable area of the Render Target.
* If the new size is larger than the non-renderable area the texture will be resized to fit. */
/// @param new_size new size in px.
/// @param clear whether or not the data currently in the RenderTarget is to be kept.
/// @note Clearing the FBO on Resize is *much* faster than keeping the data because we don't have to read back.
void Resize(const Vector2& new_size);
public:
[[nodiscard]] Vector2 GetDimensions() const;
[[nodiscard]] Texture* GetJGLTexture() const;
@@ -30,10 +41,9 @@ public:
/// Get the data back from the FBO. This is *not* async friendly.
[[nodiscard]] std::vector<GLfloat> GetData() 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 for a texture that already exists. For adding to an existing texture.
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(const Vector2& size, const Color4& clear_color = Colors::Black, bool use_depth = false);
void Erase();
~RenderTarget();
};

View File

@@ -23,8 +23,12 @@ namespace JGL {
CLAMP_TO_BORDER = 3 //Effectively the same as clamp_to_edge
};
//TODO copy constructor for this. Copying this as it is and then that copy going out of scope will crash the program as it sits.
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
class Texture {
private:
void Erase();
protected:
GLuint texture_handle = 0;
Vector2 texture_size = {0, 0};
@@ -38,9 +42,11 @@ namespace JGL {
/// Load a texture from a file,
explicit Texture(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE);
Texture(const std::string& file, const TextureFlag& flags, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE);
Texture(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
/* Initialize a texture filled with trash data
this is primarily for the RenderTarget */
explicit Texture(const Vector2& size);
~Texture();
public:
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] Vector2 GetDimensions() const;
@@ -51,7 +57,6 @@ namespace JGL {
[[nodiscard]] std::vector<Color4> GetPixelData() const;
void SetTextureHandle(GLuint handle);
void Erase();
};
}

View File

@@ -20,6 +20,7 @@ private:
void load(const GLuint* data, const long& size);
void SetData(void* data, const long& length);
void UpdateData(void* data, const long& offset, const long& length);
void Erase();
public:
VRamList(const GLuint* data, const long& length);
VRamList(const GLfloat* data, const long& length);
@@ -43,8 +44,6 @@ public:
[[nodiscard]] std::vector<GLfloat> GetDataF() const;
[[nodiscard]] std::vector<GLuint> GetDataUI() const;
[[nodiscard]] bool IsFloatArray() const;
/// Deallocate the vram the vbo took up.
void Erase();
/** Replace the data of an existing VBO in it's entirety. Must be same type.
* "length" refers to the number of elements in data. Not the number of bytes. */
void SetData(const GLfloat* data, const long& length);

View File

@@ -117,7 +117,7 @@ public:
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
j2d_render_target = new RenderTarget({500, 500}, {255,0,0,0});
j2d_render_target = new RenderTarget({1, 1}, {0,0,0,0});
}
Vector3 textAngle = {0,0,0};
@@ -155,7 +155,7 @@ public:
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,0}, {1, 1}, Colors::White, Direction::Vertical | Direction::Horizontal);
J2D::DrawMirrorSprite(*image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
@@ -194,11 +194,11 @@ public:
J2D::End();
//Draw the Render Target that we just drew all that stuff onto.
/*
J2D::Begin();
J2D::DrawRenderTargetAsSprite(*j2d_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
J2D::End();
*/
}
void OnRefresh(float elapsed) override {
@@ -244,9 +244,21 @@ int main(int argc, char** argv) {
window->Open();
window->initGL();
window->setResizable(true);
window->setVsyncEnabled(false);
window->setVsyncEnabled(true);
bool increasing = true;
while (window->isAlive()) {
if (increasing) {
j2d_render_target->Resize({j2d_render_target->GetDimensions().x + 1, j2d_render_target->GetDimensions().y + 1});
if (j2d_render_target->GetDimensions().x >= 540)
increasing = false;
}
if (!increasing) {
j2d_render_target->Resize({j2d_render_target->GetDimensions().x - 1, j2d_render_target->GetDimensions().y - 1});
if (j2d_render_target->GetDimensions().x <= 1)
increasing = true;
}
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
window->pollEvents();
window->refresh();

View File

@@ -1,4 +1,5 @@
#include <JGL/types/RenderTarget.h>
#include <ReTexture/Texture.h>
#include <jlog/Logger.hpp>
#include <stdexcept>
@@ -25,9 +26,8 @@ GLuint JGL::RenderTarget::GetActiveGLFramebufferHandle() {
}
void JGL::RenderTarget::SetActiveGLRenderTarget(const RenderTarget& render_target) {
RenderTarget rt = render_target;
glBindFramebuffer(GL_FRAMEBUFFER, rt.GetGLFramebufferObjectHandle());
glViewport(0,0, rt.GetDimensions().x, rt.GetDimensions().y);
glBindFramebuffer(GL_FRAMEBUFFER, render_target.GetGLFramebufferObjectHandle());
glViewport(0,0, render_target.GetDimensions().x, render_target.GetDimensions().y);
}
Vector2 JGL::RenderTarget::GetDimensions() const {
@@ -38,8 +38,6 @@ 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);
@@ -89,6 +87,7 @@ JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color,
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
this->clear_color = clear_color;
this->size = size;
texture_created_by_us = true;
}
std::vector<GLfloat> JGL::RenderTarget::GetData() const {
@@ -101,3 +100,62 @@ std::vector<GLfloat> JGL::RenderTarget::GetData() const {
return data;
}
void JGL::RenderTarget::Resize(const Vector2& new_size) {
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLfloat old_clear_color[4];
GLint old_viewport[4] = {0, 0, 0, 0};
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 without reading data back */
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;
unsigned int biggest;
if (new_size.x >= new_size.y)
biggest = new_size.x;
else
biggest = new_size.y;
auto cc = GetClearColor();
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
glViewport(0,0, size.x, size.y);
texture = new Texture(Vector2((float) biggest, (float) biggest));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
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]);
size = new_size;
}
JGL::RenderTarget::~RenderTarget() {
Erase();
if (texture_created_by_us)
delete texture;
}

View File

@@ -142,44 +142,49 @@ namespace JGL
}
std::vector<Color4> JGL::Texture::GetPixelData() const {
std::vector<Color4> result((size_t) (texture_size.x * texture_size.y));
glBindTexture(GL_TEXTURE_2D, texture_handle);
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
if (texture_format == TextureFormat::RGBA) {
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
return result;
}
std::vector<Color4> result((size_t) (texture_size.x * texture_size.y));
glBindTexture(GL_TEXTURE_2D, texture_handle);
//if RGB
std::vector<Color3> color3((size_t) (texture_size.x * texture_size.y));
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, color3.data());
for (const auto &c: color3)
result.emplace_back(c);
if (texture_format == TextureFormat::RGBA) {
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
glBindTexture(GL_TEXTURE_2D, current_texture);
return result;
}
void Texture::Erase() {
if (texture_handle != 0)
glDeleteTextures(1, &texture_handle);
}
//if RGB
std::vector<Color3> color3((size_t) (texture_size.x * texture_size.y));
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, color3.data());
for (const auto &c: color3)
result.emplace_back(c);
GLuint Texture::GetGLTextureHandle() const {
return texture_handle;
}
glBindTexture(GL_TEXTURE_2D, current_texture);
return result;
}
Vector2 Texture::GetDimensions() const {
return texture_size;
}
void Texture::Erase() {
if (texture_handle != 0)
glDeleteTextures(1, &texture_handle);
texture_handle = 0;
}
TextureFlag Texture::GetFlags() const {
return texture_flags;
}
GLuint Texture::GetGLTextureHandle() const {
return texture_handle;
}
TextureFormat Texture::GetFormat() const {
return texture_format;
}
Vector2 Texture::GetDimensions() const {
return texture_size;
}
TextureFlag Texture::GetFlags() const {
return texture_flags;
}
TextureFormat Texture::GetFormat() const {
return texture_format;
}
TextureFilteringMode Texture::GetFilteringMode() const {
return texture_filtering_mode;
@@ -192,4 +197,13 @@ namespace JGL
TextureWrappingMode Texture::GetWrappingMode() const {
return texture_wrapping_mode;
}
Texture::Texture(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format,
TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
load(software_texture, size, format, filtering_mode, wrapping_mode);
}
Texture::~Texture() {
Erase();
}
}

View File

@@ -25,8 +25,10 @@ void JGL::VRamList::load(const GLuint* data, const long& size) {
}
void JGL::VRamList::Erase() {
if (list_handle == 0)
JGL::Logger::Fatal("Erasing an uninitialized VRamList?");
if (list_handle == 0) {
JGL::Logger::Warning("Erasing an uninitialized VRamList?");
return;
}
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);