#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(c.r * 3.0f); byte g2bit = static_cast(c.g * 3.0f); byte b2bit = static_cast(c.b * 3.0f); byte a2bit = static_cast(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(c.r * 3.0f); byte g2bit = static_cast(c.g * 3.0f); byte b2bit = static_cast(c.b * 3.0f); byte a2bit = static_cast(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(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); }