Game Development Community

T3D 1.2 - Collada import leads to wrong data in DTS (with second UV or vertex paint)

by Fyodor -bank- Osokin · in Torque 3D Professional · 05/19/2012 (6:00 am) · 4 replies

Build: Torque 3D 1.2 (and all previous version with Collada import support)

Platform: Any

Target: TSShape assembling Colldata-imported models with second UV or with vertex paint

Issues: TSShape::assembleShape() doesn't set addresses for smTVerts2List and smColorsList vectors.

Note:
I'll try to be short on this (as the whole DTS loading routine is a bit... "mess"):

Under certain circumstances, the TSShape::assembleShape() method can lead to some memory corruption, or better - to wrong data being used (this happens when you import Collada/DAE models with more than one mesh and when you are using second UV or vertex paint features).

The bug:
The TSMesh::smTVerts2List and TSMesh::smColorsList Vectors initialized properly (using correct data) only for the first mesh of the model being assembled.

The fix:
Inside TSShape::assembleShape() replace this code block
..//skipped
      // fill in location of verts, tverts, and normals for detail levels
      if (mesh && meshType!=TSMesh::DecalMeshType)
      {
         TSMesh::smVertsList[i]  = mesh->verts.address();
         TSMesh::smTVertsList[i] = mesh->tverts.address();
         TSMesh::smNormsList[i]  = mesh->norms.address();
         TSMesh::smEncodedNormsList[i] = mesh->encodedNorms.address();
..//skipped
with:
..//skipped
      // fill in location of verts, tverts, and normals for detail levels
      if (mesh && meshType!=TSMesh::DecalMeshType)
      {
         TSMesh::smVertsList[i]  = mesh->verts.address();
         TSMesh::smTVertsList[i] = mesh->tverts.address();
         if ( smReadVersion >= 26 )
         {
            TSMesh::smTVerts2List[i] = mesh->tverts2.address();
            TSMesh::smColorsList[i] = mesh->colors.address();
         }
         TSMesh::smNormsList[i]  = mesh->norms.address();
         TSMesh::smEncodedNormsList[i] = mesh->encodedNorms.address();
..//skipped
As you see, I've added address assignment to the TSMesh::smTVerts2List and TSMesh::smColorsList Vectors, like the rest.

#1
05/19/2012 (6:00 am)
More details: (doesn't fit in one post)
If you read through the TSShape::assembleShape() method you may notice, that all of the Vectors are first sized properly:
..//skipped
   TSMesh::smVertsList.setSize(scratchSize);
   TSMesh::smTVertsList.setSize(scratchSize);

   if ( smReadVersion >= 26 )
   {
      TSMesh::smTVerts2List.setSize(scratchSize);
      TSMesh::smColorsList.setSize(scratchSize);
   }

   TSMesh::smNormsList.setSize(scratchSize);
   TSMesh::smEncodedNormsList.setSize(scratchSize);
   TSMesh::smDataCopied.setSize(scratchSize);
A bit down the code, it properly too being set to NULL:
..//skipped
   for (i=0; i<numMeshes; i++)
   {
      TSMesh::smVertsList[i]=NULL;
      TSMesh::smTVertsList[i]=NULL;
      
      if ( smReadVersion >= 26 )
      {
         TSMesh::smTVerts2List[i] = NULL;
         TSMesh::smColorsList[i] = NULL;
      }
      
      TSMesh::smNormsList[i]=NULL;
      TSMesh::smEncodedNormsList[i]=NULL;
      TSMesh::smDataCopied[i]=false;
..//skipped
And then - used.
You may think that when it sets the addresses for Vectors, the TSMesh::smTVerts2List and TSMesh::smColorsList will stay NULL?
Look at the TSMesh::assembleMesh() method:
..//skipped
      numTVerts = tsalloc.get32();
      ptr32 = getSharedData32( parentMesh, 2 * numTVerts, (S32**)smTVerts2List.address(), skip );
      tverts2.set( (Point2F*)ptr32, numTVerts );

      S32 numVColors = tsalloc.get32();
      ptr32 = getSharedData32( parentMesh, numVColors, (S32**)smColorsList.address(), skip );
      colors.set( (ColorI*)ptr32, numVColors );
..//skipped
For the first mesh everything is fine, but meshes after will get wrong data.

After my fix applied, I can safely use Forest's "wind" feature for a tree (for example) with many LODs, and I can use vertex paint for any LOD (or all) in this model without any side effects. Same for using second UV feature.

Happy TORQUEing!
#2
05/19/2012 (6:17 am)
P.S. More fixes for skinned meshes, if anyone uses this (initialization included):

In TSShape::assembleShape() method locate:
..//skipped
      for (i=0; i<numSkins; i++)
      {
         TSMesh::smVertsList[i]=NULL;
         TSMesh::smTVertsList[i]=NULL;
         TSMesh::smNormsList[i]=NULL;
         TSMesh::smEncodedNormsList[i]=NULL;
         TSMesh::smDataCopied[i]=false;
..//skipped
and replace it with
..//skipped
      for (i=0; i<numSkins; i++)
      {
         TSMesh::smVertsList[i]=NULL;
         TSMesh::smTVertsList[i]=NULL;
         if ( smReadVersion >= 26 )
         {
            TSMesh::smTVerts2List[i] = NULL;
            TSMesh::smColorsList[i] = NULL;
         }
         TSMesh::smNormsList[i]=NULL;
         TSMesh::smEncodedNormsList[i]=NULL;
         TSMesh::smDataCopied[i]=false;
..//skipped

More down, replace:
..//skipped
         // fill in location of verts, tverts, and normals for shared detail levels
         if (skin)
         {
            TSMesh::smVertsList[i]  = skin->batchData.initialVerts.address();
            TSMesh::smTVertsList[i] = skin->tverts.address();
            TSMesh::smNormsList[i]  = skin->batchData.initialNorms.address();
            TSMesh::smEncodedNormsList[i]  = skin->encodedNorms.address();
            TSMesh::smDataCopied[i] = !skip; // as long as we didn't skip this mesh, the data should be in shape now
..//skipped
with:
..//skipped
         // fill in location of verts, tverts, and normals for shared detail levels
         if (skin)
         {
            TSMesh::smVertsList[i]  = skin->batchData.initialVerts.address();
            TSMesh::smTVertsList[i] = skin->tverts.address();
            if ( smReadVersion >= 26 )
            {
               TSMesh::smTVerts2List[i] = skin->tverts2.address();
               TSMesh::smColorsList[i] = skin->colors.address();
            }
            TSMesh::smNormsList[i]  = skin->batchData.initialNorms.address();
            TSMesh::smEncodedNormsList[i]  = skin->encodedNorms.address();
            TSMesh::smDataCopied[i] = !skip; // as long as we didn't skip this mesh, the data should be in shape now
..//skipped
#3
05/19/2012 (9:01 am)
Well spotted!
#4
05/19/2012 (10:40 pm)
winner winner chicken dinner