Game Development Community

TSMaterialList help

by Erik Madison · in Torque Game Engine · 03/28/2004 (3:32 pm) · 15 replies

In conjunction with my hiding meshes resource, I'm trying to now retexture the individual parts. Everything seems to work fine, my code markers read what I expect, but the new material doesn't seem to ever appear. I'm thinking it has to be that I'm not changing the list properly, and I did/do have some strangeness happening when I clone the list for ownership. The following 2 functions are complete, if anyone would be so kind as to try running them. It will accept single mesh models just fine.

#1
03/28/2004 (3:32 pm)
ConsoleMethod(ShapeBase, reTexture, void, 4, 4, "retexture part of a model (skinname, texturename)")
{
   if (argv[2] != '[[4f3a9a525e8fc]]' && argv[3] != '[[4f3a9a525e8fc]]')
      object->reTexture(argv[2], argv[3]);
}

void ShapeBase::reTexture(const char* skinName, const char* textureName)
{
   S32 i, x;
   TSShape const* mShape = mShapeInstance->getShape();

   if (!mShapeInstance->ownMaterialList()) {
      // this shouldn't be necessary, but it is. Without it, the next line would crash.
      mShapeInstance->setMaterialList(mShape->materialList);
      mShapeInstance->cloneMaterialList();
   }
   if (mShapeInstance->ownMaterialList()) {
      Con::errorf("We now own the material list");
   }

   for (i=0; i< mShape->objects.size(); i++)
   {
      if (mShape->objects[i].nodeIndex<0) // must be a skin
      {  
         S32 nameIndex = mShape->objects[i].nameIndex;
         if (nameIndex>=0) {
            // found our skin in the model
            if (dStricmp(skinName, mShape->getName(nameIndex)) == 0) {
               // Now find the current texture of this skin
               TSMesh * mesh = mShapeInstance->mMeshObjects[i].getMesh(0);
               if (mesh)
               {
                  U32 material = mesh->primitives[0].matIndex & TSDrawPrimitive::MaterialMask;
                  if (mesh->primitives[0].matIndex & TSDrawPrimitive::NoMaterial) {
                     Con::errorf("No material on this mesh");
                     return;
                  } else {
                     TSMaterialList * materials = mShape->materialList;
                     const char* matname = materials->getMaterialName(material);
                     // And the current texture is....
                     Con::errorf("Mesh %s currently uses texture %s", skinName, matname);
                     // Find the current texture in the material list
                     for (x = 0; x < materials->mMaterialNames.size(); x++ ) 
                     {
                        const char* name = materials->mMaterialNames[x];
                        if ( !name )
                           continue;
                        const U32 len = dStrlen( name );
                        AssertFatal( len < 200, "ShapeBase::reTexture - Skin name exceeds maximum length!" );
                        if ( len < 6 )
                           continue;
                        const char* replace = dStrstr( name, matname );
                        if ( !replace )
                           continue;
                        else
                           Con::errorf("Found current texture in matlist");
                        char newName[256];
                        const char* resourcePath = mShapeInstance->hShape.getFilePath();
                        dStrcpy( newName, resourcePath );  // add path to beginning of string
                        dStrcat( newName, "/" );           // and seperater
                        dStrcat( newName, textureName );   // finally, the new texture
                        Con::errorf("newName will be %s", newName );
                        TextureHandle test = TextureHandle( newName, MeshTexture );
                        // make sure the change is valid
                        if ( test.getGLName() ) {
                           materials->mMaterials[x] = test;
                           Con::errorf("New texturing should have worked by now.");
                        }
                        // its not, so revert back to the original texture
                        else {
                           Con::errorf("Error in retexturing the model, cannot load new one");
                           materials->mMaterials[x] = TextureHandle( name, MeshTexture, false );
                        }
                     }                     
                  }
               }
               return;
            }
         }
      }
   }
   Con::errorf("ShapeBase::reTexture(): Unable to find mesh %s.", skinName);
}
#2
03/28/2004 (8:24 pm)
I think using the code tag will avoid that.
#3
03/29/2004 (7:37 pm)
Erik,

Just wanted to let you know that this is now top on my ToDo list. It is going to hold up our artists until we know for sure if we can change sub object textures at runtime or not. So starting tomorrow this has my undivided attention.

I'll let you kow what we come up with, and please let me know if you fix it first. It is very important to us.
#4
03/30/2004 (10:43 am)
I solved my problem with owning the material lists... I think.
if (isClientObject() && !mShapeInstance->ownMaterialList()) {
      mShapeInstance->cloneMaterialList();
   }

   if (mShapeInstance->ownMaterialList()) {
      Con::errorf("We now own the material list");
   }
