khanat-opennel-code/code/nel/tools/3d/build_far_bank/build_far_bank.cpp

425 lines
10 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 "nel/misc/file.h"
#include "nel/3d/tile_bank.h"
#include "nel/3d/tile_far_bank.h"
#include "nel/misc/bitmap.h"
#include "nel/misc/path.h"
#include <sys/types.h>
#include <sys/stat.h>
using namespace std;
using namespace NLMISC;
using namespace NL3D;
#define BUILD_FAR_BANK_VERSION "1.0"
#if defined (NL_OS_WINDOWS)
#define STAT _stat
#else // NL_OS_WINDOWS
#define STAT stat
#endif // NL_OS_WINDOWS
// Return true if f2 must be recomputed with f1, else return false.
// return true if date f1 > date f2
// If f1 doesn't exist, returns false
// If f2 doesn't exist, returns true
bool recompute (const char* f1, const char* f2)
{
struct STAT buf1;
struct STAT buf2;
if (STAT (f1, &buf1)!=0)
return false;
if (STAT (f2, &buf2)!=0)
return true;
return buf1.st_mtime > buf2.st_mtime;
}
// Return true if the file exist
bool isFileExist (const char* sName)
{
FILE *pFile=fopen (sName, "rb");
if (!pFile)
return false;
fclose (pFile);
return true;
}
// Fill tile far pixel with this bitmap
bool fillTileFar (uint tile, const char* sName, CTileFarBank::TFarType type, CTileFarBank& farBank, bool _256, uint8 rotate)
{
// Progress message
printf ("Computing %s...\n", sName);
// Create a stream
CIFile inputBitmap;
if (inputBitmap.open (sName))
{
try
{
// Load the texture
CBitmap bitmap;
bitmap.load (inputBitmap);
// Convert to RGBA
bitmap.convertToType (CBitmap::RGBA);
// Rotate
uint8 rot=rotate;
while (rot!=0)
{
bitmap.rotateCCW ();
rot--;
}
// Get bitmap size
uint width=bitmap.getWidth();
uint height=bitmap.getHeight();
// Check size..
if ((!((_256&&(width==256)&&(height==256))||((!_256)&&(width==128)&&(height==128)))))
{
// New size
width = height = _256?256:128;
// Output a warning message
if ((type!=CTileFarBank::alpha)||(width!=64)||(height!=64))
nlwarning ("WARNING resize %s to %d x %d\n", sName, width, height);
// Resample the picture
bitmap.resample ( width, height);
}
// Build mipmaps
bitmap.buildMipMaps ();
// Get the tile
CTileFarBank::CTileFar* pFarTile=farBank.getTile (tile);
// Copy arrays
pFarTile->setPixels (type, CTileFarBank::order0, (CRGBA*)&bitmap.getPixels (5)[0], (width>>5)*(height>>5));
pFarTile->setPixels (type, CTileFarBank::order1, (CRGBA*)&bitmap.getPixels (6)[0], (width>>6)*(height>>6));
pFarTile->setPixels (type, CTileFarBank::order2, (CRGBA*)&bitmap.getPixels (7)[0], (width>>7)*(height>>7));
// Ok.
return true;
}
catch (const Exception& except)
{
nlwarning ("ERROR %s\n", except.what());
}
}
else
{
nlwarning ("ERROR can't open bitmap %s for reading\n", sName);
}
return false;
}
// Go go go !
int main (int argc, char **argv)
{
NLMISC::CApplicationContext myApplicationContext;
// Options
bool useCurrentPath=false;
bool forceRecomputation=false;
bool outputVersion=false;
bool outputHelp=false;
string postfix;
string rootDir;
// If no argu, show help
if (argc==1)
outputHelp=true;
int nFirstGoodArgu=3;
// Correct number of argu..
// Check for options
for (int n=1; n<argc; n++)
{
if (strcmp (argv[n], "-r")==0 || strcmp (argv[n], "-R")==0)
useCurrentPath=true;
if (strcmp (argv[n], "-f")==0 || strcmp (argv[n], "-F")==0)
forceRecomputation=true;
if (strcmp (argv[n], "-v")==0 || strcmp (argv[n], "-V")==0)
outputVersion=true;
if (strcmp (argv[n], "-?")==0)
outputHelp=true;
if (strcmp (argv[n], "-?")==0)
outputHelp=true;
if (strncmp (argv[n], "-d", 2)==0)
{
rootDir = argv[n];
rootDir = rootDir.substr (2, rootDir.size ()-2);
rootDir = CPath::standardizePath (rootDir);
}
if (strncmp (argv[n], "-p", 2)==0)
{
postfix = argv[n];
postfix = postfix.substr (2, postfix.size ()-2);
}
}
// Output version?
if (outputVersion)
printf ("Version %s\n", BUILD_FAR_BANK_VERSION);
// Output help?
if (outputHelp)
{
// Ok, some help if not enough argu
printf (
"build_far_bank [input.bank][output.farbank][-r][-f][-v][-?]\n"
"options:\n"
"\t-d#: change the root directory of the small bank. # is the new directory\n"
"\t-p#: postfix tiles filename by #\n"
"\t-r: load the bitmaps from the current directory\n"
"\t-r: load the bitmaps from the current directory\n"
"\t-f: force recomputation of all the tiles\n"
"\t-v: print the version\n"
"\t-?: print help\n"
);
}
if (argc>=3)
{
// Count number of tiles
int tileCount=0;
int tileComputed=0;
// Open input file
CIFile inputFile;
if (inputFile.open(argv[1]))
{
// Get some incoming exceptions
try
{
// Ok, create a far tile bank
CTileFarBank farBank;
// Try to open input file
CIFile inputFarBank;
if (inputFarBank.open(argv[2]))
{
// Serial the bank in input
farBank.serial (inputFarBank);
}
// Force recomputation ?
if (recompute (argv[1], argv[2]))
{
// Progress message
printf ("%s have been modified, recompute all the tiles...\n", argv[1]);
forceRecomputation=true;
}
// Close this file
inputFarBank.close ();
// Progress message
printf ("Reading the bank...\n");
// Create a bank
CTileBank bank;
// Serialize the input bank
bank.serial (inputFile);
// Path relative
if (useCurrentPath)
bank.makeAllPathRelative ();
// Change root dir ?
if (!rootDir.empty ())
bank.setAbsPath (rootDir);
// Postfix tiles ?
if (!postfix.empty ())
bank.postfixTileFilename (postfix.c_str ());
// Resize far bank
farBank.setNumTile (bank.getTileCount());
// Scan each tiles...
int tile;
for (tile=0; tile<bank.getTileCount(); tile++)
{
// Get a pointer on this tile
CTile *pTile=bank.getTile(tile);
// Delete pixels
bool bDeleteDiffuse=true;
bool bDeleteAdditive=true;
bool bDeleteAlpha=true;
// Tile not free ?
if (!pTile->isFree())
{
// Get infos about the tile
sint tileSet;
sint number;
CTileBank::TTileType type;
bank.getTileXRef (tile, tileSet, number, type);
// Is a 256 ?
bool _256=(type==CTileBank::_256x256);
// Diffuse bitmap filled ?
if (pTile->getRelativeFileName (CTile::diffuse)!="")
{
// File exist ?
string tileFilename = bank.getAbsPath()+pTile->getRelativeFileName (CTile::diffuse);
if (isFileExist (tileFilename.c_str()))
{
// Recompute it?
if (recompute (tileFilename.c_str(), argv[2])||forceRecomputation)
{
// Fill infos
if (fillTileFar (tile, tileFilename.c_str(), CTileFarBank::diffuse, farBank, _256, 0))
{
// One more tile
tileCount++;
tileComputed++;
bDeleteDiffuse=false;
}
}
else
{
// One more tile
tileCount++;
printf ("Skipping %s...\n", tileFilename.c_str());
bDeleteDiffuse=false;
}
}
}
// Additive bitmap filled ?
if (pTile->getRelativeFileName (CTile::additive)!="")
{
// File exist ?
string tileFilename = bank.getAbsPath()+pTile->getRelativeFileName (CTile::additive);
if (isFileExist (tileFilename.c_str()))
{
// Recompute it?
if (recompute (tileFilename.c_str(), argv[2])||forceRecomputation)
{
// Fill infos
if (fillTileFar (tile, tileFilename.c_str(), CTileFarBank::additive, farBank, _256, 0))
{
// One more tile
tileCount++;
tileComputed++;
bDeleteAdditive=false;
}
}
else
{
// One more tile
tileCount++;
printf ("Skipping %s...\n", tileFilename.c_str());
bDeleteAdditive=false;
}
}
}
// Alpha bitmap filled ?
if (pTile->getRelativeFileName (CTile::alpha)!="")
{
// File exist ?
string tileFilename = bank.getAbsPath()+pTile->getRelativeFileName (CTile::alpha);
if (isFileExist (tileFilename.c_str()))
{
// Recompute it?
if (recompute (tileFilename.c_str(), argv[2])||forceRecomputation)
{
// Fill infos
if (fillTileFar (tile, tileFilename.c_str(), CTileFarBank::alpha, farBank, _256, pTile->getRotAlpha()))
{
// One more tile
tileCount++;
tileComputed++;
bDeleteAlpha=false;
}
}
else
{
// One more tile
tileCount++;
printf ("Skipping %s...\n", tileFilename.c_str());
bDeleteAlpha=false;
}
}
else
{
nlwarning ("ERROR tile file not found %s\n", tileFilename.c_str ());
}
}
}
// Delete diffuse pixels?
if (bDeleteDiffuse)
farBank.getTile (tile)->erasePixels (CTileFarBank::diffuse);
// Delete additif pixels?
if (bDeleteAdditive)
farBank.getTile (tile)->erasePixels (CTileFarBank::additive);
}
// Open output file
COFile outputFile;
if (outputFile.open(argv[2]))
{
// Progress message
printf ("Writing %s...\n", argv[2]);
// Writing the bank
farBank.serial (outputFile);
// Progress message
printf ("%d far tiles found.\n", tileCount);
printf ("%d far tiles computed.\n", tileComputed);
}
else // Open failed
{
nlwarning ("ERROR Can't open file %s for writing\n", argv[2]);
}
}
catch (const Exception& except)
{
nlwarning ("ERROR %s\n", except.what());
}
}
else // Open failed
{
nlwarning ("ERROR Can't open file %s for reading\n", argv[1]);
}
}
// exit
return 0;
}