#include "texture.h" #include #include // for exit #include // for basic_ostream, operator<<, cout, endl #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" // for stbi_failure_reason, stbi_image_free SDL_ScaleMode Texture::currentScaleMode = SDL_SCALEMODE_NEAREST; void Texture::setGlobalScaleMode(SDL_ScaleMode mode) { currentScaleMode = mode; } // Constructor Texture::Texture(SDL_Renderer *renderer, std::string path, bool verbose) { // Copia punteros this->renderer = renderer; this->path = path; // Inicializa texture = nullptr; width = 0; height = 0; // Carga el fichero en la textura if (path != "") { loadFromFile(path, renderer, verbose); } } // Constructor desde bytes Texture::Texture(SDL_Renderer *renderer, const std::vector &bytes, bool verbose) { this->renderer = renderer; this->path = ""; texture = nullptr; width = 0; height = 0; if (!bytes.empty()) { loadFromMemory(bytes.data(), bytes.size(), renderer, verbose); } } // Destructor Texture::~Texture() { // Libera memoria unload(); } // Helper: convierte píxeles RGBA decodificados por stbi en SDL_Texture static SDL_Texture *createTextureFromPixels(SDL_Renderer *renderer, unsigned char *data, int w, int h, int *out_w, int *out_h) { const int pitch = 4 * w; SDL_Surface *loadedSurface = SDL_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_RGBA32, (void *)data, pitch); if (loadedSurface == nullptr) { return nullptr; } SDL_Texture *newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface); if (newTexture != nullptr) { *out_w = loadedSurface->w; *out_h = loadedSurface->h; SDL_SetTextureScaleMode(newTexture, Texture::currentScaleMode); } SDL_DestroySurface(loadedSurface); return newTexture; } // Carga una imagen desde un fichero bool Texture::loadFromFile(std::string path, SDL_Renderer *renderer, bool verbose) { const std::string filename = path.substr(path.find_last_of("\\/") + 1); int req_format = STBI_rgb_alpha; int w, h, orig_format; unsigned char *data = stbi_load(path.c_str(), &w, &h, &orig_format, req_format); if (data == nullptr) { SDL_Log("Loading image failed: %s", stbi_failure_reason()); exit(1); } else if (verbose) { std::cout << "Image loaded: " << filename.c_str() << std::endl; } unload(); SDL_Texture *newTexture = createTextureFromPixels(renderer, data, w, h, &this->width, &this->height); if (newTexture == nullptr && verbose) { std::cout << "Unable to load image " << path.c_str() << std::endl; } stbi_image_free(data); texture = newTexture; return texture != nullptr; } // Carga una imagen desde bytes en memoria bool Texture::loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *renderer, bool verbose) { int w, h, orig_format; unsigned char *pixels = stbi_load_from_memory(data, (int)size, &w, &h, &orig_format, STBI_rgb_alpha); if (pixels == nullptr) { SDL_Log("Loading image from memory failed: %s", stbi_failure_reason()); return false; } unload(); SDL_Texture *newTexture = createTextureFromPixels(renderer, pixels, w, h, &this->width, &this->height); if (newTexture == nullptr && verbose) { std::cout << "Unable to create texture from memory" << std::endl; } stbi_image_free(pixels); texture = newTexture; return texture != nullptr; } // Crea una textura en blanco bool Texture::createBlank(SDL_Renderer *renderer, int width, int height, SDL_TextureAccess access) { // Crea una textura sin inicializar texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, access, width, height); if (texture == nullptr) { std::cout << "Unable to create blank texture! SDL Error: " << SDL_GetError() << std::endl; } else { this->width = width; this->height = height; SDL_SetTextureScaleMode(texture, currentScaleMode); } return texture != nullptr; } // Libera la memoria de la textura void Texture::unload() { // Libera la textura si existe if (texture != nullptr) { SDL_DestroyTexture(texture); texture = nullptr; width = 0; height = 0; } } // Establece el color para la modulacion void Texture::setColor(Uint8 red, Uint8 green, Uint8 blue) { SDL_SetTextureColorMod(texture, red, green, blue); } // Establece el blending void Texture::setBlendMode(SDL_BlendMode blending) { SDL_SetTextureBlendMode(texture, blending); } // Establece el alpha para la modulación void Texture::setAlpha(Uint8 alpha) { SDL_SetTextureAlphaMod(texture, alpha); } // Renderiza la textura en un punto específico void Texture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, float zoomW, float zoomH, double angle, SDL_Point *center, SDL_FlipMode flip) { // Establece el destino de renderizado en la pantalla SDL_FRect renderQuad = {(float)x, (float)y, (float)width, (float)height}; // Obtiene las dimesiones del clip de renderizado if (clip != nullptr) { renderQuad.w = (float)clip->w; renderQuad.h = (float)clip->h; } renderQuad.w = renderQuad.w * zoomW; renderQuad.h = renderQuad.h * zoomH; // Convierte el clip a SDL_FRect SDL_FRect srcRect; SDL_FRect *srcRectPtr = nullptr; if (clip != nullptr) { srcRect = {(float)clip->x, (float)clip->y, (float)clip->w, (float)clip->h}; srcRectPtr = &srcRect; } // Convierte el centro a SDL_FPoint SDL_FPoint fCenter; SDL_FPoint *fCenterPtr = nullptr; if (center != nullptr) { fCenter = {(float)center->x, (float)center->y}; fCenterPtr = &fCenter; } // Renderiza a pantalla SDL_RenderTextureRotated(renderer, texture, srcRectPtr, &renderQuad, angle, fCenterPtr, flip); } // Establece la textura como objetivo de renderizado void Texture::setAsRenderTarget(SDL_Renderer *renderer) { SDL_SetRenderTarget(renderer, texture); } // Obtiene el ancho de la imagen int Texture::getWidth() { return width; } // Obtiene el alto de la imagen int Texture::getHeight() { return height; } // Recarga la textura bool Texture::reLoad() { return loadFromFile(path, renderer); } // Obtiene la textura SDL_Texture *Texture::getSDLTexture() { return texture; }