16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 21:29:18 +02:00

converted remaining image loaders

This commit is contained in:
tmj-fstate
2017-02-12 23:28:30 +01:00
parent a8ece11c27
commit 1b2b3b06e7
2 changed files with 275 additions and 517 deletions

View File

@@ -48,11 +48,9 @@ opengl_texture::load() {
std::string const extension = name.substr( name.size() - 3, 3 );
if( extension == "dds" ) { load_DDS(); }
/*
else if( extension == "tga" ) { load_TGA(); }
else if( extension == "tex" ) { load_TEX(); }
else if( extension == "bmp" ) { load_BMP(); }
*/
else if( extension == "tex" ) { load_TEX(); }
else { goto fail; }
}
@@ -68,6 +66,64 @@ fail:
return;
}
void
opengl_texture::load_BMP() {
std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws );
BITMAPFILEHEADER header;
file.read( (char *)&header, sizeof( BITMAPFILEHEADER ) );
if( file.eof() ) {
data_state = resource_state::failed;
return;
}
// Read in bitmap information structure
BITMAPINFO info;
unsigned int infosize = header.bfOffBits - sizeof( BITMAPFILEHEADER );
if( infosize > sizeof( info ) ) {
WriteLog( "Warning - BMP header is larger than expected, possible format difference." );
}
file.read( (char *)&info, std::min( infosize, sizeof( info ) ) );
data_width = info.bmiHeader.biWidth;
data_height = info.bmiHeader.biHeight;
if( info.bmiHeader.biCompression != BI_RGB ) {
ErrorLog( "Compressed BMP textures aren't supported." );
data_state = resource_state::failed;
return;
}
unsigned long datasize = info.bmiHeader.biSizeImage;
if( 0 == datasize ) {
// calculate missing info
datasize = ( data_width * info.bmiHeader.biBitCount + 7 ) / 8 * data_height;
}
data.resize( datasize );
file.read( &data[0], datasize );
// fill remaining data info
if( info.bmiHeader.biBitCount == 32 ) {
data_format = GL_BGRA;
data_components = GL_RGBA;
}
else {
data_format = GL_BGR;
data_components = GL_RGB;
}
data_mapcount = 1;
data_state = resource_state::good;
return;
}
void
opengl_texture::load_DDS() {
@@ -138,9 +194,11 @@ opengl_texture::load_DDS() {
data_state = resource_state::failed;
return;
}
/*
// this approach loads only the first mipmap and relies on graphics card to fill the rest
int datasize = ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize;
*/
int datasize = filesize - offset;
// int datasize = ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize;
/*
// calculate size of accepted data
// NOTE: this is a fallback, as we should be able to just move the file caret by calculated offset and read the rest
@@ -176,6 +234,193 @@ opengl_texture::load_DDS() {
return;
}
void
opengl_texture::load_TEX() {
std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws );
char head[ 5 ];
file.read( head, 4 );
head[ 4 ] = 0;
bool hasalpha;
if( std::string( "RGB " ) == head ) {
hasalpha = false;
}
else if( std::string( "RGBA" ) == head ) {
hasalpha = true;
}
else {
ErrorLog( "Unrecognized TEX texture sub-format: " + std::string(head) );
data_state = resource_state::failed;
return;
};
file.read( (char *)&data_width, sizeof( int ) );
file.read( (char *)&data_height, sizeof( int ) );
std::size_t datasize = data_width * data_height * ( hasalpha ? 4 : 3 );
data.resize( datasize );
file.read( reinterpret_cast<char *>( &data[0] ), datasize );
// fill remaining data info
if( true == hasalpha ) {
data_format = GL_BGRA;
data_components = GL_RGBA;
}
else {
data_format = GL_BGR;
data_components = GL_RGB;
}
data_mapcount = 1;
data_state = resource_state::good;
return;
}
void
opengl_texture::load_TGA() {
std::ifstream file( name, std::ios::binary ); file.unsetf( std::ios::skipws );
// Read the header of the TGA, compare it with the known headers for compressed and uncompressed TGAs
unsigned char tgaheader[ 18 ];
file.read( (char *)tgaheader, sizeof( unsigned char ) * 18 );
while( tgaheader[ 0 ] > 0 ) {
--tgaheader[ 0 ];
unsigned char temp;
file.read( (char *)&temp, sizeof( unsigned char ) );
}
data_width = tgaheader[ 13 ] * 256 + tgaheader[ 12 ];
data_height = tgaheader[ 15 ] * 256 + tgaheader[ 14 ];
int const bytesperpixel = tgaheader[ 16 ] / 8;
// check whether width, height an BitsPerPixel are valid
if( ( data_width <= 0 )
|| ( data_height <= 0 )
|| ( ( bytesperpixel != 1 ) && ( bytesperpixel != 3 ) && ( bytesperpixel != 4 ) ) ) {
data_state = resource_state::failed;
return;
}
// allocate the data buffer
int const datasize = data_width * data_height * 4;
data.resize( datasize );
// call the appropriate loader-routine
if( tgaheader[ 2 ] == 2 ) {
// uncompressed TGA
if( bytesperpixel == 4 ) {
// read the data directly
file.read( reinterpret_cast<char*>( &data[ 0 ] ), datasize );
}
else {
// rgb or greyscale image, expand to bgra
unsigned char buffer[ 4 ] = { 255, 255, 255, 255 }; // alpha channel will be white
unsigned int *datapointer = (unsigned int*)&data[ 0 ];
unsigned int *bufferpointer = (unsigned int*)&buffer[ 0 ];
int const pixelcount = data_width * data_height;
for( int i = 0; i < pixelcount; ++i ) {
file.read( (char *)buffer, sizeof( unsigned char ) );
if( bytesperpixel == 1 ) {
// expand greyscale data
buffer[ 1 ] = buffer[ 0 ];
buffer[ 2 ] = buffer[ 0 ];
}
// copy all four values in one operation
( *datapointer ) = ( *bufferpointer );
++datapointer;
}
}
}
else if( tgaheader[ 2 ] == 10 ) {
// compressed TGA
int currentpixel = 0;
int currentbyte = 0;
unsigned char buffer[ 4 ] = { 255, 255, 255, 255 };
const int pixelcount = data_width * data_height;
unsigned int *datapointer = (unsigned int *)&data[ 0 ];
unsigned int *bufferpointer = (unsigned int *)&buffer[ 0 ];
do {
unsigned char chunkheader = 0;
file.read( (char *)&chunkheader, sizeof( unsigned char ) );
if( chunkheader < 128 ) {
// if the header is < 128, it means it is the number of RAW color packets minus 1
// that follow the header
// add 1 to get number of following color values
++chunkheader;
// read RAW color values
for( int i = 0; i < (int)chunkheader; ++i ) {
file.read( (char *)&buffer[ 0 ], bytesperpixel );
if( bytesperpixel == 1 ) {
// expand greyscale data
buffer[ 1 ] = buffer[ 0 ];
buffer[ 2 ] = buffer[ 0 ];
}
// copy all four values in one operation
( *datapointer ) = ( *bufferpointer );
++datapointer;
++currentpixel;
}
}
else {
// chunkheader > 128 RLE data, next color reapeated (chunkheader - 127) times
chunkheader -= 127; // Subteact 127 to get rid of the ID bit
// read the current color
file.read( (char *)&buffer[ 0 ], bytesperpixel );
if( bytesperpixel == 1 ) {
// expand greyscale data
buffer[ 1 ] = buffer[ 0 ];
buffer[ 2 ] = buffer[ 0 ];
}
// copy the color into the image data as many times as dictated
for( int i = 0; i < (int)chunkheader; ++i ) {
( *datapointer ) = ( *buffer );
++datapointer;
++currentpixel;
}
}
} while( currentpixel < pixelcount );
}
else {
// unrecognized TGA sub-type
data_state = resource_state::failed;
return;
}
// fill remaining data info
data_mapcount = 1;
data_format = GL_BGRA;
data_components =
( bytesperpixel == 4 ?
GL_RGBA :
GL_RGB );
data_state = resource_state::good;
return;
}
void
opengl_texture::create() {
@@ -200,7 +445,6 @@ opengl_texture::create() {
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
}
// upload texture data
// TBD, TODO: handle mipmaps other than base manually, or let the card take care of it?
int dataoffset = 0,
datasize = 0,
datawidth = data_width,
@@ -211,24 +455,28 @@ opengl_texture::create() {
|| ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT )
|| ( data_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) ) {
// compressed dds formats
if( false == Global::bDecompressDDS ) {
// let the openGL handle this
int const datablocksize =
( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ?
8 :
16 );
int const datablocksize =
( data_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ?
8 :
16 );
datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize;
datasize = ( ( std::max(datawidth, 4) + 3 ) / 4 ) * ( ( std::max(dataheight, 4) + 3 ) / 4 ) * datablocksize;
glCompressedTexImage2D(
GL_TEXTURE_2D, maplevel,
data_format, datawidth, dataheight, 0, datasize,
(GLubyte *)&data[0] + dataoffset );
glCompressedTexImage2D(
GL_TEXTURE_2D, maplevel, data_format,
datawidth, dataheight, 0,
datasize, (GLubyte *)&data[0] + dataoffset );
dataoffset += datasize;
datawidth = std::max( datawidth / 2, 1 );
dataheight = std::max( dataheight / 2, 1 );
}
dataoffset += datasize;
datawidth = std::max( datawidth / 2, 4 );
dataheight = std::max( dataheight / 2, 4 );
}
else{
// uncompressed texture data
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA8,
data_width, data_height, 0,
data_format, GL_UNSIGNED_BYTE, (GLubyte *)&data[0] );
}
}
}
@@ -268,67 +516,6 @@ void
texture_manager::Init() {
}
/*
TTexturesManager::Names::iterator TTexturesManager::LoadFromFile(std::string fileName, int filter)
{
std::string message("Loading - texture: ");
std::string realFileName(fileName);
std::ifstream file(fileName.c_str());
// Ra: niby bez tego jest lepiej, ale działa gorzej, więc przywrócone jest oryginalne
if (!file.is_open())
realFileName.insert(0, szTexturePath);
else
file.close();
// char* cFileName = const_cast<char*>(fileName.c_str());
message += realFileName;
WriteLog(message.c_str()); // Ra: chybaa miało być z komunikatem z przodu, a nie tylko nazwa
size_t pos = fileName.rfind('.');
std::string ext(fileName, pos + 1, std::string::npos);
AlphaValue texinfo;
if( ext == "dds" )
texinfo = LoadDDS( realFileName, filter );
else if( ext == "tga" )
texinfo = LoadTGA(realFileName, filter);
else if (ext == "tex")
texinfo = LoadTEX(realFileName);
else if (ext == "bmp")
texinfo = LoadBMP(realFileName);
_alphas.insert(
texinfo); // zapamiętanie stanu przezroczystości tekstury - można by tylko przezroczyste
std::pair<Names::iterator, bool> ret = _names.insert(std::make_pair(fileName, texinfo.first));
if (!texinfo.first)
{
WriteLog("Failed");
ErrorLog("Missed texture: " + realFileName);
return _names.end();
};
_alphas.insert(texinfo);
ret = _names.insert(
std::make_pair(fileName, texinfo.first)); // dodanie tekstury do magazynu (spisu nazw)
// WriteLog("OK"); //Ra: "OK" nie potrzeba, samo "Failed" wystarczy
return ret.first;
};
*/
/*
struct ReplaceSlash
{
const char operator()(const char input)
{
return input == '/' ? '\\' : input;
}
};
*/
// ustalenie numeru tekstury, wczytanie jeśli jeszcze takiej nie było
texture_manager::size_type
texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int const Filter, bool const Loadnow ) {
@@ -336,13 +523,13 @@ texture_manager::GetTextureId( std::string Filename, std::string const &Dir, int
if( Filename.find( ':' ) != std::string::npos )
Filename.erase( Filename.find( ':' ) ); // po dwukropku mogą być podane dodatkowe informacje niebędące nazwą tekstury
if( Filename.find( '|' ) != std::string::npos )
Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
if( Filename.rfind( '.' ) != std::string::npos )
Filename.erase( Filename.rfind( '.' ) ); // trim extension if there's one
for( char &c : Filename ) {
// change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh
c = ( c == '/' ? '\\' : c );
}
if( Filename.rfind('.')!= std::string::npos )
Filename.erase( Filename.find( '.' ) ); // trim extension if there's one
/*
std::transform(
Filename.begin(), Filename.end(),
@@ -461,7 +648,6 @@ texture_manager::find_on_disk( std::string const &Texturename ) {
// success
return Texturename;
}
}
// if we fail make a last ditch attempt in the default textures directory
{
@@ -470,431 +656,12 @@ texture_manager::find_on_disk( std::string const &Texturename ) {
// success
return szTexturePath + Texturename;
}
}
// no results either way, report failure
return "";
}
/*
bool TTexturesManager::GetAlpha(GLuint id)
{ // atrybut przezroczystości dla tekstury o podanym numerze (id)
Alphas::iterator iter = _alphas.find(id);
return (iter != _alphas.end() ? iter->second : false);
}
*/
/*
TTexturesManager::AlphaValue TTexturesManager::LoadBMP(std::string const &fileName)
{
AlphaValue fail(0, false);
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open())
{
// file.close();
return fail;
};
BITMAPFILEHEADER header;
file.read((char *)&header, sizeof(BITMAPFILEHEADER));
if (file.eof())
{
return fail;
}
// Read in bitmap information structure
BITMAPINFO info;
unsigned int infoSize = header.bfOffBits - sizeof(BITMAPFILEHEADER);
if( infoSize > sizeof( info ) ) {
WriteLog( "Warning - BMP header is larger than expected, possible format difference." );
}
file.read((char *)&info, std::min(infoSize, sizeof(info)));
if (file.eof())
{
return fail;
};
GLuint width = info.bmiHeader.biWidth;
GLuint height = info.bmiHeader.biHeight;
bool hasalpha = ( info.bmiHeader.biBitCount == 32 );
if( info.bmiHeader.biCompression != BI_RGB ) {
ErrorLog( "Compressed BMP textures aren't supported." );
return fail;
}
unsigned long bitSize = info.bmiHeader.biSizeImage;
if (!bitSize)
bitSize = (width * info.bmiHeader.biBitCount + 7) / 8 * height;
std::shared_ptr<GLubyte> data( new GLubyte[ bitSize ], std::default_delete<GLubyte[]>() );
file.read((char *)data.get(), bitSize);
if (file.eof())
{
return fail;
};
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
if( GLEW_VERSION_1_4 ) {
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
}
// This is specific to the binary format of the data read in.
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
// glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, data.get());
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA8,
width,
height,
0,
hasalpha ? GL_BGRA : GL_BGR,
GL_UNSIGNED_BYTE,
data.get() );
return std::make_pair(id, hasalpha);
};
TTexturesManager::AlphaValue TTexturesManager::LoadTGA(std::string fileName, int filter)
{
AlphaValue fail(0, false);
int writeback = -1; //-1 plik jest OK, >=0 - od którego bajtu zapisać poprawiony plik
GLubyte TGACompheader[] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // uncompressed TGA header
GLubyte TGAcompare[12]; // used to compare TGA header
GLubyte header[6]; // first 6 useful bytes from the header
std::fstream file(fileName.c_str(), std::ios::binary | std::ios::in);
file.read((char *)TGAcompare, sizeof(TGAcompare));
file.read((char *)header, sizeof(header));
// std::cout << file.tellg() << std::endl;
if (file.eof())
{
file.close();
return fail;
};
bool compressed = (memcmp(TGACompheader, TGAcompare, sizeof(TGACompheader)) == 0);
GLint width = header[1] * 256 + header[0]; // determine the TGA width (highbyte*256+lowbyte)
GLint height = header[3] * 256 + header[2]; // determine the TGA height (highbyte*256+lowbyte)
// check if width, height and bpp is correct
if (!width || !height || (header[4] != 24 && header[4] != 32))
{
WriteLog("Bad texture: " + fileName + " has wrong header or bits per pixel");
file.close();
return fail;
};
{ // sprawdzenie prawidłowości rozmiarów
int i, j;
for (i = width, j = 0; i; i >>= 1)
if (i & 1)
++j;
if (j == 1)
for (i = height, j = 0; i; i >>= 1)
if (i & 1)
++j;
if (j != 1)
WriteLog("Bad texture: " + fileName + " is " + std::to_string(width) + "×" + std::to_string(height) );
}
GLuint bpp = header[4]; // grab the TGA's bits per pixel (24 or 32)
GLuint bytesPerPixel = bpp / 8; // divide by 8 to get the bytes per pixel
GLuint imageSize =
width * height * bytesPerPixel; // calculate the memory required for the TGA data
GLubyte *imageData = new GLubyte[imageSize]; // reserve memory to hold the TGA data
if (!compressed)
{ // WriteLog("Not compressed.");
file.read(reinterpret_cast<char*>(imageData), imageSize);
if (file.eof())
{
delete[] imageData;
file.close();
return fail;
};
}
else
{ // skompresowany plik TGA
GLuint filesize; // current byte
GLuint colorbuffer[1]; // Storage for 1 pixel
file.seekg(0, std::ios::end); // na koniec
filesize = (int)file.tellg() - 18; // rozmiar bez nagłówka
file.seekg(18, std::ios::beg); // ponownie za nagłówkiem
GLubyte *copyto = imageData; // gdzie wstawiać w buforze
GLubyte *copyend = imageData + imageSize; // za ostatnim bajtem bufora
GLubyte *copyfrom = imageData + imageSize - filesize; // gdzie jest początek
int chunkheader = 0; // Ra: będziemy wczytywać najmłodszy bajt
if (filesize < imageSize) // jeśli po kompresji jest mniejszy niż przed
{ // Ra: nowe wczytywanie skompresowanych: czytamy całe od razu, dekompresja w pamięci
GLuint copybytes;
file.read(reinterpret_cast<char*>(copyfrom), filesize); // wczytanie reszty po nagłówku
// najpierw trzeba ustalić, ile skopiowanych pikseli jest na samym końcu
copyto = copyfrom; // roboczo przelatujemy wczytane dane
copybytes = 0; // licznik bajtów obrazka
while (copybytes < imageSize)
{
chunkheader = (unsigned char)*copyto; // jeden bajt, pozostałe zawsze zerowe
copyto += 1 + bytesPerPixel; // bajt licznika oraz jeden piksel jest zawsze
copybytes += (1 + (chunkheader & 127)) * bytesPerPixel; // ilość pikseli
if (chunkheader < 128) // jeśli kopiowanie, pikseli jest więcej
copyto += (chunkheader)*bytesPerPixel; // rozmiar kopiowanego obszaru (bez
// jednego piksela)
}
if (copybytes > imageSize)
{ // nie ma prawa być większe
WriteLog("Compression error");
delete[] imageData;
file.close();
return fail;
}
// na końcu mogą być śmieci
int extraend = copyend - copyto; // długość śmieci na końcu
if (extraend > 0)
{ // przesuwamy bufor do końca obszaru dekompresji
WriteLog("Extra bytes: " + std::to_string(extraend));
memmove(copyfrom + extraend, copyfrom, filesize - extraend);
copyfrom += extraend;
file.close();
filesize -= extraend; // to chyba nie ma znaczenia
if (Global::iModifyTGA & 2) // flaga obcinania śmieci
{ // najlepiej by było obciąć plik, ale fstream tego nie potrafi
int handle;
for( unsigned int i = 0; i < fileName.length(); ++i ) {
if( fileName[ i ] == '/' ) { fileName[ i ] = '\\'; } // bo to Windows }
}
WriteLog("Truncating extra bytes");
// NOTE: this posix code is unsafe, and being deprecated in visual c
// TODO: replace with something up to date
handle = open(fileName.c_str(), O_RDWR | O_BINARY);
chsize(handle, 18 + filesize); // obcięcie śmieci
close(handle);
extraend = 0; // skoro obcięty, to się już nie liczy
}
file.open(fileName.c_str(), std::ios::binary | std::ios::in);
}
if (chunkheader < 128) // jeśli ostatnie piksele są kopiowane
copyend -= (1 + chunkheader) *
bytesPerPixel; // bajty kopiowane na końcu nie podlegające dekompresji
else
copyend -= bytesPerPixel; // ostatni piksel i tak się nie zmieni
copyto = imageData; // teraz będzie wypełnianie od początku obszaru
while (copyto < copyend)
{
chunkheader = (unsigned char)*copyfrom; // jeden bajt, pozostałe zawsze zerowe
if (copyto > copyfrom)
{ // jeśli piksele mają być kopiowane, to możliwe jest przesunięcie ich o 1 bajt, na
// miejsce licznika
filesize = (imageData + imageSize - copyto) /
bytesPerPixel; // ile pikseli pozostało do końca
// WriteLog("Decompression buffer overflow at pixel
// "+AnsiString((copyto-imageData)/bytesPerPixel)+"+"+AnsiString(filesize));
// pozycję w pliku trzeba by zapamietać i po wczytaniu reszty pikseli starą
// metodą
// zapisać od niej dane od (copyto), poprzedzone bajtem o wartości (filesize-1)
writeback = imageData + imageSize + extraend -
copyfrom; // ile bajtów skompresowanych zostało do końca
copyfrom = copyto; // adres piksela do zapisania
file.seekg(-writeback, std::ios::end); // odległość od końca (ujemna)
if ((filesize > 128) ||
!(Global::iModifyTGA & 4)) // gdy za dużo pikseli albo wyłączone
writeback = -1; // zapis możliwe jeśli ilość problematycznych pikseli nie
// przekaracza 128
break; // bufor się zatkał, dalej w ten sposób się nie da
}
if (chunkheader < 128)
{ // dla nagłówka < 128 mamy podane ile pikseli przekopiować minus 1
copybytes = (++chunkheader) * bytesPerPixel; // rozmiar kopiowanego obszaru
memcpy(copyto, ++copyfrom, copybytes); // skopiowanie tylu bajtów
copyto += copybytes;
copyfrom += copybytes;
}
else
{ // chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times
chunkheader -= 127;
// copy the color into the image data as many times as dictated
if (bytesPerPixel == 4)
{ // przy czterech bajtach powinno być szybsze używanie int
__int32 *ptr = (__int32 *)(copyto); // wskaźnik na int
__int32 bgra = *((__int32 *)++copyfrom); // kolor wypełniający (4 bajty)
for (int counter = 0; counter < chunkheader; counter++)
*ptr++ = bgra;
copyto = reinterpret_cast<GLubyte *>(ptr); // rzutowanie, żeby nie dodawać
copyfrom += 4;
}
else
{
colorbuffer[0] = *((int *)(++copyfrom)); // pobranie koloru (3 bajty)
for (int counter = 0; counter < chunkheader; counter++)
{ // by the header
memcpy(copyto, colorbuffer, 3);
copyto += 3;
}
copyfrom += 3;
}
}
} // while (copyto<copyend)
}
else
{
WriteLog("Compressed file is larger than uncompressed!");
if (Global::iModifyTGA & 1)
writeback = 0; // no zapisać ten krótszy zaczynajac od początku...
}
// if (copyto<copyend) WriteLog("Slow loader...");
while (copyto < copyend)
{ // Ra: stare wczytywanie skompresowanych, z nadużywaniem file.read()
// również wykonywane, jeśli dekompresja w buforze przekroczy jego rozmiar
file.read((char *)&chunkheader, 1); // jeden bajt, pozostałe zawsze zerowe
if (file.eof())
{
MessageBox(NULL, "Could not read RLE header", "ERROR", MB_OK); // display error
delete[] imageData;
file.close();
return fail;
};
if (chunkheader < 128)
{ // if the header is < 128, it means the that is the number of RAW color packets minus
// 1
chunkheader++; // add 1 to get number of following color values
file.read(reinterpret_cast<char*>(copyto), chunkheader * bytesPerPixel);
copyto += chunkheader * bytesPerPixel;
}
else
{ // chunkheader>128 RLE data, next color reapeated (chunkheader-127) times
chunkheader -= 127;
file.read((char *)colorbuffer, bytesPerPixel);
// copy the color into the image data as many times as dictated
if (bytesPerPixel == 4)
{ // przy czterech bajtach powinno być szybsze używanie int
__int32 *ptr = (__int32 *)(copyto), bgra = *((__int32 *)colorbuffer);
for (int counter = 0; counter < chunkheader; counter++)
*ptr++ = bgra;
copyto = reinterpret_cast<GLubyte*>(ptr); // rzutowanie, żeby nie dodawać
}
else
for (int counter = 0; counter < chunkheader; counter++)
{ // by the header
memcpy(copyto, colorbuffer, bytesPerPixel);
copyto += bytesPerPixel;
}
}
} // while (copyto<copyend)
if (writeback >= 0)
{ // zapisanie pliku
file.close(); // tamten zamykamy, bo był tylko do odczytu
if (writeback)
{ // zapisanie samej końcówki pliku, która utrudnia dekompresję w buforze
WriteLog("Rewriting end of file...");
chunkheader = filesize - 1; // licznik jest o 1 mniejszy
file.open(fileName.c_str(), std::ios::binary | std::ios::out | std::ios::in);
file.seekg(-writeback, std::ios::end); // odległość od końca (ujemna)
file.write((char *)&chunkheader, 1); // zapisanie licznika
file.write(reinterpret_cast<char*>(copyfrom), filesize * bytesPerPixel); // piksele bez kompresji
}
else
{ // zapisywanie całości pliku, będzie krótszy, więc trzeba usunąć go w całości
WriteLog("Writing uncompressed file...");
TGAcompare[2] = 2; // bez kompresji
file.open(fileName.c_str(), std::ios::binary | std::ios::out | std::ios::trunc);
file.write((char *)TGAcompare, sizeof(TGAcompare));
file.write((char *)header, sizeof(header));
file.write(reinterpret_cast<char*>(imageData), imageSize);
}
}
};
file.close(); // plik zamykamy dopiero na samym końcu
bool alpha = (bpp == 32);
bool hash = (fileName.find('#') != std::string::npos); // true gdy w nazwie jest "#"
bool dollar = (fileName.find('$') == std::string::npos); // true gdy w nazwie nie ma "$"
size_t pos = fileName.rfind('%'); // ostatni % w nazwie
if (pos != std::string::npos)
if (pos < fileName.size())
{
filter = (int)fileName[pos + 1] - '0'; // zamiana cyfry za % na liczbę
if ((filter < 0) || (filter > 10))
filter = -1; // jeśli nie jest cyfrą
}
if (!alpha && !hash && dollar && (filter < 0))
filter = Global::iDefaultFiltering; // dotyczy tekstur TGA bez kanału alfa
// ewentualne przeskalowanie tekstury do dopuszczalnego rozumiaru
GLint w = width, h = height;
if (width > Global::iMaxTextureSize)
width = Global::iMaxTextureSize; // ogranizczenie wielkości
if (height > Global::iMaxTextureSize)
height = Global::iMaxTextureSize;
if ((w != width) || (h != height))
{ // przeskalowanie tekstury, żeby się nie wyświetlała jako biała
GLubyte *imgData = new GLubyte[width * height * bytesPerPixel]; // nowy rozmiar
gluScaleImage(bytesPerPixel == 3 ? GL_RGB : GL_RGBA, w, h, GL_UNSIGNED_BYTE, imageData,
width, height, GL_UNSIGNED_BYTE, imgData);
delete[] imageData; // usunięcie starego
imageData = imgData;
}
GLuint id = CreateTexture(imageData, (alpha ? GL_BGRA : GL_BGR), width, height, alpha, hash,
dollar, filter);
delete[] imageData;
++Global::iTextures;
return std::make_pair(id, alpha);
};
TTexturesManager::AlphaValue TTexturesManager::LoadTEX(std::string fileName)
{
AlphaValue fail(0, false);
std::ifstream file(fileName.c_str(), std::ios::binary);
char head[5];
file.read(head, 4);
head[4] = 0;
bool alpha;
if (std::string("RGB ") == head)
{
alpha = false;
}
else if (std::string("RGBA") == head)
{
alpha = true;
}
else
{
std::string message("Unrecognized texture format: ");
message += head;
Error(message.c_str());
return fail;
};
GLuint width;
GLuint height;
file.read((char *)&width, sizeof(int));
file.read((char *)&height, sizeof(int));
GLuint bpp = alpha ? 4 : 3;
GLuint size = width * height * bpp;
GLubyte *data = new GLubyte[size];
file.read(reinterpret_cast<char*>(data), size);
bool hash = (fileName.find('#') != std::string::npos);
GLuint id = CreateTexture(data, (alpha ? GL_RGBA : GL_RGB), width, height, alpha, hash);
delete[] data;
return std::make_pair(id, alpha);
};
TTexturesManager::AlphaValue TTexturesManager::LoadDDS(std::string fileName, int filter)
{
@@ -1163,12 +930,3 @@ texture_manager::Free()
glDeleteTextures( 1, &texture.id );
}
}
/*
std::string TTexturesManager::GetName(GLuint id)
{ // pobranie nazwy tekstury
for( auto const &pair : _names ) {
if( pair.second == id ) { return pair.first; }
}
return "";
};
*/