Source analysis: dinosaur skeletons and physics boxes

Discuss early Trespasser builds and all other early Trespasser stuff here! Discover more amazing stuff about the game!

Moderators: TresCom Support Team, TresCom Board Managers, TresCom Developers

Post Reply
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Source analysis: dinosaur skeletons and physics boxes

Post by machf »

And quoting myself:
machf wrote:From InfoSkeleton.cpp:

Code: Select all

//  CPhysicsInfoBiped implementation

	void GetBipedParams(CInstance* pins, Biped_Params* pparams)
	{
		Biped_Params& params = *pparams;

		// Use biomesh's ORIGINAL joint geometry (not instance's current geometry).
		rptr<CBioMesh> pbm = rptr_nonconst(pins->prdtGetRenderInfoWritable()->rpbmCast());
		Assert(pbm);

		TReal r_scale = pins->fGetScale();

		CPArray< CTransform3<> > patf3 = pbm->patf3JointsOrig;

		params.hip_radius		= rLength(patf3, 12, 16) * 0.5 * r_scale;
		params.hip_height		= patf3[12].v3Pos.tZ * r_scale;
		params.leg_length		= (rLength(patf3, 12) + 
								  rLength(patf3, 13) + 
								  rLength(patf3, 14)) * r_scale;

		Copy(params.tail_offset, patf3[0].v3Pos * r_scale);
		params.tail_length		= (rLength(patf3, 0) + 
								  rLength(patf3, 1) + 
								  rLength(patf3, 2) +
								  rLength(patf3, 3)) * r_scale;

		Copy(params.neck_offset, patf3[5].v3Pos * r_scale);
		params.neck_length		= (rLength(patf3, 5) +
								  rLength(patf3, 6) +
								  rLength(patf3, 7)) * r_scale;

		// Neck orientation vector (normalised).
		CDir3<> d3_neck = patf3[8].v3Pos - patf3[5].v3Pos;
		Copy(params.neck_dir, d3_neck);
	}

Code: Select all

//  CPhysicsInfoQuadruped implementation

	void GetQuadParams(CInstance* pins, Quad_Params* pparams)
	{
		GetBipedParams(pins, pparams);

		Quad_Params& params = *pparams;

		// Use biomesh's ORIGINAL joint geometry (not instance's current geometry).
		rptr<CBioMesh> pbm = rptr_nonconst(pins->prdtGetRenderInfoWritable()->rpbmCast());
		Assert(pbm);
		CPArray< CTransform3<> > patf3 = pbm->patf3JointsOrig;

		TReal r_scale = pins->fGetScale();

		params.front_hip_radius	= rLength(patf3, 20, 24) * 0.5 * r_scale;
		params.front_hip_height = patf3[20].v3Pos.tZ * r_scale;

		params.front_leg_length = (rLength(patf3, 20) +
								  rLength(patf3, 21) +
								  rLength(patf3, 22)) * r_scale;

		// Half-distance between centres of front-back hips.
		params.leg_offset		= (patf3[12].v3Pos + patf3[16].v3Pos - 
								   patf3[20].v3Pos - patf3[24].v3Pos).tLen() * 0.25 * r_scale;
	}

