/* Halflite Texture WAD */ IImage* CImageLoaderWAL2::loadImage(irr::io::IReadFile* file) const { miptex_halflife header; file->seek(0); file->read(&header, sizeof(header)); #ifdef __BIG_ENDIAN__ header.width = os::Byteswap::byteswap(header.width); header.height = os::Byteswap::byteswap(header.height); #endif // palette //u32 paletteofs = header.mipmap[0] + ((rawtexsize * 85) >> 6) + 2; u32 *pal = new u32 [ 192 + 256 ]; u8 *s = (u8*) pal; file->seek ( file->getSize() - 768 - 2 ); file->read ( s, 768 ); u32 i; for ( i = 0; i < 256; ++i, s+= 3 ) { pal [ 192 + i ] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2]; } ECOLOR_FORMAT format = ECF_R8G8B8; // transparency in filename;-) funny. rgb:0x0000FF is colorkey if ( file->getFileName().findFirst ( '{' ) >= 0 ) { format = ECF_A8R8G8B8; pal [ 192 + 255 ] &= 0x00FFFFFF; } u32 rawtexsize = header.width * header.height; u8 *rawtex = new u8 [ rawtexsize ]; file->seek ( header.mipmap[0] ); file->read(rawtex, rawtexsize); IImage* image = new CImage(format, core::dimension2d<u32>(header.width, header.height)); switch ( format ) { case ECF_R8G8B8: CColorConverter::convert8BitTo24Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) pal + 768, 0, false); break; case ECF_A8R8G8B8: CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) pal + 768, 0, false); break; } delete [] rawtex; delete [] pal; return image; }
/*! quake2 */ IImage* CImageLoaderWAL::loadImage(irr::io::IReadFile* file) const { miptex_quake2 header; file->seek(0); file->read(&header, sizeof(header)); #ifdef __BIG_ENDIAN__ header.width = os::Byteswap::byteswap(header.width); header.height = os::Byteswap::byteswap(header.height); #endif u32 rawtexsize = header.width * header.height; u8 *rawtex = new u8 [ rawtexsize ]; file->seek ( header.mipmap[0] ); file->read(rawtex, rawtexsize); IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.width, header.height)); CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) colormap_pcx, 0, false); delete [] rawtex; return image; }
/*! Quake1, Quake2, Hallife lmp texture */ IImage* CImageLoaderLMP::loadImage(irr::io::IReadFile* file) const { SLMPHeader header; file->seek(0); file->read(&header, sizeof(header)); // maybe palette file u32 rawtexsize = header.width * header.height; if ( rawtexsize + sizeof ( header ) != (u32)file->getSize() ) return 0; u8 *rawtex = new u8 [ rawtexsize ]; file->read(rawtex, rawtexsize); IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.width, header.height)); CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) colormap_h, 0, false); delete [] rawtex; return image; }
//! creates a surface from the file IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const { STGAHeader header; u32 *palette = 0; file->read(&header, sizeof(STGAHeader)); #ifdef __BIG_ENDIAN__ header.ColorMapLength = os::Byteswap::byteswap(header.ColorMapLength); header.ImageWidth = os::Byteswap::byteswap(header.ImageWidth); header.ImageHeight = os::Byteswap::byteswap(header.ImageHeight); #endif // skip image identification field if (header.IdLength) file->seek(header.IdLength, true); if (header.ColorMapType) { // create 32 bit palette palette = new u32[ header.ColorMapLength]; // read color map u8 * colorMap = new u8[header.ColorMapEntrySize/8 * header.ColorMapLength]; file->read(colorMap,header.ColorMapEntrySize/8 * header.ColorMapLength); // convert to 32-bit palette switch ( header.ColorMapEntrySize ) { case 16: CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette); break; case 24: CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette); break; case 32: CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette); break; } delete [] colorMap; } // read image u8* data = 0; if ( header.ImageType == 1 || // Uncompressed, color-mapped images. header.ImageType == 2 || // Uncompressed, RGB images header.ImageType == 3 // Uncompressed, black and white images ) { const s32 imageSize = header.ImageHeight * header.ImageWidth * header.PixelDepth/8; data = new u8[imageSize]; file->read(data, imageSize); } else if(header.ImageType == 10) { // Runlength encoded RGB images data = loadCompressedImage(file, header); } else { os::Printer::log("Unsupported TGA file type", file->getFileName(), ELL_ERROR); delete [] palette; return 0; } IImage* image = 0; switch(header.PixelDepth) { case 8: { if (header.ImageType==3) // grey image { image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert8BitTo24Bit((u8*)data, (u8*)image->getData(), header.ImageWidth,header.ImageHeight, 0, 0, (header.ImageDescriptor&0x20)==0); } else { image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert8BitTo16Bit((u8*)data, (s16*)image->getData(), header.ImageWidth,header.ImageHeight, (s32*) palette, 0, (header.ImageDescriptor&0x20)==0); } } break; case 16: image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert16BitTo16Bit((s16*)data, (s16*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0); break; case 24: image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert24BitTo24Bit( (u8*)data, (u8*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0, true); break; case 32: image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert32BitTo32Bit((s32*)data, (s32*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0); break; default: os::Printer::log("Unsupported TGA format", file->getFileName(), ELL_ERROR); break; } delete [] data; delete [] palette; return image; }
//! creates a surface from the file IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const { IImage* image; if (file->getSize() < 12) return 0; c8 id[2]; file->read(&id, 2); if (id[0]!='P' || id[1]<'1' || id[1]>'6') return 0; const u8 format = id[1] - '0'; const bool binary = format>3; core::stringc token; getNextToken(file, token); const u32 width = core::strtoul10(token.c_str()); getNextToken(file, token); const u32 height = core::strtoul10(token.c_str()); u8* data = 0; const u32 size = width*height; if (format==1 || format==4) { skipToNextToken(file); // go to start of data const u32 bytesize = size/8+(size & 3)?1:0; if (binary) { if (file->getSize()-file->getPos() < (long)bytesize) return 0; data = new u8[bytesize]; file->read(data, bytesize); } else { if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test return 0; data = new u8[bytesize]; memset(data, 0, bytesize); u32 shift=0; for (u32 i=0; i<size; ++i) { getNextToken(file, token); if (token == "1") data[i/8] |= (0x01 << shift); if (++shift == 8) shift=0; } } image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height)); if (image) CColorConverter::convert1BitTo16Bit(data, (s16*)image->getData(), width, height); } else { getNextToken(file, token); const u32 maxDepth = core::strtoul10(token.c_str()); if (maxDepth > 255) // no double bytes yet return 0; skipToNextToken(file); // go to start of data if (format==2 || format==5) { if (binary) { if (file->getSize()-file->getPos() < (long)size) return 0; data = new u8[size]; file->read(data, size); image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; i<size; ++i) { *ptr++ = data[i]; *ptr++ = data[i]; *ptr++ = data[i]; *ptr++ = 255; } } } else { if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test return 0; image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; i<size; ++i) { getNextToken(file, token); const u8 num = (u8)core::strtoul10(token.c_str()); *ptr++ = num; *ptr++ = num; *ptr++ = num; *ptr++ = 255; } } } } else { const u32 bytesize = 3*size; if (binary) { if (file->getSize()-file->getPos() < (long)bytesize) return 0; data = new u8[bytesize]; file->read(data, bytesize); image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; i<size; ++i) { *ptr++ = data[3*i]; *ptr++ = data[3*i+1]; *ptr++ = data[3*i+2]; *ptr++ = 255; } } } else { if (file->getSize()-file->getPos() < (long)(2*bytesize)) // optimistic test return 0; image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; i<size; ++i) { getNextToken(file, token); *ptr++ = (u8)core::strtoul10(token.c_str()); getNextToken(file, token); *ptr++ = (u8)core::strtoul10(token.c_str()); getNextToken(file, token); *ptr++ = (u8)core::strtoul10(token.c_str()); *ptr++ = 255; } } } } } delete [] data; return image; }
//! creates a surface from the file IImage* CImageLoaderJPG::loadImage(io::IReadFile* file) const { #ifndef _IRR_COMPILE_WITH_LIBJPEG_ os::Printer::log("Can't load as not compiled with _IRR_COMPILE_WITH_LIBJPEG_:", file->getFileName(), ELL_DEBUG); return 0; #else if (!file) return 0; Filename = file->getFileName(); u8 **rowPtr=0; u8* input = new u8[file->getSize()]; file->read(input, file->getSize()); // allocate and initialize JPEG decompression object struct jpeg_decompress_struct cinfo; struct irr_jpeg_error_mgr jerr; //We have to set up the error handler first, in case the initialization //step fails. (Unlikely, but it could happen if you are out of memory.) //This routine fills in the contents of struct jerr, and returns jerr's //address which we place into the link field in cinfo. cinfo.err = jpeg_std_error(&jerr.pub); cinfo.err->error_exit = error_exit; cinfo.err->output_message = output_message; // compatibility fudge: // we need to use setjmp/longjmp for error handling as gcc-linux // crashes when throwing within external c code if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. // We need to clean up the JPEG object and return. jpeg_destroy_decompress(&cinfo); delete [] input; delete [] rowPtr; // return null pointer return 0; } // Now we can initialize the JPEG decompression object. jpeg_create_decompress(&cinfo); // specify data source jpeg_source_mgr jsrc; // Set up data pointer jsrc.bytes_in_buffer = file->getSize(); jsrc.next_input_byte = (JOCTET*)input; cinfo.src = &jsrc; jsrc.init_source = init_source; jsrc.fill_input_buffer = fill_input_buffer; jsrc.skip_input_data = skip_input_data; jsrc.resync_to_restart = jpeg_resync_to_restart; jsrc.term_source = term_source; // Decodes JPG input from whatever source // Does everything AFTER jpeg_create_decompress // and BEFORE jpeg_destroy_decompress // Caller is responsible for arranging these + setting up cinfo // read file parameters with jpeg_read_header() jpeg_read_header(&cinfo, TRUE); bool useCMYK=false; if (cinfo.jpeg_color_space==JCS_CMYK) { cinfo.out_color_space=JCS_CMYK; cinfo.out_color_components=4; useCMYK=true; } else { cinfo.out_color_space=JCS_RGB; cinfo.out_color_components=3; } cinfo.output_gamma=2.2; cinfo.do_fancy_upsampling=FALSE; // Start decompressor jpeg_start_decompress(&cinfo); // Get image data u16 rowspan = cinfo.image_width * cinfo.out_color_components; u32 width = cinfo.image_width; u32 height = cinfo.image_height; // Allocate memory for buffer u8* output = new u8[rowspan * height]; // Here we use the library's state variable cinfo.output_scanline as the // loop counter, so that we don't have to keep track ourselves. // Create array of row pointers for lib rowPtr = new u8* [height]; for( u32 i = 0; i < height; i++ ) rowPtr[i] = &output[ i * rowspan ]; u32 rowsRead = 0; while( cinfo.output_scanline < cinfo.output_height ) rowsRead += jpeg_read_scanlines( &cinfo, &rowPtr[rowsRead], cinfo.output_height - rowsRead ); delete [] rowPtr; // Finish decompression jpeg_finish_decompress(&cinfo); // Release JPEG decompression object // This is an important step since it will release a good deal of memory. jpeg_destroy_decompress(&cinfo); // convert image IImage* image = 0; if (useCMYK) { image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(width, height)); const u32 size = 3*width*height; u8* data = (u8*)image->getData(); if (data) { for (u32 i=0,j=0; i<size; i+=3, j+=4) { // Also works without K, but has more contrast with K multiplied in // data[i+0] = output[j+2]; // data[i+1] = output[j+1]; // data[i+2] = output[j+0]; data[i+0] = (char)(output[j+2]*(output[j+3]/255.f)); data[i+1] = (char)(output[j+1]*(output[j+3]/255.f)); data[i+2] = (char)(output[j+0]*(output[j+3]/255.f)); } } delete [] output; } else image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(width, height), output); delete [] input; return image; #endif }