Game Development Community

T3D 1.2 ShapeBase::ChangeMaterial BugFix

by Vincent BILLET · in Torque 3D Professional · 12/05/2012 (2:22 am) · 3 replies

Changing Materials into shape instances via scripts is an essential feature for many T3D users.
Unfortunately, depending on Torque versions it worked or NOT.
So, For T3D 1.2 (MIT), here is the fix :
DefineEngineMethod( ShapeBase, changeMaterial, void, ( const char* mapTo, Material* oldMat, Material* newMat ),,
   "@brief Change one of the materials on the shape.nn"

   "This method changes materials per mapTo with others. The material that "
   "is being replaced is mapped to unmapped_mat as a part of this transition.n"

   "@note Warning, right now this only sort of works. It doesn't do a live "
   "update like it should.n"

   "@param mapTo the name of the material target to remap (from getTargetName)n"
   "@param oldMat the old Material that was mapped n"
   "@param newMat the new Material to mapnn"

   "@tsexamplen"
   "// remap the first material in the shapen"
   "%mapTo = %obj.getTargetName( 0 );n"
   "%obj.changeMaterial( %mapTo, 0, MyMaterial );n"
   "@endtsexamplen" )
{
   // if no valid new material, theres no reason for doing this
   if( !newMat )
   {
      Con::errorf("ShapeBase::changeMaterial failed: New material does not exist!");
      return;
   }

   // initilize server/client versions
   ShapeBase *serverObj = object;
   ShapeBase *clientObj = dynamic_cast< ShapeBase* > ( object->getClientObject() );

   // Check the mapTo name exists for this shape
   S32 matIndex = serverObj->getShape()->materialList->getMaterialNameList().find_next(String(mapTo));
   if (matIndex < 0)
   {
      Con::errorf("ShapeBase::changeMaterial failed: Invalid mapTo name '%s'", mapTo);
      return;
   }

   // Lets remap the old material off, so as to let room for our current material room to claim its spot
   if( oldMat )
      oldMat->mMapTo = String("unmapped_mat");

   newMat->mMapTo = mapTo;

   // Map the material in the in the matmgr
   MATMGR->mapMaterial( mapTo, newMat->getName() );

   // Replace instances with the new material being traded in. For ShapeBase
   // class we have to update the server/client objects separately so both
   // represent our changes
   delete serverObj->getShape()->materialList->mMatInstList[matIndex];
   serverObj->getShape()->materialList->mMatInstList[matIndex] = newMat->createMatInstance();
   if (clientObj)
   {
      delete clientObj->getShapeInstance()->mMaterialList->mMatInstList[matIndex];
      clientObj->getShapeInstance()->mMaterialList->mMatInstList[matIndex] = newMat->createMatInstance();
   }
   // Finish up preparing the material instances for rendering
   const GFXVertexFormat *flags = getGFXVertexFormat<GFXVertexPNTTB>();
   FeatureSet features = MATMGR->getDefaultFeatures();

   serverObj->getShape()->materialList->getMaterialInst(matIndex)->init( features, flags );
   if (clientObj)
      clientObj->getShapeInstance()->mMaterialList->getMaterialInst(matIndex)->init( features, flags );
}

in script you can use like this :
%player.changeMaterial("TexutreORPartName",0,"NewMaterialName");
or
function AIPlayer::Wear(%this,%tset)
{
	%this.changeMaterial("base.body",0,"tset_"@%tset@"_body");
	%this.changeMaterial("base.legs",0,"tset_"@%tset@"_legs");
	%this.changeMaterial("base.arms",0,"tset_"@%tset@"_arms");
	%this.changeMaterial("base.hands",0,"tset_"@%tset@"_hands");
	%this.changeMaterial("base.feet",0,"tset_"@%tset@"_feet");
	%this.changeMaterial("base.head",0,"GeorgesHead");
}

Edit : These changes can also be reported in
T3D/shapeBase.cpp
interior/interiorInstance.cpp And
T3D/tsStatic.cpp

Enjoy!

#1
12/05/2012 (7:08 am)
Didn't even know that there was a "changeMaterial" function, thought things were done via "setSkinName". Having a quick look in the CHM I see that "changeMaterial" should be able to affect TsStatic as well as ShapeBase.

Cool.
#2
12/05/2012 (7:37 am)
Speaking of setSkinName, I have heard reports of this not working on a player shape unless you use this function at shape creation (or something along those lines - complaints that it doesn't work all the time, conditions vary). Anyone else seen this?
#3
12/05/2012 (8:01 am)
@Steve,
ChangeMaterial is really usefull... It can change each Material of a particular instance of AIPlayer. If you need, like me, to change Legs, body, arms, head, feet and hands of players and AIPlayers, it is really more powerful than setSkinName.

This sample code should be report to TsStatic, and Interiors also.

@Richard,
This function worked pretty well in T3D 1.01 (even on network). It seems that a bad copy past in later versions made it unworking. The main change is
clientObj->getShapeInstance()
instead of
clientObj->getShape()