Code: Select all

	void CPhysicsInfoBiped::DrawPhysics(CInstance* pins, CDraw& draw, CCamera& cam) const
	{
#if bVER_BONES()
		// Well, for now let's use hard-coded joint connection info.
		// Later, this might be split into a connection data structure in this class, and a
		// general-purpose drawing function.

		static int ai_attach[] =
		{
			0,				// 0: Base of tail.
			0, 1, 2, 3,		// 1: Tail.
			5,				// 5: Base of torso.
			5, 6, 7, 8, 	// Torso, head.
			6,				// 10: Right arm.
			6,				// 11: Left arm.
			12,				// 12: Base of right leg.
			12, 13, 14,		// Right leg.
			16,				// 16: Base of left leg.
			16, 17, 18		// Left leg.
		};

		DrawBones(pins, CPArray<int>(ArrayData(ai_attach)), draw, cam);

		if (!setedfMain[edfSKELETONS])
			return;

		CAnimal* pani = ptCast<CAnimal>(pins);
		Assert(pani);
	
		// Draw target head location!
		if (pani->pbrBrain->msgprPhysicsControl.subMoveHead.rtUrgency.fVal > 0.0f)
		{
			// Draw a 3-cross at the target position.
			CPlacement3<> p3(pani->pbrBrain->msgprPhysicsControl.subMoveHead.dData);
			CTransform3<> tf3_shape_screen = p3 * cam.tf3ToHomogeneousScreen();
			draw.CoordinateFrame3D(tf3_shape_screen, 0.75f);
		}

		CTransform3<> tf3_shape_camera = pins->pr3GetPresence() * cam.tf3ToNormalisedCamera();

		// Draw target head orientation!
		if (pani->pbrBrain->msgprPhysicsControl.subPointHead.rtUrgency.fVal > 0.0f)
		{
			draw.Colour(CColour(255,0,0));
			// Draw a 2 meter line from pelvis in direction of orientation
			CVector3<> v3 = ((pani->pbrBrain->msgprPhysicsControl.subPointHead.dData) * 2.0f + pani->v3Pos());

			v3 = v3 * ~pani->pr3Presence();

			//CPlacement3<> p3(v3);

			//CTransform3<> tf3_shape_screen = p3 * cam.tf3ToHomogeneousScreen();

			draw.Line
			(
				// Attached joint.
				cam.ProjectPoint(v3 * tf3_shape_camera),
				//CVector3<>(0,0,0) * tf3_shape_screen,

				// Axis.
				cam.ProjectPoint(CVector3<>(0,0,0) * tf3_shape_camera)
			);
		}

		// Call parent.
		CPhysicsInfoSkeleton::DrawPhysics(pins, draw, cam);
#endif
	}

Code: Select all

	void CPhysicsInfoQuadruped::DrawPhysics(CInstance* pins, CDraw& draw, CCamera& cam) const
	{
#if bVER_BONES()
		// Since we re-use the biped joints, we call its bones routine.
		// Here, we just code the extra legs.
		static int ai_attach_extra[] =
		{
			0, 1, 2, 3, 4,	// 0: 20 empty values.
			5, 6, 7, 8, 9,
			10, 11, 12, 13, 14,
			15, 16, 17, 18, 19,
			20,				// 20: Base of right front leg.
			20, 21, 22,		// Right front leg.
			24,				// 24: Base of left front leg.
			24, 25, 26,		// Left front leg.
			0,				// 29: Static joint.
		};

		// Draw the biped stuff.
		CPhysicsInfoBiped::DrawPhysics(pins, draw, cam);

		// Draw the front legs.
		DrawBones(pins, CPArray<int>(ArrayData(ai_attach_extra)), draw, cam);
#endif
	}

Code: Select all

	void GetBipedParams(CInstance* pins, Biped_Params* pparams)
	{
		Biped_Params& params = *pparams;

		// Use biomesh's ORIGINAL joint geometry (not instance's current geometry).
		rptr<CBioMesh> pbm = rptr_nonconst(pins->prdtGetRenderInfoWritable()->rpbmCast());
		Assert(pbm);

		TReal r_scale = pins->fGetScale();

		CPArray< CTransform3<> > patf3 = pbm->patf3JointsOrig;

		params.hip_radius		= rLength(patf3, 12, 16) * 0.5 * r_scale;
		params.hip_height		= patf3[12].v3Pos.tZ * r_scale;
		params.leg_length		= (rLength(patf3, 12) + 
								  rLength(patf3, 13) + 
								  rLength(patf3, 14)) * r_scale;

		Copy(params.tail_offset, patf3[0].v3Pos * r_scale);
		params.tail_length		= (rLength(patf3, 0) + 
								  rLength(patf3, 1) + 
								  rLength(patf3, 2) +
								  rLength(patf3, 3)) * r_scale;

		Copy(params.neck_offset, patf3[5].v3Pos * r_scale);
		params.neck_length		= (rLength(patf3, 5) +
								  rLength(patf3, 6) +
								  rLength(patf3, 7)) * r_scale;

		// Neck orientation vector (normalised).
		CDir3<> d3_neck = patf3[8].v3Pos - patf3[5].v3Pos;
		Copy(params.neck_dir, d3_neck);
	}

