diff --git a/code/studio/src/plugins/tile_editor/tile_editor_main_window.cpp b/code/studio/src/plugins/tile_editor/tile_editor_main_window.cpp index ee6221229..7c9ec8f52 100644 --- a/code/studio/src/plugins/tile_editor/tile_editor_main_window.cpp +++ b/code/studio/src/plugins/tile_editor/tile_editor_main_window.cpp @@ -656,6 +656,14 @@ void TileEditorMainWindow::onTabChanged( int tab ) m_ui->diffuseTrBT->setChecked( true ); } +TileModel::TNodeTileType tabToType( int tabId ) +{ + if( tabId >= TileModel::TileNodeTypeCount ) + return TileModel::TileNodeTypeCount; + + return TileModel::TNodeTileType( tabId ); +} + void TileEditorMainWindow::onActionAddTile(int tabId) { QModelIndex idx = m_ui->tileSetLV->currentIndex(); @@ -683,10 +691,27 @@ void TileEditorMainWindow::onActionAddTile(int tabId) int c = n->childCount(); + TileModel::TNodeTileType type = tabToType( tabId ); + QStringListIterator itr( fileNames ); while( itr.hasNext() ) { - Node *newNode = TileModel::createItemNode( c, TileModel::TileDiffuse, itr.next() ); + TileItemNode *newNode = TileModel::createItemNode( type, c, TileModel::TileDiffuse, itr.next() ); + if( newNode->hasError() ) + { + QString error = newNode->getLastError(); + error += "\nContinue?"; + + int reply = QMessageBox::question( this, + tr( "Error adding tile" ), + error, + QMessageBox::Yes, QMessageBox::No ); + if( reply != QMessageBox::Yes ) + break; + else + continue; + } + n->appendRow( newNode ); c++; } diff --git a/code/studio/src/plugins/tile_editor/tile_item.cpp b/code/studio/src/plugins/tile_editor/tile_item.cpp index 20c9492af..d60fb4bbb 100644 --- a/code/studio/src/plugins/tile_editor/tile_item.cpp +++ b/code/studio/src/plugins/tile_editor/tile_item.cpp @@ -22,6 +22,8 @@ #include +#include + Node::Node() : m_parentItem(0) { } @@ -264,18 +266,230 @@ void TileTypeNode::reindex() /////////////////////////////////////////////////// +NL3D::CTile::TBitmap channelToTBitmap( TileModel::TTileChannel channel ) +{ + NL3D::CTile::TBitmap bm; + + switch( channel ) + { + case TileModel::TileDiffuse: bm = NL3D::CTile::diffuse; break; + case TileModel::TileAdditive: bm = NL3D::CTile::additive; break; + case TileModel::TileAlpha: bm = NL3D::CTile::alpha; break; + } + + return bm; +} class TileItemNodePvt { public: + + TileItemNodePvt() + { + for( int i = 0; i < TileModel::TileChannelCount; i++ ) + m_borderFirst[ i ] = false; + + m_id = -1; + } + + 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; + } + + int getWidthForType( TileModel::TNodeTileType type, TileModel::TTileChannel channel ) + { + int width = -1; + + switch( type ) + { + case TileModel::Tile128: width = 128; break; + case TileModel::Tile256: width = 256; break; + case TileModel::TileTransition: + { + if( channel != TileModel::TileAlpha ) + width = 128; + break; + } + + case TileModel::TileDisplacement: width = 32; break; + } + + return width; + } + + NL3D::CTileSet::TError checkTile( TileModel::TTileChannel channel ) + { + if( m_type == TileModel::TileDisplacement ) + return NL3D::CTileSet::ok; + + if( channel == TileModel::TileAdditive ) + return NL3D::CTileSet::ok; + + int pixel; + int component; + int index; + + NL3D::CTileSet set; + NL3D::CTile::TBitmap bm = channelToTBitmap( channel ); + + NL3D::CTileSet::TError error = NL3D::CTileSet::ok; + + switch( m_type ) + { + case TileModel::Tile128: + error = set.checkTile128( bm, m_border[ channel ], pixel, component ); + break; + case TileModel::Tile256: + error = set.checkTile256( bm, m_border[ channel ], pixel, component ); + break; + case TileModel::TileTransition: + if( channel != TileModel::TileAlpha ) + error = set.checkTile128( bm, m_border[ channel ], pixel, component ); + else + error = set.checkTileTransition( NL3D::CTileSet::TTransition( m_id ), bm, m_border[ channel ], index, pixel, component ); + break; + } + + if( error == NL3D::CTileSet::ok ) + return NL3D::CTileSet::ok; + if( error == NL3D::CTileSet::addFirstA128128 ) + return NL3D::CTileSet::addFirstA128128; + +/* + enum TError { ok=0, topInterfaceProblem, bottomInterfaceProblem, leftInterfaceProblem, + rightInterfaceProblem, addFirstA128128, topBottomNotTheSame, rightLeftNotTheSame, + sizeInvalide, errorCount }; +*/ + static const char* comp[]={"Red", "Green", "Blue", "Alpha", ""}; + + if( error != NL3D::CTileSet::ok ) + { + m_lastError = "ERROR: "; + m_lastError += NL3D::CTileSet::getErrorMessage( error ); + m_lastError += "\n"; + + switch( m_type ) + { + case TileModel::Tile128: + case TileModel::Tile256: + m_lastError += QString( "pixel: %1 component: %2" ).arg( pixel ).arg( comp[ component ] ); + break; + + case TileModel::TileTransition: + if( channel != TileModel::TileAlpha ) + { + m_lastError += QString( "pixel: %1 component: %2" ).arg( pixel ).arg( comp[ component ] ); + } + else + { + if ((error==NL3D::CTileSet::topInterfaceProblem)||(error==NL3D::CTileSet::bottomInterfaceProblem)|| + (error==NL3D::CTileSet::leftInterfaceProblem)||(error==NL3D::CTileSet::rightInterfaceProblem)|| + (error==NL3D::CTileSet::topBottomNotTheSame)||(error==NL3D::CTileSet::rightLeftNotTheSame) + ||(error==NL3D::CTileSet::topInterfaceProblem)) + { + if( index != -1 ) + { + m_lastError += QString( "tile: %1 pixel: %2 component: %3" ).arg( index ).arg( pixel ).arg( comp[ component ] ); + } + else + { + m_lastError += QString( "incompatible with a 128 tile, pixel: %1 component: %2" ).arg( pixel ).arg( comp[ component ] ); + } + } + + } + break; + } + } + + return error; + } + + bool checkPixmap( TileModel::TTileChannel channel, QPixmap &pixmap ) + { + int w = pixmap.width(); + int h = pixmap.height(); + + if( w != h ) + { + m_lastError = QObject::tr( "Not a square texture." ); + return false; + } + + int width = getWidthForType( m_type, channel ); + + if( width != -1 ) + { + if( width != w ) + { + m_lastError = QObject::tr( "Not the proper size." ); + return false; + } + } + + std::vector< NLMISC::CBGRA > pixels; + + pixmapToCBGRA( pixmap, pixels ); + + m_border[ channel ].set( w, h, pixels ); + + NL3D::CTileSet::TError error = checkTile( channel ); + if( error == NL3D::CTileSet::addFirstA128128 ) + { + m_borderFirst[ channel ] = true; + return true; + } + + if( error != NL3D::CTileSet::ok ) + return false; + + return true; + } - bool loadImage( TileModel::TTileChannel channel, const QString &fn ) + bool loadImage( TileModel::TTileChannel channel, const QString &fn, bool empty = false ) { QPixmap temp; bool b = temp.load( fn ); if( !b ) + { + m_lastError = QObject::tr( "Cannot open file %1" ).arg( fn ); return false; + } + + if( !empty ) + { + if( !checkPixmap( channel, temp ) ) + return false; + } pixmaps[ channel ] = temp; @@ -291,19 +505,34 @@ public: return pixmaps[ channel ]; } + void setType( TileModel::TNodeTileType type ){ m_type = type; } + void setId( int id ){ m_id = id; } + int id() const{ return m_id; } + + QString getLastError() const{ return m_lastError; } + bool borderFirst( TileModel::TTileChannel channel ) const{ return m_borderFirst[ channel ]; } + private: QPixmap pixmaps[ TileModel::TileChannelCount ]; - + TileModel::TNodeTileType m_type; + NL3D::CTileBorder m_border[ TileModel::TileChannelCount ]; + int m_id; + QString m_lastError; + bool m_borderFirst[ TileModel::TileChannelCount ]; }; TileModel::TTileChannel TileItemNode::s_displayChannel = TileModel::TileDiffuse; -TileItemNode::TileItemNode(int tileId, TileModel::TTileChannel channel, QString filename, Node *parent) : m_tileId(tileId) +TileItemNode::TileItemNode( TileModel::TNodeTileType type, int tileId, TileModel::TTileChannel channel, QString filename, Node *parent) { m_parentItem = parent; //nlinfo("dispalying tile %d - %s", m_tileId, m_tileFilename[TileModel::TileDiffuse].toAscii().data()); pvt = new TileItemNodePvt(); + pvt->setType( type ); + pvt->setId( tileId ); + + m_hasError = false; setTileFilename( channel, filename ); } @@ -319,11 +548,16 @@ TileItemNode::~TileItemNode() bool TileItemNode::setTileFilename(TileModel::TTileChannel channel, QString filename) { QString fn = filename; + bool empty = false; if( filename.isEmpty() || ( filename == "empty" ) ) + { fn = ":/placeHolder/images/empty_image.png"; + empty = true; + } - bool b = pvt->loadImage( channel, fn ); + bool b = pvt->loadImage( channel, fn, empty ); + m_hasError = !b; if( !b ) return false; @@ -341,6 +575,26 @@ QString TileItemNode::getTileFilename(TileModel::TTileChannel channel) return itr.value(); } +void TileItemNode::setId( int id ) +{ + pvt->setId( id ); +} + +int TileItemNode::id() const +{ + return pvt->id(); +} + +QString TileItemNode::getLastError() const +{ + return pvt->getLastError(); +} + +bool TileItemNode::borderFirst() const +{ + return false; +} + QVariant TileItemNode::data(int column, int role) const { QString tileFilename = m_tileFilename[ TileItemNode::s_displayChannel ]; @@ -375,11 +629,11 @@ QVariant TileItemNode::data(int column, int role) const } else if(role == TileModel::TileIndexRole) { - return QVariant("("+QString::number(m_tileId)+")"); + return QVariant("("+QString::number(pvt->id())+")"); } else if(role == TileModel::TileFilenameIndexRole) { - return QVariant(tileFilename + " ("+QString::number(m_tileId)+")"); + return QVariant(tileFilename + " ("+QString::number(pvt->id())+")"); } return QVariant(); diff --git a/code/studio/src/plugins/tile_editor/tile_item.h b/code/studio/src/plugins/tile_editor/tile_item.h index 611059ffa..fc5443037 100644 --- a/code/studio/src/plugins/tile_editor/tile_item.h +++ b/code/studio/src/plugins/tile_editor/tile_item.h @@ -109,26 +109,31 @@ class TileItemNodePvt; class TileItemNode : public Node { public: - TileItemNode(int tileId, TileModel::TTileChannel channel, QString filename, Node *parent=0); + TileItemNode( TileModel::TNodeTileType type, int tileId, TileModel::TTileChannel channel, QString filename, Node *parent=0); virtual ~TileItemNode(); QVariant data(int column, int role) const; int columnCount() const; bool setTileFilename(TileModel::TTileChannel channel, QString filename); QString getTileFilename(TileModel::TTileChannel channel); - void setId( int id ){ m_tileId = id; } - int id() const{ return m_tileId; } + void setId( int id ); + int id() const; + QString getLastError() const; + bool borderFirst() const; static void setDisplayChannel( TileModel::TTileChannel channel ){ s_displayChannel = channel; } static TileModel::TTileChannel displayChannel(){ return s_displayChannel; } + bool hasError() const{ return m_hasError; } + private: - int m_tileId; QMap m_tileFilename; QMap m_tileWidget; static TileModel::TTileChannel s_displayChannel; TileItemNodePvt *pvt; + + bool m_hasError; }; #endif // TILE_ITEM_H diff --git a/code/studio/src/plugins/tile_editor/tile_model.cpp b/code/studio/src/plugins/tile_editor/tile_model.cpp index 037be65cd..d1ab0d238 100644 --- a/code/studio/src/plugins/tile_editor/tile_model.cpp +++ b/code/studio/src/plugins/tile_editor/tile_model.cpp @@ -197,7 +197,7 @@ TileSetNode *TileModel::createTileSetNode(QString tileSetName) // TODO tie this to CTileSet::count from NeL for(int transPos=0; transPos<48; transPos++) { - TileItemNode *transTile= new TileItemNode(transPos, TileDiffuse, QString("empty")); + TileItemNode *transTile= new TileItemNode( TileModel::TileTransition, transPos, TileDiffuse, QString("empty")); tileTrans->appendRow(transTile); } @@ -209,7 +209,7 @@ TileSetNode *TileModel::createTileSetNode(QString tileSetName) // TODO tie this to CTileSet::CountDisplace from NeL for(int dispPos=0; dispPos<16; dispPos++) { - TileItemNode *dispTile= new TileItemNode(dispPos, TileDiffuse, QString("empty")); + TileItemNode *dispTile= new TileItemNode( TileModel::TileDisplacement, dispPos, TileDiffuse, QString("empty")); tileDisp->appendRow(dispTile); } @@ -219,9 +219,9 @@ TileSetNode *TileModel::createTileSetNode(QString tileSetName) return tileSet; } -Node *TileModel::createItemNode( int id, TTileChannel channel, const QString &fileName ) +TileItemNode *TileModel::createItemNode( TileModel::TNodeTileType type, int id, TTileChannel channel, const QString &fileName ) { - return new TileItemNode( id, channel, fileName ); + return new TileItemNode( type, id, channel, fileName ); } const char *TileModel::getTileTypeName(TileModel::TNodeTileType type) diff --git a/code/studio/src/plugins/tile_editor/tile_model.h b/code/studio/src/plugins/tile_editor/tile_model.h index e855f8871..c22a43091 100644 --- a/code/studio/src/plugins/tile_editor/tile_model.h +++ b/code/studio/src/plugins/tile_editor/tile_model.h @@ -23,6 +23,7 @@ class Node; class TileSetNode; +class TileItemNode; class TileModel : public QAbstractItemModel { @@ -42,7 +43,8 @@ public: Tile128 = 0, Tile256 = 1, TileTransition = 2, - TileDisplacement = 3 + TileDisplacement = 3, + TileNodeTypeCount = 4 }; enum TTileItemRole @@ -85,7 +87,7 @@ public: void swapRows( int a, int b ); TileSetNode *createTileSetNode(QString tileSetName); - static Node *createItemNode( int id, TTileChannel channel, const QString &fileName ); + static TileItemNode *createItemNode( TileModel::TNodeTileType type, int id, TTileChannel channel, const QString &fileName ); static const char *getTileTypeName(TNodeTileType type); static uint32 getTileTypeSize(TileModel::TNodeTileType type); diff --git a/code/studio/src/plugins/tile_editor/tilebank_loader.cpp b/code/studio/src/plugins/tile_editor/tilebank_loader.cpp index 238a41a52..73c8007d8 100644 --- a/code/studio/src/plugins/tile_editor/tilebank_loader.cpp +++ b/code/studio/src/plugins/tile_editor/tilebank_loader.cpp @@ -75,7 +75,7 @@ public: int idx = set->getTile128( i ); NL3D::CTile *tile = bank.getTile( idx ); - TileItemNode *tin = new TileItemNode( i, TileModel::TileDiffuse, "" ); + TileItemNode *tin = new TileItemNode( TileModel::Tile128, i, TileModel::TileDiffuse, "" ); for( int i = TileModel::TileDiffuse; i < TileModel::TileAlpha; i++ ) { @@ -94,7 +94,7 @@ public: int idx = set->getTile256( i ); NL3D::CTile *tile = bank.getTile( idx ); - TileItemNode *tin = new TileItemNode( i, TileModel::TileDiffuse, "" ); + TileItemNode *tin = new TileItemNode( TileModel::Tile256, i, TileModel::TileDiffuse, "" ); for( int i = TileModel::TileDiffuse; i < TileModel::TileAlpha; i++ ) {