430 lines
11 KiB
C++
430 lines
11 KiB
C++
#include "VolumeTexture3D.hpp"
|
|
#include "Debug.hpp"
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <filesystem>
|
|
#include <vector>
|
|
|
|
TSE::VolumeTexture3D::VolumeTexture3D(const string &path)
|
|
{
|
|
namespace fs = std::filesystem;
|
|
|
|
Size = Vector3(0, 0, 0);
|
|
Bpp = 0;
|
|
|
|
std::error_code ec;
|
|
const fs::path folderPath = fs::absolute(path, ec);
|
|
if(ec || !fs::exists(folderPath, ec))
|
|
{
|
|
TSE_WARNING("Can't create VolumeTexture3D because the given path is inaccessible: \n" + path);
|
|
return;
|
|
}
|
|
|
|
if(ec || !fs::is_directory(folderPath, ec))
|
|
{
|
|
TSE_WARNING("Can't create VolumeTexture3D because the given path is not a folder: \n" + folderPath.string());
|
|
return;
|
|
}
|
|
|
|
std::vector<fs::path> pngFiles;
|
|
for(fs::directory_iterator it(folderPath, ec); !ec && it != fs::directory_iterator(); it.increment(ec))
|
|
{
|
|
if(!it->is_regular_file(ec))
|
|
continue;
|
|
|
|
const fs::path &filePath = it->path();
|
|
auto extension = filePath.extension().string();
|
|
std::transform(extension.begin(), extension.end(), extension.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
|
if(extension == ".png")
|
|
pngFiles.push_back(filePath);
|
|
}
|
|
|
|
if(ec)
|
|
{
|
|
TSE_WARNING("Can't read VolumeTexture3D folder: \n" + folderPath.string());
|
|
return;
|
|
}
|
|
|
|
if(pngFiles.empty())
|
|
{
|
|
TSE_WARNING("Can't create VolumeTexture3D because the folder contains no png files: \n" + folderPath.string());
|
|
return;
|
|
}
|
|
|
|
std::sort(pngFiles.begin(), pngFiles.end());
|
|
|
|
std::vector<FIBITMAP*> loadedBitmaps;
|
|
loadedBitmaps.reserve(pngFiles.size());
|
|
|
|
uint width = 0;
|
|
uint height = 0;
|
|
|
|
for(const fs::path &filePath : pngFiles)
|
|
{
|
|
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filePath.string().c_str(), 0);
|
|
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN)
|
|
fif = FreeImage_GetFIFFromFilename(filePath.string().c_str());
|
|
|
|
if(fif == FREE_IMAGE_FORMAT::FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif))
|
|
{
|
|
TSE_WARNING("Failed to load png for VolumeTexture3D: \n" + filePath.string());
|
|
for(FIBITMAP* loadedBmp : loadedBitmaps)
|
|
FreeImage_Unload(loadedBmp);
|
|
return;
|
|
}
|
|
|
|
FIBITMAP* currentBmp = FreeImage_Load(fif, filePath.string().c_str());
|
|
if(currentBmp == nullptr)
|
|
{
|
|
TSE_WARNING("Failed to load png for VolumeTexture3D: \n" + filePath.string());
|
|
for(FIBITMAP* loadedBmp : loadedBitmaps)
|
|
FreeImage_Unload(loadedBmp);
|
|
return;
|
|
}
|
|
|
|
if(FreeImage_GetBPP(currentBmp) != 32)
|
|
{
|
|
FIBITMAP* convertedBmp = FreeImage_ConvertTo32Bits(currentBmp);
|
|
FreeImage_Unload(currentBmp);
|
|
currentBmp = convertedBmp;
|
|
}
|
|
|
|
if(currentBmp == nullptr)
|
|
{
|
|
TSE_WARNING("Failed to convert png for VolumeTexture3D: \n" + filePath.string());
|
|
for(FIBITMAP* loadedBmp : loadedBitmaps)
|
|
FreeImage_Unload(loadedBmp);
|
|
return;
|
|
}
|
|
|
|
const uint currentWidth = FreeImage_GetWidth(currentBmp);
|
|
const uint currentHeight = FreeImage_GetHeight(currentBmp);
|
|
if(loadedBitmaps.empty())
|
|
{
|
|
width = currentWidth;
|
|
height = currentHeight;
|
|
}
|
|
else if(currentWidth != width || currentHeight != height)
|
|
{
|
|
TSE_WARNING("Can't create VolumeTexture3D because all pngs must have the same dimensions: \n" + filePath.string());
|
|
FreeImage_Unload(currentBmp);
|
|
for(FIBITMAP* loadedBmp : loadedBitmaps)
|
|
FreeImage_Unload(loadedBmp);
|
|
return;
|
|
}
|
|
|
|
loadedBitmaps.push_back(currentBmp);
|
|
}
|
|
|
|
Bpp = 32;
|
|
chanels = 4;
|
|
Size = Vector3(width, height, static_cast<float>(loadedBitmaps.size()));
|
|
bmp = new FIBITMAP*[loadedBitmaps.size()];
|
|
imagePtr = new byte*[loadedBitmaps.size()];
|
|
|
|
for(size_t i = 0; i < loadedBitmaps.size(); ++i)
|
|
{
|
|
bmp[i] = loadedBitmaps[i];
|
|
imagePtr[i] = FreeImage_GetBits(bmp[i]);
|
|
}
|
|
|
|
regist();
|
|
}
|
|
|
|
TSE::VolumeTexture3D::VolumeTexture3D(const int &width, const int &height, const int &depth, int bpp)
|
|
{
|
|
switch (bpp)
|
|
{
|
|
case 32:
|
|
chanels = 4;
|
|
break;
|
|
case 24:
|
|
chanels = 3;
|
|
case 16:
|
|
chanels = 1;
|
|
case 8:
|
|
chanels = 4;
|
|
}
|
|
Bpp = bpp;
|
|
Size = Vector3(width, height, depth);
|
|
bmp = new FIBITMAP*[depth];
|
|
imagePtr = new byte*[depth];
|
|
|
|
for(int i = 0; i < Depth(); i++)
|
|
{
|
|
bmp[i] = FreeImage_Allocate(width, height, bpp);
|
|
imagePtr[i] = FreeImage_GetBits(bmp[i]);
|
|
}
|
|
regist();
|
|
}
|
|
|
|
TSE::VolumeTexture3D::VolumeTexture3D(const Vector3 &size, int bpp)
|
|
: VolumeTexture3D(size.x, size.y, size.z, bpp) { }
|
|
|
|
TSE::VolumeTexture3D::~VolumeTexture3D()
|
|
{
|
|
if(bmp != nullptr)
|
|
{
|
|
for(int i = 0; i < Depth(); i++)
|
|
{
|
|
if(bmp[i] != nullptr)
|
|
{
|
|
FreeImage_Unload(bmp[i]);
|
|
bmp[i] = nullptr;
|
|
}
|
|
}
|
|
delete [] bmp;
|
|
delete [] imagePtr;
|
|
}
|
|
if(TextureID != 0)
|
|
{
|
|
PlatformDestroy();
|
|
TextureID = 0;
|
|
}
|
|
}
|
|
|
|
TSE::uint TSE::VolumeTexture3D::bpp() const
|
|
{
|
|
return Bpp;
|
|
}
|
|
|
|
TSE::Vector2 TSE::VolumeTexture3D::size() const
|
|
{
|
|
return Vector2(Size.x, Size.y);
|
|
}
|
|
|
|
float TSE::VolumeTexture3D::Width() const
|
|
{
|
|
return Size.x;
|
|
}
|
|
|
|
float TSE::VolumeTexture3D::Height() const
|
|
{
|
|
return Size.y;
|
|
}
|
|
|
|
float TSE::VolumeTexture3D::Depth() const
|
|
{
|
|
return Size.z;
|
|
}
|
|
|
|
TSE::byte TSE::VolumeTexture3D::Chanels() const
|
|
{
|
|
return chanels;
|
|
}
|
|
|
|
TSE::byte *TSE::VolumeTexture3D::GetImagePtr(const int depth) const
|
|
{
|
|
return imagePtr[depth];
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SetPixel(const Vector3 &pos, const Color &c)
|
|
{
|
|
SetPixel(pos.x, pos.y, pos.z, c);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::GetPixel(const Vector3 &pos, Color &c) const
|
|
{
|
|
GetPixel(pos.x, pos.y, pos.z, c);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SetPixelNoApply(const Vector3 &pos, const Color &c)
|
|
{
|
|
SetPixelNoApply(pos.x, pos.y, pos.z, c);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SetChanels(const byte &ch)
|
|
{
|
|
chanels = ch;
|
|
}
|
|
|
|
TSE::uint TSE::VolumeTexture3D::GetTextureId() const
|
|
{
|
|
return TextureID;
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SetTextureId(uint id)
|
|
{
|
|
TextureID = id;
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SetPixel(const int &x, const int &y, const int &z, const Color &c)
|
|
{
|
|
SetPixelNoApply(x,y,z,c);
|
|
Apply();
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::GetPixel(const int &x, const int &y, const int &z, Color &c) const
|
|
{
|
|
|
|
if(x >= Width() || x < 0 || y >= Height() || y < 0|| z >= Depth() || z < 0)
|
|
{
|
|
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ";" + std::to_string(z) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) + ";" + std::to_string(Depth()) );
|
|
return;
|
|
}
|
|
byte* pixel = getPixelPointer(x,y,z);
|
|
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::VolumeTexture3D::Fill(const Color &c)
|
|
{
|
|
for (int x = 0; x < Width(); x++)
|
|
{
|
|
for (int y = 0; y < Height(); y++)
|
|
{
|
|
for (int z = 0; z < Depth(); z++)
|
|
{
|
|
SetPixelNoApply(x,y,z,c);
|
|
}
|
|
}
|
|
}
|
|
Apply();
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SetPixelNoApply(const int &x, const int &y, const int &z, const Color &c)
|
|
{
|
|
if(x >= Width() || x < 0 || y >= Height() || y < 0 || z >= Depth() || z < 0)
|
|
{
|
|
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ";" + std::to_string(z) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) + ";" + std::to_string(Depth()) );
|
|
return;
|
|
}
|
|
|
|
byte* pixel = getPixelPointer(x,y,z);
|
|
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::VolumeTexture3D::AddPixelNoApply(const int &x, const int &y, const int &z, const Color &c)
|
|
{
|
|
if(x >= Width() || x < 0 ||y >= Height() || y < 0 || z >= Depth() || z < 0)
|
|
{
|
|
TSE_WARNING("trying to access pixel outside of texture.\n pixel: (" + std::to_string(x) + ";" + std::to_string(y) + ";" + std::to_string(z) + ")\nTexture size: (" + std::to_string(Width()) + ";" + std::to_string(Height()) + ";" + std::to_string(Depth()) );
|
|
return;
|
|
}
|
|
|
|
byte* pixel = getPixelPointer(x,y,z);
|
|
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::VolumeTexture3D::Recreate(const int &x, const int &y, const int &z, const int &bpp, const int &chanels)
|
|
{
|
|
if(bmp != nullptr)
|
|
{
|
|
for(int i = 0; i < Depth(); i++)
|
|
{
|
|
if(bmp[i] != nullptr)
|
|
{
|
|
FreeImage_Unload(bmp[i]);
|
|
bmp[i] = nullptr;
|
|
}
|
|
}
|
|
delete [] bmp;
|
|
delete [] imagePtr;
|
|
}
|
|
if(TextureID != 0)
|
|
{
|
|
PlatformDestroy();
|
|
TextureID = 0;
|
|
}
|
|
this->chanels = chanels;
|
|
Bpp = bpp;
|
|
Size = Vector3(x, y, z);
|
|
bmp = new FIBITMAP*[z];
|
|
imagePtr = new byte*[z];
|
|
|
|
for(int i = 0; i < Depth(); i++)
|
|
{
|
|
bmp[i] = FreeImage_Allocate(x, y, bpp);
|
|
imagePtr[i] = FreeImage_GetBits(bmp[i]);
|
|
}
|
|
|
|
regist();
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::SavePNG(const std::string &path) const
|
|
{
|
|
//TODO: implement save all images as PNG in the given path, if the given path is inaccaseable, or not a folder, ust TSE_WARNING with an apropriate message
|
|
}
|
|
|
|
TSE::byte *TSE::VolumeTexture3D::getPixelPointer(const int &x, const int &y, const int &z) const
|
|
{
|
|
int alphaoffset = y * 2;
|
|
if(bpp() > 24)
|
|
alphaoffset = 0;
|
|
int offset = ((y * Width() + x) * (bpp() / 8) + alphaoffset);
|
|
return imagePtr[z] + offset;
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::bind() const
|
|
{
|
|
helper->Bind3D(this);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::unbind() const
|
|
{
|
|
helper->UnBind3D(this);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::Apply()
|
|
{
|
|
helper->Apply3D(this);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::regist()
|
|
{
|
|
helper->Regist3D(this);
|
|
}
|
|
|
|
void TSE::VolumeTexture3D::PlatformDestroy()
|
|
{
|
|
helper->PlatromDestroy3D(this);
|
|
}
|