#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); } TSE::Texture TSE::Texture::CutOut(const Vector2 &pos, Vector2 &size) const { Texture result = Texture(0,0); if(bmp == nullptr) { TSE_ERROR("Failed to cut out texture. Source bitmap was nullptr."); Texture::makeError(result); return result; } const int left = static_cast(pos.x); const int top = static_cast(pos.y); const int width = static_cast(size.x); const int height = static_cast(size.y); if(width <= 0 || height <= 0) { TSE_ERROR("Failed to cut out texture. Size must be greater than 0."); Texture::makeError(result); return result; } const int texWidth = static_cast(Width()); const int texHeight = static_cast(Height()); if(left < 0 || top < 0 || left + width > texWidth || top + height > texHeight) { TSE_ERROR("Failed to cut out texture. Region out of bounds."); Texture::makeError(result); return result; } FIBITMAP* cut = FreeImage_Copy(bmp, left, top, left + width, top + height); if(cut == nullptr) { TSE_ERROR("Failed to cut out texture. FreeImage_Copy returned nullptr."); Texture::makeError(result); return result; } Texture out = Texture(width, height, Bpp); if(out.bmp != nullptr) FreeImage_Unload(out.bmp); out.bmp = cut; out.imagePtr = FreeImage_GetBits(cut); out.Bpp = Bpp; out.chanels = chanels; out.Size = Vector2(width, height); out.Apply(); return out; } void TSE::Texture::PasteIn(const Vector2 &pos, Texture &t) { if(bmp == nullptr) { TSE_ERROR("Failed to paste texture. Destination bitmap was nullptr."); return; } if(t.bmp == nullptr) { TSE_ERROR("Failed to paste texture. Source bitmap was nullptr."); return; } if(Bpp != t.Bpp) { TSE_ERROR("Failed to paste texture. Source and destination Bpp do not match."); return; } const int left = static_cast(pos.x); const int top = static_cast(pos.y); const int srcWidth = static_cast(t.Width()); const int srcHeight = static_cast(t.Height()); const int texWidth = static_cast(Width()); const int texHeight = static_cast(Height()); if(left < 0 || top < 0 || left + srcWidth > texWidth || top + srcHeight > texHeight) { TSE_ERROR("Failed to paste texture. Region out of bounds."); return; } if(!FreeImage_Paste(bmp, t.bmp, left, top, 256)) { TSE_ERROR("Failed to paste texture. FreeImage_Paste returned false."); return; } imagePtr = FreeImage_GetBits(bmp); Apply(); } 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); }