Code: Select all

	void GetQuadParams(CInstance* pins, Quad_Params* pparams)
	{
		GetBipedParams(pins, pparams);

		Quad_Params& params = *pparams;

		// Use biomesh's ORIGINAL joint geometry (not instance's current geometry).
		rptr<CBioMesh> pbm = rptr_nonconst(pins->prdtGetRenderInfoWritable()->rpbmCast());
		Assert(pbm);
		CPArray< CTransform3<> > patf3 = pbm->patf3JointsOrig;

		TReal r_scale = pins->fGetScale();

		params.front_hip_radius	= rLength(patf3, 20, 24) * 0.5 * r_scale;
		params.front_hip_height = patf3[20].v3Pos.tZ * r_scale;

		params.front_leg_length = (rLength(patf3, 20) +
								  rLength(patf3, 21) +
								  rLength(patf3, 22)) * r_scale;

		// Half-distance between centres of front-back hips.
		params.leg_offset		= (patf3[12].v3Pos + patf3[16].v3Pos - 
								   patf3[20].v3Pos - patf3[24].v3Pos).tLen() * 0.25 * r_scale;
	}

Code: Select all

	void CPhysicsInfoBiped::Init(CAnimate* pani) const
	{
		// Create non-loaded boundary boxes.
		pani->AddBoundaryBox(ebbBODY, CVector3<>(.1, .3, .1), v3Zero, 100, mat_raptor_body, 1.0, 1.0);
		pani->AddBoundaryBox(ebbHEAD, CVector3<>(.05, .1, .05), v3Zero, 100, mat_raptor_head, 1.0, 1.0);
		pani->AddBoundaryBox(ebbTAIL, CVector3<>(.05, .2, .05), v3Zero, 100, mat_raptor_tail, 1.0, 1.0);

		pani->AddBoundaryBox(ebbRIGHT_FOOT, CVector3<>(.1, .2, .1), v3Zero, 100, 0, 0.0, 0.0);
		pani->AddBoundaryBox(ebbLEFT_FOOT,  CVector3<>(.1, .2, .1), v3Zero, 100, 0, 0.0, 0.0);
	}

Code: Select all

	void CPhysicsInfoQuadruped::Init(CAnimate* pani) const
	{
		// Construct any non-loaded boundary boxes.
		pani->AddBoundaryBox(ebbBODY, CVector3<>(.15, .3, .2), v3Zero, 100, mat_trike_body, 1.0, 1.0);
		pani->AddBoundaryBox(ebbHEAD, CVector3<>(.1, .2, .1), v3Zero, 100, mat_trike_head, 1.0, 1.0);
		pani->AddBoundaryBox(ebbTAIL, CVector3<>(.05, .2, .05), v3Zero, 100, mat_trike_tail, 1.0, 1.0);
	}

Code: Select all

	void CPhysicsInfoBiped::CreatePhysics(CInstance* pins, int i_index, float aaf_state[7][3]) const
	{
		Assert(i_index >= 0);

		// Get params from biomesh.
		Biped_Params params;
		GetBipedParams(pins, &params);

		params.mass = fMass(pins);

		// Well, MAKE A RAPTOR!
		Make_a_Raptor(pins, i_index, params, aaf_state);

		CAnimate* pani = ptCast<CAnimate>(pins);
		ActivateBoundaryBoxes(i_index, pani);
	}

Code: Select all

	void CPhysicsInfoQuadruped::CreatePhysics(CInstance* pins, int i_index, float aaf_state[7][3]) const
	{
		Assert(i_index >= 0);

		// Get params from biomesh.
		Quad_Params params;
		GetQuadParams(pins, &params);

		params.mass = fMass(pins);
/*
		// Fill with data for quad.
		params.mass = 20;

		params.leg_length = 2.2;//1.8;
		params.hip_radius = .791;
 
		params.front_hip_radius = .51;
		params.leg_offset = 1.16;

		params.tail_length = 2;
		params.neck_length = 1;
		params.neck_offset[0] = 0;
		params.neck_offset[1] = 2;
		params.neck_offset[2] = 0;

		params.tail_offset[0] = 0;
		params.tail_offset[1] =-1.17;
		params.tail_offset[2] = 0;
*/
		//  Make the quad.
		Make_a_Quad(pins, i_index, params, aaf_state);

		CAnimate* pani = ptCast<CAnimate>(pins);

		// Stuff selected physics state from current joint data.
		StuffPelState(pani, 15, i_index, RIGHT_FOOT);
		StuffPelState(pani, 19, i_index, LEFT_FOOT);
		StuffPelState(pani, 23, i_index, FRIGHT_FOOT);
		StuffPelState(pani, 27, i_index, FLEFT_FOOT);

		//
		// Now apply the boundary conditions.
		//

		ActivateBoundaryBoxes(i_index, pani);
	}

