diff --git a/src/coders/png.cpp b/src/coders/png.cpp index b3128fc8..08adb5c9 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -1,7 +1,7 @@ #include "png.hpp" #include "../graphics/core/ImageData.hpp" -#include "../graphics/core/Texture.hpp" +#include "../graphics/core/GLTexture.hpp" #include "../files/files.hpp" #include "../debug/Logger.hpp" @@ -159,8 +159,8 @@ std::unique_ptr _png_load(const char* file){ color_type = 6; bit_depth = png_get_bit_depth(png, info); - std::unique_ptr image_data (new png_byte[row_bytes * height]); - std::unique_ptr row_pointers (new png_byte*[height]); + auto image_data = std::make_unique(row_bytes * height); + auto row_pointers = std::make_unique(height); for (int i = 0; i < height; ++i ) { row_pointers[height - 1 - i] = image_data.get() + i * row_bytes; } @@ -180,7 +180,7 @@ std::unique_ptr _png_load(const char* file){ fclose(fp); return nullptr; } - auto image = std::make_unique(format, width, height, (void*)image_data.release()); + auto image = std::make_unique(format, width, height, std::move(image_data)); png_destroy_read_struct(&png, &info, &end_info); fclose(fp); return image; @@ -235,7 +235,6 @@ std::unique_ptr _png_load(const char* file){ FILE *png = nullptr; char *pngbuf = nullptr; spng_ctx *ctx = nullptr; - unsigned char *out = nullptr; png = fopen(file, "rb"); if (png == nullptr){ @@ -297,27 +296,24 @@ std::unique_ptr _png_load(const char* file){ logger.error() << "spng_decoded_image_size(): " << spng_strerror(r); return nullptr; } - out = new unsigned char[out_size]; - r = spng_decode_image(ctx, out, out_size, SPNG_FMT_RGBA8, 0); + auto out = std::make_unique(out_size); + r = spng_decode_image(ctx, out.get(), out_size, SPNG_FMT_RGBA8, 0); if (r != SPNG_SUCCESS){ - delete[] out; delete[] pngbuf; spng_ctx_free(ctx); logger.error() << "spng_decode_image(): " << spng_strerror(r); return nullptr; } - unsigned char* flipped = new unsigned char[out_size]; - + auto flipped = std::make_unique(out_size); for (size_t i = 0; i < ihdr.height; i+=1){ size_t rowsize = ihdr.width*4; for (size_t j = 0; j < rowsize; j++){ flipped[(ihdr.height-i-1)*rowsize+j] = out[i*rowsize+j]; } } - delete[] out; // <- finally delete out // no, delete spng usage - auto image = std::make_unique(ImageFormat::rgba8888, ihdr.width, ihdr.height, (void*)flipped); + auto image = std::make_unique(ImageFormat::rgba8888, ihdr.width, ihdr.height, std::move(flipped)); delete[] pngbuf; spng_ctx_free(ctx); @@ -336,7 +332,7 @@ std::unique_ptr png::load_image(const std::string& filename) { std::unique_ptr png::load_texture(const std::string& filename) { auto image = load_image(filename); - auto texture = Texture::from(image.get()); + auto texture = GLTexture::from(image.get()); texture->setNearestFilter(); return texture; } diff --git a/src/graphics/core/Batch2D.cpp b/src/graphics/core/Batch2D.cpp index 6e80af51..387fa4da 100644 --- a/src/graphics/core/Batch2D.cpp +++ b/src/graphics/core/Batch2D.cpp @@ -17,10 +17,11 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){ mesh = std::make_unique(buffer.get(), 0, attrs); index = 0; - ubyte pixels[] = { + const ubyte pixels[] = { 0xFF, 0xFF, 0xFF, 0xFF }; - blank = std::make_unique(pixels, 1, 1, ImageFormat::rgba8888); + ImageData image(ImageFormat::rgba8888, 1, 1, pixels); + blank = Texture::from(&image); currentTexture = nullptr; } @@ -38,6 +39,7 @@ void Batch2D::setPrimitive(DrawPrimitive primitive) { void Batch2D::begin(){ currentTexture = nullptr; blank->bind(); + region = blank->getUVRegion(); color = glm::vec4(1.0f); primitive = DrawPrimitive::triangle; } @@ -49,8 +51,8 @@ void Batch2D::vertex( ) { buffer[index++] = x; buffer[index++] = y; - buffer[index++] = u; - buffer[index++] = v; + buffer[index++] = u * region.getWidth() + region.u1; + buffer[index++] = v * region.getHeight() + region.v1; buffer[index++] = r; buffer[index++] = g; buffer[index++] = b; @@ -63,8 +65,8 @@ void Batch2D::vertex( ) { buffer[index++] = point.x; buffer[index++] = point.y; - buffer[index++] = uvpoint.x; - buffer[index++] = uvpoint.y; + buffer[index++] = uvpoint.x * region.getWidth() + region.u1; + buffer[index++] = uvpoint.y * region.getHeight() + region.v1; buffer[index++] = r; buffer[index++] = g; buffer[index++] = b; @@ -79,8 +81,10 @@ void Batch2D::texture(Texture* new_texture){ currentTexture = new_texture; if (new_texture == nullptr) { blank->bind(); + region = blank->getUVRegion(); } else { new_texture->bind(); + region = currentTexture->getUVRegion(); } } @@ -88,6 +92,10 @@ void Batch2D::untexture() { texture(nullptr); } +void Batch2D::setRegion(UVRegion region) { + this->region = region; +} + void Batch2D::point(float x, float y, float r, float g, float b, float a){ if (index + 6*B2D_VERTEX_SIZE >= capacity) flush(); diff --git a/src/graphics/core/Batch2D.hpp b/src/graphics/core/Batch2D.hpp index 18095cff..a1a1b308 100644 --- a/src/graphics/core/Batch2D.hpp +++ b/src/graphics/core/Batch2D.hpp @@ -6,10 +6,10 @@ #include #include "commons.hpp" +#include "../../maths/UVRegion.hpp" class Mesh; class Texture; -struct UVRegion; class Batch2D { std::unique_ptr buffer; @@ -20,6 +20,7 @@ class Batch2D { glm::vec4 color; Texture* currentTexture; DrawPrimitive primitive = DrawPrimitive::triangle; + UVRegion region {0.0f, 0.0f, 1.0f, 1.0f}; void setPrimitive(DrawPrimitive primitive); @@ -42,6 +43,7 @@ public: void begin(); void texture(Texture* texture); void untexture(); + void setRegion(UVRegion region); void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint); void sprite(float x, float y, float w, float h, int atlasRes, int index, glm::vec4 tint); void point(float x, float y, float r, float g, float b, float a); diff --git a/src/graphics/core/Batch3D.cpp b/src/graphics/core/Batch3D.cpp index 68e59c78..c25d6f0b 100644 --- a/src/graphics/core/Batch3D.cpp +++ b/src/graphics/core/Batch3D.cpp @@ -20,10 +20,11 @@ Batch3D::Batch3D(size_t capacity) mesh = std::make_unique(buffer.get(), 0, attrs); index = 0; - ubyte pixels[] = { + const ubyte pixels[] = { 255, 255, 255, 255, }; - blank = std::make_unique(pixels, 1, 1, ImageFormat::rgba8888); + ImageData image(ImageFormat::rgba8888, 1, 1, pixels); + blank = Texture::from(&image); currentTexture = nullptr; } diff --git a/src/graphics/core/Cubemap.cpp b/src/graphics/core/Cubemap.cpp index 4477c9c0..5da69e3e 100644 --- a/src/graphics/core/Cubemap.cpp +++ b/src/graphics/core/Cubemap.cpp @@ -4,7 +4,7 @@ #include Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) - : Texture(0, width, height) + : GLTexture(0, width, height) { glGenTextures(1, &id); glBindTexture(GL_TEXTURE_CUBE_MAP, id); diff --git a/src/graphics/core/Cubemap.hpp b/src/graphics/core/Cubemap.hpp index 21f6c378..7ff5913c 100644 --- a/src/graphics/core/Cubemap.hpp +++ b/src/graphics/core/Cubemap.hpp @@ -1,10 +1,10 @@ #ifndef GRAPHICS_CORE_CUBEMAP_HPP_ #define GRAPHICS_CORE_CUBEMAP_HPP_ -#include "Texture.hpp" +#include "GLTexture.hpp" /// @brief Cubemap texture -class Cubemap : public Texture { +class Cubemap : public GLTexture { public: Cubemap(uint width, uint height, ImageFormat format); diff --git a/src/graphics/core/Framebuffer.cpp b/src/graphics/core/Framebuffer.cpp index b0a452f4..12f7637c 100644 --- a/src/graphics/core/Framebuffer.cpp +++ b/src/graphics/core/Framebuffer.cpp @@ -1,7 +1,7 @@ #include "Framebuffer.hpp" #include -#include "Texture.hpp" +#include "GLTexture.hpp" Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr texture) : fbo(fbo), depth(depth), texture(std::move(texture)) @@ -25,7 +25,7 @@ static std::unique_ptr create_texture(int width, int height, int format glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); - return std::make_unique(tex, width, height); + return std::make_unique(tex, width, height); } Framebuffer::Framebuffer(uint width, uint height, bool alpha) diff --git a/src/graphics/core/GLTexture.cpp b/src/graphics/core/GLTexture.cpp new file mode 100644 index 00000000..9a47ef22 --- /dev/null +++ b/src/graphics/core/GLTexture.cpp @@ -0,0 +1,75 @@ +#include "GLTexture.hpp" +#include "gl_util.hpp" + +#include +#include +#include + +uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it + +GLTexture::GLTexture(uint id, uint width, uint height) + : Texture(width, height), id(id) { +} + +GLTexture::GLTexture(const ubyte* data, uint width, uint height, ImageFormat imageFormat) + : Texture(width, height) { + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + GLenum format = gl::to_glenum(imageFormat); + glTexImage2D( + GL_TEXTURE_2D, 0, format, width, height, 0, + format, GL_UNSIGNED_BYTE, static_cast(data) + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glGenerateMipmap(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + glBindTexture(GL_TEXTURE_2D, 0); +} + +GLTexture::~GLTexture() { + glDeleteTextures(1, &id); +} + +void GLTexture::bind(){ + glBindTexture(GL_TEXTURE_2D, id); +} + +void GLTexture::unbind() { + glBindTexture(GL_TEXTURE_2D, 0); +} + +void GLTexture::reload(const ubyte* data){ + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, static_cast(data)); + glBindTexture(GL_TEXTURE_2D, 0); +} + +std::unique_ptr GLTexture::readData() { + auto data = std::make_unique(width * height * 4); + glBindTexture(GL_TEXTURE_2D, id); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get()); + glBindTexture(GL_TEXTURE_2D, 0); + return std::make_unique(ImageFormat::rgba8888, width, height, data.release()); +} + +void GLTexture::setNearestFilter() { + bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); +} + +std::unique_ptr GLTexture::from(const ImageData* image) { + uint width = image->getWidth(); + uint height = image->getHeight(); + void* data = image->getData(); + return std::make_unique(static_cast(data), width, height, image->getFormat()); +} + +uint GLTexture::getId() const { + return id; +} diff --git a/src/graphics/core/GLTexture.hpp b/src/graphics/core/GLTexture.hpp new file mode 100644 index 00000000..8274c202 --- /dev/null +++ b/src/graphics/core/GLTexture.hpp @@ -0,0 +1,30 @@ +#ifndef GRAPHICS_CORE_GLTEXTURE_HPP_ +#define GRAPHICS_CORE_GLTEXTURE_HPP_ + +#include "Texture.hpp" + +class GLTexture : public Texture { +protected: + uint id; +public: + GLTexture(uint id, uint width, uint height); + GLTexture(const ubyte* data, uint width, uint height, ImageFormat format); + virtual ~GLTexture(); + + virtual void bind() override; + virtual void unbind() override; + virtual void reload(const ubyte* data); + + void setNearestFilter(); + + virtual std::unique_ptr readData() override; + virtual uint getId() const override; + + virtual UVRegion getUVRegion() const override { + return UVRegion(0.0f, 0.0f, 1.0f, 1.0f); + } + + static std::unique_ptr from(const ImageData* image); +}; + +#endif // GRAPHICS_CORE_GLTEXTURE_HPP_ diff --git a/src/graphics/core/ImageData.cpp b/src/graphics/core/ImageData.cpp index 1052a629..f03a841d 100644 --- a/src/graphics/core/ImageData.cpp +++ b/src/graphics/core/ImageData.cpp @@ -2,6 +2,7 @@ #include #include +#include inline int min(int a, int b) { return (a < b) ? a : b; @@ -13,25 +14,34 @@ inline int max(int a, int b) { ImageData::ImageData(ImageFormat format, uint width, uint height) : format(format), width(width), height(height) { + size_t pixsize; switch (format) { - case ImageFormat::rgb888: data = new ubyte[width*height*3]{}; break; - case ImageFormat::rgba8888: data = new ubyte[width*height*4]{}; break; + case ImageFormat::rgb888: pixsize = 3; break; + case ImageFormat::rgba8888: pixsize = 4; break; default: throw std::runtime_error("format is not supported"); } + data = std::make_unique(width * height * pixsize); } -ImageData::ImageData(ImageFormat format, uint width, uint height, void* data) - : format(format), width(width), height(height), data(data) { +ImageData::ImageData(ImageFormat format, uint width, uint height, std::unique_ptr data) + : format(format), width(width), height(height), data(std::move(data)) { +} + +ImageData::ImageData(ImageFormat format, uint width, uint height, const ubyte* data) + : format(format), width(width), height(height) { + size_t pixsize; + switch (format) { + case ImageFormat::rgb888: pixsize = 3; break; + case ImageFormat::rgba8888: pixsize = 4; break; + default: + throw std::runtime_error("format is not supported"); + } + this->data = std::make_unique(width * height * pixsize); + std::memcpy(this->data.get(), data, width * height * pixsize); } ImageData::~ImageData() { - switch (format) { - case ImageFormat::rgb888: - case ImageFormat::rgba8888: - delete[] (ubyte*)data; - break; - } } void ImageData::flipX() { @@ -39,13 +49,12 @@ void ImageData::flipX() { case ImageFormat::rgb888: case ImageFormat::rgba8888: { uint size = (format == ImageFormat::rgba8888) ? 4 : 3; - ubyte* pixels = (ubyte*)data; for (uint y = 0; y < height; y++) { for (uint x = 0; x < width/2; x++) { for (uint c = 0; c < size; c++) { - ubyte temp = pixels[(y * width + x) * size + c]; - pixels[(y * width + x) * size + c] = pixels[(y * width + (width - x - 1)) * size + c]; - pixels[(y * width + (width - x - 1)) * size + c] = temp; + ubyte temp = data[(y * width + x) * size + c]; + data[(y * width + x) * size + c] = data[(y * width + (width - x - 1)) * size + c]; + data[(y * width + (width - x - 1)) * size + c] = temp; } } } @@ -61,14 +70,13 @@ void ImageData::flipY() { case ImageFormat::rgb888: case ImageFormat::rgba8888: { uint size = (format == ImageFormat::rgba8888) ? 4 : 3; - ubyte* pixels = (ubyte*)data; for (uint y = 0; y < height/2; y++) { for (uint x = 0; x < width; x++) { for (uint c = 0; c < size; c++) { - ubyte temp = pixels[(y * width + x) * size + c]; - pixels[(y * width + x) * size + c] = - pixels[((height-y-1) * width + x) * size + c]; - pixels[((height-y-1) * width + x) * size + c] = temp; + ubyte temp = data[(y * width + x) * size + c]; + data[(y * width + x) * size + c] = + data[((height-y-1) * width + x) * size + c]; + data[((height-y-1) * width + x) * size + c] = temp; } } } @@ -93,8 +101,7 @@ void ImageData::blit(const ImageData* image, int x, int y) { } void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) { - ubyte* pixels = static_cast(data); - ubyte* source = static_cast(image->getData()); + ubyte* source = image->getData(); uint srcwidth = image->getWidth(); uint srcheight = image->getHeight(); @@ -105,9 +112,9 @@ void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) { uint dstidx = (dsty * width + dstx) * 4; uint srcidx = (srcy * srcwidth + srcx) * 3; for (uint c = 0; c < 3; c++) { - pixels[dstidx + c] = source[srcidx + c]; + data[dstidx + c] = source[srcidx + c]; } - pixels[dstidx + 3] = 255; + data[dstidx + 3] = 255; } } } @@ -120,8 +127,7 @@ void ImageData::blitMatchingFormat(const ImageData* image, int x, int y) { default: throw std::runtime_error("only unsigned byte formats supported"); } - ubyte* pixels = static_cast(data); - ubyte* source = static_cast(image->getData()); + ubyte* source = image->getData(); uint srcwidth = image->getWidth(); uint srcheight = image->getHeight(); @@ -132,7 +138,7 @@ void ImageData::blitMatchingFormat(const ImageData* image, int x, int y) { uint dstidx = (dsty * width + dstx) * comps; uint srcidx = (srcy * srcwidth + srcx) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = source[srcidx + c]; + data[dstidx + c] = source[srcidx + c]; } } } @@ -148,17 +154,14 @@ void ImageData::extrude(int x, int y, int w, int h) { default: throw std::runtime_error("only unsigned byte formats supported"); } - ubyte* pixels = static_cast(data); - int rx = x + w - 1; int ry = y + h - 1; - // top-left pixel if (x > 0 && (uint)x < width && y > 0 && (uint)y < height) { uint srcidx = (y * width + x) * comps; uint dstidx = ((y - 1) * width + x - 1) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } @@ -167,7 +170,7 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (y * width + rx) * comps; uint dstidx = ((y - 1) * width + rx + 1) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } @@ -176,7 +179,7 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (ry * width + x) * comps; uint dstidx = ((ry + 1) * width + x - 1) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } @@ -185,7 +188,7 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (ry * width + rx) * comps; uint dstidx = ((ry + 1) * width + rx + 1) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } @@ -195,7 +198,7 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (ey * width + x) * comps; uint dstidx = (ey * width + x - 1) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } } @@ -206,7 +209,7 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (y * width + ex) * comps; uint dstidx = ((y-1) * width + ex) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } } @@ -217,7 +220,7 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (ey * width + rx) * comps; uint dstidx = (ey * width + rx + 1) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } } @@ -228,25 +231,23 @@ void ImageData::extrude(int x, int y, int w, int h) { uint srcidx = (ry * width + ex) * comps; uint dstidx = ((ry+1) * width + ex) * comps; for (uint c = 0; c < comps; c++) { - pixels[dstidx + c] = pixels[srcidx + c]; + data[dstidx + c] = data[srcidx + c]; } } } } void ImageData::fixAlphaColor() { - ubyte* pixels = static_cast(data); - // Fixing black transparent pixels for Mip-Mapping for (uint ly = 0; ly < height-1; ly++) { for (uint lx = 0; lx < width-1; lx++) { - if (pixels[((ly) * width + lx) * 4 + 3]) { + if (data[((ly) * width + lx) * 4 + 3]) { for (int c = 0; c < 3; c++) { - int val = pixels[((ly) + + lx) * 4 + c]; - if (pixels[((ly) * width + lx + 1) * 4 + 3] == 0) - pixels[((ly) * width + lx + 1) * 4 + c] = val; - if (pixels[((ly + 1) * width + lx) * 4 + 3] == 0) - pixels[((ly + 1) * width + lx) * 4 + c] = val; + int val = data[((ly) + + lx) * 4 + c]; + if (data[((ly) * width + lx + 1) * 4 + 3] == 0) + data[((ly) * width + lx + 1) * 4 + c] = val; + if (data[((ly + 1) * width + lx) * 4 + 3] == 0) + data[((ly + 1) * width + lx) * 4 + c] = val; } } } @@ -264,7 +265,7 @@ ImageData* add_atlas_margins(ImageData* image, int grid_size) { int dstheight = srcheight + grid_size * 2; const ubyte* srcdata = (const ubyte*)image->getData(); - ubyte* dstdata = new ubyte[dstwidth*dstheight * 4]; + auto dstdata = std::make_unique(dstwidth*dstheight * 4); int imgres = image->getWidth() / grid_size; for (int row = 0; row < grid_size; row++) { @@ -299,5 +300,5 @@ ImageData* add_atlas_margins(ImageData* image, int grid_size) { } } } - return new ImageData(image->getFormat(), dstwidth, dstheight, dstdata); + return new ImageData(image->getFormat(), dstwidth, dstheight, std::move(dstdata)); } diff --git a/src/graphics/core/ImageData.hpp b/src/graphics/core/ImageData.hpp index 206f136f..0647730c 100644 --- a/src/graphics/core/ImageData.hpp +++ b/src/graphics/core/ImageData.hpp @@ -3,6 +3,8 @@ #include "../../typedefs.hpp" +#include + enum class ImageFormat { rgb888, rgba8888 @@ -12,10 +14,11 @@ class ImageData { ImageFormat format; uint width; uint height; - void* data; + std::unique_ptr data; public: ImageData(ImageFormat format, uint width, uint height); - ImageData(ImageFormat format, uint width, uint height, void* data); + ImageData(ImageFormat format, uint width, uint height, std::unique_ptr data); + ImageData(ImageFormat format, uint width, uint height, const ubyte* data); ~ImageData(); void flipX(); @@ -27,8 +30,8 @@ public: void extrude(int x, int y, int w, int h); void fixAlphaColor(); - void* getData() const { - return data; + ubyte* getData() const { + return data.get(); } ImageFormat getFormat() const { diff --git a/src/graphics/core/Texture.cpp b/src/graphics/core/Texture.cpp index f2c7348f..2484383e 100644 --- a/src/graphics/core/Texture.cpp +++ b/src/graphics/core/Texture.cpp @@ -1,83 +1,6 @@ #include "Texture.hpp" -#include "gl_util.hpp" - -#include -#include -#include - -uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it - -Texture::Texture(uint id, uint width, uint height) - : id(id), width(width), height(height) { -} - -Texture::Texture(ubyte* data, uint width, uint height, ImageFormat imageFormat) - : width(width), height(height) { - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - GLenum format = gl::to_glenum(imageFormat); - glTexImage2D( - GL_TEXTURE_2D, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, (GLvoid *) data - ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); - glBindTexture(GL_TEXTURE_2D, 0); -} - -Texture::~Texture() { - glDeleteTextures(1, &id); -} - -void Texture::bind(){ - glBindTexture(GL_TEXTURE_2D, id); -} - -void Texture::unbind() { - glBindTexture(GL_TEXTURE_2D, 0); -} - -void Texture::reload(ubyte* data){ - glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data); - glBindTexture(GL_TEXTURE_2D, 0); -} - -std::unique_ptr Texture::readData() { - std::unique_ptr data (new ubyte[width * height * 4]); - glBindTexture(GL_TEXTURE_2D, id); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get()); - glBindTexture(GL_TEXTURE_2D, 0); - return std::make_unique(ImageFormat::rgba8888, width, height, data.release()); -} - -void Texture::setNearestFilter() { - bind(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); -} +#include "GLTexture.hpp" std::unique_ptr Texture::from(const ImageData* image) { - uint width = image->getWidth(); - uint height = image->getHeight(); - const void* data = image->getData(); - return std::make_unique((ubyte*)data, width, height, image->getFormat()); -} - -uint Texture::getWidth() const { - return width; -} - -uint Texture::getHeight() const { - return height; -} - -uint Texture::getId() const { - return id; + return GLTexture::from(image); } diff --git a/src/graphics/core/Texture.hpp b/src/graphics/core/Texture.hpp index c95bab27..62cbae43 100644 --- a/src/graphics/core/Texture.hpp +++ b/src/graphics/core/Texture.hpp @@ -2,34 +2,36 @@ #define GRAPHICS_CORE_TEXTURE_HPP_ #include "../../typedefs.hpp" +#include "../../maths/UVRegion.hpp" #include "ImageData.hpp" #include class Texture { protected: - uint id; uint width; uint height; + + Texture(uint width, uint height) : width(width), height(height) {} public: static uint MAX_RESOLUTION; - Texture(uint id, uint width, uint height); - Texture(ubyte* data, uint width, uint height, ImageFormat format); - virtual ~Texture(); + virtual ~Texture() {} - virtual void bind(); - virtual void unbind(); - virtual void reload(ubyte* data); + virtual void bind() = 0; + virtual void unbind() = 0; - void setNearestFilter(); + virtual std::unique_ptr readData() = 0; - virtual std::unique_ptr readData(); + virtual uint getWidth() const { + return width; + } + virtual uint getHeight() const { + return height; + } + virtual UVRegion getUVRegion() const = 0; - virtual uint getWidth() const; - virtual uint getHeight() const; - - virtual uint getId() const; + virtual uint getId() const = 0; static std::unique_ptr from(const ImageData* image); }; diff --git a/src/graphics/core/TextureAnimation.cpp b/src/graphics/core/TextureAnimation.cpp index f3d0c2a2..59175ba3 100644 --- a/src/graphics/core/TextureAnimation.cpp +++ b/src/graphics/core/TextureAnimation.cpp @@ -1,5 +1,5 @@ #include "TextureAnimation.hpp" -#include "Texture.hpp" +#include "GLTexture.hpp" #include "Framebuffer.hpp" #include diff --git a/src/graphics/render/ModelBatch.cpp b/src/graphics/render/ModelBatch.cpp index 2d7c1e9d..00eb95a5 100644 --- a/src/graphics/render/ModelBatch.cpp +++ b/src/graphics/render/ModelBatch.cpp @@ -43,10 +43,11 @@ ModelBatch::ModelBatch(size_t capacity, Assets* assets, Chunks* chunks) assets(assets), chunks(chunks) { - ubyte pixels[] = { + const ubyte pixels[] = { 255, 255, 255, 255, }; - blank = std::make_unique(pixels, 1, 1, ImageFormat::rgba8888); + ImageData image(ImageFormat::rgba8888, 1, 1, pixels); + blank = Texture::from(&image); } ModelBatch::~ModelBatch() { diff --git a/src/graphics/ui/elements/Image.cpp b/src/graphics/ui/elements/Image.cpp index e3b7243e..11c61470 100644 --- a/src/graphics/ui/elements/Image.cpp +++ b/src/graphics/ui/elements/Image.cpp @@ -5,6 +5,7 @@ #include "../../core/DrawContext.hpp" #include "../../core/Batch2D.hpp" #include "../../core/Texture.hpp" +#include "../../core/Atlas.hpp" #include "../../../assets/Assets.hpp" #include "../../../maths/UVRegion.hpp" @@ -18,11 +19,28 @@ void Image::draw(const DrawContext* pctx, Assets* assets) { glm::vec2 pos = calcPos(); auto batch = pctx->getBatch2D(); - auto texture = assets->get(this->texture); - if (texture && autoresize) { - setSize(glm::vec2(texture->getWidth(), texture->getHeight())); + Texture* texture = nullptr; + auto separator = this->texture.find(':'); + if (separator == std::string::npos) { + texture = assets->get(this->texture); + batch->texture(texture); + if (texture && autoresize) { + setSize(glm::vec2(texture->getWidth(), texture->getHeight())); + } + } else { + auto atlasName = this->texture.substr(0, separator); + if (auto atlas = assets->get(atlasName)) { + texture = atlas->getTexture(); + batch->texture(atlas->getTexture()); + auto& region = atlas->get(this->texture.substr(separator+1)); + batch->setRegion(region); + if (autoresize) { + setSize(glm::vec2( + texture->getWidth()*region.getWidth(), + texture->getHeight()*region.getHeight())); + } + } } - batch->texture(texture); batch->rect( pos.x, pos.y, size.x, size.y, 0, 0, 0, UVRegion(), false, true, calcColor() diff --git a/src/maths/UVRegion.hpp b/src/maths/UVRegion.hpp index fd3bb31b..85833ba4 100644 --- a/src/maths/UVRegion.hpp +++ b/src/maths/UVRegion.hpp @@ -1,6 +1,8 @@ #ifndef MATHS_UVREGION_HPP_ #define MATHS_UVREGION_HPP_ +#include + struct UVRegion { float u1; float v1; @@ -11,6 +13,14 @@ struct UVRegion { : u1(u1), v1(v1), u2(u2), v2(v2){} UVRegion() : u1(0.0f), v1(0.0f), u2(1.0f), v2(1.0f){} + + inline float getWidth() const { + return fabs(u2-u1); + } + + inline float getHeight() const { + return fabs(v2-v1); + } }; #endif // MATHS_UVREGION_HPP_