Materials seperated from meshes for TSStatics in T3D
by Ian Omroth Hardingham · 11/17/2009 (1:33 pm) · 7 comments
One of the stranger T3D design decisions is that if you have many objects which use the same model, they also have to use the same texture. No longer with my handy resource! Also, you can change a TSStatic's material easily with a simple console command.
WARNING: this is currently un-networked, and will only work for client-servers (ie single player games). I only need this for a single player thing, but it will be the work of 5 minutes for someone knowledgeable to network it, hopefully someone will do that and post a new resource.
I've kept in my "hax" tags for the most part, so you can easily find where you've added my changes.
Alright, let's get on with the killing.
In T3D/TSStatic.h:
Find
And change to:
After:
Add:
In T3D/TSStatic.cpp:
after:
put:
After:
Put:
After:
Put:
Just below that, add these functions:
After:
Put:
In gametoolsmaterialEditorscriptsmaterialEditor.ed.cs:
After:
Put:
//hax
if (MaterialEditorGui.currentObject.useCustomMaterial)
{
MaterialEditorGui.prepareActiveMaterial( MaterialEditorGui.currentObject.customMaterialName.getId() );
return;
}
//hax[/code]
After:
Put:
After:
Put:
That's it!
Instructions for use:
All you need to do is set UseCustomMaterial to true in the Inspector for any TSStatics you want to use custom materials rather than their mesh's materials. After that, everything works as normal.
For the other feature, you can also now use %yourScriptObject.setCustomMat(%matName) on any TSStatic to change the material at game-time.
Let me know how this works for you.
WARNING: this is currently un-networked, and will only work for client-servers (ie single player games). I only need this for a single player thing, but it will be the work of 5 minutes for someone knowledgeable to network it, hopefully someone will do that and post a new resource.
I've kept in my "hax" tags for the most part, so you can easily find where you've added my changes.
Alright, let's get on with the killing.
In T3D/TSStatic.h:
Find
TSShapeInstance* mShapeInstance;
And change to:
public: TSShapeInstance* mShapeInstance; protected:
After:
const Vector<S32>& getLOSDetails() const { return mLOSDetails; }Add:
//hax bool mUseCustomMaterial; String mCustomMaterialName; bool mLoadedCustomMaterial; void loadCustomMat(String& name); void setCustomMat(String& name); //hax
In T3D/TSStatic.cpp:
after:
mCollisionType = CollisionMesh;
put:
//hax
mUseCustomMaterial = false; // note: put this to true if you always want to use custom materials
mCustomMaterialName = String("");
mLoadedCustomMaterial = false;
//haxAfter:
endGroup("Debug");Put:
//hax
addGroup("CustomMat");
addField("useCustomMaterial", TypeBool, Offset(mUseCustomMaterial, TSStatic), "use custom material?");
addField("customMaterialName", TypeRealString, Offset(mCustomMaterialName, TSStatic), "custom material name");
endGroup("CustomMat");
//haxAfter:
if ( mPlayAmbient && mAmbientThread && isServerObject() )
mShapeInstance->advanceTime( getTickSec(), mAmbientThread );Put:
//hax
// for some reason when the object is actually created we don't have a material list
// this isn't great, but it should work
if (mUseCustomMaterial && !mLoadedCustomMaterial)
{
// if we have a "" custom material, we will just pretend we loaded it so we don't keep checking
if (mCustomMaterialName.compare(String("")) == 0)
{
mLoadedCustomMaterial = true;
}
else
{
TSStatic* stat = dynamic_cast<TSStatic*>(getClientObject());
if (stat && stat->mShapeInstance->mMaterialList)
{
mLoadedCustomMaterial = true;
stat->loadCustomMat(mCustomMaterialName);
}
}
}
//haxJust below that, add these functions:
//hax
void TSStatic::loadCustomMat(String& name)
{
Material *newMat = dynamic_cast<Material*>(Sim::findObject(name));
// make sure we have our own mat list. This actually tests within the function to see if we've got our own already, and if so, doesn't clone.
mShapeInstance->cloneMaterialList();
TSMaterialList* matList = mShapeInstance->mMaterialList;
int matListSize = matList->getMaterialNameList().size();
if (matListSize > 0)
{
// WARNING: this currently only works for the first material instance... when I work out how I want to handle more, I'll change it
delete [] matList->mMatInstList[0];
matList->mMatInstList[0] = newMat->createMatInstance();
const GFXVertexFormat *flags = getGFXVertexFormat<GFXVertexPNTTB>();
FeatureSet features = MATMGR->getDefaultFeatures();
matList->getMaterialInst(0)->init( features, flags );
}
}
void TSStatic::setCustomMat(String& name)
{
TSStatic* stat = dynamic_cast<TSStatic*>(getClientObject());
if (stat && stat->mShapeInstance->mMaterialList)
{
stat->loadCustomMat(name);
mUseCustomMaterial = true;
mCustomMaterialName = name;
mLoadedCustomMaterial = true;
}
}
ConsoleMethod( TSStatic, setCustomMat, void, 3, 3, "mat name")
{
String name = String(argv[2]);
object->setCustomMat(name);
}
//haxAfter:
ConsoleMethod( TSStatic, changeMaterial, void, 5, 5, "(mapTo, fromMaterial, ToMaterial)")
{
TSStatic *obj = dynamic_cast< TSStatic* > ( object );
if(obj)
{Put:
//hax
if (obj->mUseCustomMaterial)
{
TSStatic* stat = obj;
if (obj->getServerObject())
stat = dynamic_cast< TSStatic* > (obj->getServerObject());
String name = String(argv[4]);
stat->setCustomMat(name);
return;
}
//haxIn gametoolsmaterialEditorscriptsmaterialEditor.ed.cs:
After:
function SubMaterialSelector::onSelect( %this )
{Put:
//hax
if (MaterialEditorGui.currentObject.useCustomMaterial)
{
MaterialEditorGui.prepareActiveMaterial( MaterialEditorGui.currentObject.customMaterialName.getId() );
return;
}
//hax[/code]
After:
function MaterialEditorGui::showMaterialChangeSaveDialog( %this, %toMaterial )
{
%fromMaterial = MaterialEditorGui.currentMaterial;Put:
//hax
// we don't annoyingly ask the question if we're using customMaterials
if (MaterialEditorGui.currentObject.useCustomMaterial)
{
MaterialEditorGui.changeMaterial(%fromMaterial, %toMaterial);
return;
}
//haxAfter:
MaterialEditorGui.currentObject.changeMaterial( %materialTarget, %fromMaterial.getName(), %toMaterial.getName() );
Put:
//hax
%customMat = MaterialEditorGui.currentObject.useCustomMaterial;
if (%customMat)
{
error("custom mat change - not doing all the other faff");
MaterialEditorGui.submitUndo( %action );
MaterialEditorGui.prepareActiveMaterial( %toMaterial, true );
return;
}
//haxThat's it!
Instructions for use:
All you need to do is set UseCustomMaterial to true in the Inspector for any TSStatics you want to use custom materials rather than their mesh's materials. After that, everything works as normal.
For the other feature, you can also now use %yourScriptObject.setCustomMat(%matName) on any TSStatic to change the material at game-time.
Let me know how this works for you.
About the author
#2
11/17/2009 (9:37 pm)
Nice resource ! Thanks !
#4
Would help ya there, but i came up with a similar idea and will try to get it working (i need this feature for a multitude of screens that may share the model, but shouldnt share (all) textures).
Im using the TSShapeInstance to store some "override" materialList, which (if present in the given slot) replaces the regular material, thus giving both, the TSStatic and the ShapeBase this feature.
11/19/2009 (12:18 pm)
As i see it, you only need to hook up TSStatics pack/unpack methods with the new variable(s). Would help ya there, but i came up with a similar idea and will try to get it working (i need this feature for a multitude of screens that may share the model, but shouldnt share (all) textures).
Im using the TSShapeInstance to store some "override" materialList, which (if present in the given slot) replaces the regular material, thus giving both, the TSStatic and the ShapeBase this feature.
#5
If someone is interested, i'll either give some code to Ian, so he can make a nice resource of it, or publish it together with my version of the gui-texture-canvas.
11/20/2009 (7:12 pm)
yupp, that works and is networkable. Some small TOC-Bug at shutdown, besides that, you can add a second "set" of materials and switch (those defined) with the original material. Works for an arbitrary number of materials, you just need to know the name of texture you want it to map to. If someone is interested, i'll either give some code to Ian, so he can make a nice resource of it, or publish it together with my version of the gui-texture-canvas.
#6
12/02/2009 (7:50 am)
That would be a wonderful addiction to stock T3D...
Torque Owner deepscratch
DeepScratchStudios
this is a wonderful little resource you've put up here,
very useful,
thanks.