xFile_Render.cpp

00001 #include "xFile_Render.h"
00002 
00003 #include "dma.h"
00004 #include <memory.h>
00005 
00009 xFile_Render::xFile_Render()
00010 {
00011         initialise();
00012 }
00013 
00017 xFile_Render::~xFile_Render()
00018 {
00019         cleanUp();
00020 }
00021 
00025 bool xFile_Render::initialise()
00026 {
00027 
00028         changed = true;
00029         verbose = true;
00030         numTextures = 0;
00031         numSubsetMeshes = 0;
00032         subsetMeshes = NULL;
00033         textures = NULL;
00034 
00035         m_World = Matrix4x4::IDENTITY;
00036         m_WVP = Matrix4x4::IDENTITY;
00037         m_bWorldLoaded = false;
00038         loaded = false;
00039         isAnimated = false;
00040         setAnimationSet = NULL;
00041         previousKey = 0;
00042 
00043 
00044         return true;
00045 
00046 }
00047 
00051 bool xFile_Render::cleanUp()
00052 {
00053         cleanTextures();
00054         cleanSubsets();
00055 
00056         return true;
00057 }
00058 
00062 bool xFile_Render::reset()
00063 {
00064         cleanUp();
00065         initialise();
00066         return true;
00067 }
00068 
00072 bool xFile_Render::load(LPCSTR fileName, bool verboseOutput)
00073 {
00074         reset();
00075 
00076         // Load the specified XFile using the xFile_Loader.
00077         if(!(loaded = m_XFile.load(fileName,verboseOutput)))
00078                 return loaded;
00079 
00080         // Load any textures specified in the X-File (texture loading is platform dependent).
00081         if(!(loaded = loadTextures()))
00082                 return loaded;
00083 
00084         // Divide mesh into subsets (groups of triangles sorted by material) for rendering.
00085         if(!(loaded = createSubsets()))
00086                 return loaded;
00087 
00088         // Check to see if any animations have been loaded, if so set the isAnimated flag.
00089         if(m_XFile.animationSets.size() > 0)
00090         {
00091                 isAnimated = true;
00092                 setAnimationSet = m_XFile.animationSets[0];     // By default set the first animation set from the file as the current animation
00093         }
00094 
00095         // Make sure all the matrices are updated the first time .
00096         update(m_XFile.rootFrame);                                              
00097 
00098         return loaded;
00099 }
00100 
00106 bool xFile_Render::createSubsets()
00107 {
00108 
00109         numSubsetMeshes = m_XFile.meshes.size();                                        // One SubsetMesh per-mesh in the xFile_Loader data.
00110         subsetMeshes = new SubsetMesh* [numSubsetMeshes];
00111 
00112         for(int nMesh = 0; nMesh < numSubsetMeshes; nMesh++)
00113         {
00114                 subsetMeshes[nMesh] = new SubsetMesh();
00115                 subsetMeshes[nMesh]->pMesh = m_XFile.meshes[nMesh];
00116 
00117                 // Loop through every material in the current mesh.
00118                 for(int nMaterial = 0; nMaterial < m_XFile.meshes[nMesh]->materialList->nMaterials; nMaterial ++)
00119                 {
00120                         // Create a subset for this material and add i to the subset mesh.
00121                         Subset* newSubset = new Subset();
00122                         newSubset->pMesh = subsetMeshes[nMesh];
00123                         newSubset->pMaterial =  m_XFile.meshes[nMesh]->materialList->materials[nMaterial];
00124 
00125                         // Add every triangle from the current mesh with the current material to this subset.
00126                         for(int nFace = 0; nFace < m_XFile.meshes[nMesh]->materialList->nFaceIndexes; nFace ++)
00127                         {
00128                                 if(m_XFile.meshes[nMesh]->materialList->faceIndex[nFace] == nMaterial)
00129                                 {
00130                                         newSubset->faces.push_back(nFace);
00131                                 }
00132                         }
00133 
00134                         // Match the texture file name specified in the current material with an actual CTexture loaded in earlier.
00135                         newSubset->TextureIndex = getTextureIndex(newSubset->pMaterial);
00136 
00137                         // Add the subset to the static memory.
00138                         newSubset->DMAAddress = AddSubsetToDMA(newSubset,false);
00139 
00140                         subsetMeshes[nMesh]->subsets.push_back(newSubset);
00141                 }
00142         }
00143 
00144         return true;
00145 }
00146 
00153 AnimationSet* xFile_Render::getAnimationSet(LPCSTR animationSetName)
00154 {
00155         if(! animationSetName)
00156                 return NULL;
00157 
00158         AnimationSet* animationSet = NULL;
00159 
00160         // loop through all animation sets and return the first one with a name that matches the search string.
00161         for(int i = 0; i < m_XFile.animationSets.size(); i ++)
00162         {
00163                 animationSet = m_XFile.animationSets[i];
00164                 if(strcmp(animationSet->Name.c_str(),animationSetName) == 0)
00165                 {
00166                         // Search succeeded.
00167                         return animationSet;
00168                 }
00169         }
00170 
00171         // Search Failed.
00172         return NULL;
00173 }
00174 
00179 void xFile_Render::setAnimation(LPCSTR animationSetName)
00180 {
00181         if(!isAnimated)
00182                 return;
00183 
00184         // Search for the specified animation set
00185         if(animationSetName != NULL)
00186         {
00187                 setAnimationSet = getAnimationSet(animationSetName);
00188         }
00189 
00190         //Return if no set found
00191         if(setAnimationSet == NULL)
00192                 return;
00193 
00194         //Reset Previous Key
00195         previousKey = 0;
00196 
00197         // Animations in set map 1-to-1 with frames
00198         for(int nFrame = 0; nFrame < m_XFile.frames.size(); nFrame ++)
00199         {
00200                 Frame* currentFrame = m_XFile.frames[nFrame];
00201 
00202                 for(int nAnimation = 0; nAnimation < setAnimationSet->Animations.size(); nAnimation ++)
00203                 {
00204                         Animation* currentAnimation = setAnimationSet->Animations[nAnimation];
00205 
00206                         if(currentAnimation->BoneName == currentFrame->Name)
00207                         {
00208                                 currentAnimation->pBone = currentFrame;
00209                         }
00210                 }
00211         }
00212 }
00213 
00219 void xFile_Render::updateAnimation(DWORD time, bool Loop)
00220 {
00221 
00222         Animation* currentAnimation = NULL;
00223         AnimationKey* currentAnimationKey = NULL;
00224         TimedFloatKeys* currentKey = NULL;
00225         TimedFloatKeys* nextKey = NULL;
00226         DWORD TimeDiff = 0;
00227         float Scalar = 0.0f;
00228 
00229         //Return if no set found
00230         if(setAnimationSet == NULL)
00231                 return;
00232 
00233         // Bounds time to animation length
00234         if(time > setAnimationSet->Length)
00235         {
00236                 time = (Loop==true)?time%(setAnimationSet->Length+1):setAnimationSet->Length;
00237         }
00238 
00239         for(int nAnimation = 0; nAnimation < setAnimationSet->Animations.size(); nAnimation ++)
00240         {
00241                 currentAnimation = setAnimationSet->Animations[nAnimation];
00242 
00243                 //If the current animation is mapped to a bone (frame)
00244                 if(currentAnimation->pBone)
00245                 {       
00246                         for(int i=previousKey; i< currentAnimation->AnimationKeys.size(); i++) 
00247                         {
00248                                 previousKey = i;
00249                                 currentAnimationKey = currentAnimation->AnimationKeys[i];
00250 
00251                                 for(int j = 0; j < currentAnimationKey->keys.size(); j ++)
00252                                 {
00253                                                                                 
00254                                         currentKey = currentAnimationKey->keys[j];
00255 
00256                                         if(time >= currentKey->time)
00257                                         {
00258 
00259                                                 nextKey = currentKey;
00260 
00261                                                 if((i+1) < currentAnimation->nAnimationKeys)
00262                                                         nextKey = currentAnimation->AnimationKeys[i+1]->keys[j];
00263 
00264 
00265                                                 // Get difference in keys' times
00266                                                 TimeDiff = nextKey->time - currentKey->time;
00267                                                 
00268                                                 // avoid dividing by 0
00269                                                 if(!TimeDiff)
00270                                                         TimeDiff = 1;
00271 
00272                                                 // Calculate a scalar value to use
00273                                                 Scalar = (float)(time - currentKey->time) / (float)TimeDiff;
00274 
00275                                                 // Calculate interpolated matrix
00276                                                 matDiff = nextKey->tfkeys->valueMatrix - currentKey->tfkeys->valueMatrix;
00277                                                 matDiff = matDiff * Scalar;
00278                                                 matDiff = matDiff + currentKey->tfkeys->valueMatrix;
00279 
00280                                                 // Set the transform
00281                                                 currentAnimation->pBone->transform->frameMatrix = matDiff;
00282                                                 
00283                                                 
00284                                         }
00285                                 }
00286 
00287                         }
00288                 }else
00289                 {
00290                         cout <<  "Animation Does Not Have A Bone: " << currentAnimation->Name << "\n";
00291                 }
00292         }
00293 }
00294 
00299 bool xFile_Render::cleanSubsets()
00300 {
00301         for(UINT i = 0; i < numSubsetMeshes; i++)
00302         {
00303                 if(subsetMeshes[i])
00304                 {
00305                         delete subsetMeshes[i];
00306                         subsetMeshes[i] = NULL;
00307                 }
00308         }
00309         return true;
00310 }
00311 
00317 bool xFile_Render::loadTextures()
00318 {
00319 
00320         // Delete any previously loaded textures
00321         if(textures)
00322         {
00323                 delete [] textures;
00324                 textures = NULL;
00325         }
00326 
00327         // initialise textures array
00328         numTextures = m_XFile.textureFileNames.size();
00329         textures = new mappedTexture*[numTextures];
00330 
00331         for(UINT i = 0; i < numTextures; i++)
00332         {
00333                 textures[i] = new mappedTexture();
00334                 textures[i]->FileName = m_XFile.textureFileNames[i]->szString;
00335 
00336                 bool textureAlreadyLoaded = false;
00337 
00338                 // if the texture is already loaded, reference it.
00339                 for(int j = i; j >= 0; j--)
00340                 {
00341                         if(textures[j] != NULL && textures[j]->texture != NULL)
00342                         {
00343                                 if(textures[j]->FileName == textures[i]->FileName)
00344                                 {
00345                                         textures[i]->texture = textures[j]->texture;
00346                                         textureAlreadyLoaded = true;
00347                                         break;
00348                                 }
00349                                         
00350                         }
00351                 }
00352                 
00353                 // if the texture is not loaded, load it.
00354                 if(!textureAlreadyLoaded)
00355                 {
00356                         textures[i]->texture = new CTexture();
00357 
00358                         if(!textures[i]->texture->LoadBitmap(textures[i]->FileName.c_str()))
00359                         {
00360                                 cout << "Could Not Load Texture: " << textures[i]->FileName << "\n";
00361                                 delete textures[i];
00362                                 textures[i] = NULL;
00363                         }else
00364                         {
00365                                 cout << "Loaded Texture: " << textures[i]->FileName << "\n";
00366                         }
00367                 }
00368                 
00369 
00370 
00371         }
00372         
00373         return true;
00374 }
00375 
00380 bool xFile_Render::cleanTextures()
00381 {
00382         for(UINT i = 0; i < numTextures; i++)
00383         {
00384                 if(textures[i])
00385                 {
00386                         delete textures[i];
00387                         textures[i] = NULL;
00388                 }
00389         }
00390         return true;
00391 }
00392 
00399 int xFile_Render::getTextureIndex(Material* material)
00400 {
00401         if(! material)
00402                 return 0;
00403 
00404         for(UINT i = 0; i < numTextures; i++)
00405         {
00406                 if(textures[i] && material->nTexturesFileNames)
00407                 {
00408                         if(textures[i]->FileName.c_str() == material->textureFileNames[0]->szString.c_str())
00409                         {
00410                                 return i;
00411                         }
00412                 }
00413         }
00414         return -1;
00415 }
00416 
00423 void xFile_Render::update(Frame* parent)
00424 {
00425         if(!parent)
00426                 return;
00427 
00428         Matrix4x4 parentTransform = parent->transform->transformedMatrix;
00429 
00430         for(UINT i = 0; i < parent->childFrames.size(); i ++)
00431         {
00432                 parent->childFrames[i]->transform->transformedMatrix =  parent->childFrames[i]->transform->frameMatrix * parentTransform;
00433                 update(parent->childFrames[i]);
00434         }
00435 }
00436 
00440 void xFile_Render::render(DWORD time)
00441 {
00442         if(!loaded)
00443                 return;
00444 
00445         // If Animated, update the animation at the current time.
00446         if(isAnimated)
00447         {
00448                 updateAnimation(time);
00449         }
00450 
00451         // Update the matrix hierarchy if it has been changed.
00452         if(changed || isAnimated)
00453         {
00454                 update(m_XFile.rootFrame);
00455                 changed = false;        //keep track of whether the meshes world matrices have changed since the last frame and only update when they have.
00456         }
00457 
00458         // Draw the Meshes
00459         for(int nMesh = 0; nMesh < numSubsetMeshes; nMesh ++)
00460         {
00461                 SetWorldMatrix(subsetMeshes[nMesh]->pMesh->pFrame->transform->transformedMatrix);
00462                 drawMesh(nMesh);
00463         }
00464 
00465 }
00466 
00470 void xFile_Render::drawMesh(int subsetMeshIndex)
00471 {
00472         assert(m_bWorldLoaded);
00473 
00474         // Wait for all to be idle in VU1 land
00475         // Before uploading the data
00476         VIFDynamicDMA.Add32(FLUSH);
00477 
00478         // Upload the matrices in the dynamic buffer
00479         // because they can change every frame (but only once per mesh).
00480         VIFDynamicDMA.AddUnpack(V4_32, 1, 16);
00481         VIFDynamicDMA.AddMatrix(Pipeline.GetLightDirs());
00482         VIFDynamicDMA.AddMatrix(Pipeline.GetLightCols());
00483         VIFDynamicDMA.AddMatrix(m_WVP);
00484         VIFDynamicDMA.AddMatrix(m_World);
00485 
00486 
00487         // Loop through all subsets of the mesh
00488         for(int nSubset = 0; nSubset < subsetMeshes[subsetMeshIndex]->subsets.size(); nSubset ++)
00489         {
00490                 // if the subset has a mapped texture, set it Now
00491                 int textureIndex = subsetMeshes[subsetMeshIndex]->subsets[nSubset]->TextureIndex;
00492         
00493                 if(textureIndex > -1 && textures[textureIndex]->texture != NULL)
00494                 {
00495                         textures[textureIndex]->texture->Upload(TEXBUF480);
00496                         textures[textureIndex]->texture->Select();
00497                 }
00498 
00499                 // Call the packet with the static data that doesn't change per frame to draw the subset.
00500                 VIFDynamicDMA.DMACall(subsetMeshes[subsetMeshIndex]->subsets[nSubset]->DMAAddress);
00501         }
00502 }
00503 
00508 void xFile_Render::setGlobalPose(const Matrix4x4& newPose)
00509 {
00510         if(loaded)
00511         {
00512                 m_XFile.rootFrame->transform->transformedMatrix  =  newPose;
00513                 changed = true;
00514         }
00515 }
00516 
00521 void xFile_Render::SetWorldMatrix(const Matrix4x4 & matWorld)
00522 {
00523         m_World = matWorld;
00524         m_WVP = m_World * Pipeline.GetViewProjection();
00525         m_bWorldLoaded = true;
00526 }
00527 
00532 void xFile_Render::SetWVPMatrix(const Matrix4x4 & matWVP)
00533 {
00534         m_WVP = matWVP;
00535 }
00536 
00543 int xFile_Render::AddSubsetToDMA(Subset* pSubset,bool bTransparent)
00544 {
00545         if(!pSubset)
00546                 return 0;
00547 
00548         int m_iStaticAddr = VIFStaticDMA.GetPointer();
00549 
00550         VIFStaticDMA.Add32(FLUSH);                      // Make sure VU1 isn't busy
00551         VIFStaticDMA.Add32(STCYCL(1,1));        // Unpack linearly, i.e. don't skip any spaces
00552         VIFStaticDMA.Add32(BASE(32));           // The double buffers start at VU1 address 16 (giving us 16 QW to store data that won't change)
00553         VIFStaticDMA.Add32(OFFSET(496));        // The size of each buffer.
00554 
00555         VIFStaticDMA.AddUnpack(V4_32, 0, 1);    // Unpack 8QW of data that won't change
00556         VIFStaticDMA.AddVector(Pipeline.GetScaleVector());      // 0: The scales
00557 
00558 
00559         int iNumTrisPerChunk = 27;
00560         bool bFirst = true;
00561 
00562         int nMesh = 0;
00563 
00564         Mesh* pMesh = pSubset->pMesh->pMesh;
00565 
00566         int iNumTris = pSubset->faces.size();
00567         int iAbsoluteTri = 0;
00568         int texCoord = -1;
00569 
00570         while(iNumTris > 0)
00571         {
00572                 int iTrisThisChunk;
00573 
00574                 if(iNumTris > iNumTrisPerChunk)
00575                 {
00576                         iTrisThisChunk = iNumTrisPerChunk;
00577                         iNumTris -= iTrisThisChunk;
00578                 }
00579                 else
00580                 {
00581                         iTrisThisChunk = iNumTris;
00582                         iNumTris -= iTrisThisChunk;
00583                 }
00584 
00585                 VIFStaticDMA.AddUnpack(V4_32, 0, iTrisThisChunk * 9 + 2, 1);
00586 
00587                 VIFStaticDMA.Add128(iTrisThisChunk * 9);
00588 
00589                 VIFStaticDMA.Add128(
00590                         GS_GIFTAG_BATCH(iTrisThisChunk * 3, // NLOOP
00591                         1,      // EOP
00592                         1,      // PRE
00593                         // GS_PRIM(    PRIM, IIP, TME, FGE,  ABE         , AA1, FST, CTXT, FIX)
00594                         GS_PRIM(GS_TRIANGLE,  1,   1,   0 , bTransparent ,   0,   0,    0,   0),        // PRIM
00595                         GIF_FLG_PACKED,
00596                         GS_BATCH_3(GIF_REG_ST, GIF_REG_RGBAQ, GIF_REG_XYZ2)));
00597 
00598 
00599                 for(int iTriangle = 0; iTriangle < iTrisThisChunk; iTriangle++)
00600                 {
00601                         MeshFace& pTriangle = pMesh->faces[pSubset->faces[iAbsoluteTri]];
00602 
00603                         Vector& pVert1 = pMesh->vertices[pTriangle.faceVertexIndices[0]];
00604                         Vector& pVert2 = pMesh->vertices[pTriangle.faceVertexIndices[1]];
00605                         Vector& pVert3 = pMesh->vertices[pTriangle.faceVertexIndices[2]];
00606 
00607                         // Mesh May not have texture coordinates so make defaults
00608                         static Coords2d pUV1 = Coords2d(0,0);
00609                         static Coords2d pUV2 = Coords2d(0,0);
00610                         static Coords2d pUV3 = Coords2d(0,0);
00611 
00612                         // If the mesh has texture coordinates, set them
00613                         if(pMesh->textureCoords && pMesh->textureCoords->nTextCoords > 0)
00614                         {
00615                                 pUV1 = pMesh->textureCoords->textCoords[pTriangle.faceVertexIndices[0]];
00616                                 pUV2 = pMesh->textureCoords->textCoords[pTriangle.faceVertexIndices[1]];
00617                                 pUV3 = pMesh->textureCoords->textCoords[pTriangle.faceVertexIndices[2]];
00618                         }else
00619                         {
00620                                 cout << "=== WARNING: Mesh is missing TEXTURE COORDINATS.\n";
00621                         }
00622 
00623                         // Mesh may not have normals so make defaults.
00624                         static Vector pNorm1 = Vector(0,0,0); 
00625                         static Vector pNorm2 = Vector(0,0,0); 
00626                         static Vector pNorm3 = Vector(0,0,0); 
00627 
00628                         // If the mesh has normals, set them.
00629                         if(pMesh->normals && pMesh->normals->nNormals > 0)
00630                         {
00631                                 pNorm1 = pMesh->normals->normals[pTriangle.faceVertexIndices[0]];
00632                                 pNorm2 = pMesh->normals->normals[pTriangle.faceVertexIndices[1]];
00633                                 pNorm3 = pMesh->normals->normals[pTriangle.faceVertexIndices[2]];
00634                         }else
00635                         {
00636                                 cout << "=== WARNING: Mesh is missing NORMALS. \n";
00637                         }
00638 
00639                         VIFStaticDMA.AddVector(Vector4(pUV1.u, pUV1.v, 1, 0));
00640                         VIFStaticDMA.AddVector(Vector4(pNorm1.x, pNorm1.y, pNorm1.z, 0));
00641                         VIFStaticDMA.AddVector(Vector4(pVert1.x, pVert1.y, pVert1.z, 1));
00642 
00643                         VIFStaticDMA.AddVector(Vector4(pUV2.u, pUV2.v, 1, 0));
00644                         VIFStaticDMA.AddVector(Vector4(pNorm2.x, pNorm2.y, pNorm2.z, 0));
00645                         VIFStaticDMA.AddVector(Vector4(pVert2.x, pVert2.y, pVert2.z, 1));
00646 
00647                         VIFStaticDMA.AddVector(Vector4(pUV3.u, pUV3.v, 1, 0));
00648                         VIFStaticDMA.AddVector(Vector4(pNorm3.x, pNorm3.y, pNorm3.z, 0));
00649                         VIFStaticDMA.AddVector(Vector4(pVert3.x, pVert3.y, pVert3.z, 1));
00650 
00651                         iAbsoluteTri++;
00652                 }
00653 
00654                 if(bFirst)
00655                 {
00656                         VIFStaticDMA.Add32(MSCALL(0));
00657                         bFirst = false;
00658                 }
00659                 else
00660                         VIFStaticDMA.Add32(MSCNT);
00661         }
00662 
00663 
00664         VIFStaticDMA.Add32(FLUSH);
00665 
00666         VIFStaticDMA.DMARet();
00667 
00668         return m_iStaticAddr;
00669 }

Generated on Sun May 18 21:45:09 2008 for PS2X by  doxygen 1.5.4