Texture Atlas constructors.

This commit is contained in:
2025-02-18 13:52:43 -05:00
parent ae84a68e11
commit 03a687179c
6 changed files with 102 additions and 25 deletions

View File

@@ -53,13 +53,11 @@ public:
/// Load a texture from raw pixels.
Texture(const Color3* pixels, const Vector2i& size, FilteringMode filtering_mode = FilteringMode::BILINEAR,
SampleRate anisotropy = SampleRate::NONE, WrappingMode wrapping_mode = WrappingMode::CLAMP_TO_EDGE);
/// Construct a Texture Atlas from many different textures.
/// @note THIS IS UNFINISHED.
Texture(const Texture* textures, const size_t& texture_count);
/// Initialize a texture filled with trash data.
/// @see RenderTarget
explicit Texture(const Vector2i& size, FilteringMode filtering_mode = FilteringMode::NEAREST);
Texture(const Texture& rhs);
Texture() = default;
~Texture();
public:
/// @returns True if this system supports anisotropy.

View File

@@ -0,0 +1,36 @@
#pragma once
#include <JGL/types/Texture.h>
// A texture which actually contains multiple such that you can pass it in to draw sprite or draw partial sprite.
// It also makes for more efficient sprite batch because you don't have to swap textures between.
namespace JGL {
struct AtlasRegion {
Vector2i position = { 0, 0 };
Vector2i size = { 0, 0 };
};
class TextureAtlas;
}
class JGL::TextureAtlas : public Texture {
protected:
std::vector<AtlasRegion> regions;
public:
unsigned int RegionCount() { return regions.size(); }
[[nodiscard]] AtlasRegion GetRegion(unsigned int region) const;
public:
/// Create a texture atlas from multiple separate images.
/// @param pixels The array(s) of pixels.
/// @param sizes The size of each image.
/// @param texture_count The number of textures this atlas will contain.
TextureAtlas(const Color4** pixels, const Vector2i** sizes, unsigned int texture_count, FilteringMode filtering_mode = FilteringMode::NEAREST);
/// Create a texture atlas from a single image
/// @param pixels The array of pixels.
/// @param size The size of the image.
/// @param regions The individual regions that will make up your atlas.
/// @param region_count The number of regions there are.
TextureAtlas(const Color4* pixels, const Vector2i& size, AtlasRegion** regions, unsigned int region_count, FilteringMode filtering_mode = FilteringMode::NEAREST);
};

View File

@@ -61,7 +61,7 @@ namespace JGL {
}
namespace JGL::J2D {
inline State default_state
inline constexpr State default_state
{
{0, 0, 0, 1},
{1, 1, 1, 1},

View File

@@ -288,7 +288,7 @@ void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget*
void JGL::RenderTarget::Blit(const Texture* source, RenderTarget* destination, const Vector2i& position) {
auto temp = new RenderTarget(source);
Blit(*temp, destination);
Blit(*temp, destination, position);
delete temp;
}

View File

@@ -293,26 +293,6 @@ Texture::Texture(const Texture& rhs) {
operator delete(this_texture);
}
Texture::Texture(const Texture* textures, const size_t& texture_count) {
int length = 0;
int biggest_y = 0;
for (int i = 0; i < texture_count; i++) {
if (biggest_y < textures[i].size.y)
biggest_y = textures[i].size.y;
length += textures[i].size.x;
}
auto* result = new Texture(Vector2i(length, biggest_y));
auto render_target = RenderTarget(result);
int next_x = 0;
for (int i = 0; i < texture_count; i++) {
RenderTarget::Blit(&textures[i], &render_target, Vector2i(next_x, 0));
next_x += textures[i].GetDimensions().x;
}
}
bool Texture::SizeExceedsMaximum(const Vector2i& s) {
auto max_size = Texture::MaxSize();

View File

@@ -0,0 +1,63 @@
#include <JGL/types/TextureAtlas.h>
#include <JGL/types/RenderTarget.h>
#include <JGL/logger/logger.h>
using namespace JGL;
AtlasRegion TextureAtlas::GetRegion(unsigned int region) const {
if (region >= regions.size()) {
Logger::Error("Requesting region " + std::to_string(region) + "but it's outside of the texture atlas?");
return { {0, 0},{0, 0} };
}
return regions[region];
}
TextureAtlas::TextureAtlas(const Color4** pixels, const Vector2i** sizes, unsigned int texture_count, FilteringMode filtering_mode) {
std::vector<Texture> textures(texture_count);
int x_length = 0; int largest_height = 0;
for (unsigned int i = 0; i < texture_count; i++) {
textures[i] = Texture(pixels[i], *sizes[i], FilteringMode::NEAREST);
x_length += sizes[i]->x;
if (sizes[i]->y > largest_height)
largest_height = sizes[i]->y;
}
int rows = 1;
while (x_length > Texture::MaxSize().x)
x_length /= 2, rows += 1;
auto* result = new Texture(Vector2i(x_length, largest_height * rows), filtering_mode);
auto* render_target = new RenderTarget(result);
int current_x = 0; int current_y = 0;
for (unsigned int i = 0; i < texture_count; i++) {
if (current_x + sizes[i]->x > x_length)
current_x = 0, current_y += largest_height;
RenderTarget::Blit(&textures[i], render_target, Vector2i(current_x, current_y));
regions.emplace_back(AtlasRegion({ current_x, current_y }, { sizes[i]->x, sizes[i]->y }));
current_x += sizes[i]->x;
}
render_target->RegenerateMipMaps();
delete render_target;
this->texture_handle = result->GetHandle();
this->size = result->GetDimensions();
this->invert_y = result->Inverted();
this->filtering_mode = result->GetFilteringMode();
this->wrapping_mode = result->GetWrappingMode();
this->anisotropy = result->GetAnisotropySampleRate();
this->format = result->GetFormat();
// Don't call destructor so the v-ram isn't cleared.
operator delete(result);
}
TextureAtlas::TextureAtlas(const Color4* pixels, const Vector2i& size, AtlasRegion** regions, unsigned int region_count, FilteringMode filtering_mode) : Texture(pixels, size, filtering_mode) {
this->regions.resize(region_count);
for (unsigned int i = 0; i < region_count; ++i)
this->regions[i] = *regions[i];
}