It does prevent crashing at that point but the new texture still doesn't stick. Hmm. Sometimes I don't know whether to thank Sierra for allowing TGE, or smack them for forcing all decent examples to be stripped. Theres some pretty powerful functions in TGE with not one single usage example :P
#5
03/30/2004 (10:56 am)
I got this in the code, but haven't had a chance to actually test it yet. I tried briefly by going into the console and making a new vehicle, then trying it but I guess I don't know the right names for the materials :) I tried the name of the texture file as it is on disk, with and without the extension but kept getting a not found error.

Think i'll right a routine to print out the materials in a shape.
#6
03/30/2004 (11:13 am)
Once you finish the hiding meshes snippet, you'll have a modeldump function that will output the proper names for everything :) Or you can just grab that part from the rest.
#7
03/30/2004 (5:11 pm)
Interestingly enough even if I use the name that I get from "modelDump" I still get a not found error.

Anyway i'll dig some more. In the meantime, have you seen this resource?
#8
03/31/2004 (5:33 am)
Do your mesh names contain anything funky? I found on mine, Legmesh works great, Leg-mesh does not. And of course bodymesh-145 won't work either.

I hadn't fully read that resource, as it was mostly added to head long ago. I was just re-reading its current incode incarnation last night, and I think I know the problem now.

That code never sets the material list, it merely sets a variable and tells the server its changed. Server sends the info to the client ghosts, who check if the current skin is the same as the variable, and if not they match it. I don't think I can use a variable, as I would need to know the part to change, as well as the new texture. If Im changing numerous parts to numerous textures, that could get hairy real quick.

So... I may need to redo how the material list is handled. It seems like it should be as easy as deleting the old list and creating a new one, but so far I haven't been able to do that without crashing.
#9
03/31/2004 (5:35 am)
No funky names. "herbe" is the name on the text model i'm messing with. I just added some debug code and every one it checks comes back with a nodeIndex of 0 not less than 0. I'm building a debug version as I type this so I can step through some things.
#10
03/31/2004 (5:44 am)
Ok I stepped through the modeldump procedure to get a better understanding of things. Apparently our test cube has no "skins" or what the model dump procedure calls skins. It has materials.

Whats the difference?

Shape Hierarchy:

   Details:
      Detail-0, Subtree 0, objectDetail 0, size 10
      Collision-1, Subtree 0, objectDetail 1, size -1

   Subtrees:
      Subtree 0
         Root --> Object left with following details:  10
              --> Object top with following details:  10
              --> Object bottom with following details:  10
              --> Object front with following details:  10
              --> Object Back with following details:  10
              --> Object right with following details:  10
              --> Object Col with following details:  -1

   Sequences:

   Material list:
   material #0: "herbe".
   material #1: "top: Add, Illum".
   material #2: "plateox2".
   material #3: "LizardMan".
   material #4: "spec".  Subtractive-translucent.
   material #5: "spec".
#11
03/31/2004 (8:15 am)
See the other post for the differences. hmm, herbe is the texture/skin/material name, not the mesh/part name. The model dump should have had a section:
Skins:
      Skin AABody with following details:  145 (43)
      Skin AAA-eyes-mouth with following details:  145 (44)
Here, skin means mesh/part. The eye/mouth mesh I cannot access as currently named, the body is just fine and works very well. A partial output of my materials/textures:
Material list:
   material #0: "base.legs".
   material #1: "basic_hand".
On this model, I use
Quote:%this.skinoff(AABody)
and poof, the body disappears. My hopefully real-soon-now method of changing the texture will be
Quote:%this.retexture(AABody, whiteTShirt) or %this.retexture(AABody, CamoShirt)
#12
03/31/2004 (9:11 am)
I guess I just don't understand the difference between a MATERIAL and a SKIN in this context. However, I don't do the modelling. I guess what I need to figure out and understand is how do my modellers make a model with a SKIN vs a MATERIAL and what does this mean.
#13
03/31/2004 (9:25 am)
The way it should be, and the way modeldump() outputs it is:
Mesh=skin=model=wireframe
material=texture
In code, as I said, skin means material means texture. That is wrong.
retexture(skin, material) and retexture(mesh, texture) are both the same.
#14
03/31/2004 (10:36 am)
Well as Ben clarified for me in the other thread, Material is the texture placed on the model. THIS is what I need to be able to change. I don't need to change the MESH, but the TEXTURE on the mesh.

The point of this is to allow us to dynamiclly swap out the textures used to personalize the vehicles.
#15
03/31/2004 (4:54 pm)
In the context of meshes, a "skin" is a mesh set up for vertex deformation. I imagine it got it's name from the the Skin modifier used in 3ds Max to link vertices to the bone structure. I believe the Skin meshes have to be loaded a bit differently then normal mesh objects.