khanat-opennel-code/code/studio/src/plugins/tile_editor/tile_bank.cpp
dfighter1985 caf76f09c8 Most of the functionality works with the new code.
--HG--
branch : gsoc2014-dfighter
2014-08-04 21:22:44 +02:00

395 lines
9.5 KiB
C++

#include "tile_bank.h"
#include "nel/3d/tile_bank.h"
#include <QPixmap>
namespace{
bool pixmapToCBGRA( QPixmap &pixmap, std::vector< NLMISC::CBGRA >& pixels )
{
QImage img = pixmap.toImage();
if( img.format() != QImage::Format_ARGB32 )
img = img.convertToFormat( QImage::Format_ARGB32 );
if( img.format() != QImage::Format_ARGB32 )
return false;
int c = img.width() * img.height();
const unsigned char *data = img.bits();
const unsigned int *idata = reinterpret_cast< const unsigned int* >( data );
NLMISC::CBGRA bgra;
pixels.clear();
int i = 0;
while( i < c )
{
bgra.A = ( idata[ i ] & 0xFF000000 ) >> 24;
bgra.R = ( idata[ i ] & 0x00FF0000 ) >> 16;
bgra.G = ( idata[ i ] & 0x0000FF00 ) >> 8;
bgra.B = ( idata[ i ] & 0x000000FF );
pixels.push_back( bgra );
i++;
}
return true;
}
NL3D::CTile::TBitmap channelToTBitmap( TileConstants::TTileChannel channel )
{
return NL3D::CTile::TBitmap( int( channel ) );
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TileBankPvt
{
public:
bool checkSize( TileConstants::TNodeTileType type, TileConstants::TTileChannel channel, int w, int h )
{
int width = -1;
switch( type )
{
case TileConstants::Tile128:
width = 128;
break;
case TileConstants::Tile256:
width = 256;
break;
case TileConstants::TileTransition:
{
if( channel == TileConstants::TileAlpha )
width = 64;
else
width = 128;
}
break;
case TileConstants::TileDisplacement:
width = 32;
break;
}
if( width == w )
return true;
return false;
}
NL3D::CTileSet::TError checkTile( NL3D::CTileSet *set, int tile, TileConstants::TNodeTileType type, NL3D::CTileBorder &border, NL3D::CTile::TBitmap bitmap, QString &msg )
{
NL3D::CTileSet::TError error;
if( bitmap == NL3D::CTile::additive )
return NL3D::CTileSet::ok;
if( type == TileConstants::TileDisplacement )
return NL3D::CTileSet::ok;
int component;
int pixel;
int idx;
switch( type )
{
case TileConstants::Tile128:
error = set->checkTile128( bitmap, border, pixel, component );
break;
case TileConstants::Tile256:
error = set->checkTile256( bitmap, border, pixel, component );
break;
case TileConstants::TileTransition:
{
if( bitmap != NL3D::CTile::alpha )
error = set->checkTile128( bitmap, border, pixel, component );
else
error = set->checkTileTransition( NL3D::CTileSet::TTransition( tile ), bitmap, border, idx, pixel, component );
break;
}
}
if( ( error != NL3D::CTileSet::ok ) && ( error != NL3D::CTileSet::addFirstA128128 ) )
{
static const char* comp[]={"Red", "Green", "Blue", "Alpha", ""};
msg = NL3D::CTileSet::getErrorMessage( error );
msg += "\n";
msg += " pixel %1 component %2";
msg = msg.arg( pixel );
msg = msg.arg( comp[ component ] );
}
return error;
}
void setTile( NL3D::CTileSet *set, int tile, int rotation, const QString &name, NL3D::CTile::TBitmap bm, TileConstants::TNodeTileType type, NL3D::CTileBorder &border )
{
switch( type )
{
case TileConstants::Tile128:
set->setTile128( tile, name.toUtf8().constData(), bm, m_bank );
break;
case TileConstants::Tile256:
set->setTile256( tile, name.toUtf8().constData(), bm, m_bank );
break;
case TileConstants::TileTransition:
if( bm != NL3D::CTile::alpha )
set->setTileTransition( NL3D::CTileSet::TTransition( tile ), name.toUtf8().constData(), bm, m_bank, border );
else
set->setTileTransitionAlpha( NL3D::CTileSet::TTransition( tile ), name.toUtf8().constData(), m_bank, border, rotation );
break;
case TileConstants::TileDisplacement:
set->setDisplacement( NL3D::CTileSet::TDisplacement( tile ), name.toUtf8().constData(), m_bank );
break;
}
}
void buildBorder( QPixmap &pm, NL3D::CTileBorder &border )
{
std::vector< NLMISC::CBGRA > pixels;
pixmapToCBGRA( pm, pixels );
border.set( pm.width(), pm.height(), pixels );
}
NL3D::CTileBank m_bank;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TileBank::TileBank()
{
m_pvt = new TileBankPvt();
resetError();
}
TileBank::~TileBank()
{
delete m_pvt;
}
void TileBank::addTileSet( const QString &name )
{
m_pvt->m_bank.addTileSet( name.toUtf8().constData() );
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( 0 );
}
void TileBank::removeTileSet( int idx )
{
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( idx );
if( set == NULL )
return;
int c = m_pvt->m_bank.getLandCount();
for( int i = 0; i < c; i++ )
{
NL3D::CTileLand *land = m_pvt->m_bank.getLand( i );
land->removeTileSet( set->getName() );
}
m_pvt->m_bank.removeTileSet( idx );
}
void TileBank::renameTileSet( int idx, const QString &newName )
{
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( idx );
if( set == NULL )
return;
std::string oldName = set->getName();
set->setName( newName.toUtf8().constData() );
int c = m_pvt->m_bank.getLandCount();
for( int i = 0; i < c; i++ )
{
NL3D::CTileLand *land = m_pvt->m_bank.getLand( i );
land->removeTileSet( oldName );
land->addTileSet( newName.toUtf8().constData() );
}
}
void TileBank::addLand( const QString &name )
{
m_pvt->m_bank.addLand( name.toUtf8().constData() );
}
void TileBank::removeLand( int idx )
{
m_pvt->m_bank.removeLand( idx );
}
void TileBank::setLandSets( int idx, const QStringList &l )
{
NL3D::CTileLand *land = m_pvt->m_bank.getLand( idx );
land->clear();
QStringListIterator itr( l );
while( itr.hasNext() )
{
land->addTileSet( itr.next().toUtf8().constData() );
}
}
void TileBank::getLandSets( int idx, QStringList &l )
{
NL3D::CTileLand *land = m_pvt->m_bank.getLand( idx );
if( land == NULL )
return;
l.clear();
std::set< std::string> sets = land->getTileSets();
std::set< std::string >::const_iterator itr = sets.begin();
while( itr != sets.end() )
{
l.push_back( itr->c_str() );
++itr;
}
}
bool TileBank::addTile( int setIdx, const QString &name, const QVariant &pixmap, TileConstants::TTileChannel channel, TileConstants::TNodeTileType type )
{
resetError();
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( setIdx );
int tile;
switch( type )
{
case TileConstants::Tile128: set->addTile128( tile, m_pvt->m_bank ); break;
case TileConstants::Tile256: set->addTile256( tile, m_pvt->m_bank ); break;
}
bool b = setTile( setIdx, tile, name, pixmap, channel, type );
if( b )
return true;
// There was an error, roll back
switch( type )
{
case TileConstants::Tile128: set->removeTile128( tile, m_pvt->m_bank ); break;
case TileConstants::Tile256: set->removeTile128( tile, m_pvt->m_bank ); break;
}
return false;
}
void TileBank::removeTile( int ts, int type, int tile )
{
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( ts );
switch( type )
{
case TileConstants::Tile128: set->removeTile128( tile, m_pvt->m_bank ); break;
case TileConstants::Tile256: set->removeTile256( tile, m_pvt->m_bank ); break;
}
}
bool TileBank::setTile( int tileset, int tile, const QString &name, const QVariant &pixmap, TileConstants::TTileChannel channel, TileConstants::TNodeTileType type )
{
resetError();
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( tileset );
if( set == NULL )
return false;
QPixmap pm = pixmap.value< QPixmap >();
if( pm.isNull() )
{
m_hasError = true;
m_lastError = "Failed to load image.";
return false;
}
if( pm.width() != pm.height() )
{
m_hasError = true;
m_lastError = "Image isn't square.";
return false;
}
if( !m_pvt->checkSize( type, channel, pm.width(), pm.height() ) )
{
m_hasError = true;
m_lastError = "Invalid image size.";
return false;
}
NL3D::CTileBorder border;
m_pvt->buildBorder( pm, border );
QString msg;
NL3D::CTileSet::TError error = m_pvt->checkTile( set, tile, type, border, channelToTBitmap( channel ), msg );
// Tile checks out fine, set it
if( ( error == NL3D::CTileSet::ok ) || ( error == NL3D::CTileSet::addFirstA128128 ) )
{
if( error == NL3D::CTileSet::addFirstA128128 )
set->setBorder( channelToTBitmap( channel ), border );
m_pvt->setTile( set, tile, 0 /* rotation */, name, channelToTBitmap( channel ), type, border );
return true;
}
setError( msg );
return false;
}
void TileBank::replaceImage( int ts, int type, int tile, TileConstants::TTileChannel channel, const QString &name, const QVariant &pixmap )
{
setTile( ts, tile, name, pixmap, channel, TileConstants::TNodeTileType( type ) );
}
void TileBank::clearImage( int ts, int type, int tile, TileConstants::TTileChannel channel )
{
NL3D::CTileSet *set = m_pvt->m_bank.getTileSet( ts );
int tileId;
NL3D::CTile::TBitmap bm = channelToTBitmap( channel );
switch( type )
{
case TileConstants::Tile128:
set->clearTile128( tile, bm, m_pvt->m_bank );
break;
case TileConstants::Tile256:
set->clearTile256( tile, bm, m_pvt->m_bank );
break;
case TileConstants::TileTransition:
set->clearTransition( NL3D::CTileSet::TTransition( tile ), bm, m_pvt->m_bank );
break;
case TileConstants::TileDisplacement:
set->clearDisplacement( NL3D::CTileSet::TDisplacement( tile ), m_pvt->m_bank );
break;
}
}