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:
786
Texture.cpp
786
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<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 "";
|
||||
};
|
||||
*/
|
||||
Reference in New Issue
Block a user