// NeL - MMORPG Framework
// 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 .
#include "std3d.h"
#include "nel/3d/tile_bank.h"
#include "nel/3d/texture_file.h"
#include "nel/3d/tile_noise_map.h"
#include "nel/misc/stream.h"
#include "nel/misc/common.h"
#include "nel/misc/path.h"
#include "nel/misc/file.h"
#include
using namespace NLMISC;
using namespace std;
namespace NL3D
{
// ***************************************************************************
// ***************************************************************************
// TileBankLand.
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
const sint CTileLand::_Version=0;
// ***************************************************************************
void CTileLand::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
{
(void)f.serialVersion(_Version);
f.serial (_Name);
f.serialCont (_TileSet);
}
// ***************************************************************************
void CTileLand::addTileSet (const std::string& name)
{
_TileSet.insert (name);
}
// ***************************************************************************
void CTileLand::removeTileSet (const std::string& name)
{
_TileSet.erase (name);
}
// ***************************************************************************
void CTileLand::setName (const std::string& name)
{
_Name=name;
};
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
// CTileBank.
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
const sint CTileBank::_Version=4;
// ***************************************************************************
CTileBank::CTileBank ()
{
// Default _DisplacementMap
_DisplacementMap.resize (1);
// Fill it with 0
_DisplacementMap[0].setEmpty ();
}
// ***************************************************************************
void CTileBank::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
{
f.serialCheck (std::string ("BANK"));
sint streamver = f.serialVersion(_Version);
// Version 1 not compatible
if (f.isReading())
{
if (streamver<2)
throw EOlderStream(f);
}
switch (streamver)
{
case 4:
// Displacement map array
f.serialCont (_DisplacementMap);
if (f.isReading())
{
// Checks
nlassert (!_DisplacementMap.empty());
// Set first empty
_DisplacementMap[0].setEmpty ();
}
case 3:
// Absolute path
f.serial (_AbsPath);
case 2:
// Serial all containers
f.serialCont (_LandVector);
f.serialCont (_TileSetVector);
f.serialCont (_TileVector);
}
// Compute XRef in read mode
if (f.isReading())
computeXRef ();
// If Version<=2, remove diffuse and alpha tiles in transitions
if (streamver<=2)
{
// Must be reading
nlassert (f.isReading());
// Reset _AbsPath
_AbsPath="";
// Remove diffuse and additive in transition
uint tileCount=(uint)getTileCount ();
for (uint i=0; iclearTransition ((CTileSet::TTransition)number, CTile::diffuse, *this);
// Remove alpha bitmap
getTileSet(tileSet)->clearTransition ((CTileSet::TTransition)number, CTile::alpha, *this);
}
}
}
}
// ***************************************************************************
sint CTileBank::addLand (const std::string& name)
{
sint last=(sint)_LandVector.size();
_LandVector.push_back(CTileLand());
_LandVector[last].setName (name);
return last;
}
// ***************************************************************************
void CTileBank::removeLand (sint landIndex)
{
// Check args
nlassert (landIndex>=0);
nlassert (landIndex<(sint)_LandVector.size());
_LandVector.erase (_LandVector.begin ()+landIndex);
}
// ***************************************************************************
sint CTileBank::addTileSet (const std::string& name)
{
sint last=(sint)_TileSetVector.size();
_TileSetVector.push_back(CTileSet());
_TileSetVector[last].setName (name);
for (int i=0; i=0);
nlassert (setIndex<(sint)_TileSetVector.size());
for (int i=0; i=0);
nlassert (tileIndex<(sint)_TileVector.size());
// Free
_TileVector[tileIndex].free();
// Resize tile table
int i;
for (i=(sint)_TileVector.size()-1; i>=0; i--)
{
if (!_TileVector[i].isFree ())
break;
}
if (i<(sint)_TileVector.size()-1)
_TileVector.resize (i+1);
}
// ***************************************************************************
sint CTileBank::getNumBitmap (CTile::TBitmap bitmap) const
{
std::set setString;
for (int i=0; i<(sint)_TileVector.size(); i++)
{
if (!_TileVector[i].isFree())
{
const std::string &str=_TileVector[i].getRelativeFileName (bitmap);
if (str!="")
{
std::vector vect (str.length()+1);
memcpy (&*vect.begin(), str.c_str(), str.length()+1);
toLower(&*vect.begin());
setString.insert (std::string (&*vect.begin()));
}
}
}
return (sint)setString.size();
}
// ***************************************************************************
void CTileBank::computeXRef ()
{
// Resize
_TileXRef.resize (_TileVector.size());
// Erase number of the tileset in xref
for (int tile=0; tile<(sint)_TileVector.size(); tile++)
_TileXRef[tile]._XRefTileSet=-1;
// Erase number of the tileset in xref
for (int s=0; s<(sint)_TileSetVector.size(); s++)
{
int t;
CTileSet *tileSet=getTileSet (s);
for (t=0; tgetNumTile128(); t++)
{
int index=tileSet->getTile128 (t);
_TileXRef[index]._XRefTileSet=s;
_TileXRef[index]._XRefTileNumber=t;
_TileXRef[index]._XRefTileType=_128x128;
}
for (t=0; tgetNumTile256(); t++)
{
int index=tileSet->getTile256 (t);
_TileXRef[index]._XRefTileSet=s;
_TileXRef[index]._XRefTileNumber=t;
_TileXRef[index]._XRefTileType=_256x256;
}
for (t=0; tgetTransition (t)->getTile();
_TileXRef[index]._XRefTileSet=s;
_TileXRef[index]._XRefTileNumber=t;
_TileXRef[index]._XRefTileType=transition;
}
}
}
// ***************************************************************************
void CTileBank::xchgTileset (sint firstTileSet, sint secondTileSet)
{
// Some check
nlassert ((firstTileSet>=0)&&(firstTileSet<(sint)_TileSetVector.size()));
nlassert ((secondTileSet>=0)&&(secondTileSet<(sint)_TileSetVector.size()));
// Xchange the sets
CTileSet tmp=_TileSetVector[firstTileSet];
_TileSetVector[firstTileSet]=_TileSetVector[secondTileSet];
_TileSetVector[secondTileSet]=tmp;
}
// ***************************************************************************
void TroncFileName (char* sDest, const char* sSrc)
{
const char* ptr=strrchr (sSrc, '\\');
if (ptr==NULL)
ptr=strrchr (sSrc, '/');
if (ptr)
{
ptr++;
strcpy (sDest, ptr);
}
else
{
strcpy (sDest, sSrc);
}
}
// ***************************************************************************
// TODO: this is a temporary hack, see if it could be removed
void CTileBank::makeAllPathRelative ()
{
// For all tiles
for (sint nTile=0; nTile<(sint)_TileVector.size(); nTile++)
{
// Tronc filename
char sTmpFileName[512];
// Diffuse
TroncFileName (sTmpFileName, _TileVector[nTile].getRelativeFileName (CTile::diffuse).c_str());
_TileVector[nTile].setFileName (CTile::diffuse, sTmpFileName);
// Additive
TroncFileName (sTmpFileName, _TileVector[nTile].getRelativeFileName (CTile::additive).c_str());
_TileVector[nTile].setFileName (CTile::additive, sTmpFileName);
// Alpha
TroncFileName (sTmpFileName, _TileVector[nTile].getRelativeFileName (CTile::alpha).c_str());
_TileVector[nTile].setFileName (CTile::alpha, sTmpFileName);
}
// For all displaces
for (uint i=0; i<_DisplacementMap.size(); i++)
{
// Tronc filename
char sTmpFileName[512];
TroncFileName (sTmpFileName, _DisplacementMap[i]._FileName.c_str());
_DisplacementMap[i]._FileName = sTmpFileName;
}
}
// ***************************************************************************
void CTileBank::makeAllExtensionDDS ()
{
// For all tiles
for (sint nTile=0; nTile<(sint)_TileVector.size(); nTile++)
{
string tmp;
string::size_type pos;
// Diffuse
tmp= _TileVector[nTile].getRelativeFileName (CTile::diffuse);
pos= tmp.rfind(".tga");
if (pos == string::npos)
pos = tmp.rfind(".png");
if(pos!= string::npos)
{
tmp.replace(pos, 4, ".dds");
_TileVector[nTile].setFileName (CTile::diffuse, tmp);
}
// Additive.
tmp= _TileVector[nTile].getRelativeFileName (CTile::additive);
pos= tmp.rfind(".tga");
if (pos == string::npos)
pos = tmp.rfind(".png");
if(pos!= string::npos)
{
tmp.replace(pos, 4, ".dds");
_TileVector[nTile].setFileName (CTile::additive, tmp);
}
// Alpha.
tmp= _TileVector[nTile].getRelativeFileName (CTile::alpha);
pos= tmp.rfind(".tga");
if (pos == string::npos)
pos = tmp.rfind(".png");
if(pos!= string::npos)
{
tmp.replace(pos, 4, ".dds");
_TileVector[nTile].setFileName (CTile::alpha, tmp);
}
}
}
// ***************************************************************************
void CTileBank::cleanUnusedData ()
{
// Clean each tileset
for (uint i=0; i<_TileSetVector.size(); i++)
{
// Clean the tileset
_TileSetVector[i].cleanUnusedData ();
}
// Clear the land vector
_LandVector.clear();
}
// ***************************************************************************
CTileNoiseMap *CTileBank::getTileNoiseMap (uint tileNumber, uint tileSubNoise)
{
if (_DisplacementMap.size() == 0)
{
// it happens when serial a tile bank with version < 4
return NULL;
}
// Check tile number..
if (tileNumber<_TileVector.size())
{
// Get tileset number
uint tileSet=_TileXRef[tileNumber]._XRefTileSet;
// Checks
if (tileSet<_TileSetVector.size())
{
nlassert (tileSubNoise=_DisplacementMap.size())
return NULL;
// Return the tile noise map
CTileNoise &tileNoise=_DisplacementMap[_TileSetVector[tileSet]._DisplacementBitmap[tileSubNoise]];
// Not loaded ?
if (tileNoise._TileNoiseMap==NULL)
{
// Load a bitmap
CTextureFile texture (getAbsPath()+tileNoise._FileName);
texture.loadGrayscaleAsAlpha (false);
texture.generate ();
texture.convertToType (CBitmap::Luminance);
// Alloc
tileNoise._TileNoiseMap=new CTileNoiseMap;
// Good size ?
if ((texture.getWidth ()==NL3D_TILE_NOISE_MAP_SIZE)&&(texture.getHeight()==NL3D_TILE_NOISE_MAP_SIZE))
{
// Copy
memcpy (tileNoise._TileNoiseMap->Pixels, &texture.getPixels()[0], NL3D_TILE_NOISE_MAP_SIZE*NL3D_TILE_NOISE_MAP_SIZE);
// Remap lumels
for (uint i=0; iPixels[i]=(sint8)((uint8)tileNoise._TileNoiseMap->Pixels[i]-128);
if (tileNoise._TileNoiseMap->Pixels[i]==-128)
tileNoise._TileNoiseMap->Pixels[i]=-127;
}
}
else
{
// This is not a normal behaviour.
string pathname= getAbsPath()+tileNoise._FileName;
if( texture.getWidth ()==0 || texture.getHeight ()==0 )
nlwarning("TileNoiseMap not found: %s.", pathname.c_str());
else
nlwarning("Bad TileNoiseMap size: %s.", pathname.c_str());
// Not good size, copy a static map
sint8 notGoodSizeForm[NL3D_TILE_NOISE_MAP_SIZE*NL3D_TILE_NOISE_MAP_SIZE]=
{
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 99, 99, 99, 99, 99, 99, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 99, 99, 99, 99, 99, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 99, 00, 99, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 99, 99, 99, 99, 99, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 99, 99, 99, 99, 99, 99, 99, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
};
// Copy
memcpy (tileNoise._TileNoiseMap->Pixels, notGoodSizeForm, NL3D_TILE_NOISE_MAP_SIZE*NL3D_TILE_NOISE_MAP_SIZE);
}
}
// Return the noise map
return tileNoise._TileNoiseMap;
}
}
if (_DisplacementMap.empty() || _DisplacementMap[0]._TileNoiseMap)
return NULL;
// Checks
nlassert (_DisplacementMap[0]._TileNoiseMap);
return _DisplacementMap[0]._TileNoiseMap;
}
// ***************************************************************************
void CTileBank::removeDisplacementMap (uint mapId)
{
// Checks
nlassert (mapId<_DisplacementMap.size());
if (mapId!=0)
{
// Check if another tileSet uses it
uint tileSet;
for (tileSet=0; tileSet<_TileSetVector.size(); tileSet++)
{
// It uses it ?
uint tile;
for (tile=0; tile0)&&(_DisplacementMap[mapId]._FileName==""))
_DisplacementMap.resize (mapId--);
}
}
}
}
// ***************************************************************************
uint CTileBank::getDisplacementMap (const string &fileName)
{
// Lower string
string lower=toLower(fileName);
// Look for this texture filename
uint noiseTile;
for (noiseTile=0; noiseTile<_DisplacementMap.size(); noiseTile++)
{
// Same name ?
if (lower==_DisplacementMap[noiseTile]._FileName)
return noiseTile;
}
// Look for a free space
for (noiseTile=0; noiseTile<_DisplacementMap.size(); noiseTile++)
{
// Same name ?
if (_DisplacementMap[noiseTile]._FileName=="")
break;
}
if (noiseTile==_DisplacementMap.size())
{
// Add a tile
_DisplacementMap.resize (noiseTile+1);
}
// Set the file name
_DisplacementMap[noiseTile]._FileName=lower;
return noiseTile;
}
// ***************************************************************************
const char* CTileBank::getDisplacementMap (uint noiseMap)
{
return _DisplacementMap[noiseMap]._FileName.c_str();
}
// ***************************************************************************
void CTileBank::setDisplacementMap (uint noiseMap, const char *newName)
{
_DisplacementMap[noiseMap]._FileName=newName;
}
// ***************************************************************************
uint CTileBank::getDisplacementMapCount () const
{
return (uint)_DisplacementMap.size();
}
// ***************************************************************************
const CTileVegetableDesc &CTileBank::getTileVegetableDesc(uint tileNumber) const
{
// Check tile number..
if (tileNumber<_TileVector.size())
{
// Get tileset number
uint tileSet=_TileXRef[tileNumber]._XRefTileSet;
// Checks
if (tileSet<_TileSetVector.size())
{
return _TileSetVector[tileSet].getTileVegetableDesc();
}
}
// if fails for any reason, return an empty tileVegetableDesc;
static CTileVegetableDesc emptyTvd;
return emptyTvd;
}
// ***************************************************************************
void CTileBank::loadTileVegetableDescs()
{
// For all tileSets.
uint tileSet;
for(tileSet=0; tileSet<_TileSetVector.size(); tileSet++)
{
// load their fileName
_TileSetVector[tileSet].loadTileVegetableDesc();
}
}
// ***************************************************************************
void CTileBank::initTileVegetableDescs(CVegetableManager *vegetableManager)
{
// For all tileSets.
uint tileSet;
for(tileSet=0; tileSet<_TileSetVector.size(); tileSet++)
{
CTileVegetableDesc &tvd= _TileSetVector[tileSet].getTileVegetableDesc();
tvd.registerToManager(vegetableManager);
}
}
// ***************************************************************************
void CTileBank::postfixTileFilename (const char *postfix)
{
// For each tiles
uint tile;
for (tile=0; tile<_TileVector.size (); tile++)
{
// For each bitmap
uint bitmap;
for (bitmap=0; bitmap=5)
{
f.serial (SurfaceData);
}
// serial the oriented info which tell if the tile has a special orientation
if (streamver>=4)
{
f.serial (_Oriented);
}
// serial vegetable info.
if (streamver>=3)
{
// serialisze only the FileName, not the descrpitor
f.serial(_TileVegetableDescFileName);
}
// New version
if (streamver>=2)
{
uint displace;
for (displace=FirstDisplace; displacesetFileName (type, name);
tile->setRotAlpha (0);
}
// ***************************************************************************
CTileSet::TError CTileSet::checkTile128 (CTile::TBitmap type, const CTileBorder& border, int& pixel, int& composante)
{
// Self check
if ((border.getWidth()!=128)||(border.getHeight()!=128))
return sizeInvalide;
if (!CTileBorder::compare (border, border, CTileBorder::top, CTileBorder::bottom, pixel, composante))
return topBottomNotTheSame;
if (!CTileBorder::compare (border, border, CTileBorder::left, CTileBorder::right, pixel, composante))
return rightLeftNotTheSame;
// Check
if (_Border128[type].isSet())
{
// Other check
if (!CTileBorder::compare (border, _Border128[type], CTileBorder::top, CTileBorder::top, pixel, composante))
return topInterfaceProblem;
if (!CTileBorder::compare (border, _Border128[type], CTileBorder::bottom, CTileBorder::bottom, pixel, composante))
return bottomInterfaceProblem;
if (!CTileBorder::compare (border, _Border128[type], CTileBorder::left, CTileBorder::left, pixel, composante))
return leftInterfaceProblem;
if (!CTileBorder::compare (border, _Border128[type], CTileBorder::right, CTileBorder::right, pixel, composante))
return rightInterfaceProblem;
}
else
{
return addFirstA128128;
}
return ok;
}
// ***************************************************************************
void CTileSet::addTile256 (int& indexInTileSet, CTileBank& bank)
{
// Create a tile
sint index=bank.createTile ();
// Index of the new tile
indexInTileSet=(int)_Tile256.size();
// Add to the end of the list
_Tile256.push_back (index);
}
// ***************************************************************************
CTileSet::TError CTileSet::checkTile256 (CTile::TBitmap type, const CTileBorder& border, int& pixel, int& composante)
{
// Self check
if ((border.getWidth()!=256)||(border.getHeight()!=256))
return sizeInvalide;
if (!CTileBorder::compare (border, border, CTileBorder::top, CTileBorder::bottom, pixel, composante))
return topBottomNotTheSame;
if (!CTileBorder::compare (border, border, CTileBorder::left, CTileBorder::right, pixel, composante))
return rightLeftNotTheSame;
// Check if prb
if ((!_Border256[type].isSet())&&(_Border128[type].isSet()))
{
_Border256[type]=_Border128[type];
_Border256[type].doubleSize ();
}
// Check
if (_Border256[type].isSet())
{
// Other check
if (!CTileBorder::compare (border, _Border256[type], CTileBorder::top, CTileBorder::top, pixel, composante))
return topInterfaceProblem;
if (!CTileBorder::compare (border, _Border256[type], CTileBorder::bottom, CTileBorder::bottom, pixel, composante))
return bottomInterfaceProblem;
if (!CTileBorder::compare (border, _Border256[type], CTileBorder::left, CTileBorder::left, pixel, composante))
return leftInterfaceProblem;
if (!CTileBorder::compare (border, _Border256[type], CTileBorder::right, CTileBorder::right, pixel, composante))
return rightInterfaceProblem;
}
else
{
return addFirstA128128;
}
return ok;
}
// ***************************************************************************
void CTileSet::setTile256 (int indexInTileSet, const std::string& name, CTile::TBitmap type, CTileBank& bank)
{
// Edit a tile
CTile *tile=bank.getTile (_Tile256[indexInTileSet]);
tile->setFileName (type, name);
tile->setRotAlpha (0);
}
// ***************************************************************************
void CTileSet::setTileTransition (TTransition transition, const std::string& name, CTile::TBitmap type, CTileBank& bank,
const CTileBorder& border)
{
// Check is not an alpha channel
nlassert (type!=CTile::alpha); // use setTileTransitionAlpha
// Create a tile
_BorderTransition[transition][type]=border;
// Set the tile file name
CTile *tile=bank.getTile (_TileTransition[transition]._Tile);
tile->setFileName (type, name);
}
// ***************************************************************************
void CTileSet::setTileTransitionAlpha (TTransition transition, const std::string& name, CTileBank& bank,
const CTileBorder& border, uint8 rot)
{
// Check some args
nlassert (rot<4);
// Create a tile
_BorderTransition[transition][CTile::alpha]=border;
// Set the tile file name
CTile *tile=bank.getTile (_TileTransition[transition]._Tile);
tile->setFileName (CTile::alpha, name);
tile->setRotAlpha (rot);
}
// ***************************************************************************
CTileSet::TError CTileSet::checkTileTransition (TTransition transition, CTile::TBitmap type, const CTileBorder& border, int& indexError,
int& pixel, int& composante)
{
nlassert (transition>=0);
nlassert (transition=0);
nlassert (indexInTileSet<(sint)_Tile128.size());
// Old index
int index=_Tile128[indexInTileSet];
// Erase
_Tile128.erase (_Tile128.begin()+indexInTileSet);
bank.freeTile (index);
// Erase border if it is the last texture
deleteBordersIfLast (bank, CTile::diffuse);
deleteBordersIfLast (bank, CTile::additive);
deleteBordersIfLast (bank, CTile::alpha);
}
// ***************************************************************************
void CTileSet::removeTile256 (int indexInTileSet, CTileBank& bank)
{
// Check args
nlassert (indexInTileSet>=0);
nlassert (indexInTileSet<(sint)_Tile256.size());
// Old index
int index=_Tile256[indexInTileSet];
// Erase
_Tile256.erase (_Tile256.begin()+indexInTileSet);
bank.freeTile (index);
// Erase border if it is the last texture
deleteBordersIfLast (bank, CTile::diffuse);
deleteBordersIfLast (bank, CTile::additive);
deleteBordersIfLast (bank, CTile::alpha);
}
// ***************************************************************************
CTileSet::TTransition CTileSet::getTransitionTile (TFlagBorder _top, TFlagBorder _bottom, TFlagBorder _left, TFlagBorder _right)
{
for (int n=first; n=first)&&(transition<=last));
TTransition trans=getTransitionTile (getComplementaryBorder (_TransitionFlags[transition][top]),
getComplementaryBorder (_TransitionFlags[transition][bottom]),
getComplementaryBorder (_TransitionFlags[transition][left]),
getComplementaryBorder (_TransitionFlags[transition][right]));
nlassert (trans!=notfound);
return trans;
}
// ***************************************************************************
CTileSet::TFlagBorder CTileSet::getComplementaryBorder (TFlagBorder border)
{
switch (border)
{
case _0000:
return _1111;
case _0001:
return _1110;
case _0111:
return _1000;
case _1000:
return _0111;
case _1110:
return _0001;
case _1111:
return _0000;
default:
nlassert (0); // no
}
return _0000;
}
// ***************************************************************************
CTileSet::TFlagBorder CTileSet::getInvertBorder (TFlagBorder border)
{
switch (border)
{
case _0000:
return _0000;
case _0001:
return _1000;
case _0111:
return _1110;
case _1000:
return _0001;
case _1110:
return _0111;
case _1111:
return _1111;
default:
nlassert (0); // no
}
return _0000;
}
// ***************************************************************************
CTileSet::TFlagBorder CTileSet::getOrientedBorder (TBorder where, TFlagBorder border)
{
switch (where)
{
case left:
case bottom:
return border;
case top:
case right:
return getInvertBorder (border);
default:
nlassert (0); // no
}
return _0000;
}
// ***************************************************************************
CTileSet::TTransition CTileSet::rotateTransition (TTransition transition)
{
return getTransitionTile (
getOrientedBorder (top, getOrientedBorder (right, _TransitionFlags[transition][right])), // top
getOrientedBorder (bottom, getOrientedBorder (left, _TransitionFlags[transition][left])), // bottom
getOrientedBorder (left, getOrientedBorder (top, _TransitionFlags[transition][top])), // left
getOrientedBorder (right, getOrientedBorder (bottom, _TransitionFlags[transition][bottom])) // right
);
}
// ***************************************************************************
void CTileSet::clearTile128 (int indexInTileSet, CTile::TBitmap type, CTileBank& bank)
{
int nTile=_Tile128[indexInTileSet];
bank.getTile (nTile)->clearTile(type);
// Erase border if it is the last texture
deleteBordersIfLast (bank, type);
}
// ***************************************************************************
void CTileSet::clearTile256 (int indexInTileSet, CTile::TBitmap type, CTileBank& bank)
{
int nTile=_Tile256[indexInTileSet];
bank.getTile (nTile)->clearTile(type);
// Erase border if it is the last texture
deleteBordersIfLast (bank, type);
}
// ***************************************************************************
void CTileSet::clearTransition (TTransition transition, CTile::TBitmap type, CTileBank& bank)
{
int nTile=_TileTransition[transition]._Tile;
if (nTile!=-1)
bank.getTile (nTile)->clearTile(type);
_BorderTransition[transition][type].reset();
// Erase border if it is the last texture
deleteBordersIfLast (bank, type);
}
// ***************************************************************************
// Delete 128 and 256 borders if no more valid texture file name for each bitmap type.
void CTileSet::deleteBordersIfLast (const CTileBank& bank, CTile::TBitmap type)
{
// delete is true
bool bDelete=true;
// iterator..
std::vector::iterator ite=_Tile128.begin();
// Check all the 128x128 tiles
while (ite!=_Tile128.end())
{
// If the file name is valid
if (bank.getTile (*ite)->getRelativeFileName(type)!="")
{
// Don't delete,
bDelete=false;
break;
}
ite++;
}
// If break, not empty, return
if (ite!=_Tile128.end())
return;
// Check all the 256x256 tiles
ite=_Tile256.begin();
while (ite!=_Tile256.end())
{
// If the file name is valid
if (bank.getTile (*ite)->getRelativeFileName(type)!="")
{
// Don't delete,
bDelete=false;
break;
}
ite++;
}
// If break, not empty, return
if (ite!=_Tile256.end())
return;
// Check all the transitions tiles
sint trans;
for (trans=0; transgetRelativeFileName(type)!="")
{
// Don't delete,
bDelete=false;
break;
}
}
}
if (trans!=count)
return;
// Ok, erase borders because no tile use it anymore
_Border128[type].reset();
_Border256[type].reset();
}
// ***************************************************************************
void CTileSet::clearDisplacement (TDisplacement displacement, CTileBank& bank)
{
// checks
nlassert (displacement>=FirstDisplace);
nlassert (displacement<=LastDisplace);
// Backup the id
int id=_DisplacementBitmap[displacement];
// Clear map id
_DisplacementBitmap[displacement]=0;
// Tell the bank we remove it
bank.removeDisplacementMap (id);
}
// ***************************************************************************
void CTileSet::setDisplacement (TDisplacement displacement, const std::string& fileName, CTileBank& bank)
{
// checks
nlassert (displacement>=FirstDisplace);
nlassert (displacement<=LastDisplace);
// Clear it
bank.removeDisplacementMap (_DisplacementBitmap[displacement]);
// Get displacement map
_DisplacementBitmap[displacement]=bank.getDisplacementMap (fileName);
}
// ***************************************************************************
void CTileSet::cleanUnusedData ()
{
_Name="";
_ChildName.clear();
_Border128[0].reset ();
_Border128[1].reset ();
_Border256[0].reset ();
_Border256[1].reset ();
for (uint i=0; i& array)
{
// Check array size
nlassert (width>0);
nlassert (height>0);
nlassert ((sint)array.size()==width*height);
// Copy size
_Width=width;
_Height=height;
// Last line
int lastLine=(_Height-1)*width;
int lastCol=(_Width-1);
_Borders[top].resize (_Width);
_Borders[bottom].resize (_Width);
_Borders[left].resize (_Height);
_Borders[right].resize (_Height);
// Copy top/bottom border
for (int w=0; w<_Width; w++)
{
_Borders[top][w]=array[w];
_Borders[bottom][w]=array[w+lastLine];
}
// Copy left/right border
for (int h=0; h<_Height; h++)
{
_Borders[left][h]=array[h*_Width];
_Borders[right][h]=array[h*_Width+lastCol];
}
// Set
_Set=true;
}
// ***************************************************************************
void CTileBorder::get (int &width, int &height, std::vector& array) const
{
// Go
if (_Set)
{
width=_Width;
height=_Height;
array.resize (0);
array.resize (_Width*_Height);
nlassert (_Borders[bottom].size()==(uint)_Width);
nlassert (_Borders[top].size()==(uint)_Width);
nlassert (_Borders[left].size()==(uint)_Height);
nlassert (_Borders[right].size()==(uint)_Height);
// Fill
CBGRA black(0,0,0);
for (int p=0; p<_Width*_Height; p++)
{
array[p]=black;
}
// Last line
int lastLine=(_Height-1)*_Width;
int lastCol=(_Width-1);
// Copy top/bottom border
for (int w=0; w<_Width; w++)
{
array[w]=_Borders[top][w];
array[w+lastLine]=_Borders[bottom][w];
}
// Copy left/right border
for (int h=0; h<_Height; h++)
{
array[h*_Width]=_Borders[left][h];
array[h*_Width+lastCol]=_Borders[right][h];
}
}
else
{
width=0;
height=0;
array.resize (0);
}
}
// ***************************************************************************
bool CTileBorder::compare (const CTileBorder& border1, const CTileBorder& border2, TBorder where1, TBorder where2, int& pixel, int& composante)
{
// Check border is initialized
nlassert (border1.isSet());
nlassert (border2.isSet());
if (border1._Borders[where1].size()!=border2._Borders[where2].size())
return false;
for (pixel=0; pixel<(int)border1._Borders[where1].size(); pixel++)
{
if (border1._Borders[where1][pixel].R!=border2._Borders[where2][pixel].R)
{
composante=0;
return false;
}
else if (border1._Borders[where1][pixel].G!=border2._Borders[where2][pixel].G)
{
composante=1;
return false;
}
else if (border1._Borders[where1][pixel].B!=border2._Borders[where2][pixel].B)
{
composante=2;
return false;
}
else if (border1._Borders[where1][pixel].A!=border2._Borders[where2][pixel].A)
{
composante=3;
return false;
}
}
return true;
}
// ***************************************************************************
bool CTileBorder::allAlphaSet (const CTileBorder& border, TBorder where, int& pixel, int& composante)
{
// Check border is initialized
nlassert (border.isSet());
// always Alpha
composante=3;
for (pixel=0; pixel<(int)border._Borders[where].size(); pixel++)
{
if (border._Borders[where][pixel].A!=0xff)
return false;
}
return true;
}
// ***************************************************************************
bool CTileBorder::operator== (const CTileBorder& border) const
{
return (_Width==border._Width) && (_Height==border._Height) && (_Borders==border._Borders);
}
// ***************************************************************************
void CTileBorder::operator= (const CTileBorder& border)
{
_Set=border._Set;
_Width=border._Width;
_Height=border._Width;
_Borders[top]=border._Borders[top];
_Borders[bottom]=border._Borders[bottom];
_Borders[left]=border._Borders[left];
_Borders[right]=border._Borders[right];
}
// ***************************************************************************
void CTileBorder::doubleSize ()
{
_Borders[top].resize (_Width*2);
_Borders[bottom].resize (_Width*2);
_Borders[left].resize (_Height*2);
_Borders[right].resize (_Height*2);
for (int w=0; w<_Width; w++)
{
_Borders[top][w+_Width]=_Borders[top][w];
_Borders[bottom][w+_Width]=_Borders[bottom][w];
}
for (int h=0; h<_Height; h++)
{
_Borders[left][h+_Height]=_Borders[left][h];
_Borders[right][h+_Height]=_Borders[right][h];
}
}
// ***************************************************************************
void CTileBorder::rotate()
{
// Copy the right
std::vector tmpLeft=_Borders[left];
// Top inverted becomes left
uint i, size;
size=(uint)_Borders[top].size();
_Borders[left].resize (size);
// copy inverted
for (i=0; iPixels, 0, NL3D_TILE_NOISE_MAP_SIZE*NL3D_TILE_NOISE_MAP_SIZE);
}
// ***************************************************************************
void CTileNoise::reset()
{
// Erase the map
if (_TileNoiseMap)
{
delete _TileNoiseMap;
_TileNoiseMap=NULL;
}
// Erase filename
_FileName="";
}
// ***************************************************************************
} // NL3D