/* * * 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 . */ #ifndef BLT_TEXTURE_H #define BLT_TEXTURE_H #include #include #include #include #include #include "blt/std/types.h" namespace blt::gfx { class texture_file; class texture_data { friend texture_file; private: unsigned char* m_data = nullptr; int m_width = 0, m_height = 0, m_channels = 0; public: texture_data(unsigned char* data, int width, int height, int channels): m_data(data), m_width(width), m_height(height), m_channels(channels) {} texture_data(int width, int height, int channels = 4): m_width(width), m_height(height), m_channels(channels) { m_data = static_cast(std::malloc(width * height * channels)); } texture_data() = default; inline unsigned char* data() { return m_data; } [[nodiscard]] inline const unsigned char* data() const { return m_data; } [[nodiscard]] inline int width() const { return m_width; } [[nodiscard]] inline int height() const { return m_height; } [[nodiscard]] inline int channels() const { return m_channels; } ~texture_data() { std::free(m_data); } }; class texture_file { private: std::string m_name; std::string m_path; blt::i32 desired_channels; mutable texture_data m_texture; 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 texture_file(const std::string& path, const std::string& name = "", blt::i32 desired_channels = 0); texture_file& resize(int target_width, int target_height); inline texture_data& texture() const { return m_texture; } [[nodiscard]] inline int channels() const { return m_texture.m_channels; } [[nodiscard]] inline int width() const { return m_texture.m_width; } [[nodiscard]] inline int height() const { return m_texture.m_height; } [[nodiscard]] inline const std::string& getName() const { return m_name; } }; struct texture_gl { protected: unsigned int textureID = 0; GLint textureBindType; GLint textureColorMode; int m_width, m_height; texture_gl(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); } protected: void setDefaults(GLint type, GLint wrap = GL_REPEAT) const; inline void generateMipmaps() const { glGenerateMipmap(textureBindType); } public: inline void bind() const { glBindTexture(textureBindType, textureID); } inline void unbind() const { glBindTexture(textureBindType, 0); } [[nodiscard]] inline unsigned int getTextureID() const { return textureID; } [[nodiscard]] inline GLint getBindType() const { return textureBindType; } virtual void updateSize(blt::i32, blt::i32) {} [[nodiscard]] int getHeight() const { return m_height; } [[nodiscard]] int getWidth() const { return m_width; } virtual ~texture_gl() { glDeleteTextures(1, &textureID); } }; struct texture_gl2D : public texture_gl { public: explicit texture_gl2D(const texture_data& data); texture_gl2D(int width, int height, GLint colorMode = GL_RGBA8); 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, GLint dataMode = GL_UNSIGNED_BYTE) const; void upload(void* data, int width, int height, GLint dataColorMode = GL_RGBA, GLint dataMode = GL_UNSIGNED_BYTE); void upload(const texture_data& file_data) const; inline void updateSize(blt::i32 width, blt::i32 height) final { resize(width, height); } /** * Resizes the internal memory for the texture but does NOT resize the texture image stored */ void resize(int width, int height); }; struct texture_gl2D_multisample : public texture_gl { private: blt::i32 samples; public: texture_gl2D_multisample(int width, int height, blt::i32 samples, GLint colorMode = GL_RGBA8); inline void updateSize(blt::i32 width, blt::i32 height) final { resize(width, height); } /** * Resizes the internal memory for the texture but does NOT resize the texture image stored */ void resize(int width, int height); }; struct gl_texture2D_array : public texture_gl { protected: int m_layers; public: gl_texture2D_array(int width, int height, int layers, GLint colorMode = GL_RGBA8); 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; }; class gl_buffer_texture : public texture_gl2D { 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 ): texture_gl2D(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