#include "texture.h" #include #include "../lib/glew/GL/glew.h" #include "../lib/glfw/glfw3.h" #include "../lib/stb_image.h" #include "logger.h" Texture::Texture(uint32_t id, const glm::ivec2& size) : id_(id), size_(size) { } Texture::~Texture() { if (id_ != 0) { glDeleteTextures(1, &id_); Logger::info(sstr("Texture ", id_, " destroyed")); } } std::shared_ptr Texture::load(const char* filename) { Logger::info(sstr("Loading texture: ", filename)); // Load image int width, height, channels; stbi_uc* pixels = stbi_load(filename, &width, &height, &channels, STBI_rgb_alpha); if (!pixels) { Logger::error(sstr("Failed to load texture: ", filename, " - ", stbi_failure_reason())); return nullptr; } // Flip image vertically (OpenGL expects bottom row first) const int row_size = width * 4; // 4 channels (RGBA) auto* row_buffer = new stbi_uc[row_size]; for (int y = 0; y < height / 2; ++y) { stbi_uc* row1 = pixels + y * row_size; stbi_uc* row2 = pixels + (height - 1 - y) * row_size; std::copy(row1, row1 + row_size, row_buffer); std::copy(row2, row2 + row_size, row1); std::copy(row_buffer, row_buffer + row_size, row2); } delete[] row_buffer; // Generate OpenGL texture GLuint texture_id; glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); // Upload texture data glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Set trilinear filtering glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Generate mipmaps glGenerateMipmap(GL_TEXTURE_2D); // Free image data stbi_image_free(pixels); Logger::info(sstr("Texture loaded successfully: ", filename, " (", width, "x", height, ", ", channels, " channels)")); return std::shared_ptr( new Texture(texture_id, glm::ivec2(width, height))); } void Texture::bind() const { glBindTexture(GL_TEXTURE_2D, id_); }