136 lines
4.5 KiB
C++
136 lines
4.5 KiB
C++
#include "Texture.hpp"
|
|
|
|
/* Have to pass our deleter to abstract base class at instantiation */
|
|
Texture::Texture() : GLObject(texture_deleter) {}
|
|
|
|
/* If an image path is passed at creation, the path will be stored in the class for later loading */
|
|
Texture::Texture(fs::path path) : Texture()
|
|
{
|
|
associate(path);
|
|
}
|
|
|
|
/* Store an image path as a member variable for loading later. Each texture should have one image
|
|
* path (support for multiple mipmap levels may be added later) */
|
|
void Texture::associate(fs::path path)
|
|
{
|
|
this->path = path;
|
|
}
|
|
|
|
/* Generate an ID for this Texture and save it */
|
|
void Texture::generate()
|
|
{
|
|
GLuint id;
|
|
glGenTextures(1, &id);
|
|
this->id(id);
|
|
}
|
|
|
|
/* Generate a GL_TEXTURE_2D texture ID and allocate GL_RGB8 storage for the given size */
|
|
void Texture::generate(glm::vec2 size)
|
|
{
|
|
generate();
|
|
bind();
|
|
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, size.x, size.y);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
Game::log_gl_errors();
|
|
}
|
|
|
|
/* When called with no parameters, use the stored path variable */
|
|
void Texture::load()
|
|
{
|
|
load(path);
|
|
}
|
|
|
|
/* Create an SDL Surface from the supplied path and forward it to the loading function which accepts
|
|
* a surface pointer */
|
|
void Texture::load(fs::path path)
|
|
{
|
|
/* open path as surface which will free itself when it goes out of scope (at the end of this function) */
|
|
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> surface(IMG_Load(path.c_str()), SDL_FreeSurface);
|
|
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> flipped_surface(rotozoomSurfaceXY(surface.get(), 0, 1, -1, 0), SDL_FreeSurface);
|
|
load(flipped_surface.get());
|
|
}
|
|
|
|
/* Create an SDL Surface from the supplied RW pointer and forward it to the loading function which accepts
|
|
* a surface pointer */
|
|
void Texture::load(SDL_RWops* rw)
|
|
{
|
|
/* load RW as an SDL surface to translate image format into pixel data, flip, and get dimensions */
|
|
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> surface(IMG_Load_RW(rw, 0), SDL_FreeSurface);
|
|
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> flipped_surface(rotozoomSurfaceXY(surface.get(), 0, 1, -1, 0), SDL_FreeSurface);
|
|
load(flipped_surface.get());
|
|
}
|
|
|
|
/* Forward pixels and size to the generic pixel loading function */
|
|
void Texture::load(SDL_Surface* surface)
|
|
{
|
|
load(surface->pixels, {surface->w, surface->h}, GL_RGBA, GL_UNSIGNED_BYTE);
|
|
std::ostringstream message;
|
|
message << "loaded " << path << " (" << surface->w << "x" << surface->h << ")";
|
|
Game::log(message.str());
|
|
}
|
|
|
|
/* Bind texture and load pixel data using this class's generated ID */
|
|
void Texture::load(void* pixels, glm::vec2 size, GLenum format, GLenum type)
|
|
{
|
|
if (!generated())
|
|
{
|
|
generate(size);
|
|
}
|
|
bind();
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.x, size.y, format, type, pixels);
|
|
Game::log_gl_errors();
|
|
}
|
|
|
|
/* The texture must have been previously generated with a size to use this generic pixel data load function */
|
|
void Texture::load(void* pixels, GLenum format, GLenum type)
|
|
{
|
|
if (!generated())
|
|
{
|
|
throw std::invalid_argument("This texture has not been generated and has no size property, so a size must be provided");
|
|
}
|
|
else
|
|
{
|
|
load(pixels, size(), format, type);
|
|
}
|
|
}
|
|
|
|
void Texture::bind() const
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, this->id());
|
|
}
|
|
|
|
/* Return the size in pixels of mipmap level 0 (the only mipmap level supported by this class). If the texture hasn't been,
|
|
* generated, return {0, 0}. */
|
|
glm::vec2 Texture::size() const
|
|
{
|
|
if (generated())
|
|
{
|
|
bind();
|
|
int width, height;
|
|
int miplevel = 0;
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_WIDTH, &width);
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_HEIGHT, &height);
|
|
return {width, height};
|
|
}
|
|
else
|
|
{
|
|
return {0, 0};
|
|
}
|
|
}
|
|
|
|
/* Textures are considered equal if they have the same ID */
|
|
bool Texture::operator==(const Texture& texture) const
|
|
{
|
|
return id() == texture.id();
|
|
}
|
|
|
|
/* This function gets passed to the abstract base class for deleting the texture data when the ID
|
|
* pointer goes out of scope (when all instances of this texture and its copies are out of scope) */
|
|
void texture_deleter(GLuint* id)
|
|
{
|
|
/* not sure why SDL_Log works here at program end but SDL_LogDebug and SDL_LogInfo don't */
|
|
SDL_Log("destroying texture ID %i", *id);
|
|
glDeleteTextures(1, id);
|
|
}
|