texture workings

main
Brett 2023-12-17 15:04:57 -05:00
parent cb07322ceb
commit 84637028c5
6 changed files with 12334 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

266
include/blt/gfx/texture.h Normal file
View File

@ -0,0 +1,266 @@
/*
* <Short Description>
* Copyright (C) 2023 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_TEXTURE_H
#define BLT_TEXTURE_H
#ifdef __EMSCRIPTEN__
#else
#endif
namespace blt::gfx
{
class file_texture {
private:
std::string m_Name;
std::string m_Path;
int width = 0, height = 0, channels = 0;
unsigned char* m_Data = nullptr;
public:
/**
* @param path path to the texture file
* @param name reference name for this texture. If empty the texture will use path as its identifier
*/
explicit file_texture(const std::string& path, const std::string& name = ""):
m_Name(name.empty() ? path : name), m_Path(path) {}
static file_texture* load(file_texture*& texture) {
// we want to load every texture as if it has transparency,
// otherwise textures won't be correctly resized and loaded to the gpu
constexpr int channel_count = 4;
texture->m_Data = stbi_load(
texture->m_Path.c_str(), &texture->width, &texture->height,
&texture->channels, channel_count
);
texture->channels = channel_count;
return texture;
}
static file_texture* resize(
file_texture* texture, int target_width, int target_height
) {
if (target_width == texture->width && target_height == texture->height)
return texture;
// since we will be replacing the loaded data pointer, is it wise to use the allocator
// that matches with what stb image uses, which is malloc, since we unload with stbi_image_free -> (free)
auto* output_Data = (unsigned char*) malloc(
target_width * target_height * texture->channels
);
// resize the texture
if (stbir_resize_uint8(
// input
texture->m_Data, texture->width, texture->height, 0,
// output
output_Data, target_width, target_height, 0,
// channels
texture->channels
)) {
BLT_WARN("Error resizing block texture image!");
}
// free up the old data
stbi_image_free(texture->m_Data);
texture->m_Data = output_Data;
texture->width = target_width;
texture->height = target_height;
return texture;
}
unsigned char* data() {
return m_Data;
}
[[nodiscard]] int getChannels() const {
return channels;
}
[[nodiscard]] int getWidth() const {
return width;
}
[[nodiscard]] int getHeight() const {
return height;
}
[[nodiscard]] const std::string& getName() {
return m_Name;
}
~file_texture() {
stbi_image_free(m_Data);
}
};
struct gl_texture {
protected:
unsigned int textureID = 0;
GLint textureBindType;
GLint textureColorMode;
int m_width, m_height;
gl_texture(
int width, int height, GLint bind_type = GL_TEXTURE_2D,
GLint color_mode = GL_RGBA
):
textureBindType(bind_type), textureColorMode(color_mode), m_width(width),
m_height(height) {
glGenTextures(1, &textureID);
}
public:
inline void bind() const {
glBindTexture(textureBindType, textureID);
}
inline void unbind() const {
glBindTexture(textureBindType, 0);
}
void setDefaults() const {
bind();
glTexParameteri(textureBindType, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(textureBindType, GL_TEXTURE_WRAP_T, GL_REPEAT);
// nearest preserves the pixely look
glTexParameteri(textureBindType, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(textureBindType, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
// Anisotropy helps preserve textures at oblique angles
float a = 0;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &a);
glTexParameterf(textureBindType, GL_TEXTURE_MAX_ANISOTROPY_EXT, a);
unbind();
}
inline void generateMipmaps() const {
// it's a little inefficient binding and unbinding for these small calls, they really should be done in the constructor or data upload
bind();
glGenerateMipmap(textureBindType);
unbind();
}
[[nodiscard]] inline unsigned int getTextureID() const {
return textureID;
}
virtual ~gl_texture() {
glDeleteTextures(1, &textureID);
}
};
struct gl_texture2D : public gl_texture {
public:
gl_texture2D(int width, int height, GLint colorMode = GL_RGBA):
gl_texture(width, height, GL_TEXTURE_2D, colorMode) {
bind();
glTexStorage2D(
textureBindType, std::stoi(fp::settings::get("MIPMAP_LEVELS")), colorMode,
width, height
);
}
void upload(
void* data, GLint dataColorMode = GL_RGBA, int level = 0, int x_offset = 0,
int y_offset = 0, int sub_width = -1,
int sub_height = -1
) const {
if (sub_width < 0)
sub_width = m_width;
if (sub_height < 0)
sub_height = m_height;
bind();
glTexSubImage2D(
textureBindType, level, x_offset, y_offset, sub_width, sub_height,
dataColorMode, GL_UNSIGNED_BYTE, data
);
unbind();
}
void upload(file_texture* texture) const {
upload(texture->data(), texture->getChannels() == 4 ? GL_RGBA : GL_RGB);
}
/**
* Resizes the internal memory for the texture but does NOT resize the texture image stored
*/
inline void resize(int width, int height) {
m_width = width;
m_height = height;
bind();
glTexStorage2D(textureBindType, 0, textureColorMode, m_width, m_height);
unbind();
}
};
struct gl_texture2D_array : public gl_texture {
protected:
int m_layers;
public:
gl_texture2D_array(int width, int height, int layers, GLint colorMode = GL_RGBA8):
gl_texture(width, height, GL_TEXTURE_2D_ARRAY, colorMode), m_layers(layers) {
bind();
// 6+ mipmaps is about where I stop noticing any difference (size is 4x4 pixels, so that makes sense)
glTexStorage3D(textureBindType, 6, colorMode, width, height, layers);
BLT_DEBUG("Creating 2D Texture Array with ID: %d", textureID);
}
void upload(
void* data, int index, GLint dataColorMode = GL_RGBA, int level = 0,
int x_offset = 0, int y_offset = 0, int sub_width = -1,
int sub_height = -1
) const {
if (sub_width < 0)
sub_width = m_width;
if (sub_height < 0)
sub_height = m_height;
bind();
glTexSubImage3D(
textureBindType, level, x_offset, y_offset, index, sub_width, sub_height, 1,
dataColorMode, GL_UNSIGNED_BYTE, data
);
unbind();
}
};
class gl_buffer_texture : public gl_texture2D {
private:
public:
// make sure a framebuffer is bound before constructing!
gl_buffer_texture(
int width, int height, GLint format = GL_RGB32F,
GLint colorAttachment = GL_COLOR_ATTACHMENT0
): gl_texture2D(width, height, format) {
bind();
// no mipmaping and no interpolation to position textures!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//
glFramebufferTexture2D(
GL_FRAMEBUFFER, colorAttachment, GL_TEXTURE_2D, this->textureID, 0
);
}
};
}
#endif //BLT_TEXTURE_H

17
src/blt/gfx/texture.cpp Normal file
View File

@ -0,0 +1,17 @@
/*
* <Short Description>
* Copyright (C) 2023 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/