/* +-------------------------------------------------------+ ____/ \____ /| Open source game framework licensed to freely use, | \ / / | copy, and modify, created for dank.game | +--\ ^__^ /--+ | | | ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox | | ~~~~~~~~~~~~ | +-------------------------------------------------------+ | SPACE ~~~~~ | / | ~~~~~~~ BOX |/ +-------------*/ #pragma once #include #include #include #include "glm/vec2.hpp" #include "SDL.h" #include "SDL_image.h" #include "sdl2-gfx/SDL2_rotozoom.h" #include "filesystem.hpp" #include "GLObject.hpp" #include "Log.hpp" namespace sb { /*! * The Texture class abstracts the image file opening, data loading and binding steps of Open GL texture creation. Currently it * supports only the GL_TEXTURE_2D target with one mipmap level. Support for other types of textures may be added in the future. * * The texture object's ID can be used to pass this texture directly to OpenGL functions. */ class Texture : public GLObject { private: /* An image file path can be set with Texture::allocate(fs::path) and later loaded with Texture::load(). */ fs::path path = ""; /* Size and format are unset until memory for pixel data is allocated. */ std::optional _size; std::optional _format; /* The filter will be applied using glTexParameter whenever Texture::generate(glm::vec2, GLenum, std::optional) is * called without a filter specified. */ GLint _filter = GL_NEAREST; public: /*! * Construct an empty Texture. The deleter will be passed to the base sb::GLObject class. */ Texture(); /*! * If an image path is passed at creation, the path will be stored in the class for later loading. * * @param path path to an image to be used as the default texture, which will be loaded later with Texture::load() */ Texture(fs::path path); /*! * Store an image path as a member variable for loading later. Each texture can have only one image * path (support for multiple paths to enable multiple texture mipmap levels may be added later). * * @param path path to an image that can be loaded by the SDL image library */ void associate(fs::path path); /*! * Set the resize filter of the texture. This must be set before Texture::generate(glm::vec2, GLenum, std::optional) * is called for it to be applied. * * @param value Resize filter to use (see `glTexParameter` for options) */ void filter(GLint value); /*! * Forward the GL texture generate function to the base class */ void generate(); /*! * Generate a GL_TEXTURE_2D texture ID and allocate the specified format storage for the given size. * * @param size Width and height of the texture in texels * @param format Sized internal format to be used to store texture data (for example, `GL_RGBA8`, `GL_RGB8`) * @param filter Resize function to use (see `glTexParameter`). Overrides the value of Texture::filter. */ void generate(glm::vec2 size, GLenum format = GL_RGBA8, std::optional filter = std::nullopt); /*! * Load a texture from the path that was previously set. * * @see ::Texture(fs::path) * @see ::associate(fs::path) * @see ::load(fs::path) */ void load(); /*! * Load a texture from a path to an image file. This will create an SDL Surface from the image file at a given path and * forward it to the load overload which accepts a surface pointer. * * Unless the texture has already been generated, the texture will be generated with storage for the size of the image. * * @param path Filesystem path to an image file */ void load(fs::path path); /*! * Load texture from an SDL read/write stream object. * * Unless the texture has already been generated, the texture will be generated with storage for the size of the image. * * @param rw an SDL read/write object pointing to an image file that will be read for pixel data */ void load(SDL_RWops* rw); /*! * Load texture from an SDL surface. * * Unless the texture has already been generated, the texture will be generated with storage for the size of the image. * * @param surface an SDL surface filled with texture pixel data */ void load(SDL_Surface* surface); /*! * Load raw pixel data into texture using OpenGL's `glTexSubImage2D`. The format and type determine how the data will be loaded. * The format is the pixel format, and the type is the type of the data. * * Unless the texture has already been generated, the texture will be generated with storage for the size of the image. * * @param pixels Raw pointer to pixel data memory. The type of data pointed to should be given to the format argument. * @param size Dimensions of the image * @param format Format of each pixel * @param type Type pointed to by the pixel data pointer */ void load(void* pixels, glm::vec2 size, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE); /*! * @overload load(void* pixels, glm::vec2 size, GLenum format, GLenum type) * * The texture must have been previously generated with a size to use this generic pixel data load function. * * see OpenGL's `glTexSubImage2D` * * @param pixels pointer to pixel data * @param format GL format of pixel data (for example, GL_RGBA) * @param type data type of the pixel data (for example, GL_UNSIGNED_BYTE if each byte is one of the RGBA values) */ void load(void* pixels, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE); /*! * Return the size in pixels of mipmap level 0 (the only mipmap level supported by this class). If the texture hasn't been * generated or loaded with a size given, an exception will be thrown because it currently has no size. * * @return glm::vec2 A vector consisting of {TEXTURE_MIPMAP_WIDTH, TEXTURE_MIPMAP_HEIGHT} */ glm::vec2 size() const; /*! * Call `glBindTexture`, binding this texture's ID to the target `GL_TEXTURE_2D`. The texture must have previously been * generated, using Texture::generate() or Texture::generate(glm::vec2, GLenum, GLint), otherwise an exception will be * thrown. * * > While a texture is bound, GL operations on the target to which it is bound affect the bound texture, and queries of * > the target to which it is bound return state from the bound texture. In effect, the texture targets become aliases for * > the textures currently bound to them. * > * > - OpenGL Manual */ void bind() const override; /*! * Textures are considered equal if they have the same ID. * * @param texture texture to compare this texture to */ bool operator==(const Texture& texture) const; }; void texture_deleter(GLuint*); }