khanat-opennel-code/code/nel/tools/3d/tga_cut/tga_cut.cpp
2010-05-08 15:37:08 +02:00

301 lines
7.1 KiB
C++

// 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();
}
}
}