/*=========================================================================== File: main.cpp This tool turns a greyscale image into a raw look up table. Copyright (c) Radical Entertainment, Inc. All rights reserved. ===========================================================================*/ #include #include #include #include #include #include #include #include #include "Param.hpp" #include Parameters* Param; char outFile[P3DMAXNAME]; struct TextureData { TextureData() : m_TextureID( 0 ), m_NumIDs( 0 ), m_ShaderID( 0 ), m_AnimationChunk( 0 ), m_ControllerChunk( 0 ), // m_MultiControllerChunk( 0 ), m_pSetChunk( 0 ), m_WritenOut( false ) {}; ~TextureData() { delete m_TextureID; } // Set chunk is deleted by the output chunk. TLUID* m_TextureID; // List of texture chunks to put into set chunk. int m_NumIDs; // Number in list. If number is negative then just the animation/controller chunk are removed and multicontroller modified. TLUID m_ShaderID; // The shader this data is for. TLUID m_AnimationChunk; // Texture animation chunk to remove. TLUID m_ControllerChunk; // Texture frame controller chunk to remove. // TLUID m_MultiControllerChunk; // MultiController to remove texture frame controller from. tlSetChunk* m_pSetChunk; // Set chunk which will be written to file. bool m_WritenOut; // Has the set chunk been written out? }; static const int TEXTURE_COLLECTION_SIZE = 256; static TextureData* g_TextureCollection[ TEXTURE_COLLECTION_SIZE ]; static int g_TextureCollectionCount = 0; int main(int argc, char* argv[]) { Param = new Parameters(argc,argv); bool sameFile = false; // Have we switched to a new output file. tlDataChunk::RegisterDefaultChunks(); tlFile* output = 0; for( int i = 0; i < TEXTURE_COLLECTION_SIZE; ++i ) { g_TextureCollection[ i ] = 0; } if( Param->Files.Count() < 1 ) { printf( "Must specify at least one input file.\n" ); exit( -1 ); } if( Param->ShaderName == 0 ) { printf( "Must specify the name of the shader with texture animation.\n" ); exit( -1 ); } bool wildCardShader = false; int shaderNameLen = strlen( Param->ShaderName ); if( Param->ShaderName[ shaderNameLen - 1 ] == '*' ) { wildCardShader = true; --shaderNameLen; Param->ShaderName[ shaderNameLen ] = '\0'; } // for each file on the command-line, do the following: for(int curFile = 0; curFile < Param->Files.Count(); curFile++) { tlFile input(new tlFileByteStream(Param->Files[ curFile ], omREAD), tlFile::FROMFILE); if(!input.IsOpen()) { printf("Could not open %s\n", Param->Files[ curFile ]); exit( -1 ); } tlDataChunk* inChunk = new tlDataChunk( &input ); char outFileName[256]; if( output == 0 ) { if( Param->OutputFile ) { strcpy(outFileName, Param->OutputFile); } else { strcpy(outFileName, Param->Files[curFile]); RemoveExtension(outFileName); strcat(outFileName, ".p3d"); } output = new tlFile(new tlFileByteStream(outFileName, omWRITE), tlFile::CHUNK32); if( ( output == 0 ) || ( !output->IsOpen() ) ) { printf("Could not open %s for writing\n", outFileName); exit(-1); } sameFile = false; } for( int i = 0; i < g_TextureCollectionCount; ++i ) { delete g_TextureCollection[ i ]; g_TextureCollection[ i ] = 0; } /*************************************************/ // First pass for input file, nose through the frame controllers. // Go through all the sub-chunks of the input and look for shader name //in heirarchy of texture frame controller. int inChunkIndex; for( inChunkIndex = 0; inChunkIndex < inChunk->SubChunkCount(); inChunkIndex++ ) { tlDataChunk* sub = inChunk->GetSubChunk( inChunkIndex ); if( sub->ID() == Pure3D::Animation::FrameControllerData::FRAME_CONTROLLER ) { // We have a frame controller... tlFrameControllerChunk* controller = static_cast( sub ); if( controller->GetType() == Pure3DAnimationTypes::TEXTURE_TEX ) { // and it's a texture controller. So check the hierarchy name. bool foundShader = false; const char* heirName = controller->HierarchyName(); if( wildCardShader ) { foundShader = strncmp( heirName, Param->ShaderName, shaderNameLen ) == 0; } else { foundShader = strcmp( heirName, Param->ShaderName ) == 0; } if( foundShader ) { // We found the shader so remember the texture animation data. TextureData* texData = new TextureData(); if( texData == 0 ) { printf( "Unable to allocate texture data.\n" ); exit( -1 ); } texData->m_ShaderID = tlEntity::MakeUID( heirName ); texData->m_ControllerChunk = tlEntity::MakeUID( controller->GetName() ); texData->m_AnimationChunk = tlEntity::MakeUID( controller->AnimationName() ); // Look to see if we already have this shader. //If we do, we'll just erase the controller and animation and modify the multicontroller. //The first texData will be used to create the chunk set. for( int i = 0; i < g_TextureCollectionCount; ++i ) { if( g_TextureCollection[ i ]->m_ShaderID == texData->m_ShaderID ) { texData->m_NumIDs = -1; break; } } g_TextureCollection[ g_TextureCollectionCount ] = texData; ++g_TextureCollectionCount; } } } } /*************************************************/ // Second pass. Now we look for the animation to go with all those texture frame controllers //we found. for( inChunkIndex = 0; inChunkIndex < inChunk->SubChunkCount(); inChunkIndex++ ) { tlDataChunk* sub = inChunk->GetSubChunk( inChunkIndex ); // Is this an animation? if( sub->ID() != Pure3D::Animation::AnimationData::ANIMATION ) { // No, not interested. continue; } tlAnimationChunk* anim = static_cast( sub ); // Is it a texture animation? if( anim->GetAnimationType() != Pure3DAnimationTypes::TEXTURE_TEX ) { // No, not interested. continue; } // We've found a texture animation. Check if it's one we are looking for. TLUID animID = tlEntity::MakeUID( anim->GetName() ); for( int i = 0; i < g_TextureCollectionCount; ++i ) { if( ( g_TextureCollection[ i ]->m_NumIDs == 0 ) && ( g_TextureCollection[ i ]->m_AnimationChunk == animID ) ) { // We've found the animation to match a frame controller. Let the mess begin. TextureData* texData = g_TextureCollection[ i ]; // just for convience. // Examine the sub chunks...there should be a goup list in there... for( int subChunkIndex = 0; subChunkIndex < anim->SubChunkCount(); ++subChunkIndex ) { tlDataChunk* animSub = anim->GetSubChunk( subChunkIndex ); if( animSub->ID() == Pure3D::Animation::AnimationData::GROUP_LIST ) { // Found the group list. Now we'll nose around the groups... tlAnimationGroupListChunk* groupList = static_cast( animSub ); for( int listChunkIndex = 0; listChunkIndex < groupList->SubChunkCount(); ++listChunkIndex ) { // Look at all the channels in the groups in the group list. tlDataChunk* listSub = groupList->GetSubChunk( listChunkIndex ); if( listSub->ID() == Pure3D::Animation::AnimationData::GROUP ) { tlAnimationGroupChunk* group = static_cast( listSub ); for( int channelIndex = 0; channelIndex < (int)group->GetNumChannels(); ++channelIndex ) { int i; // In the group (whew), look at all the channels. // Is it an entity channel? tlDataChunk* channelSub = group->GetSubChunk( channelIndex ); if( channelSub->ID() != Pure3D::Animation::ChannelData::ENTITY ) { // No, not interested. continue; } // Is the entity channel a texture? tlEntityChannelChunk* entityChannel = static_cast( channelSub ); if( entityChannel->Param() != Pure3DAnimationTypes::TEXTURE_TEX ) { // No, not interested. continue; } // Okay we have the entity channel for a texture animation, now we //record the texture names. // We might end up allocating extra space for textures, but we'll //leave the UIDs at zero at the end of the array. texData->m_TextureID = new TLUID[ entityChannel->GetNumFrames() ]; if( texData->m_TextureID == 0 ) { printf( "Unable to allocate texture array.\n" ); exit( -1 ); } for( i = 0; i < (int)entityChannel->GetNumFrames(); ++i ) { texData->m_TextureID[ i ] = 0; } // Get all the frame values. char** values = entityChannel->GetValues(); for( i = 0; i < (int)entityChannel->GetNumFrames(); ++i ) { TLUID textureID = tlEntity::MakeUID( values[ i ] ); // We have the texture tUID, look if it's a duplicate. bool textureDup = false; for( int j = 0; j < texData->m_NumIDs; ++j ) { if( texData->m_TextureID[ j ] == textureID ) { // this one is a duplicate, skip it. textureDup = true; break; } } if( !textureDup ) { // It's not a duplicate so remember it. texData->m_TextureID[ texData->m_NumIDs ] = textureID; ++texData->m_NumIDs; } } } } } } } } } } /*************************************************/ // Third pass, create the set chunks from the textures we got from those texture animations. for( inChunkIndex = 0; inChunkIndex < inChunk->SubChunkCount(); inChunkIndex++ ) { tlDataChunk* sub = inChunk->GetSubChunk( inChunkIndex ); if( sub->ID() == Pure3D::Texture::TEXTURE ) { // We've found a texture, check to see if it's one of the textures we are looking for. TextureData* texData = 0; int textureIDIndex = 0; TLUID textureID = tlEntity::MakeUID( sub->GetName() ); for( int i = 0; i < g_TextureCollectionCount; ++i ) { texData = g_TextureCollection[ i ]; for( textureIDIndex = 0; textureIDIndex < texData->m_NumIDs; ++textureIDIndex ) { if( textureID == texData->m_TextureID[ textureIDIndex ] ) { if( texData->m_pSetChunk == 0 ) { texData->m_pSetChunk = new tlSetChunk(); if( texData->m_pSetChunk == 0 ) { printf( "Unable to create tlSetChunk.\n" ); exit( -1 ); } } if( textureIDIndex == 0 ) { // This is the first texture in the set so we'll use the name for //the set. texData->m_pSetChunk->SetName( sub->GetName() ); } texData->m_pSetChunk->AppendSubChunk( sub, 0 ); break; } } } } } /*************************************************/ // Forth pass, process the file. Copy all the chunks over, //except the texture frame controllers, texture animations, //and textures we've used. Also, modify the multicontrollers //to exclude the texture frame controllers. tlDataChunk* outChunk = new tlDataChunk; if( Param->WriteHistory && !sameFile ) { // put a history chunk in the output // a history chunk shows what version of the tool // was run on the file with what command-line // parameters outChunk->AppendSubChunk(Param->HistoryChunk()); sameFile = true; } if( outChunk == 0 ) { printf( "Unable to create output chunk.\n" ); exit( -1 ); } for( inChunkIndex = 0; inChunkIndex < inChunk->SubChunkCount(); inChunkIndex++ ) { tlDataChunk* sub = inChunk->GetSubChunk( inChunkIndex ); if( sub->ID() == Pure3D::Texture::TEXTURE ) { bool inAnySet = false; for( int i = 0; i < g_TextureCollectionCount; ++i ) { // Theorically a texture can go into multiple sets so go through them all. bool found = false; TextureData* texData = g_TextureCollection[ i ]; for( int j = 0; j < texData->m_NumIDs; ++j ) { // Look to see if this texture is in this set. if( tlEntity::MakeUID( sub->GetName() ) == texData->m_TextureID[ j ] ) { found = true; inAnySet = true; break; } } if( found && ( texData->m_NumIDs > 0 ) ) { // This texture has gone into this set chunk. We'll write the //set chunk out at this point so it's roughly in the same place in //file to protect against load order dependency problems. if( texData->m_WritenOut == false ) { texData->m_pSetChunk->SetChildCount( texData->m_NumIDs ); outChunk->AppendSubChunk( texData->m_pSetChunk ); texData->m_WritenOut = true; // Only write it once. } } } if( !inAnySet ) { // This isn't a texture we're interested in so write it out. outChunk->AppendSubChunk( sub ); } } else if( sub->ID() == Pure3D::Animation::FrameControllerData::FRAME_CONTROLLER ) { // This is a frame controller. If it's one we've used then don't include it. bool found = false; TLUID controllerID = tlEntity::MakeUID( sub->GetName() ); for( int i = 0; i < g_TextureCollectionCount; ++i ) { if( controllerID == g_TextureCollection[ i ]->m_ControllerChunk ) { found = true; break; } } if( !found ) { outChunk->AppendSubChunk( sub ); } } else if( sub->ID() == Pure3D::Animation::AnimationData::ANIMATION ) { // This is an animation. If it's one we've used then don't include it. bool found = false; TLUID animID = tlEntity::MakeUID( sub->GetName() ); for( int i = 0; i < g_TextureCollectionCount; ++i ) { if( animID == g_TextureCollection[ i ]->m_AnimationChunk ) { found = true; break; } } if( !found ) { outChunk->AppendSubChunk( sub ); } } else if( sub->ID() == P3D_MULTI_CONTROLLER ) { // This is a multicontroller. If a track references an framecontroller we //used then exclude that track. tlMultiControllerChunk16* multiCont = static_cast( sub ); for( int subIndex = 0; subIndex < multiCont->SubChunkCount(); ++subIndex ) { tlDataChunk* subChunk = multiCont->GetSubChunk( subIndex ); if( subChunk->ID() == P3D_MULTI_CONTROLLER_TRACKS ) { tlMultiControllerTracksChunk16* tracks = static_cast( subChunk ); unsigned long numTracks = tracks->GetNumTracks(); tlMultiControllerTrackData* trackArray = tracks->GetTracks(); for( int i = 0; i < numTracks; ++i ) { TLUID trackID = tlEntity::MakeUID( trackArray[ i ].name ); for( int j = 0; j < g_TextureCollectionCount; ++j ) { if( trackID == g_TextureCollection[ j ]->m_ControllerChunk ) { // Remove this track. --numTracks; tracks->SetNumTracks( numTracks ); multiCont->SetNumTracks( multiCont->GetNumTracks() - 1 ); if( i < numTracks ) { trackArray[ i ] = trackArray[ numTracks ]; --i; } } } } } else if( subChunk->ID() == P3D_MULTI_CONTROLLER_TRACK ) { tlMultiControllerTrackChunk16* track = static_cast( subChunk ); TLUID trackID = tlEntity::MakeUID( track->GetName() ); for( int i = 0; i < g_TextureCollectionCount; ++i ) { if( trackID == g_TextureCollection[ i ]->m_ControllerChunk ) { multiCont->RemoveSubChunk( subIndex ); multiCont->SetNumTracks( multiCont->GetNumTracks() - 1 ); } } } } outChunk->AppendSubChunk( sub ); } else { outChunk->AppendSubChunk( sub ); } } outChunk->Write( output ); delete outChunk; outChunk = 0; if( Param->OutputFile == 0 ) { // We have multiple output files so get rid of the //the output file now. delete output; output = 0; } for( i = 0; i < g_TextureCollectionCount; ++i ) { delete g_TextureCollection[ i ]; g_TextureCollection[ i ] = 0; } } // end of main for loop delete Param; return 0; }