Applying Materials by Mesh Name
by Joshua Halls (Xerves) · 03/30/2009 (5:58 pm) · 10 comments
Just a note, this is my first resource so please be kind :-). Also, we are using TGEA 1.7.1 right now and not 1.8 so I am not 100% sure if this will work nor am I 100% sure this will work in 1.7.1 as there are a lot of changes in place since we are using the MMO KIT. Please let me know if you run into any issues.
This resource is intended to be used with the Mesh Hiding Resource, but I believe technically it would work without it.
The following include needs to be added to the top of the file.
Find these following lines of code
After it add
You will next need to find the HideMeshMask define that was created in the Mesh Hiding resource, you need to add another mask. You should change it to look like this (it should
Change the following lines in packUpdate
To This
Then change the following a bit further down
To This
Further down after this bit of code
Add the following
In unpackUpdate after the following Mesh Code
Add the following
Now at the end of shapebase.cpp add the following block of code.
That should be it. Compile and hopefully everything works. As you can see by the Console Method the setMeshSkin call needs to be called from the server side. This will make sure it properly gets communicated over the network the change needs to be made. I don't use TorqueScript for the scripting method as we use Python, so hopefully someone would be better able to fill that in. The process looks like this though.
char.setMeshSkin("myMesh", "~/scriptsAndAssets/data/shapes/player/newMaterial")
This resource is intended to be used with the Mesh Hiding Resource, but I believe technically it would work without it.
T3d/shapebase.h
The following include needs to be added to the top of the file.
#include "core/tDictionary.h"
Find these following lines of code
CollisionTimeout* mTimeoutList;
static CollisionTimeout* sFreeTimeoutList;After it add
//Skin Dictonary for Meshes -- X typedef Map<StringTableEntry,StringTableEntry> pDict; pDict mSkinDictionary; //setMeshSkin function void setMeshSkin(StringTableEntry mesh, StringTableEntry texture);
You will next need to find the HideMeshMask define that was created in the Mesh Hiding resource, you need to add another mask. You should change it to look like this (it should
#ifdef _res__hideMeshResource
HideMeshMask = Parent::NextFreeMask << 8,
SkinMeshMask = Parent::NextFreeMask << 9,
SoundMaskN = Parent::NextFreeMask << 10, ///< Extends + MaxSoundThreads bitsT3D/shapeBase.cpp
Change the following lines in packUpdate
if(!stream->writeFlag(mask & (NameMask | DamageMask | SoundMask |
#ifdef _res__hideMeshResource
HideMeshMask |
#endif
ThreadMask | ImageMask | CloakMask | MountedMask | InvincibleMask | ShieldMask | SkinMask)))To This
if(!stream->writeFlag(mask & (NameMask | DamageMask | SoundMask |
#ifdef _res__hideMeshResource
HideMeshMask |
#endif
SkinMeshMask | ThreadMask | ImageMask | CloakMask | MountedMask | InvincibleMask | ShieldMask | SkinMask)))Then change the following a bit further down
if (stream->writeFlag(mask & (NameMask | ShieldMask | CloakMask | InvincibleMask | SkinMask
#ifdef _res__hideMeshResource
| HideMeshMask
#endifTo This
if (stream->writeFlag(mask & (NameMask | ShieldMask | CloakMask | InvincibleMask | SkinMask | SkinMeshMask
#ifdef _res__hideMeshResource
| HideMeshMask
#endifFurther down after this bit of code
#ifdef _res__hideMeshResource
if (stream->writeFlag(mask & HideMeshMask)) {
stream->writeInt(mToggledMeshes.size(), 7);
for(int x = 0; x < mToggledMeshes.size(); x++)
stream->writeInt(mToggledMeshes[x], 8);
}
#endifAdd the following
if (stream->writeFlag(mask & SkinMeshMask))
{
// -- Start Skin changes per Mesh
stream->write(mSkinDictionary.size());
for(pDict::Iterator it = mSkinDictionary.begin(); it != mSkinDictionary.end(); it++)
{
stream->writeString(it->value); //Key
stream->writeString(it->key); //Value
}
// -- End Skin changes per Mesh
}In unpackUpdate after the following Mesh Code
#ifdef _res__hideMeshResource
if (stream->readFlag())
{ // HideMeshMask
mToggledMeshes.clear();
S32 count = stream->readInt(7);
for(S32 x = 0; x < count; x++)
mToggledMeshes.push_back(stream->readInt(8));
//Con::warnf("hiddenMesh::: %d", count);
updateToggledMeshes();
}
#endifAdd the following
if (stream->readFlag()) //SkinMeshMask
{
U32 meshSkinCnt = 0;
stream->read(&meshSkinCnt);
for(S32 i=0; i < meshSkinCnt; i++)
{
setMeshSkin(stream->readSTString(),stream->readSTString());
}
}Now at the end of shapebase.cpp add the following block of code.
void ShapeBase::setMeshSkin(StringTableEntry mesh, StringTableEntry texture)
{
char tex[512];
const char* matname;
dStrcpy(tex,texture);
texture=StringTable->insert(dStrlwr(tex),true);
if (isGhost())
{
// Find the Material name from the Mesh we specified
for (int i=0; i<mShapeInstance->getShape()->objects.size(); i++)
{
S32 nameIndex = mShapeInstance->getShape()->objects[i].nameIndex;
if (nameIndex>=0)
{
//Compare the mesh we specified to the object
if (!dStricmp(mesh, mShapeInstance->getShape()->getName(nameIndex)))
{
TSMesh * imesh = mShapeInstance->mMeshObjects[i].getMesh(0);
if (mesh)
{
U32 material = imesh->primitives[0].matIndex & TSDrawPrimitive::MaterialMask;
if (imesh->primitives[0].matIndex & TSDrawPrimitive::NoMaterial)
{
Con::errorf("No material on this mesh");
return;
}
else
{
TSMaterialList * materials = mShapeInstance->getMaterialList();
matname = materials->getMaterialName(material);
break;
}
}
}
}
}
//If we found the material name lets cycle through and find it and set the texture
if (matname)
{
if (!mShapeInstance->ownMaterialList())
mShapeInstance->cloneMaterialList();
// Cycle through the materials.
TSMaterialList* pMatList = mShapeInstance->getMaterialList();
for (S32 j = 0; j < pMatList->mMaterialNames.size(); j++)
{
if (!dStrcmp(pMatList->mMaterialNames[j],matname))
{
//Make sure this texture already isn't already applied -- X
if (mSkinDictionary.contains(mesh) && !dStrcmp(mSkinDictionary[mesh],texture))
{
return;
}
if (texture)
{
pMatList->setMaterial(j,texture);
pMatList->mapMaterials();
mShapeInstance->initMatInstances();
}
}
}
}
//Set the value in the dictionary.
mSkinDictionary[mesh] = texture;
}
else
{
if( !mSkinDictionary.contains( mesh ) || dStrcmp(mSkinDictionary[mesh],texture))
{
mSkinDictionary[mesh] = texture;
setMaskBits(SkinMeshMask);
}
}
}
ConsoleMethod( ShapeBase, setMeshSkin, void, 4, 4, "setMeshSkin(MeshName,texture)")
{
if (object->isGhost())
return; //only valid server side
object->setMeshSkin(StringTable->insert(argv[2]),StringTable->insert(argv[3]));
}That should be it. Compile and hopefully everything works. As you can see by the Console Method the setMeshSkin call needs to be called from the server side. This will make sure it properly gets communicated over the network the change needs to be made. I don't use TorqueScript for the scripting method as we use Python, so hopefully someone would be better able to fill that in. The process looks like this though.
char.setMeshSkin("myMesh", "~/scriptsAndAssets/data/shapes/player/newMaterial")
About the author
Part of the team that works on The Repopulation, a SciFi based MMO using a heavily modified version of the Torque MMO Kit - T3D. I also take care of the T3D version of the Torque MMO Kit.
#2
03/31/2009 (1:15 am)
very useful. ;)
#3
03/31/2009 (7:05 pm)
What if one mesh has got two sub meshes? So your resource should only work on a "1 mesh : 1 material" assumption~
#4
I am guessing that is where those 0s are coming into play for the sub materials. I believe for the most part our models are using 1 material per mesh so it wasn't needed.
04/01/2009 (9:41 am)
TSMesh * imesh = mShapeInstance->mMeshObjects[i].getMesh(0);
if (mesh)
{
U32 material = imesh->primitives[0].matIndex & TSDrawPrimitive::MaterialMask;
if (imesh->primitives[0].matIndex & TSDrawPrimitive::NoMaterial)I am guessing that is where those 0s are coming into play for the sub materials. I believe for the most part our models are using 1 material per mesh so it wasn't needed.
#5
TSMaterialList * materials = mShapeInstance->getShape()->materialList;
Should be
TSMaterialList * materials = mShapeInstance->getMaterialList();
05/19/2009 (3:37 pm)
Found an error in this, I updated the original resource, but posting the change if anyone is using it.TSMaterialList * materials = mShapeInstance->getShape()->materialList;
Should be
TSMaterialList * materials = mShapeInstance->getMaterialList();
#6
mShapeInstance->initMatInstances();
Change that to
mShapeInstance->initMaterialList();
05/19/2009 (3:39 pm)
Also, for T3D users.mShapeInstance->initMatInstances();
Change that to
mShapeInstance->initMaterialList();
#7
I'm guessing it's caused by the difference between 1.7.1 & 1.8.1 as there dosn't seem to be any AFX changes in this area that could be intefering, anyone any Ideas?
I know it's proly something real simple, but at the min don't have time to try figure it out, the dog needs walking :-)
06/21/2009 (4:57 am)
Hi, am trying to implement this in 1.8.1 AFX, I get the following error on build:-Quote:here is the affending code line
1>------ Build started: Project: ADV, Configuration: Debug Win32 ------
1>Compiling...
1>shapeBase.cpp
1>d:torqueafx113_combo_tgea181enginesourcet3dshapebase.cpp(4615) : error C2248: 'MaterialList::mMaterialNames' : cannot access protected member declared in class 'MaterialList'
for (S32 j = 0; j < pMatList->mMaterialNames.size(); j++)
Quote:
1> d:torqueafx113_combo_tgea181enginesourcematerialsmateriallist.h(80) : see declaration of 'MaterialList::mMaterialNames'
1> d:torqueafx113_combo_tgea181enginesourcematerialsmateriallist.h(21) : see declaration of 'MaterialList'
1>
d:torqueafx113_combo_tgea181enginesourcet3dshapebase.cpp(4617) : error C2248: 'MaterialList::mMaterialNames' : cannot access protected member declared in class 'MaterialList'
1>
d:torqueafx113_combo_tgea181enginesourcematerialsmateriallist.h(80) : see declaration of 'MaterialList::mMaterialNames'
1>
d:torqueafx113_combo_tgea181enginesourcematerialsmateriallist.h(21) : see declaration of 'MaterialList'
1>
d:torqueafx113_combo_tgea181enginesourcet3dshapebase.cpp(4628) : error C2039: 'initMatInstances' : is not a member of 'TSShapeInstance'
1>
d:torqueafx113_combo_tgea181enginesourcetstsshapeinstance.h(78) : see declaration of 'TSShapeInstance'
I'm guessing it's caused by the difference between 1.7.1 & 1.8.1 as there dosn't seem to be any AFX changes in this area that could be intefering, anyone any Ideas?
I know it's proly something real simple, but at the min don't have time to try figure it out, the dog needs walking :-)
#8
--Josh
06/21/2009 (10:14 am)
Looks like mMaterialNames was moved over from a public variable to a protected one. The easiest thing to do would be be put it back in public. If you go look at the header file you should see it is now in the protected area. The best thing to do would be to find a way to do what is needed in the class so it isn't exposed, but I don't believe that change was even in T3D for some reason. The other error the fix is in the post above for T3D.--Josh
#9
MeshHide works a treat but when I
I have tried with several different shapes with from 1 to many meshes and the results are the same, no change.
have you come across anything like this before Josh?
ok, trying on a fresh install, mine is pretty heavily modified, so is possible something else is intefering, I hope its not something to do with the 1.8.1 only able to apply 1 skin change bug..
will keep posted
06/21/2009 (5:37 pm)
ok, movedVector<String> mMaterialNames;out of protected area, plus applied the T3D fix project now compiles and runs.
MeshHide works a treat but when I
d.setmeshskin("body","~/scriptsAndAssets/data/shapes/DesertEagle/gold.body.jpg")I get echo'd in console log:-Quote:and nothing happens..
==>d.setmeshskin("body","~/scriptsAndAssets/data/shapes/DesertEagle/gold.body.jpg");
Material Info for object Default Material 0 - DE_Normal
[0] Files: shaders/procedural/shaderV_c0010004.hlsl, shaders/procedural/shaderP_c0010004.hlsl Pix Version: 3.00
Material Info for object DEbase - base.body
[0] Files: shaders/procedural/shaderV_c8410004.hlsl, shaders/procedural/shaderP_c8410004.hlsl Pix Version: 3.00
Material Info for object MuzzleFlash - flash
[0] Files: shaders/procedural/shaderV_e0080004.hlsl, shaders/procedural/shaderP_e0080004.hlsl Pix Version: 3.00
Material Info for object DEClip - DEClip
[0] Files: shaders/procedural/shaderV_c8410004.hlsl, shaders/procedural/shaderP_c8410004.hlsl Pix Version: 3.00
Material Info for object DEShell - DEShell
[0] Files: shaders/procedural/shaderV_c8410004.hlsl, shaders/procedural/shaderP_c8410004.hlsl Pix Version: 3.00
Material Info for object Default Material 1 - Desert Eagle
[0] Files: shaders/procedural/shaderV_c0010004.hlsl, shaders/procedural/shaderP_c0010004.hlsl Pix Version: 3.00
I have tried with several different shapes with from 1 to many meshes and the results are the same, no change.
have you come across anything like this before Josh?
ok, trying on a fresh install, mine is pretty heavily modified, so is possible something else is intefering, I hope its not something to do with the 1.8.1 only able to apply 1 skin change bug..
will keep posted
#10
will have a hammer at this later see if I can find the problem. But am begining to think it's 1.8.1 :-(
06/22/2009 (9:51 am)
ok, fresh install of 1.8.1 AFX and same problem, mesh skin dosn't change, I even commented out the if isghost return bit just incase but no joy.will have a hammer at this later see if I can find the problem. But am begining to think it's 1.8.1 :-(

Associate Konrad Kiss
Bitgap Games