Plastic Gem #34: TGEA Decals
by Anthony Rosenbaum · 07/28/2008 (6:35 am) · 13 comments
Download Code File

TGEA Decals
You might have noticed that the latest incarnation of TGEA 1.7 does not have decals and the decal manager activated. This resource will show you how to turn the decals back on, by the end you will be able to restore footprints and bullets holes, included in stock TGEA.
In sourcesceneGraphdecalManager.h after the end brace of the DecalData class add
1) Expose DecalData to the console.
2) Impliment the DecalData on the console
In sourcesceneGraphdecalManager.cpp after the bool DecalData::preload(bool server, char errorBuffer[256]) function ad
3) Add DecalData to the Core Datatypes
In consoleconsoleTypes.h after class ParticleEmitterData; ADD
AND after DefineConsoleType( TypeParticleEmitterDataPtr, ParticleEmitterData* ); ADD
Now we have to uncomment code to turn the decals on players and add code to projectiles
.
4) Load the images into the datablock.
In T3D/player.cpp
In bool PlayerData::preload(bool server, char errorBuffer[256]) Un comment out
5) Expose the field for the footstep decals.
in void PlayerData::initPersistFields() uncomment
6) Make the decals supported by the network
in void PlayerData::packData(BitStream* stream) uncomment
in void PlayerData::unpackData(BitStream* stream)in comment
Walla you will have foot steps if decalData is set on the playerData.
Now lets get us some bullet holes for the projectiles. This bullet hole code is a straight port from TGE.
7) Forward associate the DecalData to the ProjectileData class.
In T3d/projectile.h after class TSThread;; add
8) Declare some variables to hold the decal data.
Within the ProjectileData class Add
9) Tell the compiler where to find the decalManager.
In T3d/projectile.cpp after the includes add
10) Initialize the new decal variables.
In ProjectileData::ProjectileData() at the bottom add
11) Expose the decal field in the datablock to the console.
In void ProjectileData::initPersistFields() at the bottom add
12) Load the decals if there are specified in the datablock.
In bool ProjectileData::preload(bool server, char errorBuffer[256]) before return true; add
13) Send the decal information over the network.
In void ProjectileData::packData(BitStream* stream) before if(stream->writeFlag(hasLight)) ADD
In void ProjectileData::unpackData(BitStream* stream) before hasLight = stream->readFlag(); ADD
14) Render the decals when the the projectiles explodes.
In void Projectile::explode(const Point3F& p, const Point3F& n, const U32 collideType) after the if (pExplosion->registerObject() == false) block add
You'll need to be sure to make decal Datablocks and associate them to the playerData and projectileData like so:
In YOURGAMENAME/server/scripts/player.cs somewhere before PlayerData
In PlayerData ADD
In YOURGAMENAME/server/scripts/crossbow.cs somewhere before ProjectileData
Enjoy!

