diff --git a/Texture.cpp b/Texture.cpp index 8893ce24..70dd9441 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -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( &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( &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(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 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 data( new GLubyte[ bitSize ], std::default_delete() ); - 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(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(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(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(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(ptr); // rzutowanie, żeby nie dodawać - } - else - for (int counter = 0; counter < chunkheader; counter++) - { // by the header - memcpy(copyto, colorbuffer, bytesPerPixel); - copyto += bytesPerPixel; - } - } - } // while (copyto= 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(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(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(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 ""; -}; -*/ \ No newline at end of file diff --git a/Texture.h b/Texture.h index e6082728..f975216c 100644 --- a/Texture.h +++ b/Texture.h @@ -41,10 +41,10 @@ struct opengl_texture { void create(); private: -// void load_BMP(); + void load_BMP(); void load_DDS(); -// void load_TEX(); -// void load_TGA(); + void load_TEX(); + void load_TGA(); void set_filtering(); };