Merge branch 'main' into entities

This commit is contained in:
MihailRis 2024-06-30 22:16:14 +03:00
commit 316233816f
17 changed files with 247 additions and 177 deletions

View File

@ -1,7 +1,7 @@
#include "png.hpp" #include "png.hpp"
#include "../graphics/core/ImageData.hpp" #include "../graphics/core/ImageData.hpp"
#include "../graphics/core/Texture.hpp" #include "../graphics/core/GLTexture.hpp"
#include "../files/files.hpp" #include "../files/files.hpp"
#include "../debug/Logger.hpp" #include "../debug/Logger.hpp"
@ -159,8 +159,8 @@ std::unique_ptr<ImageData> _png_load(const char* file){
color_type = 6; color_type = 6;
bit_depth = png_get_bit_depth(png, info); bit_depth = png_get_bit_depth(png, info);
std::unique_ptr<png_byte[]> image_data (new png_byte[row_bytes * height]); auto image_data = std::make_unique<png_byte[]>(row_bytes * height);
std::unique_ptr<png_byte*[]> row_pointers (new png_byte*[height]); auto row_pointers = std::make_unique<png_byte*[]>(height);
for (int i = 0; i < height; ++i ) { for (int i = 0; i < height; ++i ) {
row_pointers[height - 1 - i] = image_data.get() + i * row_bytes; row_pointers[height - 1 - i] = image_data.get() + i * row_bytes;
} }
@ -180,7 +180,7 @@ std::unique_ptr<ImageData> _png_load(const char* file){
fclose(fp); fclose(fp);
return nullptr; return nullptr;
} }
auto image = std::make_unique<ImageData>(format, width, height, (void*)image_data.release()); auto image = std::make_unique<ImageData>(format, width, height, std::move(image_data));
png_destroy_read_struct(&png, &info, &end_info); png_destroy_read_struct(&png, &info, &end_info);
fclose(fp); fclose(fp);
return image; return image;
@ -235,7 +235,6 @@ std::unique_ptr<ImageData> _png_load(const char* file){
FILE *png = nullptr; FILE *png = nullptr;
char *pngbuf = nullptr; char *pngbuf = nullptr;
spng_ctx *ctx = nullptr; spng_ctx *ctx = nullptr;
unsigned char *out = nullptr;
png = fopen(file, "rb"); png = fopen(file, "rb");
if (png == nullptr){ if (png == nullptr){
@ -297,27 +296,24 @@ std::unique_ptr<ImageData> _png_load(const char* file){
logger.error() << "spng_decoded_image_size(): " << spng_strerror(r); logger.error() << "spng_decoded_image_size(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
out = new unsigned char[out_size]; auto out = std::make_unique<ubyte[]>(out_size);
r = spng_decode_image(ctx, out, out_size, SPNG_FMT_RGBA8, 0); r = spng_decode_image(ctx, out.get(), out_size, SPNG_FMT_RGBA8, 0);
if (r != SPNG_SUCCESS){ if (r != SPNG_SUCCESS){
delete[] out;
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
logger.error() << "spng_decode_image(): " << spng_strerror(r); logger.error() << "spng_decode_image(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
unsigned char* flipped = new unsigned char[out_size]; auto flipped = std::make_unique<ubyte[]>(out_size);
for (size_t i = 0; i < ihdr.height; i+=1){ for (size_t i = 0; i < ihdr.height; i+=1){
size_t rowsize = ihdr.width*4; size_t rowsize = ihdr.width*4;
for (size_t j = 0; j < rowsize; j++){ for (size_t j = 0; j < rowsize; j++){
flipped[(ihdr.height-i-1)*rowsize+j] = out[i*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<ImageData>(ImageFormat::rgba8888, ihdr.width, ihdr.height, (void*)flipped); auto image = std::make_unique<ImageData>(ImageFormat::rgba8888, ihdr.width, ihdr.height, std::move(flipped));
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
@ -336,7 +332,7 @@ std::unique_ptr<ImageData> png::load_image(const std::string& filename) {
std::unique_ptr<Texture> png::load_texture(const std::string& filename) { std::unique_ptr<Texture> png::load_texture(const std::string& filename) {
auto image = load_image(filename); auto image = load_image(filename);
auto texture = Texture::from(image.get()); auto texture = GLTexture::from(image.get());
texture->setNearestFilter(); texture->setNearestFilter();
return texture; return texture;
} }

View File

@ -17,10 +17,11 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs); mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
index = 0; index = 0;
ubyte pixels[] = { const ubyte pixels[] = {
0xFF, 0xFF, 0xFF, 0xFF 0xFF, 0xFF, 0xFF, 0xFF
}; };
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888); ImageData image(ImageFormat::rgba8888, 1, 1, pixels);
blank = Texture::from(&image);
currentTexture = nullptr; currentTexture = nullptr;
} }
@ -38,6 +39,7 @@ void Batch2D::setPrimitive(DrawPrimitive primitive) {
void Batch2D::begin(){ void Batch2D::begin(){
currentTexture = nullptr; currentTexture = nullptr;
blank->bind(); blank->bind();
region = blank->getUVRegion();
color = glm::vec4(1.0f); color = glm::vec4(1.0f);
primitive = DrawPrimitive::triangle; primitive = DrawPrimitive::triangle;
} }
@ -49,8 +51,8 @@ void Batch2D::vertex(
) { ) {
buffer[index++] = x; buffer[index++] = x;
buffer[index++] = y; buffer[index++] = y;
buffer[index++] = u; buffer[index++] = u * region.getWidth() + region.u1;
buffer[index++] = v; buffer[index++] = v * region.getHeight() + region.v1;
buffer[index++] = r; buffer[index++] = r;
buffer[index++] = g; buffer[index++] = g;
buffer[index++] = b; buffer[index++] = b;
@ -63,8 +65,8 @@ void Batch2D::vertex(
) { ) {
buffer[index++] = point.x; buffer[index++] = point.x;
buffer[index++] = point.y; buffer[index++] = point.y;
buffer[index++] = uvpoint.x; buffer[index++] = uvpoint.x * region.getWidth() + region.u1;
buffer[index++] = uvpoint.y; buffer[index++] = uvpoint.y * region.getHeight() + region.v1;
buffer[index++] = r; buffer[index++] = r;
buffer[index++] = g; buffer[index++] = g;
buffer[index++] = b; buffer[index++] = b;
@ -79,8 +81,10 @@ void Batch2D::texture(Texture* new_texture){
currentTexture = new_texture; currentTexture = new_texture;
if (new_texture == nullptr) { if (new_texture == nullptr) {
blank->bind(); blank->bind();
region = blank->getUVRegion();
} else { } else {
new_texture->bind(); new_texture->bind();
region = currentTexture->getUVRegion();
} }
} }
@ -88,6 +92,10 @@ void Batch2D::untexture() {
texture(nullptr); 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){ void Batch2D::point(float x, float y, float r, float g, float b, float a){
if (index + 6*B2D_VERTEX_SIZE >= capacity) if (index + 6*B2D_VERTEX_SIZE >= capacity)
flush(); flush();

View File

@ -6,10 +6,10 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "commons.hpp" #include "commons.hpp"
#include "../../maths/UVRegion.hpp"
class Mesh; class Mesh;
class Texture; class Texture;
struct UVRegion;
class Batch2D { class Batch2D {
std::unique_ptr<float[]> buffer; std::unique_ptr<float[]> buffer;
@ -20,6 +20,7 @@ class Batch2D {
glm::vec4 color; glm::vec4 color;
Texture* currentTexture; Texture* currentTexture;
DrawPrimitive primitive = DrawPrimitive::triangle; DrawPrimitive primitive = DrawPrimitive::triangle;
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
void setPrimitive(DrawPrimitive primitive); void setPrimitive(DrawPrimitive primitive);
@ -42,6 +43,7 @@ public:
void begin(); void begin();
void texture(Texture* texture); void texture(Texture* texture);
void untexture(); 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, const UVRegion& region, glm::vec4 tint);
void sprite(float x, float y, float w, float h, int atlasRes, int index, 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); void point(float x, float y, float r, float g, float b, float a);

View File

@ -20,10 +20,11 @@ Batch3D::Batch3D(size_t capacity)
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs); mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
index = 0; index = 0;
ubyte pixels[] = { const ubyte pixels[] = {
255, 255, 255, 255, 255, 255, 255, 255,
}; };
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888); ImageData image(ImageFormat::rgba8888, 1, 1, pixels);
blank = Texture::from(&image);
currentTexture = nullptr; currentTexture = nullptr;
} }

View File

@ -4,7 +4,7 @@
#include <GL/glew.h> #include <GL/glew.h>
Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
: Texture(0, width, height) : GLTexture(0, width, height)
{ {
glGenTextures(1, &id); glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id); glBindTexture(GL_TEXTURE_CUBE_MAP, id);

View File

@ -1,10 +1,10 @@
#ifndef GRAPHICS_CORE_CUBEMAP_HPP_ #ifndef GRAPHICS_CORE_CUBEMAP_HPP_
#define GRAPHICS_CORE_CUBEMAP_HPP_ #define GRAPHICS_CORE_CUBEMAP_HPP_
#include "Texture.hpp" #include "GLTexture.hpp"
/// @brief Cubemap texture /// @brief Cubemap texture
class Cubemap : public Texture { class Cubemap : public GLTexture {
public: public:
Cubemap(uint width, uint height, ImageFormat format); Cubemap(uint width, uint height, ImageFormat format);

View File

@ -1,7 +1,7 @@
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include "Texture.hpp" #include "GLTexture.hpp"
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture) Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
: fbo(fbo), depth(depth), texture(std::move(texture)) : fbo(fbo), depth(depth), texture(std::move(texture))
@ -25,7 +25,7 @@ static std::unique_ptr<Texture> 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_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
return std::make_unique<Texture>(tex, width, height); return std::make_unique<GLTexture>(tex, width, height);
} }
Framebuffer::Framebuffer(uint width, uint height, bool alpha) Framebuffer::Framebuffer(uint width, uint height, bool alpha)

View File

@ -0,0 +1,75 @@
#include "GLTexture.hpp"
#include "gl_util.hpp"
#include <GL/glew.h>
#include <stdexcept>
#include <memory>
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<const 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);
}
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<const GLvoid*>(data));
glBindTexture(GL_TEXTURE_2D, 0);
}
std::unique_ptr<ImageData> GLTexture::readData() {
auto data = std::make_unique<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<ImageData>(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> GLTexture::from(const ImageData* image) {
uint width = image->getWidth();
uint height = image->getHeight();
void* data = image->getData();
return std::make_unique<GLTexture>(static_cast<ubyte*>(data), width, height, image->getFormat());
}
uint GLTexture::getId() const {
return id;
}

View File

@ -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<ImageData> 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<GLTexture> from(const ImageData* image);
};
#endif // GRAPHICS_CORE_GLTEXTURE_HPP_

View File

@ -2,6 +2,7 @@
#include <assert.h> #include <assert.h>
#include <stdexcept> #include <stdexcept>
#include <cstring>
inline int min(int a, int b) { inline int min(int a, int b) {
return (a < b) ? a : 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) ImageData::ImageData(ImageFormat format, uint width, uint height)
: format(format), width(width), height(height) { : format(format), width(width), height(height) {
size_t pixsize;
switch (format) { switch (format) {
case ImageFormat::rgb888: data = new ubyte[width*height*3]{}; break; case ImageFormat::rgb888: pixsize = 3; break;
case ImageFormat::rgba8888: data = new ubyte[width*height*4]{}; break; case ImageFormat::rgba8888: pixsize = 4; break;
default: default:
throw std::runtime_error("format is not supported"); throw std::runtime_error("format is not supported");
} }
data = std::make_unique<ubyte[]>(width * height * pixsize);
} }
ImageData::ImageData(ImageFormat format, uint width, uint height, void* data) ImageData::ImageData(ImageFormat format, uint width, uint height, std::unique_ptr<ubyte[]> data)
: format(format), width(width), height(height), data(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<ubyte[]>(width * height * pixsize);
std::memcpy(this->data.get(), data, width * height * pixsize);
} }
ImageData::~ImageData() { ImageData::~ImageData() {
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888:
delete[] (ubyte*)data;
break;
}
} }
void ImageData::flipX() { void ImageData::flipX() {
@ -39,13 +49,12 @@ void ImageData::flipX() {
case ImageFormat::rgb888: case ImageFormat::rgb888:
case ImageFormat::rgba8888: { case ImageFormat::rgba8888: {
uint size = (format == ImageFormat::rgba8888) ? 4 : 3; uint size = (format == ImageFormat::rgba8888) ? 4 : 3;
ubyte* pixels = (ubyte*)data;
for (uint y = 0; y < height; y++) { for (uint y = 0; y < height; y++) {
for (uint x = 0; x < width/2; x++) { for (uint x = 0; x < width/2; x++) {
for (uint c = 0; c < size; c++) { for (uint c = 0; c < size; c++) {
ubyte temp = pixels[(y * width + x) * size + c]; ubyte temp = data[(y * width + x) * size + c];
pixels[(y * width + x) * size + c] = pixels[(y * width + (width - x - 1)) * size + c]; data[(y * width + x) * size + c] = data[(y * width + (width - x - 1)) * size + c];
pixels[(y * width + (width - x - 1)) * size + c] = temp; data[(y * width + (width - x - 1)) * size + c] = temp;
} }
} }
} }
@ -61,14 +70,13 @@ void ImageData::flipY() {
case ImageFormat::rgb888: case ImageFormat::rgb888:
case ImageFormat::rgba8888: { case ImageFormat::rgba8888: {
uint size = (format == ImageFormat::rgba8888) ? 4 : 3; uint size = (format == ImageFormat::rgba8888) ? 4 : 3;
ubyte* pixels = (ubyte*)data;
for (uint y = 0; y < height/2; y++) { for (uint y = 0; y < height/2; y++) {
for (uint x = 0; x < width; x++) { for (uint x = 0; x < width; x++) {
for (uint c = 0; c < size; c++) { for (uint c = 0; c < size; c++) {
ubyte temp = pixels[(y * width + x) * size + c]; ubyte temp = data[(y * width + x) * size + c];
pixels[(y * width + x) * size + c] = data[(y * width + x) * size + c] =
pixels[((height-y-1) * width + x) * size + c]; data[((height-y-1) * width + x) * size + c];
pixels[((height-y-1) * width + x) * size + c] = temp; 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) { void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) {
ubyte* pixels = static_cast<ubyte*>(data); ubyte* source = image->getData();
ubyte* source = static_cast<ubyte*>(image->getData());
uint srcwidth = image->getWidth(); uint srcwidth = image->getWidth();
uint srcheight = image->getHeight(); 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 dstidx = (dsty * width + dstx) * 4;
uint srcidx = (srcy * srcwidth + srcx) * 3; uint srcidx = (srcy * srcwidth + srcx) * 3;
for (uint c = 0; c < 3; c++) { 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: default:
throw std::runtime_error("only unsigned byte formats supported"); throw std::runtime_error("only unsigned byte formats supported");
} }
ubyte* pixels = static_cast<ubyte*>(data); ubyte* source = image->getData();
ubyte* source = static_cast<ubyte*>(image->getData());
uint srcwidth = image->getWidth(); uint srcwidth = image->getWidth();
uint srcheight = image->getHeight(); 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 dstidx = (dsty * width + dstx) * comps;
uint srcidx = (srcy * srcwidth + srcx) * comps; uint srcidx = (srcy * srcwidth + srcx) * comps;
for (uint c = 0; c < comps; c++) { 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: default:
throw std::runtime_error("only unsigned byte formats supported"); throw std::runtime_error("only unsigned byte formats supported");
} }
ubyte* pixels = static_cast<ubyte*>(data);
int rx = x + w - 1; int rx = x + w - 1;
int ry = y + h - 1; int ry = y + h - 1;
// top-left pixel // top-left pixel
if (x > 0 && (uint)x < width && y > 0 && (uint)y < height) { if (x > 0 && (uint)x < width && y > 0 && (uint)y < height) {
uint srcidx = (y * width + x) * comps; uint srcidx = (y * width + x) * comps;
uint dstidx = ((y - 1) * width + x - 1) * comps; uint dstidx = ((y - 1) * width + x - 1) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (y * width + rx) * comps;
uint dstidx = ((y - 1) * width + rx + 1) * comps; uint dstidx = ((y - 1) * width + rx + 1) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (ry * width + x) * comps;
uint dstidx = ((ry + 1) * width + x - 1) * comps; uint dstidx = ((ry + 1) * width + x - 1) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (ry * width + rx) * comps;
uint dstidx = ((ry + 1) * width + rx + 1) * comps; uint dstidx = ((ry + 1) * width + rx + 1) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (ey * width + x) * comps;
uint dstidx = (ey * width + x - 1) * comps; uint dstidx = (ey * width + x - 1) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (y * width + ex) * comps;
uint dstidx = ((y-1) * width + ex) * comps; uint dstidx = ((y-1) * width + ex) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (ey * width + rx) * comps;
uint dstidx = (ey * width + rx + 1) * comps; uint dstidx = (ey * width + rx + 1) * comps;
for (uint c = 0; c < comps; c++) { 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 srcidx = (ry * width + ex) * comps;
uint dstidx = ((ry+1) * width + ex) * comps; uint dstidx = ((ry+1) * width + ex) * comps;
for (uint c = 0; c < comps; c++) { for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c]; data[dstidx + c] = data[srcidx + c];
} }
} }
} }
} }
void ImageData::fixAlphaColor() { void ImageData::fixAlphaColor() {
ubyte* pixels = static_cast<ubyte*>(data);
// Fixing black transparent pixels for Mip-Mapping // Fixing black transparent pixels for Mip-Mapping
for (uint ly = 0; ly < height-1; ly++) { for (uint ly = 0; ly < height-1; ly++) {
for (uint lx = 0; lx < width-1; lx++) { 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++) { for (int c = 0; c < 3; c++) {
int val = pixels[((ly) + + lx) * 4 + c]; int val = data[((ly) + + lx) * 4 + c];
if (pixels[((ly) * width + lx + 1) * 4 + 3] == 0) if (data[((ly) * width + lx + 1) * 4 + 3] == 0)
pixels[((ly) * width + lx + 1) * 4 + c] = val; data[((ly) * width + lx + 1) * 4 + c] = val;
if (pixels[((ly + 1) * width + lx) * 4 + 3] == 0) if (data[((ly + 1) * width + lx) * 4 + 3] == 0)
pixels[((ly + 1) * width + lx) * 4 + c] = val; 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; int dstheight = srcheight + grid_size * 2;
const ubyte* srcdata = (const ubyte*)image->getData(); const ubyte* srcdata = (const ubyte*)image->getData();
ubyte* dstdata = new ubyte[dstwidth*dstheight * 4]; auto dstdata = std::make_unique<ubyte[]>(dstwidth*dstheight * 4);
int imgres = image->getWidth() / grid_size; int imgres = image->getWidth() / grid_size;
for (int row = 0; row < grid_size; row++) { 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));
} }

View File

@ -3,6 +3,8 @@
#include "../../typedefs.hpp" #include "../../typedefs.hpp"
#include <memory>
enum class ImageFormat { enum class ImageFormat {
rgb888, rgb888,
rgba8888 rgba8888
@ -12,10 +14,11 @@ class ImageData {
ImageFormat format; ImageFormat format;
uint width; uint width;
uint height; uint height;
void* data; std::unique_ptr<ubyte[]> data;
public: public:
ImageData(ImageFormat format, uint width, uint height); 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<ubyte[]> data);
ImageData(ImageFormat format, uint width, uint height, const ubyte* data);
~ImageData(); ~ImageData();
void flipX(); void flipX();
@ -27,8 +30,8 @@ public:
void extrude(int x, int y, int w, int h); void extrude(int x, int y, int w, int h);
void fixAlphaColor(); void fixAlphaColor();
void* getData() const { ubyte* getData() const {
return data; return data.get();
} }
ImageFormat getFormat() const { ImageFormat getFormat() const {

View File

@ -1,83 +1,6 @@
#include "Texture.hpp" #include "Texture.hpp"
#include "gl_util.hpp" #include "GLTexture.hpp"
#include <GL/glew.h>
#include <stdexcept>
#include <memory>
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<ImageData> Texture::readData() {
std::unique_ptr<ubyte[]> 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<ImageData>(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);
}
std::unique_ptr<Texture> Texture::from(const ImageData* image) { std::unique_ptr<Texture> Texture::from(const ImageData* image) {
uint width = image->getWidth(); return GLTexture::from(image);
uint height = image->getHeight();
const void* data = image->getData();
return std::make_unique<Texture>((ubyte*)data, width, height, image->getFormat());
}
uint Texture::getWidth() const {
return width;
}
uint Texture::getHeight() const {
return height;
}
uint Texture::getId() const {
return id;
} }

View File

@ -2,34 +2,36 @@
#define GRAPHICS_CORE_TEXTURE_HPP_ #define GRAPHICS_CORE_TEXTURE_HPP_
#include "../../typedefs.hpp" #include "../../typedefs.hpp"
#include "../../maths/UVRegion.hpp"
#include "ImageData.hpp" #include "ImageData.hpp"
#include <memory> #include <memory>
class Texture { class Texture {
protected: protected:
uint id;
uint width; uint width;
uint height; uint height;
Texture(uint width, uint height) : width(width), height(height) {}
public: public:
static uint MAX_RESOLUTION; static uint MAX_RESOLUTION;
Texture(uint id, uint width, uint height); virtual ~Texture() {}
Texture(ubyte* data, uint width, uint height, ImageFormat format);
virtual ~Texture();
virtual void bind(); virtual void bind() = 0;
virtual void unbind(); virtual void unbind() = 0;
virtual void reload(ubyte* data);
void setNearestFilter(); virtual std::unique_ptr<ImageData> readData() = 0;
virtual std::unique_ptr<ImageData> readData(); virtual uint getWidth() const {
return width;
}
virtual uint getHeight() const {
return height;
}
virtual UVRegion getUVRegion() const = 0;
virtual uint getWidth() const; virtual uint getId() const = 0;
virtual uint getHeight() const;
virtual uint getId() const;
static std::unique_ptr<Texture> from(const ImageData* image); static std::unique_ptr<Texture> from(const ImageData* image);
}; };

View File

@ -1,5 +1,5 @@
#include "TextureAnimation.hpp" #include "TextureAnimation.hpp"
#include "Texture.hpp" #include "GLTexture.hpp"
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include <GL/glew.h> #include <GL/glew.h>

View File

@ -43,10 +43,11 @@ ModelBatch::ModelBatch(size_t capacity, Assets* assets, Chunks* chunks)
assets(assets), assets(assets),
chunks(chunks) chunks(chunks)
{ {
ubyte pixels[] = { const ubyte pixels[] = {
255, 255, 255, 255, 255, 255, 255, 255,
}; };
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888); ImageData image(ImageFormat::rgba8888, 1, 1, pixels);
blank = Texture::from(&image);
} }
ModelBatch::~ModelBatch() { ModelBatch::~ModelBatch() {

View File

@ -5,6 +5,7 @@
#include "../../core/DrawContext.hpp" #include "../../core/DrawContext.hpp"
#include "../../core/Batch2D.hpp" #include "../../core/Batch2D.hpp"
#include "../../core/Texture.hpp" #include "../../core/Texture.hpp"
#include "../../core/Atlas.hpp"
#include "../../../assets/Assets.hpp" #include "../../../assets/Assets.hpp"
#include "../../../maths/UVRegion.hpp" #include "../../../maths/UVRegion.hpp"
@ -18,11 +19,28 @@ void Image::draw(const DrawContext* pctx, Assets* assets) {
glm::vec2 pos = calcPos(); glm::vec2 pos = calcPos();
auto batch = pctx->getBatch2D(); auto batch = pctx->getBatch2D();
auto texture = assets->get<Texture>(this->texture); Texture* texture = nullptr;
auto separator = this->texture.find(':');
if (separator == std::string::npos) {
texture = assets->get<Texture>(this->texture);
batch->texture(texture);
if (texture && autoresize) { if (texture && autoresize) {
setSize(glm::vec2(texture->getWidth(), texture->getHeight())); setSize(glm::vec2(texture->getWidth(), texture->getHeight()));
} }
batch->texture(texture); } else {
auto atlasName = this->texture.substr(0, separator);
if (auto atlas = assets->get<Atlas>(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->rect( batch->rect(
pos.x, pos.y, size.x, size.y, pos.x, pos.y, size.x, size.y,
0, 0, 0, UVRegion(), false, true, calcColor() 0, 0, 0, UVRegion(), false, true, calcColor()

View File

@ -1,6 +1,8 @@
#ifndef MATHS_UVREGION_HPP_ #ifndef MATHS_UVREGION_HPP_
#define MATHS_UVREGION_HPP_ #define MATHS_UVREGION_HPP_
#include <cmath>
struct UVRegion { struct UVRegion {
float u1; float u1;
float v1; float v1;
@ -11,6 +13,14 @@ struct UVRegion {
: u1(u1), v1(v1), u2(u2), v2(v2){} : u1(u1), v1(v1), u2(u2), v2(v2){}
UVRegion() : u1(0.0f), v1(0.0f), u2(1.0f), v2(1.0f){} 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_ #endif // MATHS_UVREGION_HPP_