texture workings
parent
cb07322ceb
commit
84637028c5
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
|
@ -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
|
|
@ -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/>.
|
||||
*/
|
Loading…
Reference in New Issue