Making skins work more than once in TGEA 1.8.1
by Charles Fusner ("Cog3125") · 06/04/2009 (4:48 pm) · 7 comments
While experimenting with TGEA 1.8.1, I found that setSkinName, while it did change whole materials, not just textures, would only work one time. I found this was a known issue and in this thread...
http://www.garagegames.com/community/forums/viewthread/74084
...I got pointed in the direction of the right code to look at. I came up with a generalized solution that worked fairly well for me, and posted it there. Recently, I got some feedback (thanks Andrew) that it is more straightforward than some other public solutions that have been proposed, so basically, this is just a reformat of those instructions as a public resource to make it a little easier to find for anyone who might still need it.
Step A:
In tsShapeInstance.h, find the definition for the TSShapeInstance class, and near the beginning add a new private member variable
Step B:
In tsShapeInstance.cpp, find the method TSShapeInstance::buildInstanceData (there are multiple constructors, but they both call this method). Near the end of this method, add an initialization for our new member as follows...
Step C:
Also in tsShapeInstance.cpp, find the method TSShapeInstance::reSkin. There are several simple, but key changes for this method...
1.) Near the very top, find the line which reads
... and get rid of it. We're going to be substituting our new member variable for all instances of this variable, so it's now obsolete. Substituting a StringTableEntry works, because StringTableEntry is typed as a const char * anyway, and has the incidental side benefit that string storage space is minimized for multiple instances of this TSShapeInstance which wear the same skin.
So, of course, our next changes involve getting rid of references to that old variable.
2.) Scroll down a bit, and look for the lines
And replace it with...
3.) Scroll down a bit further this time, and find the lines that read...
Replace this with...
Step D:
Lastly, we need to set the mSkinName member with the name of the new base for next time.
Be careful where you put this line! Make sure you insert it at the VERY END OF THE METHOD, OUTSIDE THE FOR LOOP. If you put it anywhere inside the for loop, you create an unfortunate bug where if the object has multiple materials to be skinned only the first one actually changes.
So, at the very end of the method, add...
Now, when the first call to reSkin is made, mSkinName contains "base" (from the constructor), which is appropriate, since all textures to be skinned should start out this way. Each time a re-skin is performed, mSkinName is set to the last thing we changed to, so it keeps working no matter how many re-skins you do.
http://www.garagegames.com/community/forums/viewthread/74084
...I got pointed in the direction of the right code to look at. I came up with a generalized solution that worked fairly well for me, and posted it there. Recently, I got some feedback (thanks Andrew) that it is more straightforward than some other public solutions that have been proposed, so basically, this is just a reformat of those instructions as a public resource to make it a little easier to find for anyone who might still need it.
Step A:
In tsShapeInstance.h, find the definition for the TSShapeInstance class, and near the beginning add a new private member variable
// Add me just before the first "public:" in the
// class definition for TSShapeInstance...
private:
StringTableEntry mSkinName;Step B:
In tsShapeInstance.cpp, find the method TSShapeInstance::buildInstanceData (there are multiple constructors, but they both call this method). Near the end of this method, add an initialization for our new member as follows...
mSkinName = StringTable->insert("base", false);Step C:
Also in tsShapeInstance.cpp, find the method TSShapeInstance::reSkin. There are several simple, but key changes for this method...
1.) Near the very top, find the line which reads
const char* defaultBaseName = "base";
... and get rid of it. We're going to be substituting our new member variable for all instances of this variable, so it's now obsolete. Substituting a StringTableEntry works, because StringTableEntry is typed as a const char * anyway, and has the incidental side benefit that string storage space is minimized for multiple instances of this TSShapeInstance which wear the same skin.
So, of course, our next changes involve getting rid of references to that old variable.
2.) Scroll down a bit, and look for the lines
else
newBaseName = String(defaultBaseName);And replace it with...
else
newBaseName = String(mSkinName);3.) Scroll down a bit further this time, and find the lines that read...
bool replacedRoot = makeSkinPath(pathName, NAME_BUFFER_LENGTH,
resourcePath, pName, defaultBaseName,
newBaseName); Replace this with...
bool replacedRoot = makeSkinPath(pathName, NAME_BUFFER_LENGTH,
resourcePath, pName, mSkinName,
newBaseName);Step D:
Lastly, we need to set the mSkinName member with the name of the new base for next time.
Be careful where you put this line! Make sure you insert it at the VERY END OF THE METHOD, OUTSIDE THE FOR LOOP. If you put it anywhere inside the for loop, you create an unfortunate bug where if the object has multiple materials to be skinned only the first one actually changes.
So, at the very end of the method, add...
mSkinName = StringTable->insert(newBaseName,false);
Now, when the first call to reSkin is made, mSkinName contains "base" (from the constructor), which is appropriate, since all textures to be skinned should start out this way. Each time a re-skin is performed, mSkinName is set to the last thing we changed to, so it keeps working no matter how many re-skins you do.
#2
06/08/2009 (7:46 pm)
Woot!
#3
P.S. When I try obj.setSkinName("purple") the object turns invisible.
I have a material.cs in the same folder as the DTS and textures that looks like this:
06/09/2009 (1:26 pm)
Quick question about exporting the multiple textures. In 3dsMax I have an object with a texture applied to it called 'base.house2.png'. I exported it as is then opened the base.house2.png in photoshop, tinted it purple, and saved it as 'purple.house2.png'. Should I be applying the texture in MAX somehow?P.S. When I try obj.setSkinName("purple") the object turns invisible.
I have a material.cs in the same folder as the DTS and textures that looks like this:
new Material(House2Base)
{
mapTo = "base";
baseTex[0] = "base";
};
new Material(House2Purple)
{
mapTo = "purple";
baseTex[0] = "purple";
};
#4
Hi
try this and see if it works, change your material.cs to:-
then try:-
obj.setSkinName("purple");
obj.setSkinName("base");
and see if that works :-)
06/09/2009 (2:43 pm)
@Jeff BrownHi
try this and see if it works, change your material.cs to:-
new Material(House2Base)
{
mapTo = "base.house2";
baseTex[0] = "base.house2";
};
new Material(House2Purple)
{
mapTo = "purple.house2";
baseTex[0] = "purple.house2";
};you need to tell it the whole texture name else it could get confused with say. "purple.rock.jpg"then try:-
obj.setSkinName("purple");
obj.setSkinName("base");
and see if that works :-)
#5
06/09/2009 (10:11 pm)
@David - It works perfectly, thanks a lot.
#6
"There is a texture object leak, check the log for more details."
gfxtextureobject.cpp @38
08/24/2009 (12:41 am)
using a debug exe, when changing the texture, on exit i found this error:"There is a texture object leak, check the log for more details."
gfxtextureobject.cpp @38
#7
www.garagegames.com/community/forums/viewthread/58560/1#comment-668147
08/24/2009 (1:13 am)
this work for me, (with this resource i can change only one time):www.garagegames.com/community/forums/viewthread/58560/1#comment-668147

Torque Owner David Robert Pemberton
www.deadlyassets.com
This change also works in AFX 1.8.1
just a couple of point to note.
getskinname now returns NULL and not the skinname
if you accedently setskinname(..) with an incorrect skinname, then try it with a correct skinname its broke again.
so if you,
%obj.setskinname("base"); //ok
%obj.setskinname("green"); //ok
%obj.setskinname("red"); //ok
%obj.setskinname("blu"); //(typo should be blue) texture dosn't change
%obj.setskinname("green"); // %obj is still red
%obj.setskinname("base"); // %obj still red
took me a while to realise I had a typo and was wondering why setskinname had broke again.
Just make sure you name all your skins correctly :-)
A great fix