Mountimage Replacement for Equipment
by Peter Simard · 07/03/2006 (11:34 am) · 42 comments
Here are the code modifications:
shapebase.h changes
Insert these lines into the ShapeBaseData public block:
Add this new class above your ShapeBase definition:
Add a new mask to your ShapeBaseMasks. Make sure you assign its number to the next available one in the list.
Add this inside your ShapeBase public block
shapebase.cc changes
Add this to the top of ShapeBaseData::ShapeBaseData()
Add these inside of ShapeBaseData::initPersistantFields()
Insert these lines into ShapeBaseData::packData()
Now add these lines to ShapeBaseData::unPackData()
At the top of ShapeBase::onRemove()
Inside of ShapeBase::renderObject() add the following line:
In ShapeBase::packUpdate() make the following changes
In ShapeBase::unpackUpdate() make the following changes
Add this code to the end of the file
USAGE
shapebase.h changes
Insert these lines into the ShapeBaseData public block:
MatrixF mountOffset; Point3F mountScale;
Add this new class above your ShapeBase definition:
class equipmentMesh
{
// Contains the data for a mounted equipment
public:
ShapeBaseData* shapeData;
TSShapeInstance* shapeInstance;
U32 nodeNumber;
bool pendingRemoval;
};Add a new mask to your ShapeBaseMasks. Make sure you assign its number to the next available one in the list.
EquipmentMask = Parent::NextFreeMask << 5,
Add this inside your ShapeBase public block
void renderEquipment(SceneState* state);
bool mountEquipment(ShapeBaseData* imageData, const char* slotName);
void setEquipmentSlot(U32 shapeDataID, U32 nodeNumber);
void processEquipment();
void setEquipmentDeleteFlag();
void removeOldEquipment();
void getRenderEquipmentTransform(U32 mountPoint,MatrixF* mat);
Vector<equipmentMesh*> equipment;shapebase.cc changes
Add this to the top of ShapeBaseData::ShapeBaseData()
mountOffset.identity();
mountScale.set(1, 1, 1);Add these inside of ShapeBaseData::initPersistantFields()
addGroup("Mount");
addField("offset", TypeMatrixPosition, Offset(mountOffset,ShapeBaseData));
addField("rotation", TypeMatrixRotation, Offset(mountOffset,ShapeBaseData));
addField("scale", TypePoint3F, Offset(mountScale,ShapeBaseData));
endGroup("Mount");Insert these lines into ShapeBaseData::packData()
void ShapeBaseData::packData(BitStream* stream)
{
Parent::packData(stream);
[b]stream->write(mountScale.x);
stream->write(mountScale.y);
stream->write(mountScale.z);
if (!stream->writeFlag(mountOffset.isIdentity()))
stream->writeAffineTransform(mountOffset);
[/b]Now add these lines to ShapeBaseData::unPackData()
void ShapeBaseData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
[b]stream->read(&mountScale.x);
stream->read(&mountScale.y);
stream->read(&mountScale.z);
if (stream->readFlag())
mountOffset.identity();
else
stream->readAffineTransform(&mountOffset);
[/b]At the top of ShapeBase::onRemove()
equipment.clear();
Inside of ShapeBase::renderObject() add the following line:
if (shiri != NULL)
{
renderMountedImage(state, shiri);
}
else
{
renderImage(state, image);
}
[b]renderEquipment(state);[/b]In ShapeBase::packUpdate() make the following changes
[b]Modify the mask list to add the equipment mask[/b]
if(!stream->writeFlag(mask & (NameMask | DamageMask | SoundMask |
ThreadMask | ImageMask | CloakMask | MountedMask | [b]EquipmentMask[/b]
)))
[b]Add this after it packs the sound data[/b]
if (stream->writeFlag(mask & EquipmentMask)) {
stream->writeInt(equipment.size(), 8);
//Con::printf("Writing %i items", equipment.size());
for(int i = 0; i < equipment.size(); i++)
{
equipmentMesh* eqp = equipment[i];
if(stream->writeFlag(eqp))
{
stream->writeInt(eqp->shapeData->getId(), DataBlockObjectIdBitSize);
stream->writeInt(eqp->nodeNumber, 8);
}
}
}In ShapeBase::unpackUpdate() make the following changes
[b]After unpacking the sound data[/b]
if (stream->readFlag()) {
setEquipmentDeleteFlag();
U32 eqpSize = stream->readInt(8);
for(int i = 0; i < eqpSize; i++)
{
if(stream->readFlag())
{
U32 shapeDataID = stream->readInt(DataBlockObjectIdBitSize);
U32 nodeNumber = stream->readInt(8);
setEquipmentSlot(shapeDataID, nodeNumber);
}
}
removeOldEquipment();
}Add this code to the end of the file
// Script hook
ConsoleMethod( ShapeBase, mountEquipment, bool, 4, 4, "(ShapeBaseData image, const char* slot)")
{
ShapeBaseData* imageData;
if (Sim::findObject(argv[2],imageData)) {
object->mountEquipment(imageData,argv[3]);
return true;
}
else
{
return false;
}
}
// Render the mounted equipment
void ShapeBase::renderEquipment(SceneState* state)
{
PROFILE_START(RenderEquipment);
for(int x=0; x < equipment.size(); x++)
{
Point3F cameraOffset;
getRenderTransform().getColumn(3,&cameraOffset);
cameraOffset -= state->getCameraPosition();
F32 dist = cameraOffset.len();
F32 fogAmount = state->getHazeAndFog(dist,cameraOffset.z);
TSShapeInstance* pShapeInstance = equipment[x]->shapeInstance;
if (pShapeInstance) {
MatrixF mat;
getRenderEquipmentTransform(equipment[x]->nodeNumber, &mat);
mat.mul(equipment[x]->shapeData->mountOffset);
glPushMatrix();
dglMultMatrix(&mat);
if (mCloakLevel != 0.0)
pShapeInstance->setAlphaAlways(0.15 + (1 - mCloakLevel) * 0.85);
else
pShapeInstance->setAlphaAlways(1.0);
mShapeInstance->setEnvironmentMap(state->getEnvironmentMap());
mShapeInstance->setEnvironmentMapOn(true, 1.0);
glScalef(equipment[x]->shapeData->mountScale.x, equipment[x]->shapeData->mountScale.y, equipment[x]->shapeData->mountScale.z);
pShapeInstance->setupFog(fogAmount,state->getFogColor());
pShapeInstance->animate();
pShapeInstance->render();
mShapeInstance->setEnvironmentMapOn(false, 1.0);
glPopMatrix();
}
}
PROFILE_END();
}
// Returns mount point to world space transform
void ShapeBase::getRenderEquipmentTransform(U32 mountPoint,MatrixF* mat)
{
MatrixF mountTransform = mShapeInstance->mNodeTransforms[mountPoint];
const Point3F& scale = getScale();
// The position of the mount point needs to be scaled.
Point3F position = mountTransform.getPosition();
position.convolve( scale );
mountTransform.setPosition( position );
// Also we would like the object to be scaled to the model.
mountTransform.scale( scale );
mat->mul(getRenderTransform(), mountTransform);
return;
}
// Called from the script to add/change an equipment slot
// Any changes will set the network mask and will send
// the changes out to all clients in their next update
bool ShapeBase::mountEquipment(ShapeBaseData* imageData, const char* slotName)
{
if(isGhost())
return false;
U32 mountNode = mDataBlock->shape->findNode(slotName);
if(mountNode < 0)
{
// If no mountNode avalible
Con::errorf("Unable to locate node: \"%s\" while attempting to mount to %s", slotName, imageData->getName());
return false;
}
// Search the equipment Vector for the same node/shapeData
for(int x=0; x < equipment.size(); x++)
{
equipmentMesh* eqp = equipment[x];
if(!eqp)
continue;
if(eqp->nodeNumber == mountNode)
{
if(eqp->shapeData == imageData)
{
// The same shapeData is already equiped in that slot
eqp->pendingRemoval = false;
return false;
}
else
{
// A new shapeData is going into the slot.
// Delete the current one. We dont need to delete the mesh
// because the mesh is only created on the client
delete eqp;
equipment.erase(x);
}
}
}
setMaskBits(EquipmentMask);
// Doesnt add a new equipment item because its blank
if(!imageData)
return false;
// No mounted item in that slot, add one to the vector
equipmentMesh *eqp = new equipmentMesh();
eqp->nodeNumber = mountNode;
eqp->shapeData = imageData;
eqp->shapeInstance = NULL;
eqp->pendingRemoval = false;
equipment.push_back(eqp);
return true;
}
// Called anytime there is an equipment update.
// By default the eqipment will be deleted this frame
// unless an update is sent with the same mesh/slot
void ShapeBase::setEquipmentDeleteFlag()
{
for(int x=0; x < equipment.size(); x++)
{
equipmentMesh* eqp = equipment[x];
eqp->pendingRemoval = true;
}
}
void ShapeBase::removeOldEquipment()
{
for(int x = equipment.size()-1; x > -1 ; x--)
{
equipmentMesh* eqp = equipment[x];
if(eqp->pendingRemoval)
{
delete eqp;
equipment.erase(x);
}
}
if(!isGhost())
{
setMaskBits(EquipmentMask);
}
}
// Set the node to certain equipment.
// Will create the clientside mesh if
// it is the first time its equiped.
void ShapeBase::setEquipmentSlot(U32 shapeDataID, U32 nodeNumber)
{
// This method will only be called on a ghosts unpackUpdate
if(!isGhost())
return;
for(int x=0; x < equipment.size(); x++)
{
equipmentMesh* eqp = equipment[x];
if(!eqp)
continue;
if(eqp->nodeNumber == nodeNumber && eqp->shapeData->getId() == shapeDataID)
{
// You already have that equipped, so set the removal flag to false.
// This will ensure the garbage removal doesnt remove it
eqp->pendingRemoval = false;
return;
}
}
equipmentMesh* eqp = new equipmentMesh();
eqp->nodeNumber = nodeNumber;
eqp->pendingRemoval = false;
Sim::findObject(shapeDataID, eqp->shapeData);
equipment.push_back(eqp);
eqp->shapeInstance = new TSShapeInstance(eqp->shapeData->shape , isClientObject());
}USAGE
//The definition of the mesh that gets mounted
datablock ShapeBaseData(mesh_testShield)
{
offset = "-0.1 0 -0.9";
shapeFile = "starter.fps/data/shapes/weapons/shield02.dts";
scale = "1.5 1.5 1.5";
rotation = "0 0 1 -72";
emap = true;
};
// Mounts the shield to Mount0. %player needs to be a valid ShapeBase
%player.mountEquipment(mesh_testShield, "mount0");
#42
Follow the TGEA changes...
Note: the vehicle tires were vanishing because the prepBatchRender function got redefined (adding the equipmentIndex variable)... so the vehicles were then calling it from GameBase... so instead of changing prepBatchRender, i copied the function to prepBatchEQRender... and left the original alone... all works fine...
use this for the prepRenderImage loop (took out the debug render..):
<code>
// eq change
for (U32 i = 0; i < equipment.size(); i++)
{
TSShapeInstance* pShapeInstance = equipment[i]->shapeInstance;
if (pShapeInstance)
{
if (mCloakLevel == 0.0f && mFadeVal == 1.0f)
{
pShapeInstance->setCurrentDetail( 0 );
prepBatchEQRender( state, -1, i );
}
}
} // end eq render
</code>
use this for the prepBatchRender loop:
<code>
if( equipmentIndex != -1 )
{
TSShapeInstance* pShapeInstance = equipment[equipmentIndex]->shapeInstance;
if( pShapeInstance )
{
GFX->pushWorldMatrix();
MatrixF mat;
getRenderEquipmentTransform(equipment[equipmentIndex]->nodeNumber,&mat);
GFX->setWorldMatrix( mat );
pShapeInstance->animate();
pShapeInstance->render(rdata);
GFX->popWorldMatrix();
}
}
</code>
Howya make code comments? meh!...
04/01/2011 (3:03 pm)
This ported to T3D pretty easily...Follow the TGEA changes...
Note: the vehicle tires were vanishing because the prepBatchRender function got redefined (adding the equipmentIndex variable)... so the vehicles were then calling it from GameBase... so instead of changing prepBatchRender, i copied the function to prepBatchEQRender... and left the original alone... all works fine...
use this for the prepRenderImage loop (took out the debug render..):
<code>
// eq change
for (U32 i = 0; i < equipment.size(); i++)
{
TSShapeInstance* pShapeInstance = equipment[i]->shapeInstance;
if (pShapeInstance)
{
if (mCloakLevel == 0.0f && mFadeVal == 1.0f)
{
pShapeInstance->setCurrentDetail( 0 );
prepBatchEQRender( state, -1, i );
}
}
} // end eq render
</code>
use this for the prepBatchRender loop:
<code>
if( equipmentIndex != -1 )
{
TSShapeInstance* pShapeInstance = equipment[equipmentIndex]->shapeInstance;
if( pShapeInstance )
{
GFX->pushWorldMatrix();
MatrixF mat;
getRenderEquipmentTransform(equipment[equipmentIndex]->nodeNumber,&mat);
GFX->setWorldMatrix( mat );
pShapeInstance->animate();
pShapeInstance->render(rdata);
GFX->popWorldMatrix();
}
}
</code>
Howya make code comments? meh!...

Torque Owner Vince Gee
WinterLeaf Entertainment