-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactoring of texture functionalities (3/X)
- Loading branch information
Showing
5 changed files
with
177 additions
and
270 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,4 +54,11 @@ namespace Engine | |
float g; | ||
float b; | ||
}; | ||
|
||
struct PxColor | ||
{ | ||
unsigned char r; | ||
unsigned char g; | ||
unsigned char b; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,286 +1,180 @@ | ||
#include "Texture.hpp" | ||
#include "GLTexture.hpp" | ||
|
||
namespace Engine | ||
{ | ||
// ----- Private ----- | ||
|
||
void Texture::InitFromFile(const std::string &filepath) | ||
uint32 GLTexture::Init(const std::string &filepath, bool saveBackup) | ||
{ | ||
ActivateTextureFlipOnLoad(); | ||
_imgBuffer = stbi_load(filepath.c_str(), &_width, &_height, &_nrChannels, 0); | ||
DeactivateTextureFlipOnLoad(); | ||
uint32 initStatus = EXIT_FAILURE; | ||
_textureBuffer = new TextureBuffer(filepath, saveBackup); | ||
|
||
if(_imgBuffer != nullptr) | ||
if(_textureBuffer->GetInitStatus() == EXIT_SUCCESS) | ||
{ | ||
if(_saveToBuffer) | ||
{ | ||
_backupBuffer = (unsigned char*)malloc(_width * _height * 3); | ||
if(_backupBuffer != nullptr) | ||
{ | ||
std::memcpy(_backupBuffer, _imgBuffer, _width * _height * 3); | ||
} | ||
} | ||
|
||
if(_nrChannels == 1) | ||
{ | ||
_format = GL_RED; | ||
} | ||
else if(_nrChannels == 3) | ||
{ | ||
_format = GL_RGB; | ||
} | ||
else if(_nrChannels == 4) | ||
{ | ||
_format = GL_RGBA; | ||
} | ||
else | ||
{ | ||
_format = 0; | ||
Logger::Error("Failed", "Image-Texture-Format", filepath); | ||
} | ||
|
||
if(_format != 0) | ||
{ | ||
//Create texture | ||
GLCall(glGenTextures(1, &_textureID)) | ||
Bind(); | ||
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, _format, _width, _height, 0, _format, GL_UNSIGNED_BYTE, _imgBuffer)) | ||
|
||
//Texture parameters | ||
GLCall(glGenerateMipmap(GL_TEXTURE_2D)) | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)) | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)) | ||
|
||
//Activate anisotropic filtering | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0)) | ||
GLCall(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4.0f)) | ||
Unbind(); | ||
|
||
std::string texInfo = "(X: " + std::to_string(_width) + ", Y: " + std::to_string(_height) + ", Channels: " + std::to_string(_nrChannels) + ")"; | ||
Logger::Info("Loaded", "Texture", filepath); | ||
Logger::Info("", "", texInfo); | ||
} | ||
//Save internal parameters | ||
_width = _textureBuffer->GetWidth(); | ||
_height = _textureBuffer->GetHeight(); | ||
_channels = _textureBuffer->GetChannels(); | ||
_format = _textureBuffer->GetFormat(); | ||
|
||
//Create texture from buffer | ||
GLCall(glGenTextures(1, &_textureID)) | ||
Bind(); | ||
GLCall(glTexImage2D(GL_TEXTURE_2D, | ||
0, | ||
_format, | ||
_width, | ||
_height, | ||
0, | ||
_format, | ||
GL_UNSIGNED_BYTE, | ||
_textureBuffer->GetRawData())) | ||
|
||
// Generate mip map | ||
GLCall(glGenerateMipmap(GL_TEXTURE_2D)) | ||
|
||
//Old defaults | ||
// GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)) | ||
// GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)) | ||
|
||
//Activate anisotropic filtering | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0)) | ||
GLCall(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4.0f)) | ||
Unbind(); | ||
|
||
Logger::Info("Created", "GLTexture", filepath); | ||
initStatus = EXIT_SUCCESS; | ||
} | ||
else | ||
{ | ||
Logger::Error("Failed", "Texture-Load", filepath); | ||
Logger::Error("Failed", "TextureBuffer", filepath); | ||
} | ||
|
||
if(!_saveToBuffer) | ||
{ | ||
stbi_image_free(_imgBuffer); | ||
} | ||
return initStatus; | ||
} | ||
|
||
void Texture::Create(uint32 width, uint32 height, GLint internalFormat, GLenum format, GLenum type) | ||
uint32 GLTexture::Create(GLint internalFormat, GLenum type) | ||
{ | ||
//Create texture | ||
GLCall(glGenTextures(1, &_textureID)) | ||
Bind(); | ||
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, nullptr)) | ||
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, _format, type, nullptr)) | ||
Unbind(); | ||
|
||
std::string texInfo = "(X: " + std::to_string(width) + ", Y: " + std::to_string(height) + ", Format: " + std::to_string(format) + ")"; | ||
Logger::Info("Created", "Texture", texInfo); | ||
} | ||
std::string texInfo = "( X: " + std::to_string(_width) + | ||
", Y: " + std::to_string(_height) + | ||
", Channels: " + std::to_string(_channels) + " )"; | ||
Logger::Info("Created", "GLTexture", texInfo); | ||
|
||
//Warning: Raw/unsafe accessing of the pixel buffer. | ||
//Be sure to check bounds and saved status before! | ||
glm::uvec3 Texture::GetPxColorRaw(uint32 x, uint32 y) const | ||
{ | ||
glm::uvec3 colorOut; | ||
colorOut.x = *(_imgBuffer + (y * _width * 3) + (x * 3) + 0); | ||
colorOut.y = *(_imgBuffer + (y * _width * 3) + (x * 3) + 1); | ||
colorOut.z = *(_imgBuffer + (y * _width * 3) + (x * 3) + 2); | ||
return colorOut; | ||
return EXIT_SUCCESS; | ||
} | ||
|
||
// ----- Public ----- | ||
|
||
Texture::Texture(const std::string &filepath, uint32 numberOfRows, bool saveToBuffer) | ||
: _width(0), _height(0), _nrChannels(0), _format(0), _textureID(0), _numberOfRows(numberOfRows), _saveToBuffer(saveToBuffer), _imgBuffer(nullptr), _backupBuffer(nullptr) | ||
GLTexture::GLTexture(const std::string& filepath, bool saveBackup, uint32 numberOfRows) | ||
: _initStatus(EXIT_FAILURE), _width(0), _height(0), _channels(0), | ||
_textureID(0), _numberOfRows(numberOfRows), _format(0), _textureBuffer(nullptr) | ||
{ | ||
InitFromFile(filepath); | ||
_initStatus = Init(filepath, saveBackup); | ||
} | ||
|
||
Texture::Texture(int32 width, int32 height, GLint internalFormat, GLenum format, GLenum type) | ||
: _width(width), _height(height), _nrChannels(0), _format(format), _textureID(0), _numberOfRows(0), _saveToBuffer(false), _imgBuffer(nullptr), _backupBuffer(nullptr) | ||
GLTexture::GLTexture(uint32 width, uint32 height, GLint internalFormat, GLenum format, GLenum type) | ||
: _initStatus(EXIT_FAILURE), _width(width), _height(height), _channels(0), | ||
_textureID(0), _numberOfRows(0), _format(format), _textureBuffer(nullptr) | ||
{ | ||
Create(width, height, internalFormat, format, type); | ||
_initStatus = Create(internalFormat, type); | ||
} | ||
|
||
Texture::~Texture() | ||
GLTexture::~GLTexture() | ||
{ | ||
GLCall(glDeleteTextures(1, &_textureID)) | ||
|
||
if(_saveToBuffer) | ||
if(_textureBuffer != nullptr) | ||
{ | ||
stbi_image_free(_imgBuffer); | ||
free(_backupBuffer); | ||
delete _textureBuffer; | ||
} | ||
} | ||
|
||
void Texture::Bind() const | ||
void GLTexture::Bind() const | ||
{ | ||
GLCall(glActiveTexture(GL_TEXTURE0)) | ||
GLCall(glBindTexture(GL_TEXTURE_2D, _textureID)) | ||
} | ||
|
||
void Texture::BindToSlot(const uint32 slot) const | ||
void GLTexture::BindToSlot(const uint32 slot) const | ||
{ | ||
GLCall(glActiveTexture(GL_TEXTURE0 + slot)) | ||
GLCall(glBindTexture(GL_TEXTURE_2D, _textureID)) | ||
} | ||
|
||
void Texture::Unbind() const | ||
void GLTexture::Unbind() const | ||
{ | ||
GLCall(glBindTexture(GL_TEXTURE_2D, 0)) | ||
} | ||
|
||
void Texture::ActivateTextureFlipOnLoad() const | ||
void GLTexture::AddMinFilterMipmapLinear() const | ||
{ | ||
stbi_set_flip_vertically_on_load(true); | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)) | ||
} | ||
|
||
void Texture::DeactivateTextureFlipOnLoad() const | ||
void GLTexture::AddMinFilterNearest() const | ||
{ | ||
stbi_set_flip_vertically_on_load(false); | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)) | ||
} | ||
|
||
void Texture::AddFilterNearest() const | ||
void GLTexture::AddMaxFilterNearest() const | ||
{ | ||
Bind(); | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)) | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)) | ||
} | ||
|
||
void Texture::AddFilterLinear() const | ||
void GLTexture::AddMinFilterLinear() const | ||
{ | ||
Bind(); | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)) | ||
} | ||
|
||
void GLTexture::AddMaxFilterLinear() const | ||
{ | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)) | ||
} | ||
|
||
void Texture::AddWrapRepeat() const | ||
void GLTexture::AddWrapRepeat() const | ||
{ | ||
Bind(); | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)) | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)) | ||
} | ||
|
||
void Texture::ClampToEdge() const | ||
void GLTexture::AddClampToEdge() const | ||
{ | ||
Bind(); | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)) | ||
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)) | ||
} | ||
|
||
void Texture::AddBorderColor() const | ||
void GLTexture::AddBorderColor(const glm::vec4& color) const | ||
{ | ||
Bind(); | ||
const float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; | ||
GLCall(glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor)) | ||
GLCall(glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, &color[0])) | ||
} | ||
|
||
void Texture::ModifyTexture(uint32 x, uint32 y, const glm::vec3& color) | ||
uint32 GLTexture::GetWidth() const | ||
{ | ||
if(_saveToBuffer) | ||
{ | ||
if((int32)x < _width && (int32)y < _height) | ||
{ | ||
*(_imgBuffer + (y * _width * 3) + (x * 3) + 0) = (unsigned char)(color.x * 255); | ||
*(_imgBuffer + (y * _width * 3) + (x * 3) + 1) = (unsigned char)(color.y * 255); | ||
*(_imgBuffer + (y * _width * 3) + (x * 3) + 2) = (unsigned char)(color.z * 255); | ||
} | ||
{ | ||
Logger::Error("Failed", "Modification", "Array access out of bounds"); | ||
} | ||
} | ||
else | ||
{ | ||
Logger::Error("Failed", "Modification", "Texture wasn't saved"); | ||
} | ||
return _width; | ||
} | ||
|
||
void Texture::ResetTextureModification(uint32 x, uint32 y) | ||
uint32 GLTexture::GetHeight() const | ||
{ | ||
if(_saveToBuffer) | ||
{ | ||
if((int32)x < _width && (int32)y < _height) | ||
{ | ||
*(_imgBuffer + (y * _width * 3) + (x * 3) + 0) = *(_backupBuffer + (y * _width * 3) + (x * 3) + 0); | ||
*(_imgBuffer + (y * _width * 3) + (x * 3) + 1) = *(_backupBuffer + (y * _width * 3) + (x * 3) + 1); | ||
*(_imgBuffer + (y * _width * 3) + (x * 3) + 2) = *(_backupBuffer + (y * _width * 3) + (x * 3) + 2); | ||
} | ||
{ | ||
Logger::Error("Failed", "Modification", "Array access out of bounds"); | ||
} | ||
} | ||
else | ||
{ | ||
Logger::Error("Failed", "Modification", "Texture wasn't saved"); | ||
} | ||
} | ||
|
||
void Texture::CommitModifications() const | ||
{ | ||
Bind(); | ||
GLCall(glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RGB, GL_UNSIGNED_BYTE, _imgBuffer)); | ||
Unbind(); | ||
} | ||
|
||
uint32 Texture::GetWidth() const | ||
{ | ||
return (uint32)_width; | ||
} | ||
|
||
uint32 Texture::GetHeight() const | ||
{ | ||
return (uint32)_height; | ||
return _height; | ||
} | ||
|
||
uint32 Texture::GetTextureID() const | ||
uint32 GLTexture::GetTextureID() const | ||
{ | ||
return _textureID; | ||
} | ||
|
||
uint32 Texture::GetNumberOfRows() const | ||
uint32 GLTexture::GetNumberOfRows() const | ||
{ | ||
return _numberOfRows; | ||
} | ||
|
||
bool Texture::Subsample(uint32 xpos, uint32 ypos, uint32 sampleAmount, glm::uvec3* colorOut) const | ||
TextureBuffer* GLTexture::GetTextureBuffer() const | ||
{ | ||
if(_saveToBuffer == false) | ||
{ | ||
Logger::Error("Failed", "Subsampling", "Texture wasn't saved"); | ||
return false; | ||
} | ||
|
||
*colorOut = GetPxColorRaw(xpos, ypos); | ||
return true; | ||
|
||
uint32 pxAmount = sampleAmount * sampleAmount; | ||
glm::uvec3 totalColor = {0, 0, 0}; | ||
|
||
for(uint32 x = 0; x < sampleAmount; x++) | ||
{ | ||
for(uint32 y = 0; y < sampleAmount; y++) | ||
{ | ||
if((int32)(xpos + x) < _width && (int32)(ypos + y)< _height) | ||
{ | ||
totalColor += GetPxColorRaw(xpos + x, ypos + y); | ||
} | ||
else | ||
{ | ||
Logger::Error("Failed", "Subsampling", "Array access out of bounds"); | ||
} | ||
} | ||
} | ||
|
||
colorOut->x = totalColor.x / pxAmount; | ||
colorOut->y = totalColor.y / pxAmount; | ||
colorOut->z = totalColor.z / pxAmount; | ||
|
||
return true; | ||
return _textureBuffer; | ||
} | ||
} |
Oops, something went wrong.