1 /***************************************************************************
2                           movingobject.cpp  -  Moving object class
3                              -------------------
4     begin                : Wed Dec 4 2002
5     copyright            : (C) 2002 by CJP
6     email                : cornware-cjp@users.sourceforge.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #include <cstdio>
18 
19 #include "movingobject.h"
20 #include "movobjinput.h"
21 #include "physics.h"
22 
CMovingObject(CDataManager * manager)23 CMovingObject::CMovingObject(CDataManager *manager) : CDataObject(manager, CDataObject::eMovingObject)
24 {
25 	//default mass:
26 	m_InvMass = 1.0;
27 
28 	m_InputData = new CMovObjInput;
29 
30 	m_LastNetworkUpdateTime = -1000.0; //first update will always come through this
31 
32 	m_Ground.nor = CVector(0,0,0);
33 }
34 
~CMovingObject()35 CMovingObject::~CMovingObject()
36 {
37 	unload();
38 	delete m_InputData; //I guess this will happen for all CMovingObject-derived classes
39 }
40 
load(const CString & filename,const CParamList & list)41 bool CMovingObject::load(const CString &filename, const CParamList &list)
42 {
43 	CDataObject::load(filename, list);
44 
45 	m_MovObjID = list.getValue("ID", "0").toInt();
46 	m_InputData->m_MovObjID = m_MovObjID;
47 
48 	return true;
49 }
50 
unload()51 void CMovingObject::unload()
52 {
53 	//for(unsigned int i=0; i < m_Bodies.size(); i++)
54 	//	m_Bodies[i].destroyODE();
55 	m_Bodies.clear();
56 
57 	m_Sounds.clear();
58 	m_Textures.clear();
59 
60 	CDataObject::unload();
61 }
62 
addForce(CVector F)63 void CMovingObject::addForce(CVector F)
64 {
65 	m_Ftot += F;
66 }
67 
addTorque(CVector M)68 void CMovingObject::addTorque(CVector M)
69 {
70 	m_Mtot += M;
71 }
72 
addForceAt(CVector F,CVector pos)73 void CMovingObject::addForceAt(CVector F, CVector pos)
74 {
75 	m_Ftot += F;
76 	m_Mtot += F.crossProduct(pos);
77 
78 	/*
79 	CVector Madd = F.crossProduct(pos);
80 	printf("    F = %s\n", CString(F).c_str());
81 	printf("    p = %s\n", CString(pos).c_str());
82 	printf("    M = %s\n", CString(Madd).c_str());
83 	*/
84 }
85 
update(CPhysics * simulator,float dt)86 void CMovingObject::update(CPhysics *simulator, float dt)
87 {
88 	//Integration step of the simulation:
89 
90 	//printf("Ftot = (%s) kN\n", CString(m_Ftot/1000.0).c_str());
91 
92 	//linear things:
93 	CVector accel = m_Ftot * m_InvMass;
94 
95 	m_Position += (m_Velocity + 0.5*dt*accel)*dt;
96 	m_Velocity += dt*accel;
97 
98 	//angular things:
99 
100 	//inverse inertia tensor, corrected for body orientation
101 	CMatrix invInertia = m_OrientationMatrix.transpose() * m_InvInertia * m_OrientationMatrix;
102 
103 	CVector angaccel = invInertia * m_Mtot;
104 
105 	CMatrix dM;
106 	dM.setRotation((m_AngularVelocity + 0.5*dt*angaccel)*dt);
107 	m_OrientationMatrix *= dM;
108 	m_AngularVelocity += dt*angaccel;
109 
110 
111 	//Place the bodies:
112 	placeBodies();
113 
114 	//Reset the forces:
115 	m_Ftot = CVector (0,0,0);
116 	m_Mtot = CVector (0,0,0);
117 }
118 
determineGroundPlane(CPhysics * simulator)119 void CMovingObject::determineGroundPlane(CPhysics *simulator)
120 {
121 	//TODO: some good default for non-car moving objects
122 }
123 
correctCollisions()124 void CMovingObject::correctCollisions()
125 {
126 	for(unsigned int c=0; c < m_SimCollisions.size(); c++)
127 	{
128 		CCollisionData col = m_SimCollisions[c];
129 
130 		//printf("depth = %.3f\n", col.depth);
131 		CVector dr = col.nor * col.depth;
132 
133 		//correct the position
134 		m_Position += dr;
135 
136 		//set the collision velocity to zero
137 		m_Velocity -= col.vmean;
138 		float radcomp = m_Velocity.dotProduct(col.nor);
139 		if(radcomp < 0.0)
140 			m_Velocity -= radcomp * col.nor;
141 		m_Velocity += col.vmean;
142 	}
143 }
144 
getData(CBinBuffer & b) const145 CBinBuffer &CMovingObject::getData(CBinBuffer &b) const
146 {
147 	b += (Uint8)m_MovObjID;
148 
149 	b.addFloat32(m_LastUpdateTime, 0.005); //more accurate than 1/100 sec
150 
151 	CVector
152 		p = m_Position,
153 		o = m_OrientationMatrix.getRotation(),
154 		v = m_Velocity,
155 		w = m_AngularVelocity;
156 
157 	b.addVector32(p, 0.001);
158 	b.addVector16(o, 0.0002);
159 	b.addVector16(v, 0.01);
160 	b.addVector16(w, 0.001);
161 
162 	return b;
163 }
164 
setData(const CBinBuffer & b,unsigned int & pos)165 bool CMovingObject::setData(const CBinBuffer &b, unsigned int &pos)
166 {
167 	Uint8 ID = b.getUint8(pos);
168 	if(ID != m_MovObjID) return false; //wrong delivery, in some way
169 
170 	float time = b.getFloat32(pos, 0.005);
171 	//printf("Received package: sendTime = %.2f\n", time);
172 	if(time < m_LastNetworkUpdateTime)
173 	{
174 		printf("Old package: time %.2f < %.2f\n", time, m_LastNetworkUpdateTime);
175 		return false; //it was an old package
176 	}
177 	if(time > theWorld->m_LastTime + 3.0)
178 	{
179 		printf("Too late package: time %.2f > %.2f + 3.0\n", time, theWorld->m_LastTime);
180 		return false; //probably a package from a previous game session
181 	}
182 
183 	m_LastNetworkUpdateTime = time;
184 	m_LastUpdateTime = theWorld->m_LastTime;
185 
186 	//TODO: correct game time for average lag time
187 
188 	CVector
189 		p = b.getVector32(pos, 0.001),
190 		o = b.getVector16(pos, 0.0002),
191 		v = b.getVector16(pos, 0.01),
192 		w = b.getVector16(pos, 0.001);
193 
194 	/*
195 	A little hack:
196 	We do not REALLY set the position to the position in the message.
197 	Instead, we mix it with the current position.
198 	This damps out "synchronisation errors"
199 	*/
200 
201 	//no damping at low speeds
202 	float dampFactor = v.abs2() / (10.0 + v.abs2());
203 
204 	//lower damping at higher differences in speed (e.g. collisions)
205 	float vdif2 = (v - m_Velocity).abs2();
206 	dampFactor *= 10.0 / (10.0 + vdif2);
207 
208 	if(dampFactor > 0.95) dampFactor = 0.95; //not too much damping
209 	if(!(dampFactor >= 0.0 && dampFactor <= 1.0)) dampFactor = 0.0; //you never know
210 	//printf("dampFactor = %s\n", CString(dampFactor).c_str());
211 
212 	 //some damping to correct for "synchronisation noise"
213 	//We only do damping in the direction of v
214 	CVector vdir = v.normal();
215 	CVector p_vdir = p.component(vdir);
216 	CVector p_ortho = p - p_vdir;
217 	m_Position = p_ortho + (1.0 - dampFactor) * p_vdir + dampFactor * m_Position.component(vdir);
218 
219 	m_OrientationMatrix.setRotation(o);
220 	m_Velocity = v;
221 	m_AngularVelocity = w;
222 
223 	return true;
224 }
225