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");
#22
This is exactly what I've been looking for - unfortuantely I can't get it to work?? .....
Sorry ignore me I was being stupid :(
11/28/2006 (9:56 am)
Hi Peter, This is exactly what I've been looking for - unfortuantely I can't get it to work?? .....
Sorry ignore me I was being stupid :(
#23
11/29/2006 (8:05 am)
Thanks Nick, yes we
#24
12/03/2006 (10:00 am)
Is there any way to unmount the equipment? Since it not an image or an object I can't seem to unmount anything!?
#25
Now call %player.mountEquipment with the same image and slotname to clear it.
EDIT unnoticed bug fix.
01/10/2007 (3:20 pm)
To clear a mountEquipment I changed bool ShapeBase::mountEquipment(ShapeBaseData* imageData, const char* slotName)find and change this:
....
if(eqp->nodeNumber == mountNode)
{
if(eqp->shapeData == imageData)
{
// The same shapeData is already equiped in that slot
//Con::errorf("Shape \"%s\" removed.", imageData->getName());
eqp->pendingRemoval = true;
delete eqp->shapeInstance;
delete eqp;
equipment.erase(x);
setMaskBits(EquipmentMask);
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);
}
}Now call %player.mountEquipment with the same image and slotname to clear it.
EDIT unnoticed bug fix.
#26
question: am I right in thinking that this should be used for everything BUT weapons? because the equipment does not allow for the states and triggers that happen with ShapeImages ?
in particular, combining this mod with say a melee mod, where it utilitzes the shapeImage's ability to play arm threads...
or am I missing something/wrong?
09/19/2007 (3:18 pm)
first, love this mod!question: am I right in thinking that this should be used for everything BUT weapons? because the equipment does not allow for the states and triggers that happen with ShapeImages ?
in particular, combining this mod with say a melee mod, where it utilitzes the shapeImage's ability to play arm threads...
or am I missing something/wrong?
#27
11/05/2007 (12:16 pm)
Hello all! I followed the procedure to install this wonderful resource line for line, and now TGE fails before starting up. I looked at the debug file and it looks like I am getting shapebase memory errors. I am using TGE 1.5.2 with AFX. Any suggestions?
#28
11/14/2007 (6:42 pm)
Question ? I need to add a lamp to my player when he enters a dark cave so he can see. Would this be the best resource for this purpose or would it be better to just use the mountimage like the weapons.
#29
Then in ShapeBase::prepRenderImage, around line 2240, below
then change the ShapeBase::prepBatchRender method to look like this
Notice the change at the top. Make sure you also change this in the header file; shapebase.h
like
If I remember correctly thats all. The only thing that worries me a bit is the comment at the top of the ShapeBase::prepBatchRender method
Thank you for this resource Peter!
edit:
another thing that bothers me a bit is the line
01/12/2008 (5:49 am)
To get this working in TGEA neither add the ShapeBase::renderEquipment method or call to it in ShapeBase::renderObject().Then in ShapeBase::prepRenderImage, around line 2240, below
for (U32 i = 0; i < MaxMountedImages; i++)
{
.....
}addfor (U32 i = 0; i < equipment.size(); i++)
{
TSShapeInstance* pShapeInstance = equipment[i]->shapeInstance;
if (pShapeInstance)
{
DetailManager::selectPotentialDetails(pShapeInstance,getRenderTransform(),state);
if (mCloakLevel == 0.0f && mFadeVal == 1.0f)
{
prepBatchRender( state, -1, i );
// render debug
if( gShowBoundingBox )
{
RenderInst *ri = gRenderInstManager.allocInst();
ri->obj = this;
ri->state = state;
ri->type = RenderInstManager::RIT_Object;
//ri->equipedObjIdx = i; // dont know what to do with this.
gRenderInstManager.addInst( ri );
}
}
}
}then change the ShapeBase::prepBatchRender method to look like this
void ShapeBase::prepBatchRender(SceneState* state, S32 mountedImageIndex, [b]S32 equipmentIndex[/b] )
{
// CHANGES IN HERE SHOULD BE DUPLICATED IN TSSTATIC!
RectI viewport = GFX->getViewport();
MatrixF proj = GFX->getProjectionMatrix();
GFX->pushWorldMatrix();
MatrixF world = GFX->getWorldMatrix();
TSMesh::setCamTrans( world );
TSMesh::setSceneState( state );
TSMesh::setCubemap( mDynamicCubemap );
TSMesh::setObject( this );
gClientSceneGraph->getLightManager()->sgSetupLights(this);
if( mountedImageIndex != -1 )
{
MountedImage& image = mMountedImageList[mountedImageIndex];
if( image.dataBlock && image.shapeInstance && DetailManager::selectCurrentDetail(image.shapeInstance))
{
MatrixF mat;
getRenderImageTransform(mountedImageIndex, &mat);
GFX->setWorldMatrix( mat );
image.shapeInstance->animate();
image.shapeInstance->render();
}
}[b]else if( equipmentIndex != -1 )
{
TSShapeInstance* pShapeInstance = equipment[equipmentIndex]->shapeInstance;
if( pShapeInstance )
{
MatrixF mat;
getRenderEquipmentTransform(equipment[equipmentIndex]->nodeNumber, &mat);
mat.mul(equipment[equipmentIndex]->shapeData->mountOffset);
mat.scale( equipment[equipmentIndex]->shapeData->mountScale );
GFX->setWorldMatrix( mat );
pShapeInstance->selectCurrentDetail(mat, state);
pShapeInstance->animate();
pShapeInstance->render();
}
}[/b]else
{
MatrixF mat = getRenderTransform();
mat.scale( mObjScale );
GFX->setWorldMatrix( mat );
mShapeInstance->selectCurrentDetail(mat, state);
mShapeInstance->animate();
mShapeInstance->render();
}
gClientSceneGraph->getLightManager()->sgResetLights();
GFX->popWorldMatrix();
GFX->setProjectionMatrix( proj );
GFX->setViewport( viewport );
}Notice the change at the top. Make sure you also change this in the header file; shapebase.h
like
virtual void prepBatchRender( SceneState *state, S32 mountedImageIndex, [b]S32 equipmentIndex = -1[/b] );
If I remember correctly thats all. The only thing that worries me a bit is the comment at the top of the ShapeBase::prepBatchRender method
// CHANGES IN HERE SHOULD BE DUPLICATED IN TSSTATIC!
Thank you for this resource Peter!
edit:
another thing that bothers me a bit is the line
ri->equipedObjIdx = i;in my post i commented it out, but I've added equipedObjIdx as a member of struct RenderInstance, which is a bit useless, because it does nothing a the moment.
#30
You do not have the correct version of the TGE or related art needed to connect to this server.........more stuff........(ShapeBaseData: Couldn't load shape "Game1")
Game 1 being the name of my folder where all my game stuff is.
If I comment out all the code that's just been change my game runs fine.
Any ideas or thoughts?
Thx.
02/04/2008 (10:39 pm)
Hello, I have followed the instructions as close as possible and keep getting this DISCONNECT error message. Has anyone come across this error when trying to run the game? You do not have the correct version of the TGE or related art needed to connect to this server.........more stuff........(ShapeBaseData: Couldn't load shape "Game1")
Game 1 being the name of my folder where all my game stuff is.
If I comment out all the code that's just been change my game runs fine.
Any ideas or thoughts?
Thx.
#31
in ShapeBase::prepRenderImage change:
and in ShapeBase::prepBatchRender change:
That worked for me.
02/07/2008 (2:20 pm)
For recent TGEA builds you may need to make two changes to Vincent van Delden's code.in ShapeBase::prepRenderImage change:
-DetailManager::selectPotentialDetails(pShapeInstance,getRenderTransform(),state); +DetailManager::selectPotentialDetails(pShapeInstance,dist,invScale);
and in ShapeBase::prepBatchRender change:
-pShapeInstance->selectCurrentDetail(mat, state); +DetailManager::selectCurrentDetail(pShapeInstance);
That worked for me.
#32
-Was able to get it working in very short order.
Nicely Done!
02/07/2008 (8:12 pm)
This is an excellent resource.-Was able to get it working in very short order.
Nicely Done!
#33
If you mount equiptment then quit the game. The textures of the mounted equiptment are never removed and they leak (you get a message about it in debug mode).
The fix is to change the code in:
ShapeBase::onRemove
05/09/2008 (3:41 pm)
Just found a bug. This is in TGEA 1.7, but I think it applies to all versions.If you mount equiptment then quit the game. The textures of the mounted equiptment are never removed and they leak (you get a message about it in debug mode).
The fix is to change the code in:
ShapeBase::onRemove
for(int x = equipment.size()-1; x > -1 ; x--)
{
equipmentMesh* eqp = equipment[x];
eqp->pendingRemoval = true;
eqp->shapeInstance->destroy();
delete eqp->shapeInstance;
delete eqp;
equipment.erase(x);
}
equipment.clear();
#34
Thanks!
Guimo
06/17/2008 (5:17 pm)
Nice resource! Just a question, It looks like I'm having problems mounting the object in a node. My mesh has the default origin point and an aditional mountPoint defined in the DTS, it looks like this code its trying to mount on the origin instead of the mountpoint. Any suggestion to solve this?Thanks!
Guimo
#35
In TGEA 1.7.1:
in lightingSystem\synapseGaming\sgObjectBasedProjecter.cpp, around line 639
(right before "for(U32 i=0; i
in engine\lightingSystem\sgObjectShadows.cc, line 302 ( right after "if (shapebase) {" )
Note: You'll notice I have the scale statement commented out in the TGEA version, and the detail selection commented out in the TGE version... both statements caused the shadow not to render... no idea why and didnt dig into it...
10/30/2008 (4:40 pm)
To have the eq render shadows like mounted images, add this:In TGEA 1.7.1:
in lightingSystem\synapseGaming\sgObjectBasedProjecter.cpp, around line 639
(right before "for(U32 i=0; i
//render eq shadows...
for(U32 i=0; i<shapebase->equipment.size(); i++)
{
TSShapeInstance* mountinst = shapebase->equipment[i]->shapeInstance;
if(!mountinst) continue;
MatrixF shapeworld;
shapebase->getRenderEquipmentTransform(shapebase->equipment[i]->nodeNumber, &shapeworld);
// shapeworld.scale(sgParentObject->getScale());
lightspace.mul(sgWorldToLightY, shapeworld);
lightspace = shadowscale * lightspace;
newmat.mul(proj, lightspace);
sgRenderShape(mountinst, newmat, 0, newmat, -1);
}In TGE 1.5.2:in engine\lightingSystem\sgObjectShadows.cc, line 302 ( right after "if (shapebase) {" )
// render equipment items to shadow bitmap
for(S32 x=0; x < shapebase->equipment.size(); x++)
{
TSShapeInstance *instance = shapebase->equipment[x]->shapeInstance;
if(instance)
{
MatrixF mat;
shapebase->getRenderEquipmentTransform(shapebase->equipment[x]->nodeNumber, &mat);
//shadow->selectShapeDetail(instance, dist, maxscale);
shadow->renderToBitmap(instance, mat, pos, Point3F(1,1,1));
}
}Note: You'll notice I have the scale statement commented out in the TGEA version, and the detail selection commented out in the TGE version... both statements caused the shadow not to render... no idea why and didnt dig into it...
#36
Until/if a solution to the above is found, I'm happy and thankful to use this resource.
Also, a weird problem:
I'm trying to load equipment on an NPC during placement w/ the World Editor. I try to load equipment in script with the mountEquipment call, but it does not show up. Although the game has correctly toggled it, as it shows up if I call it twice more (off then on again) during run-time. I know something is wonky, because mountImage works fine during the Player::onAdd() call.
*EDIT 12.14.08*
Fixed this bug I mentioned above. Was occuring in TGEA 1.71.
In shapeBase.cpp:
With this fix it is safe to delete all other occurences of "setMaskBits(EquipmentMask);".
If anyone has a better performing solution, please share. Thanks!
12/13/2008 (10:44 am)
Is there a way to just mount a DTS (tsShapeInstance), instead of an Image Object? GuiObjectView has this functionality, but I've been unable to port it to shapeBase.Until/if a solution to the above is found, I'm happy and thankful to use this resource.
Also, a weird problem:
I'm trying to load equipment on an NPC during placement w/ the World Editor. I try to load equipment in script with the mountEquipment call, but it does not show up. Although the game has correctly toggled it, as it shows up if I call it twice more (off then on again) during run-time. I know something is wonky, because mountImage works fine during the Player::onAdd() call.
*EDIT 12.14.08*
Fixed this bug I mentioned above. Was occuring in TGEA 1.71.
In shapeBase.cpp:
U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);[b]
//=============
//MOUNT EQUIP FIX
if (equipment.size() > 0)
{
setMaskBits(EquipmentMask);
}
//=============[/b]With this fix it is safe to delete all other occurences of "setMaskBits(EquipmentMask);".
If anyone has a better performing solution, please share. Thanks!
#37
01/10/2009 (12:19 am)
Is it a good idea to use this for weapon mounts?
#38
08/11/2009 (5:08 pm)
Has anyone tried this in TGEA 1.81? When I use it, vehicle wheels are invisible. They work, have collision, and even cast a shadow, but are invisible.
#39
Inside of ShapeBase::renderObject() add the following line:
view plainprint?
if (shiri != NULL)
{
renderMountedImage(state, shiri);
}
else
{
renderImage(state, image);
}
renderEquipment(state);
02/22/2010 (10:53 am)
This doesn't exist in TGEA 1.8.2?Inside of ShapeBase::renderObject() add the following line:
view plainprint?
if (shiri != NULL)
{
renderMountedImage(state, shiri);
}
else
{
renderImage(state, image);
}
renderEquipment(state);
#40
06/22/2010 (8:53 am)
YAY ARI! I found you... 
Torque 3D Owner Peter Simard
Default Studio Name