// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/> // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include "nel/misc/file.h" #include "nel/misc/bitmap.h" #include "nel/misc/file.h" #include "nel/misc/debug.h" #include <math.h> using namespace NLMISC; using namespace std; #define TGA16 16 #define NOT_DEFINED 0xff const int CutSize = 160; const int SaveSize = 256; void writeInstructions(); int main(int argc, char **argv); // *************************************************************************** bool getZoneNameFromXY (sint32 x, sint32 y, std::string &zoneName) { if ((y>0) || (y<-255) || (x<0) || (x>255)) return false; zoneName = toString(-y) + "_"; zoneName += ('A' + (x/26)); zoneName += ('A' + (x%26)); return true; } void writeInstructions() { cout<<endl; cout<<"tga_cut"<<endl; cout<<" Cut TGA image file (24bits or 32 bits) into smaller TGA"<<endl; cout<<"syntax : tga_cut <input.tga>"<<endl; cout<<endl; cout<<"/? for this help"<<endl; cout<<endl; } // *************************************************************************** void dividSize (CBitmap &bitmap) { // Must be RGBA nlassert (bitmap.getPixelFormat () == CBitmap::RGBA); // Copy the bitmap CBitmap temp = bitmap; // Resize the destination const uint width = temp.getWidth (); const uint height = temp.getHeight (); const uint newWidth = temp.getWidth ()/2; const uint newHeight = temp.getHeight ()/2; bitmap.resize (newWidth, newHeight, CBitmap::RGBA); // Pointers uint8 *pixelSrc = &(temp.getPixels ()[0]); uint8 *pixelDest = &(bitmap.getPixels ()[0]); // Resample uint x, y; for (y=0; y<newHeight; y++) for (x=0; x<newWidth; x++) { const uint offsetSrc = ((y*2)*width+x*2)*4; const uint offsetDest = (y*newWidth+x)*4; uint i; for (i=0; i<4; i++) { pixelDest[offsetDest+i] = ((uint)pixelSrc[offsetSrc+i] + (uint)pixelSrc[offsetSrc+4+i] + (uint)pixelSrc[offsetSrc+4*width+i] + (uint)pixelSrc[offsetSrc+4*width+4+i])>>2; } } } // *************************************************************************** int main(int argc, char **argv) { // Parse Command Line. //==================== if(argc<2) { writeInstructions(); return 0; } if(!strcmp(argv[1],"/?")) { writeInstructions(); return 0; } if(!strcmp(argv[1],"-?")) { writeInstructions(); return 0; } if(argc != 2) { writeInstructions(); return 0; } // Reading TGA and converting to RGBA //==================================== CBitmap picTga; CBitmap picSrc; std::string inputFileName(argv[1]); NLMISC::CIFile input; if(!input.open(inputFileName)) { cerr<<"Can't open input file "<<inputFileName<<endl; exit(1); } uint8 imageDepth = picTga.load(input); if(imageDepth==0) { cerr<<"Can't load file : "<<inputFileName<<endl; exit(1); } if(imageDepth!=16 && imageDepth!=24 && imageDepth!=32 && imageDepth!=8) { cerr<<"Image not supported : "<<imageDepth<<endl; exit(1); } if(!input.seek (0, NLMISC::IStream::begin)) { cerr << "Seek to beginning failed"<<endl; exit(1); } // Reading header, // To make sure that the bitmap is TGA, we check imageType and imageDepth. uint8 lengthID; uint8 cMapType; uint8 imageType; uint16 tgaOrigin; uint16 length; uint8 depth; uint16 xOrg; uint16 yOrg; uint16 width2; uint16 height2; uint8 imageDepth2; uint8 desc; input.serial(lengthID); input.serial(cMapType); input.serial(imageType); input.serial(tgaOrigin); input.serial(length); input.serial(depth); input.serial(xOrg); input.serial(yOrg); input.serial(width2); input.serial(height2); input.serial(imageDepth2); input.serial(desc); input.close(); sint32 height = picTga.getHeight(); sint32 width= picTga.getWidth(); picTga.convertToType (CBitmap::RGBA); // Vectors for RGBA data CObjectVector<uint8> RGBASrc = picTga.getPixels(); CObjectVector<uint8> RGBASrc2; CObjectVector<uint8> RGBADest; RGBADest.resize(SaveSize*SaveSize*4); uint dstRGBADestId= 0; // Copy to the dest bitmap. picSrc.resize(SaveSize, SaveSize, CBitmap::RGBA); picSrc.getPixels(0) = RGBADest; // Must be RGBA nlassert (picSrc.getPixelFormat () == CBitmap::RGBA); // Pointers uint8 *pixelSrc = &(picTga.getPixels ()[0]); uint8 *pixelDest = &(picSrc.getPixels ()[0]); // clear the whole texture for (sint y = 0;y < SaveSize;++y) { for (sint x = 0;x < SaveSize;++x) { pixelDest[(y*SaveSize+x)*4]=-1; pixelDest[(y*SaveSize+x)*4+1]=-1; pixelDest[(y*SaveSize+x)*4+2]=-1; pixelDest[(y*SaveSize+x)*4+3]=-1; } } // Resample sint xzone, yzone; for (yzone = int(yOrg/CutSize)*CutSize; yzone < yOrg+height; yzone += CutSize) { for (xzone = int(xOrg/CutSize)*CutSize; xzone < xOrg+width; xzone += CutSize) { sint x, y; for (y=0; y<CutSize; y++) { for (x=0; x<CutSize; x++) { const uint offsetDest = (y*SaveSize+x)*4; uint i; if (x+xzone-xOrg>= width || y+yzone-yOrg>=height || x+xzone-xOrg<0 || y+yzone-yOrg<0) { // black outside the bitmap for (i=0; i<4; i++) { pixelDest[offsetDest+i] = 0; } } else { const uint offsetSrc = ((y+yzone-yOrg)*width+x+xzone-xOrg)*4; for (i=0; i<4; i++) { pixelDest[offsetDest+i] = pixelSrc[offsetSrc+i]; } } } } #if 0 // if we don't want to save the empty pictures (useless now) int empty = 1; for (y = 0;y < CutSize;++y) { for (x=0;x<CutSize;++x) { // test if pixel is black (RGB==0) int offset = (y*SaveSize+x)*4; if (pixelDest[offset] || pixelDest[offset+1] || pixelDest[offset+2]) { empty = 0; break; } } } if (empty) continue; #endif // if the picture is empty, we don't save it !!! NLMISC::COFile output; string ZoneName; if (!getZoneNameFromXY(xzone/CutSize, -(yzone/CutSize+1), ZoneName)) { cerr<<"Too large image"<<endl; exit(1); } ZoneName += ".tga"; if(!output.open(ZoneName)) { cerr<<"Can't open output file "<<ZoneName<<endl; exit(1); } cout<<"Saving "<<ZoneName<<endl; // Saving TGA file try { picSrc.writeTGA (output, 16); } catch(NLMISC::EWriteError &e) { cerr<<e.what()<<endl; exit(1); } output.close(); } } }