Add the ability to use mipmaps with RenderTargets.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 50s

This commit is contained in:
2025-02-11 18:48:15 -05:00
parent 4ac28a2c10
commit 7498390180
7 changed files with 72 additions and 38 deletions

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});
@@ -114,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,26 +4,10 @@
#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;
}
@@ -71,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_8X);
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

@@ -51,8 +51,15 @@ void J2D::Begin(RenderTarget* render_target, bool clear_buffers) {
}
void J2D::End() {
if (current_state.current_render_target)
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();

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);
@@ -262,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) {
@@ -364,3 +351,18 @@ JGL::RenderTarget::RenderTarget(const JGL::RenderTarget& rhs) {
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,7 @@ 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;
@@ -109,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);
@@ -116,7 +137,6 @@ 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.");