360 lines
7.9 KiB
C++
360 lines
7.9 KiB
C++
#include "Texture.hpp"
|
|
#include "Debug.hpp"
|
|
#include "Color.hpp"
|
|
#include "ErrorTextureData.hpp"
|
|
|
|
TSE::Texture::Texture(const string &path)
|
|
{
|
|
FREE_IMAGE_FORMAT fif = FREE_IMAGE_FORMAT::FIF_UNKNOWN;
|
|
bmp = nullptr;
|
|
imagePtr = nullptr;
|
|
Size = Vector2(0,0);
|
|
|
|
fif = FreeImage_GetFileType(path.c_str(), 0);
|
|
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN)
|
|
fif = FreeImage_GetFIFFromFilename(path.c_str());
|
|
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN)
|
|
{
|
|
TSE_ERROR("Failed to load image. Unsupported Format.");
|
|
Bpp = 24;
|
|
makeError(*this);
|
|
return;
|
|
}
|
|
if(FreeImage_FIFSupportsReading(fif))
|
|
{
|
|
bmp = FreeImage_Load(fif, path.c_str());
|
|
if(FreeImage_GetBPP(bmp) != 32)
|
|
{
|
|
auto tmpBmp = FreeImage_ConvertTo32Bits(bmp);
|
|
FreeImage_Unload(bmp);
|
|
bmp = tmpBmp;
|
|
}
|
|
}
|
|
if(bmp == nullptr)
|
|
{
|
|
TSE_ERROR("Failed to load image. Bitmap was nullptr.");
|
|
Bpp = 24;
|
|
makeError(*this);
|
|
return;
|
|
}
|
|
Bpp = FreeImage_GetBPP(bmp);
|
|
imagePtr = FreeImage_GetBits(bmp);
|
|
|
|
switch (Bpp)
|
|
{
|
|
case 32:
|
|
chanels = 4;
|
|
break;
|
|
case 24:
|
|
chanels = 3;
|
|
case 8:
|
|
chanels = 4;
|
|
}
|
|
|
|
Size = Vector2(FreeImage_GetWidth(bmp), FreeImage_GetHeight(bmp));
|
|
regist();
|
|
}
|
|
|
|
TSE::Texture::Texture(const int &width, const int &height, int bpp)
|
|
{
|
|
switch (bpp)
|
|
{
|
|
case 32:
|
|
chanels = 4;
|
|
break;
|
|
case 24:
|
|
chanels = 3;
|
|
case 8:
|
|
chanels = 4;
|
|
}
|
|
Bpp = bpp;
|
|
Size = Vector2(width, height);
|
|
bmp = FreeImage_Allocate(width, height, bpp);
|
|
imagePtr = FreeImage_GetBits(bmp);
|
|
regist();
|
|
}
|
|
|
|
TSE::Texture::Texture(const Vector2 &size, int bpp)
|
|
{
|
|
switch (bpp)
|
|
{
|
|
case 32:
|
|
chanels = 4;
|
|
break;
|
|
case 24:
|
|
chanels = 3;
|
|
case 8:
|
|
chanels = 4;
|
|
}
|
|
Bpp = bpp;
|
|
Size = size;
|
|
bmp = FreeImage_Allocate(size.x, size.y, bpp);
|
|
imagePtr = FreeImage_GetBits(bmp);
|
|
regist();
|
|
}
|
|
|
|
TSE::Texture::~Texture()
|
|
{
|
|
if(bmp != nullptr)
|
|
{
|
|
FreeImage_Unload(bmp);
|
|
bmp = nullptr;
|
|
}
|
|
if(TextureID != 0)
|
|
{
|
|
//glDeleteTextures(1, &TextureID); --> need to do in platform openGL
|
|
PlatformDestroy();
|
|
TextureID = 0;
|
|
}
|
|
}
|
|
|
|
TSE::uint TSE::Texture::bpp() const
|
|
{
|
|
return Bpp;
|
|
}
|
|
|
|
TSE::Vector2 TSE::Texture::size() const
|
|
{
|
|
return Size;
|
|
}
|
|
|
|
float TSE::Texture::Width() const
|
|
{
|
|
return Size.x;
|
|
}
|
|
|
|
float TSE::Texture::Height() const
|
|
{
|
|
return Size.y;
|
|
}
|
|
|
|
TSE::byte TSE::Texture::Chanels() const
|
|
{
|
|
return chanels;
|
|
}
|
|
|
|
TSE::byte *TSE::Texture::GetImagePtr() const
|
|
{
|
|
return imagePtr;
|
|
}
|
|
|
|
void TSE::Texture::SetPixel(const Vector2 &pos, const Color &c)
|
|
{
|
|
SetPixel(pos.x, pos.y, c);
|
|
}
|
|
|
|
void TSE::Texture::GetPixel(const Vector2 &pos, Color &c) const
|
|
{
|
|
GetPixel(pos.x, pos.y, c);
|
|
}
|
|
|
|
void TSE::Texture::SetPixelNoApply(const Vector2 &pos, const Color &c)
|
|
{
|
|
SetPixelNoApply(pos.x, pos.y, c);
|
|
}
|
|
|
|
void TSE::Texture::ToSprite(Sprite &s)
|
|
{
|
|
s = Sprite(this, Rect(0,0,1,1));
|
|
}
|
|
|
|
void TSE::Texture::SetChanels(const byte &ch)
|
|
{
|
|
chanels = ch;
|
|
}
|
|
|
|
TSE::uint TSE::Texture::GetTextureId() const
|
|
{
|
|
return TextureID;
|
|
}
|
|
|
|
void TSE::Texture::SetTextureId(uint id)
|
|
{
|
|
TextureID = id;
|
|
}
|
|
|
|
void TSE::Texture::SetPixel(const int &x, const int &y, const Color &c)
|
|
{
|
|
SetPixelNoApply(x,y,c);
|
|
Apply();
|
|
}
|
|
|
|
void TSE::Texture::GetPixel(const int &x, const int &y, Color &c) const
|
|
{
|
|
if(x >= Width() || x < 0 ||y >= Height() || y < 0)
|
|
{
|
|
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) );
|
|
return;
|
|
}
|
|
byte* pixel = getPixelPointer(x,y);
|
|
byte b = *pixel++;
|
|
byte g = *pixel++;
|
|
byte r = *pixel++;
|
|
byte a = *pixel++;
|
|
if(bpp() == 8)
|
|
c = Color(r,r,r);
|
|
else if(bpp() == 24)
|
|
c = Color(r,g,b,a);
|
|
else if(bpp() == 32)
|
|
c = Color(r,g,b);
|
|
}
|
|
|
|
void TSE::Texture::Fill(const Color &c)
|
|
{
|
|
for (int x = 0; x < Width(); x++)
|
|
{
|
|
for (int y = 0; y < Height(); y++)
|
|
{
|
|
SetPixelNoApply(x,y,c);
|
|
}
|
|
|
|
}
|
|
Apply();
|
|
}
|
|
|
|
void TSE::Texture::SetPixelNoApply(const int &x, const int &y, const Color &c)
|
|
{
|
|
if(x >= Width() || x < 0 ||y >= Height() || y < 0)
|
|
{
|
|
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) );
|
|
return;
|
|
}
|
|
|
|
byte* pixel = getPixelPointer(x,y);
|
|
if(chanels == 4 && bpp() == 8)
|
|
{
|
|
byte r2bit = static_cast<byte>(c.r * 3.0f);
|
|
byte g2bit = static_cast<byte>(c.g * 3.0f);
|
|
byte b2bit = static_cast<byte>(c.b * 3.0f);
|
|
byte a2bit = static_cast<byte>(c.a * 3.0f);
|
|
|
|
byte result = (r2bit << 6) | (g2bit << 4) | (b2bit << 2) | a2bit;
|
|
*pixel++ = result;
|
|
return;
|
|
}
|
|
*pixel++ = c.B();
|
|
if(bpp() > 8)
|
|
{
|
|
*pixel++ = c.G();
|
|
*pixel++ = c.R();
|
|
if(bpp() > 24)
|
|
*pixel++ = c.A();
|
|
}
|
|
}
|
|
|
|
void TSE::Texture::AddPixelNoApply(const int &x, const int &y, const Color &c)
|
|
{
|
|
if(x >= Width() || x < 0 ||y >= Height() || y < 0)
|
|
{
|
|
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) );
|
|
return;
|
|
}
|
|
|
|
byte* pixel = getPixelPointer(x,y);
|
|
if(chanels == 4 && bpp() == 8) //TODO add propper adding, becouse currently is only setting
|
|
{
|
|
byte r2bit = static_cast<byte>(c.r * 3.0f);
|
|
byte g2bit = static_cast<byte>(c.g * 3.0f);
|
|
byte b2bit = static_cast<byte>(c.b * 3.0f);
|
|
byte a2bit = static_cast<byte>(c.a * 3.0f);
|
|
|
|
byte result = (r2bit << 6) | (g2bit << 4) | (b2bit << 2) | a2bit;
|
|
*pixel++ = result;
|
|
return;
|
|
}
|
|
Color bc(pixel[2], pixel[1], pixel[0], pixel[3]);
|
|
|
|
bc = c + bc;
|
|
|
|
*pixel++ = bc.B();
|
|
if(bpp() > 8)
|
|
{
|
|
*pixel++ = bc.G();
|
|
*pixel++ = bc.R();
|
|
if(bpp() > 24)
|
|
*pixel++ = bc.A();
|
|
}
|
|
}
|
|
|
|
void TSE::Texture::Recreate(const int &x, const int &y, const int &bpp, const int &chanels)
|
|
{
|
|
if(bmp != nullptr)
|
|
{
|
|
FreeImage_Unload(bmp);
|
|
bmp = nullptr;
|
|
}
|
|
if(TextureID != 0)
|
|
{
|
|
PlatformDestroy();
|
|
TextureID = 0;
|
|
}
|
|
this->chanels = chanels;
|
|
Bpp = bpp;
|
|
Size = Vector2(x, y);
|
|
bmp = FreeImage_Allocate(x, y, bpp);
|
|
imagePtr = FreeImage_GetBits(bmp);
|
|
regist();
|
|
}
|
|
|
|
void TSE::Texture::SavePNG(const std::string &path) const
|
|
{
|
|
if(!FreeImage_Save(FREE_IMAGE_FORMAT::FIF_PNG, bmp, path.c_str(), PNG_Z_NO_COMPRESSION))
|
|
TSE_ERROR("Failed to save Image to \"" + path + "\"");
|
|
}
|
|
|
|
TSE::byte *TSE::Texture::getPixelPointer(const int &x, const int &y) const
|
|
{
|
|
int alphaoffset = y * 2;
|
|
if(bpp() > 24)
|
|
alphaoffset = 0;
|
|
int offset = ((y * Width() + x) * (bpp() / 8) + alphaoffset);
|
|
return imagePtr + offset;
|
|
}
|
|
|
|
void TSE::Texture::makeError(Texture &tex)
|
|
{
|
|
tex.Bpp = errorTexBpp;
|
|
tex.chanels = errorTexChannels;
|
|
tex.Size = Vector2(errorTexWidth, errorTexHeight);
|
|
|
|
tex.bmp = FreeImage_ConvertFromRawBits(
|
|
const_cast<BYTE*>(errorTextureData), // wichtig: cast!
|
|
errorTexWidth,
|
|
errorTexHeight,
|
|
errorTexWidth * errorTexChannels,
|
|
errorTexBpp,
|
|
FI_RGBA_RED_MASK,
|
|
FI_RGBA_GREEN_MASK,
|
|
FI_RGBA_BLUE_MASK,
|
|
true // top-down
|
|
);
|
|
|
|
tex.imagePtr = FreeImage_GetBits(tex.bmp);
|
|
tex.regist();
|
|
}
|
|
|
|
void TSE::Texture::bind() const
|
|
{
|
|
helper->Bind(this);
|
|
}
|
|
|
|
void TSE::Texture::unbind() const
|
|
{
|
|
helper->UnBind(this);
|
|
}
|
|
|
|
void TSE::Texture::Apply()
|
|
{
|
|
helper->Apply(this);
|
|
}
|
|
|
|
void TSE::Texture::regist()
|
|
{
|
|
helper->Regist(this);
|
|
}
|
|
|
|
void TSE::Texture::PlatformDestroy()
|
|
{
|
|
helper->PlatromDestroy(this);
|
|
}
|