Inferno Game Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

163 lines
3.7 KiB

#include <climits> // UINT_MAX
#include <memory> // std::shared_ptr
#include <utility> // std::move
#include "glad/glad.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#include "inferno/assert.h"
#include "inferno/render/texture.h"
namespace Inferno {
Texture::Texture(const std::string& path)
: m_path(std::move(path))
{
int width;
int height;
int channels;
// Load image data
stbi_set_flip_vertically_on_load(1);
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, STBI_default);
ASSERT(data, "Failed to load image: '{}'", path);
m_width = width;
m_height = height;
if (channels == 4) {
m_internalFormat = GL_RGBA8;
m_dataFormat = GL_RGBA;
}
else if (channels == 3) {
m_internalFormat = GL_RGB8;
m_dataFormat = GL_RGB;
}
create(data);
// Clean resources
stbi_image_free(data);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_id);
}
void Texture::bind(uint32_t unit) const
{
// Set active unit
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, m_id);
// Reset unit
glActiveTexture(GL_TEXTURE0);
}
void Texture::unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::create(unsigned char* data)
{
m_id = UINT_MAX;
// Create texture object
glGenTextures(1, &m_id);
// Bind texture object
glBindTexture(GL_TEXTURE_2D, m_id);
// Set unpacking of pixel data to byte-alignment,
// this prevents alignment issues when using a single byte for color
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Generate texture
glTexImage2D(
GL_TEXTURE_2D, // Texture target
0, // Midmap level, base starts at level 0
m_internalFormat, // Texture format
m_width, m_height, // Image width/height
0, // Always 0 (legacy)
m_dataFormat, // Texture source format
GL_UNSIGNED_BYTE, // Texture source datatype
data); // Image data
// Set the texture wrapping / filtering options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // X
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Y
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Minify
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Magnify
// Automatically generate all mipmap levels
glGenerateMipmap(GL_TEXTURE_2D);
// Unbind texture object
glBindTexture(GL_TEXTURE_2D, 0);
}
// -----------------------------------------
TextureManager* TextureManager::s_instance = nullptr;
void TextureManager::initialize()
{
ASSERT(!s_instance, "TextureManager already exists!");
s_instance = this;
info() << "TextureManager initialized";
}
void TextureManager::destroy()
{
delete s_instance;
s_instance = nullptr;
}
void TextureManager::add(const std::string& path, const std::shared_ptr<Texture>& texture)
{
// Construct (key, value) pair and insert it into the unordered_map
m_textureList.emplace(path, texture);
}
std::shared_ptr<Texture> TextureManager::load(const std::string& path)
{
if (exists(path)) {
return get(path);
}
std::shared_ptr<Texture> texture = std::make_shared<Texture>(path);
add(path, texture);
return get(path);
}
std::shared_ptr<Texture> TextureManager::get(const std::string& path)
{
return exists(path) ? m_textureList.at(path) : nullptr;
}
bool TextureManager::exists(const std::string& path)
{
return m_textureList.find(path) != m_textureList.end();
}
void TextureManager::remove(const std::string& path)
{
if (exists(path)) {
m_textureList.erase(path);
}
}
void TextureManager::remove(const std::shared_ptr<Texture>& texture)
{
if (exists(texture->path())) {
m_textureList.erase(texture->path());
}
}
}