hyporo-cpp/source/hpr/gpu/texture.hpp

225 lines
5.6 KiB
C++
Raw Normal View History

2023-03-13 22:27:09 +05:00
#pragma once
#include <hpr/containers.hpp>
#include <string>
#include <filesystem>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#ifndef __gl_h_
#include <glad/glad.h>
#endif
namespace hpr::gpu
{
class Texture
{
public:
using ustring = std::basic_string<unsigned char>;
public:
enum class Format
{
RGB = GL_RGB,
RGBA = GL_RGBA
};
protected:
unsigned int p_index;
std::string p_filename;
ustring p_source;
int p_width;
int p_height;
Format p_internalFormat;
Format p_imageFormat;
public:
inline
Texture() :
p_index {0},
p_filename {},
p_source {},
p_width {},
p_height {},
p_internalFormat {Format::RGBA},
p_imageFormat {Format::RGBA}
{}
inline
Texture(int width, int height) :
p_index {0},
p_filename {},
p_source {},
p_width {width},
p_height {height},
p_internalFormat {Format::RGBA},
p_imageFormat {Format::RGBA}
{}
inline
Texture(const std::string& filename) :
p_index {0},
p_filename {filename},
p_source {},
p_width {},
p_height {},
p_internalFormat {Format::RGB},
p_imageFormat {Format::RGB}
{}
virtual
~Texture() = default;
[[nodiscard]]
unsigned int index() const
{
return p_index;
}
int& width()
{
return p_width;
}
[[nodiscard]]
int width() const
{
return p_width;
}
int& height()
{
return p_height;
}
[[nodiscard]]
int height() const
{
return p_height;
}
void active() const
{
glActiveTexture(GL_TEXTURE0 + p_index);
}
void bind() const
{
glBindTexture(GL_TEXTURE_2D, p_index);
}
void unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void alphaChannel(bool enabled)
{
if (enabled)
{
p_internalFormat = Format::RGBA;
p_imageFormat = Format::RGBA;
}
else
{
p_internalFormat = Format::RGB;
p_imageFormat = Format::RGB;
}
}
void load(const std::string& filename)
{
auto filepath = std::filesystem::canonical(std::filesystem::path(filename)).string();
stbi_set_flip_vertically_on_load(true);
int channelsCount;
unsigned char* source = stbi_load(filepath.c_str(), &p_width, &p_height, &channelsCount, 0);
if (!source)
throw std::runtime_error("Failed to load texture source");
else
create(source);
stbi_image_free(source);
}
void load()
{
load(p_filename);
}
void create()
{
glGenTextures(1, &p_index);
bind();
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
unbind();
}
void create(const ustring& source)
{
glGenTextures(1, &p_index);
bind();
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, source.data());
p_source = source;
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
unbind();
}
void rescale()
{
bind();
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, !p_source.empty() ? p_source.data() : nullptr);
unbind();
}
void rescale(int width, int height)
{
p_width = width;
p_height = height;
bind();
glTexImage2D(GL_TEXTURE_2D, 0, (GLint)p_internalFormat, p_width, p_height, 0, (GLint)p_imageFormat, GL_UNSIGNED_BYTE, !p_source.empty() ? p_source.data() : nullptr);
unbind();
}
void destroy()
{
glDeleteTextures(1, &p_index);
2023-04-10 22:01:56 +05:00
p_index = 0;
2023-03-13 22:27:09 +05:00
}
bool valid() const
{
return p_index != 0;
}
};
}