// Copyright (c) 2022 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "Texture.hpp" using namespace Dawn; Texture::Texture() : ITexture() { useEffect([&]{ this->texturePropertiesNeedUpdating = true; }, { &this->wrapModeX, &this->wrapModeY, &this->filterModeMin, &this->filterModeMag, &this->mipmapFilterModeMin, &this->mipmapFilterModeMag }); } void Texture::bind(textureslot_t slot) { assertTrue(this->id != -1); glActiveTexture(GL_TEXTURE0 + slot); glBindTexture(GL_TEXTURE_2D, this->id); if(this->texturePropertiesNeedUpdating) { this->updateTextureProperties(); this->texturePropertiesNeedUpdating = false; } } int32_t Texture::getWidth() { return this->width; } int32_t Texture::getHeight() { return this->height; } void Texture::setSize(int32_t width, int32_t height, enum TextureFormat format) { if(this->id != -1) { glDeleteTextures(1, &this->id); this->id = -1; } this->width = width; this->height = height; this->format = format; glGenTextures(1, &this->id); if(this->id <= 0) throw "Texture generation failed!"; // Initialize the texture to blank glActiveTexture(GL_TEXTURE0); this->bufferRaw(NULL); } void Texture::fill(struct Color color) { struct Color *pixels = (struct Color *)memoryAllocate( sizeof(struct Color) * this->width * this->height ); this->buffer(pixels); memoryFree(pixels); } bool_t Texture::isReady() { return this->id != -1; } void Texture::updateTextureProperties() { auto setWrapMode = [&](GLenum axis, enum TextureWrapMode wm) { switch(wm) { case TEXTURE_WRAP_MODE_REPEAT: glTexParameteri(GL_TEXTURE_2D, axis, GL_REPEAT); break; case TEXTURE_WRAP_MODE_MIRRORED_REPEAT: glTexParameteri(GL_TEXTURE_2D, axis, GL_MIRRORED_REPEAT); break; case TEXTURE_WRAP_MODE_CLAMP_TO_EDGE: glTexParameteri(GL_TEXTURE_2D, axis, GL_CLAMP_TO_EDGE); break; case TEXTURE_WRAP_MODE_CLAMP_TO_BORDER: glTexParameteri(GL_TEXTURE_2D, axis, GL_CLAMP_TO_BORDER); break; default: assertUnreachable(); } }; setWrapMode(GL_TEXTURE_WRAP_S, this->wrapModeX); setWrapMode(GL_TEXTURE_WRAP_T, this->wrapModeY); auto setFilterMode = [&]( GLenum minMag, enum TextureFilterMode filter, enum TextureFilterMode mapFilterMode ) { switch(filter) { case TEXTURE_FILTER_MODE_NEAREST: { switch(mapFilterMode) { case TEXTURE_FILTER_MODE_NEAREST: glTexParameteri(GL_TEXTURE_2D, minMag, GL_NEAREST_MIPMAP_NEAREST); break; case TEXTURE_FILTER_MODE_LINEAR: glTexParameteri(GL_TEXTURE_2D, minMag, GL_LINEAR_MIPMAP_NEAREST); break; default: assertUnreachable(); } break; } case TEXTURE_FILTER_MODE_LINEAR: { switch(mapFilterMode) { case TEXTURE_FILTER_MODE_NEAREST: glTexParameteri(GL_TEXTURE_2D, minMag, GL_NEAREST_MIPMAP_LINEAR); break; case TEXTURE_FILTER_MODE_LINEAR: glTexParameteri(GL_TEXTURE_2D, minMag, GL_LINEAR_MIPMAP_LINEAR); break; default: assertUnreachable(); } break; } default: { assertUnreachable(); } } }; setFilterMode(GL_TEXTURE_MIN_FILTER, this->filterModeMin, this->mipmapFilterModeMin); setFilterMode(GL_TEXTURE_MAG_FILTER, this->filterModeMag, this->mipmapFilterModeMag); } void Texture::bufferRaw(void *data) { assertTrue(this->isReady()); glBindTexture(GL_TEXTURE_2D, this->id); GLenum format; switch(this->format) { case TEXTURE_FORMAT_R: format = GL_RED; break; case TEXTURE_FORMAT_RG: format = GL_RG; break; case TEXTURE_FORMAT_RGB: format = GL_RGB; break; case TEXTURE_FORMAT_RGBA: format = GL_RGBA; break; default: assertUnreachable(); } glTexImage2D( GL_TEXTURE_2D, 0, format, this->width, this->height, 0, format, GL_UNSIGNED_BYTE, data ); glGenerateMipmap(GL_TEXTURE_2D); this->texturePropertiesNeedUpdating = true; } void Texture::buffer(struct Color pixels[]) { this->bufferRaw((void*)pixels); } void Texture::buffer(uint8_t pixels[]) { this->bufferRaw((void*)pixels); } Texture::~Texture() { if(this->id != -1) glDeleteTextures(1, &this->id); }