Code: Select all

	void StuffPelState
	(
		CAnimate* pani, 
		int i_joint,
		int i_pel, 
		int i_elem
	)
	{
		Assert(i_pel >= 0);
		Assert(i_elem >= 0);
		Assert(i_joint >= 0);

		// Get the current relative joint transform, convert to placement.
		CTransform3<>& tf3_joint = pani->sriBones.patf3JointTransforms[i_joint];
		CPlacement3<> p3_joint(tf3_joint.mx3Mat, tf3_joint.v3Pos * pani->pr3GetPresence().rScale);

		// Convert to world space, and stuff it in the pelvis.
		CPlacement3<> p3_world = p3_joint * pani->p3GetPlacement();
		Copy(&Pel[i_pel][i_elem], p3_world, 0);
	}
Sort of explains why foot physics boxes in quadrupeds don't work the same as in bipeds...

Some of this info can be used to verify the alias files used by TPDC... the way the bones are linked is hardcoded, as you can see. 20 bones for bipeds, plus another one to be the origin; 28 bones for quadrupeds, plus one for the origin.
(From PVA.cpp)

Code: Select all

	if (i_PVA < 0)
	{
		// All text prop PVAs must use the final joint as the origin.
		return patf3_joints[i_last_normal_joint].v3Pos;
	}
Everything else after those is an interpolated or additional joint. I had already sort of figured that out back then when I looked at the dinos in the Beta 96:
viewtopic.php?p=90218#p90218

Still trying to figure out:
  • Whether you can rearrange bones or not (since you have only 2 basic skeletons, well, 3 with Anne, and a Brachi doesn't look anything like a Trike or a Steg, for example, although they all use the Quadruped skeleton)
  • How physics boxes are attached to the skeleton and why custom ones may get resized sometimes when the level starts
  • Wondering if Anne's left arm can be made semi-fucntional by editing and recompiling the code (you'll notice that her left arm bones have no parents, or rather, aren't attached to the rest of the skeleton)
  • Wanting to modify the code for Quadrupeds so that their foot boxes work too (though if I can get custom skeletons to work, I wouldn't need that anymore, but still...)
I'll add more as I look at further sections of the code. And BTW, it's a pity that I found this in PVA.cpp:

Code: Select all

 * 18    9/27/98 11:41p Agrant
 * removed dead code
This means the code for predefined vertex assignments (like the Para in the Beta 96) isn't there anymore...
Anyway, there appears to be an error there:

Code: Select all

		case 4:
		case 7:
		case 9:
		case 10:
		// Quad. It's between all 4 hips.
			return (patf3_joints[12].v3Pos + patf3_joints[16].v3Pos +
					patf3_joints[16].v3Pos + patf3_joints[20].v3Pos) * 0.25;
I think one of those patf3_joints[16] should have been patf3_joints[24] instead? Unless they are averaging in the "width" sense and in the "length" sense, and then averaging both those numbers... no, that wouldn't work, it's an error, indeed.
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
Rebel
-=TresCom Developer=-
-=TresCom Developer=-
Posts: 6121
Joined: Sun Nov 10, 2002 10:26 pm
Location: That country nobody likes (you know the one)
Contact:

Re: Source analysis: dinosaur skeletons and physics boxes

Post by Rebel »

From what I remember reading, there was coding done on Anne's left arm, but the idea was abandoned. The last time I messed with the code, I was working on having Anne carry more than one object. I got her to store two items, but I couldn't get her to retrieve the additional object. But, I'm fairly certain it could be done by someone with s little more patience and Witt.
User avatar
Draconisaurus
T-Rex Killer
T-Rex Killer
Posts: 14046
Joined: Mon Dec 06, 2004 5:21 pm
Antispam: No
Location: Isla Sorna
Contact:

Re: Source analysis: dinosaur skeletons and physics boxes

Post by Draconisaurus »

Rebel wrote:From what I remember reading, there was coding done on Anne's left arm, but the idea was abandoned. The last time I messed with the code, I was working on having Anne carry more than one object. I got her to store two items, but I couldn't get her to retrieve the additional object. But, I'm fairly certain it could be done by someone with s little more patience and Witt.
Hmmm, just wanted to chime in with the fact that, once upon a time, I (or rather, my ex-girldfriend) did get 3 weapons held at once. It's all here: viewtopic.php?p=68443#p68443
The additional object could be retrieved, but only after the third object was dropped. There also appears to be some wonky wrist position thing, but it still works. There is a savegame that still works in the thread, if you want to try it out.
Post Reply