libmx2/MX2_Project/webmx/mx2/include/texture.hpp
Source: libmx2/MX2_Project/webmx/mx2/include/texture.hpp
/**
* @file texture.hpp
* @brief SDL_Texture RAII wrapper with loading, saving, and flip utilities.
*/
#ifndef _TEXTURE_H___
#define _TEXTURE_H___
#include "SDL.h"
#include "tee_stream.hpp"
#include "wrapper.hpp"
#include <iostream>
#include <optional>
#include <string>
#include <vector>
namespace mx {
class mxWindow;
/**
* @class Texture
* @brief RAII wrapper around an SDL_Texture.
*
* Manages the lifetime of an SDL_Texture and provides helpers for loading
* from image files, creating blank textures, saving to BMP, and an in-place
* vertical flip of an SDL_Surface. Only move semantics are supported;
* copying is disabled to prevent double-free.
*/
class Texture {
public:
/** @brief Default constructor — no texture loaded. */
Texture() = default;
Texture(const Texture &tex) = delete;
/** @brief Move constructor — transfers ownership of the SDL_Texture. */
Texture(Texture &&tex);
Texture &operator=(const Texture &tex) = delete;
/** @brief Move-assign — transfers ownership of the SDL_Texture. */
Texture &operator=(Texture &&tex);
/** @brief Destructor — destroys the SDL_Texture if held. */
~Texture();
/**
* @brief Create an empty (blank) texture of the given dimensions.
* @param window Owning window supplying the renderer.
* @param width Texture width in pixels.
* @param height Texture height in pixels.
*/
void createTexture(mxWindow *window, int width, int height);
/**
* @brief Load a texture from an image file.
* @param window Owning window supplying the renderer.
* @param filename Path to the image file (PNG, BMP, etc.).
*/
void loadTexture(mxWindow *window, const std::string &filename);
/**
* @brief Load a texture with optional colour-key transparency.
* @param window Owning window.
* @param filename Image file path.
* @param w Output: loaded image width.
* @param h Output: loaded image height.
* @param color If @c true, apply the colour key.
* @param key Colour to treat as transparent.
*/
void loadTexture(mxWindow *window, const std::string &filename, int &w, int &h, bool color, SDL_Color key);
/**
* @brief Save the texture to a file.
* @param window Owning window supplying the renderer.
* @param filename Destination file path (BMP format).
* @return @c true on success.
*/
bool saveTexture(mxWindow *window, const std::string &filename);
/**
* @brief Return the SDL_Texture as an optional.
* @return std::optional with the texture, or std::nullopt if not loaded.
*/
std::optional<SDL_Texture *> handle() const {
if (texture)
return texture;
return std::nullopt;
}
/**
* @brief Unwrap the SDL_Texture pointer, throwing on null.
* @return Raw SDL_Texture pointer.
* @throws mx::Exception if texture is not loaded.
*/
SDL_Texture *unwrap() const {
if (texture) {
return texture;
}
throw Exception("unwrap: Invalid texture");
return 0;
}
/**
* @brief Return a Wrapper around the SDL_Texture handle.
* @return Wrapper<SDL_Texture*> holding the pointer or nullopt.
*/
Wrapper<SDL_Texture *> wrapper() const {
if (texture)
return texture;
return std::nullopt;
}
/**
* @brief Flip an SDL_Surface vertically (in-place).
* @param surface Surface to flip.
* @return The same surface pointer after flipping.
*/
static SDL_Surface *flipSurface(SDL_Surface *surface) {
if (SDL_LockSurface(surface) != 0) {
return surface;
}
Uint8 *pixels = (Uint8 *)surface->pixels;
int pitch = surface->pitch;
std::vector<Uint8> tempRow(pitch);
for (int y = 0; y < surface->h / 2; ++y) {
Uint8 *row1 = pixels + y * pitch;
Uint8 *row2 = pixels + (surface->h - y - 1) * pitch;
memcpy(tempRow.data(), row1, pitch);
memcpy(row1, row2, pitch);
memcpy(row2, tempRow.data(), pitch);
}
SDL_UnlockSurface(surface);
return surface;
}
/** @return Width of the loaded texture in pixels. */
int width() const { return width_; }
/** @return Height of the loaded texture in pixels. */
int height() const { return height_; }
private:
SDL_Texture *texture = nullptr; ///< Managed SDL texture handle.
int width_ = 0; ///< Cached texture width.
int height_ = 0; ///< Cached texture height.
int imageType(const std::string &type);
bool saveBMP(SDL_Texture *texture, SDL_Renderer *renderer, const std::string &name);
};
} // namespace mx
#endif