Ability to resize render targets.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s
This commit is contained in:
@@ -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();
|
||||
};
|
@@ -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();
|
||||
};
|
||||
|
||||
}
|
@@ -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);
|
||||
|
22
main.cpp
22
main.cpp
@@ -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();
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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, ¤t_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();
|
||||
}
|
||||
}
|
@@ -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, ¤t_element_array_buffer);
|
||||
|
Reference in New Issue
Block a user