TGEA Decals
You might have noticed that the latest incarnation of TGEA 1.7 does not have decals and the decal manager activated. This resource will show you how to turn the decals back on, by the end you will be able to restore footprints and bullets holes, included in stock TGEA.
In sourcesceneGraphdecalManager.h after the end brace of the DecalData class add
1) Expose DecalData to the console.
// > pg decals DECLARE_CONSOLETYPE(DecalData) // < pg decals
2) Impliment the DecalData on the console
In sourcesceneGraphdecalManager.cpp after the bool DecalData::preload(bool server, char errorBuffer[256]) function ad
// > pg decals IMPLEMENT_CONSOLETYPE(DecalData) IMPLEMENT_SETDATATYPE(DecalData) IMPLEMENT_GETDATATYPE(DecalData) // < pg decals
3) Add DecalData to the Core Datatypes
In consoleconsoleTypes.h after class ParticleEmitterData; ADD
class DecalData;
AND after DefineConsoleType( TypeParticleEmitterDataPtr, ParticleEmitterData* ); ADD
// > pg decals DefineConsoleType( TypeDecalDataPtr, DecalData*); // < pg decals
Now we have to uncomment code to turn the decals on players and add code to projectiles
.
4) Load the images into the datablock.
In T3D/player.cpp
In bool PlayerData::preload(bool server, char errorBuffer[256]) Un comment out
// > pg decals
if (!decalData && decalID != 0 )
if (!Sim::findObject(decalID, decalData))
Con::errorf(ConsoleLogEntry::General, "PlayerData::preload Invalid packet, bad datablockId(decalData): 0x%x", decalID);
// < pg decals5) Expose the field for the footstep decals.
in void PlayerData::initPersistFields() uncomment
// > pg decals
addField("decalData", TypeDecalDataPtr, Offset(decalData, PlayerData));
// < pg decals6) Make the decals supported by the network
in void PlayerData::packData(BitStream* stream) uncomment
// > pg decals
if( stream->writeFlag( decalData ) )
{
stream->writeRangedU32( decalData->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
}
stream->write(decalOffset);
// < pg decalsin void PlayerData::unpackData(BitStream* stream)in comment
// > pg decals
if( stream->readFlag() )
{
decalID = (S32) stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
}
stream->read(&decalOffset);
// < pg decalsWalla you will have foot steps if decalData is set on the playerData.
Now lets get us some bullet holes for the projectiles. This bullet hole code is a straight port from TGE.
7) Forward associate the DecalData to the ProjectileData class.
In T3d/projectile.h after class TSThread;; add
// > pg decals class DecalData; // < pg decals
8) Declare some variables to hold the decal data.
Within the ProjectileData class Add
// > pg decals
enum DecalConstants { // Number of decals constant
NumDecals = 6,
};
DecalData* decals[NumDecals]; // Decal Datablocks
S32 decalId[NumDecals]; // Decal IDs
U32 decalCount;
// < pg decals9) Tell the compiler where to find the decalManager.
In T3d/projectile.cpp after the includes add
// > pg decals #include "sceneGraph/decalManager.h" // < pg decals
10) Initialize the new decal variables.
In ProjectileData::ProjectileData() at the bottom add
// > pg decals
decalCount = 0;
for (U32 i = 0; i < NumDecals; i++)
{
decals[i] = NULL;
decalId[i] = 0;
}
// < pg deacls11) Expose the decal field in the datablock to the console.
In void ProjectileData::initPersistFields() at the bottom add
// > pg decals
addField("decals", TypeDecalDataPtr, Offset(decals, ProjectileData), NumDecals);
// < pg decals12) Load the decals if there are specified in the datablock.
In bool ProjectileData::preload(bool server, char errorBuffer[256]) before return true; add
// > pg decals
// load up all the supplied decal datablocks
// move non-null ones to the front of the array
// for our random decal picker later
U32 i;
DecalData *tmpDecals[NumDecals];
for (i = 0; i < NumDecals; i++)
{
tmpDecals[i] = NULL;
if(!decals[i] && decalId[i] != 0)
if(!Sim::findObject(decalId[i], decals[i]))
Con::errorf( ConsoleLogEntry::General, "ProjectileData::preload Invalid packet, bad datablockId(decals): 0x%x", decalId[i]);
if (!server && decals[i])
{
tmpDecals[decalCount] = decals[i];
decalCount++;
}
}
if (!server && decalCount > 0)
for (i = 0; i < NumDecals; i++)
decals[i] = tmpDecals[i];
// < pg decals13) Send the decal information over the network.
In void ProjectileData::packData(BitStream* stream) before if(stream->writeFlag(hasLight)) ADD
// > pg decals
for (U32 i = 0; i < NumDecals; i++)
if (stream->writeFlag(decals[i] != NULL))
stream->writeRangedU32(decals[i]->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
// < pg decalsIn void ProjectileData::unpackData(BitStream* stream) before hasLight = stream->readFlag(); ADD
// > pg decals
for (U32 i = 0; i < NumDecals; i++)
if (stream->readFlag())
decalId[i] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
// < pg decals14) Render the decals when the the projectiles explodes.
In void Projectile::explode(const Point3F& p, const Point3F& n, const U32 collideType) after the if (pExplosion->registerObject() == false) block add
// > pg decal
if(mDataBlock->decalCount > 0)
{
if(collideType & (TerrainObjectType | InteriorObjectType))
{
// randomly choose a decal between 0 and (decal count - 1)
U32 idx = (U32)(mCeil(mDataBlock->decalCount * Platform::getRandom()) - 1.0f);
// this should never choose a NULL idx, but check anyway
if(mDataBlock->decals[idx] != NULL)
{
DecalManager *decalMngr = gClientSceneGraph->getCurrentDecalManager();
if(decalMngr)
decalMngr->addDecal(p, n, mDataBlock->decals[idx]);
}
}
}
// < decal pgYou'll need to be sure to make decal Datablocks and associate them to the playerData and projectileData like so:
In YOURGAMENAME/server/scripts/player.cs somewhere before PlayerData
// > decal pg
datablock DecalData(PlayerFootprint)
{
sizeX = 0.25;
sizeY = 0.25;
textureName = "~/data/shapes/player/footprint"; // use a texture you have
};
// < decal pgIn PlayerData ADD
// > decal pg // Foot Prints decalData = PlayerFootprint; decalOffset = 0.25; // < decal pg
In YOURGAMENAME/server/scripts/crossbow.cs somewhere before ProjectileData
datablock DecalData(crossbowHole0){
sizeX = 0.03;
sizeY = 0.03;
textureName = "~/data/shapes/particles/bullethole"; // use a texture you have
};
datablock DecalData(crossbowHole2: crossbowHole0){
textureName = "~/data/shapes/particles/bullethole1";
};
datablock DecalData(crossbowHole3: crossbowHole0){
textureName = "~/data/shapes/particles/bullethole2";
};
datablock DecalData(crossbowHole4: crossbowHole0){
textureName = "~/data/shapes/particles/bullethole3";
};
datablock DecalData(crossbowHole5: crossbowHole0){
textureName = "~/data/shapes/particles/bullethole4";
};In the ProjectileData Adddecals[0] = crossbowHole0; decals[1] = crossbowHole1; decals[2] = crossbowHole2; decals[3] = crossbowHole3; decals[4] = crossbowHole4; decals[5] = crossbowHole5;
Enjoy!
About the author
#2
07/28/2008 (8:31 pm)
Very useful. Something TGEA has needed stock for a long time.
#3
07/29/2008 (5:06 am)
@Konrad thanks for the input, the resource and zip reflct your changes
#4
Each time i enter a game, and shoot, it crash...
In debug mode::: it says :::
Projectile(CrossbowProjectile)::Explode : couldn't register explosion
FATAL ... /source/scenegraph/sceneobject.cpp @ 382 Error, Sceneobject not properly removed from sceneGraph.
In my crossbow script, in the end, it shows the MissionCleanup group routine so i don't think it's a script
problem but in the engine side. I must do something wrong in the step 14, Render the decals when the projectiles explode. That's probably this. I'm gonna check the code again... Please, if someone can point me to the right direction it will be great.
thank you very much!
11/30/2008 (11:21 am)
Hi! I compile the project fine exept i got a little problem.Each time i enter a game, and shoot, it crash...
In debug mode::: it says :::
Projectile(CrossbowProjectile)::Explode : couldn't register explosion
FATAL ... /source/scenegraph/sceneobject.cpp @ 382 Error, Sceneobject not properly removed from sceneGraph.
In my crossbow script, in the end, it shows the MissionCleanup group routine so i don't think it's a script
problem but in the engine side. I must do something wrong in the step 14, Render the decals when the projectiles explode. That's probably this. I'm gonna check the code again... Please, if someone can point me to the right direction it will be great.
thank you very much!
#5
01/03/2009 (7:06 am)
This doesn't work for Atlas terrains. Do you guys now how to make it work with Atlas terrains?
#6
In decalManager.cpp, change:
to:
01/06/2009 (5:36 pm)
Vasily,In decalManager.cpp, change:
U32 DecalManager::smDecalMask = TerrainObjectType | InteriorObjectType | StaticObjectType;
to:
U32 DecalManager::smDecalMask = TerrainObjectType | InteriorObjectType | StaticObjectType | AtlasObjectType;
#7
01/07/2009 (4:49 am)
Oh, thanks Adam. I've probably missed that line when I tried to figure out myself. Thanks, I'll try it out.
#8
01/07/2009 (5:00 am)
No, I haven't missed that. In scenegraph/decalManager.cpp there's not smDecalMask section... I'm using TGEA 1.7.1 + AFX if that matters. So, it doesn't work stil... :-(
#9
01/07/2009 (7:45 am)
Vasily - perhaps the decal mask is something we ADDED for this resource? So you have to infact ADD the line indicated by Adam? The gist is that somewhere the decal code needs to know what sort of objects to collide with and that is what this variable is for.
#10
01/07/2009 (11:29 am)
Thanks for your suggestion, Paul. I tried it, but without success. May be you could tell me which line should it be? Thanks in advance.
#11
03/11/2009 (1:02 pm)
im having a problem where it only shows the bullet holes on the ground. not on any objects, interiors, etc
#12
in void Projectile::explode()
make it:
...
if(collideType & (TerrainObjectType | InteriorObjectType | StaticObjectType | AtlasObjectType))
...
03/11/2009 (7:09 pm)
figured it out. the function to change is in projectile.cpp.in void Projectile::explode()
make it:
...
if(collideType & (TerrainObjectType | InteriorObjectType | StaticObjectType | AtlasObjectType))
...
#13
09/18/2009 (6:12 am)
I`m having the same problem as Vasily, the decals don`t work on Atlas terrains, and the line of code that Adam posted for decalManager.cpp doesn`t exist anywhere in 1.8.1 (or 1.7.1 as far I can tell). Anyone have a solution?
Associate Konrad Kiss
Bitgap Games
At step 7 class WindEmitter is not used in TGEA, might want to make that class TSThread.
Then you get some compiler errors, so to fix these, in ConsoleTypes.h after class ParticleEmitterData; add
Then, still a number of errors coming up. To fix these, comment out the line added in step 1. We already have a DECLARE_CONOBJECT(DecalData); above the new declaration, which is probably good enough, so:
Then it works great!