spacebox/src/Texture.hpp

192 lines
7.6 KiB
C++

/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#pragma once
#include <sstream>
#include <stdexcept>
#include <optional>
#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<glm::vec2> _size;
std::optional<GLenum> _format;
/* The filter will be applied using glTexParameter whenever Texture::generate(glm::vec2, GLenum, std::optional<GLint>) 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<GLint>) 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<GLint> 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*);
}