Render Targets Update.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m54s

Allow rendering onto a texture that's been loaded already.

Make DrawSprite commands work regardless of if the texture was loaded in inverted or not.

You however cannot draw onto a texture which is upside-down in vram because your draw commands would be positioned incorrectly.
This commit is contained in:
2024-10-08 18:25:31 -04:00
parent 0a757407d8
commit 0417c37460
6 changed files with 120 additions and 71 deletions

View File

@@ -42,7 +42,7 @@ public:
[[nodiscard]] std::vector<GLfloat> GetData() const;
public:
/// 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);
explicit RenderTarget(Texture* texture, const Color4& clear_color = Colors::Black);
/// 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);
~RenderTarget();

View File

@@ -37,8 +37,7 @@ namespace JGL {
void load(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
public:
/// 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(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE, const TextureFlag& flags = TextureFlag::INVERT_Y);
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 */
@@ -54,6 +53,7 @@ namespace JGL {
[[nodiscard]] TextureFormat GetFormat() const;
[[nodiscard]] std::vector<Color4> GetPixelData() const;
void SetTextureHandle(GLuint handle);
void SetFlags(const TextureFlag& flags);
};
}

View File

@@ -94,7 +94,9 @@ Gizmo c({350, 300});
Gizmo d({450, 250});
Texture* image;
Texture* image2;
RenderTarget* j2d_render_target;
RenderTarget* image2_render_target;
class JGLDemoWindow : public ReWindow::RWindow
{
@@ -116,8 +118,15 @@ public:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
j2d_render_target = new RenderTarget({1, 1}, {0,0,0,0});
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR, JGL::TextureWrappingMode::CLAMP_TO_EDGE);
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0});
image2 = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::NEAREST);
image2_render_target = new RenderTarget(image2);
J2D::Begin(image2_render_target);
J2D::FillRect(Colors::Red, {0,0}, {4,4});
J2D::DrawString(Colors::Red, "TEST", 0, 16, 1, 16, Jupiteroid);
J2D::End();
}
Vector3 textAngle = {0,0,0};
@@ -157,14 +166,13 @@ public:
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::DrawSprite(*image2, {300, 300}, sprite_radians, {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::DrawPartialSprite(*image, {225, 300}, image->GetDimensions() * 0.25, image->GetDimensions() * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
@@ -197,6 +205,7 @@ public:
J2D::Begin();
J2D::DrawRenderTargetAsSprite(*j2d_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
J2D::DrawRenderTargetAsSprite(*image2_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
J2D::End();
}
@@ -246,20 +255,7 @@ int main(int argc, char** argv) {
window->setResizable(true);
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

@@ -53,6 +53,9 @@ namespace JGL {
glGetIntegerv(GL_VIEWPORT, viewport);
current_fbo = JGL::RenderTarget::GetActiveGLFramebufferHandle();
JGL::RenderTarget::SetActiveGLRenderTarget(*rt);
if (!(rt->GetJGLTexture()->GetFlags() & INVERT_Y))
Logger::Warning("You're rendering onto a texture that is upside-down. Your draw commands won't work how you'd expect.");
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
@@ -302,17 +305,22 @@ namespace JGL {
//Correct for the render-target being upside-down.
Direction d{};
if (inversion == Direction::None)
if (inversion == Direction::None && !(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
d = Direction::Vertical;
else if (inversion == Direction::Horizontal)
d = Direction::Horizontal | Direction::Vertical;
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical)
else if (inversion == Direction::Horizontal) {
d = Direction::Horizontal;
if (!(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
d = Direction::Horizontal | Direction::Vertical;
}
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical) {
d = Direction::Horizontal;
if (!(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
d = Direction::Horizontal | Direction::Vertical;
}
//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);
J2D::DrawPartialSprite(*rt.GetJGLTexture(), position, {0, 0}, rt.GetDimensions(), rad_rotation, origin, scale, color, d);
J2D::DrawPartialSprite(*rt.GetJGLTexture(), position, {0, 0}, rt.GetDimensions(), 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,
@@ -323,7 +331,11 @@ namespace JGL {
const Vector2 size = texture.GetDimensions();
std::array<Vector2, 4> textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
std::array<Vector2, 4> textureCoordinates{};
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
// TODO: Kind of a mess, refactor to be more sensible later.
// Factors in scaling and origin correctly.
@@ -352,13 +364,12 @@ namespace JGL {
pos2.y + offset.y * scale.y
};
if (inversion == Direction::Vertical)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
else if (inversion == Direction::Horizontal)
textureCoordinates = {Vector2(1, 0), Vector2(1, 1), Vector2(0, 1), Vector2(0, 0)};
else if ((inversion& Direction::Horizontal) && (inversion& Direction::Vertical))
textureCoordinates = {Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1)};
std::swap(textureCoordinates[0], textureCoordinates[1]),
std::swap(textureCoordinates[3], textureCoordinates[2]);
if (inversion == Direction::Horizontal)
std::swap(textureCoordinates[0], textureCoordinates[3]),
std::swap(textureCoordinates[1], textureCoordinates[2]);
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
@@ -387,18 +398,32 @@ namespace JGL {
Logger::Error("Drawing J2D element before J2D begin.");
const Vector2 textureSize = texture.GetDimensions();
std::array<GLfloat, 8> textureCoordinates{};
// Calculate texture coordinates (relative to the whole texture)
std::array<GLfloat, 8> textureCoordinates = {
sub_texture_position.x / textureSize.x,
sub_texture_position.y / textureSize.y,
sub_texture_position.x / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
sub_texture_position.y / textureSize.y
};
if (!(texture.GetFlags() & INVERT_Y))
textureCoordinates = {
sub_texture_position.x / textureSize.x,
sub_texture_position.y / textureSize.y,
sub_texture_position.x / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
sub_texture_position.y / textureSize.y
};
else {
textureCoordinates = {
sub_texture_position.x / textureSize.x,
(textureSize.y - sub_texture_position.y) / textureSize.y,
sub_texture_position.x / textureSize.x,
(textureSize.y - (sub_texture_position.y + sub_texture_size.y)) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(textureSize.y - (sub_texture_position.y + sub_texture_size.y)) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(textureSize.y - sub_texture_position.y) / textureSize.y
};
}
if (inversion& Direction::Vertical)
std::swap(textureCoordinates[1], textureCoordinates[3]),
@@ -460,21 +485,35 @@ namespace JGL {
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
Vector2 size = texture.GetDimensions();
std::array<Vector2, 4> textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
if (mirror_axis == Direction::Horizontal) {
size.x *= 2;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(2, 0), Vector2(2, 1)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(2, 1), Vector2(2, 0)};
}
if (mirror_axis == Direction::Horizontal)
size.x *= 2,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT),
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(2, 1), Vector2(2, 0)};
else if (mirror_axis == Direction::Vertical) {
size.y *= 2;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 2), Vector2(0, 0), Vector2(1, 0), Vector2(1, 2)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(1, 2), Vector2(1, 0)};
}
else if (mirror_axis == Direction::Vertical)
size.y *= 2,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT),
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(1, 2), Vector2(1, 0)};
else if ((mirror_axis& Direction::Horizontal) && (mirror_axis& Direction::Vertical))
size *= 2,
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(2, 2), Vector2(2, 0)};
else if ((mirror_axis& Direction::Horizontal) && (mirror_axis& Direction::Vertical)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
size *= 2;
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 2), Vector2(0, 0), Vector2(2, 0), Vector2(2, 2)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(2, 2), Vector2(2, 0)};
}
const Vector2 offset = origin * size;
Vector2 pos2 = position;

View File

@@ -48,6 +48,28 @@ Color4 JGL::RenderTarget::GetClearColor() const {
return clear_color;
}
/// Idk why you'd ever want to clear it out if you're rendering onto a texture you passed in :shrug:.
JGL::RenderTarget::RenderTarget(JGL::Texture* texture, const Color4& clear_color) {
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, viewport);
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glViewport(0,0, size.x, size.y);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("A new framebuffer could not be allocated.");
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
this->clear_color = clear_color;
this->size = texture->GetDimensions();
this->texture = texture;
texture_created_by_us = false;
}
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth) {
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint viewport[4] = {0, 0, 0, 0};
@@ -88,6 +110,7 @@ JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color,
this->clear_color = clear_color;
this->size = size;
texture_created_by_us = true;
this->texture->SetFlags(INVERT_Y);
}
std::vector<GLfloat> JGL::RenderTarget::GetData() const {

View File

@@ -5,7 +5,7 @@ using namespace ReTexture;
namespace JGL
{
Texture::Texture(const std::string& file, const ReTexture::TextureFlag& flags, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode)
Texture::Texture(const std::string& file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode, const ReTexture::TextureFlag& flags)
{
auto* t = new ReTexture::SoftwareTexture(file, flags);
GLuint previous_texture;
@@ -17,19 +17,6 @@ namespace JGL
delete t;
}
Texture::Texture(const std::string& file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
auto* t = new SoftwareTexture(file);
load(t, {(float) t->getWidth(), (float) t->getHeight()}, t->getTextureFormat(), filtering_mode, wrapping_mode);
texture_flags = TextureFlag::NONE;
delete t;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
Texture::Texture(const Vector2& size) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
@@ -216,4 +203,8 @@ namespace JGL
auto software_texture = SoftwareTexture(pixels_correct, rhs.texture_format, rhs.GetDimensions().x, rhs.GetDimensions().y);
this->load(&software_texture, rhs.GetDimensions(), rhs.texture_format, rhs.texture_filtering_mode, rhs.texture_wrapping_mode);
}
void Texture::SetFlags(const TextureFlag &flags) {
this->texture_flags = flags;
}
}