1 #include "pch.h"
2 #include "RenderConst.h"
3 #include "Def_Str.h"
4 #include "../common/data/SceneXml.h"
5 #include "../common/CScene.h"
6 #include "../common/Axes.h"
7 #include "../../vdrift/pathmanager.h"
8 #include "../../btOgre/BtOgreGP.h"
9 #include "../../road/Road.h"
10 #include "../common/ShapeData.h"
11 #ifdef SR_EDITOR
12 #include "../../editor/CApp.h"
13 #include "../../editor/CGui.h"
14 #else
15 #include "../CGame.h"
16 #include "../../vdrift/game.h"
17 #endif
18 #include <BulletCollision/CollisionDispatch/btCollisionObject.h>
19 #include <BulletCollision/CollisionShapes/btCollisionShape.h>
20 #include <LinearMath/btDefaultMotionState.h>
21 #include <BulletDynamics/Dynamics/btRigidBody.h>
22 #include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
23 #include <LinearMath/btSerializer.h>
24 #include <BulletFileLoader/btBulletFile.h>
25 #include <BulletWorldImporter/btBulletWorldImporter.h>
26
27 #include <OgreManualObject.h>
28 #include <OgreMeshManager.h>
29 #include <OgreMaterialManager.h>
30 #include <OgreEntity.h>
31 #include <OgreSceneManager.h>
32 #include <OgreSceneNode.h>
33 #include <OgreRenderWindow.h>
34 #include <OgreSubEntity.h>
35 #include <OgreCamera.h>
36 #include <MyGUI.h>
37 #include <MyGUI_InputManager.h>
38 using namespace Ogre;
39 using namespace MyGUI;
40 using namespace std;
41
42
43
44 /// Objects ... .. . . .
45 //----------------------------------------------------------------------------------------------------------------------
46 class BulletWorldOffset : public btBulletWorldImporter
47 {
48 public:
49 btTransform mTrOfs; // in offset
50 btDefaultMotionState* ms; // out
51 btRigidBody* rb; // out
52
BulletWorldOffset(btDynamicsWorld * world=0)53 BulletWorldOffset(btDynamicsWorld* world=0)
54 : btBulletWorldImporter(world), ms(0), rb(0)
55 {
56 mTrOfs.setIdentity();
57 }
58
59 //todo: shape->setUserPointer((void*)SU_ObjectDynamic); // mark shapes..
60
createCollisionObject(const btTransform & startTransform,btCollisionShape * shape,const char * bodyName)61 btCollisionObject* createCollisionObject(const btTransform& startTransform,btCollisionShape* shape, const char* bodyName)
62 {
63 return createRigidBody(false,0,startTransform,shape,bodyName);
64 }
65
createRigidBody(bool isDynamic,btScalar mass,const btTransform & startTransform,btCollisionShape * shape,const char * bodyName)66 btRigidBody* createRigidBody(bool isDynamic, btScalar mass, const btTransform& startTransform,
67 btCollisionShape* shape, const char* bodyName)
68 {
69 btVector3 localInertia;
70 localInertia.setZero();
71
72 if (mass)
73 shape->calculateLocalInertia(mass,localInertia);
74
75 ms = new btDefaultMotionState();
76 ms->setWorldTransform(mTrOfs);
77 btRigidBody* body = new btRigidBody(mass,ms,shape,localInertia);
78 body->setDamping(0.1f, 0.3f);
79 //body->setFriction(0.5f);
80 rb = body;
81
82 #ifdef SR_EDITOR
83 //body->setActivationState(DISABLE_DEACTIVATION);
84 #else
85 body->setActivationState(WANTS_DEACTIVATION); // game creates deactivated (sleeping)
86 #endif
87
88 if (m_dynamicsWorld)
89 m_dynamicsWorld->addRigidBody(body);
90
91 /*if (bodyName)
92 {
93 char* newname = duplicateName(bodyName);
94 m_objectNameMap.insert(body,newname);
95 m_nameBodyMap.insert(newname,body);
96 }*/
97 m_allocatedRigidBodies.push_back(body);
98 return body;
99 }
100 };
101
102
103 // Create
104 //-------------------------------------------------------------------------------------------------------
CreateObjects()105 void App::CreateObjects()
106 {
107 // maps for file exist (optimize)
108 using std::map; using std::string;
109 map<string,bool> objExists, objHasBlt;
110
111 for (int i=0; i < scn->sc->objects.size(); ++i)
112 {
113 const string& s = scn->sc->objects[i].name;
114 objExists[s] = false; objHasBlt[s] = false;
115 }
116 for (map<string,bool>::iterator it = objExists.begin(); it != objExists.end(); ++it)
117 {
118 bool ex = PATHMANAGER::FileExists(PATHMANAGER::Data()+"/objects/"+ (*it).first + ".mesh");
119 bool ex0 = PATHMANAGER::FileExists(PATHMANAGER::Data()+"/objects0/"+ (*it).first + ".mesh");
120 bool exC = PATHMANAGER::FileExists(PATHMANAGER::Data()+"/objectsC/"+ (*it).first + ".mesh");
121 (*it).second = ex || ex0 || exC;
122 if (!ex) LogO("Warning: CreateObjects mesh doesn't exist: " + (*it).first + ".mesh");
123 }
124 for (map<string,bool>::iterator it = objHasBlt.begin(); it != objHasBlt.end(); ++it)
125 (*it).second = PATHMANAGER::FileExists(PATHMANAGER::Data()+"/objects/"+ (*it).first + ".bullet");
126
127 // loader
128 #ifndef SR_EDITOR
129 btDiscreteDynamicsWorld* world = pGame->collision.world;
130 #endif
131 BulletWorldOffset* fileLoader = new BulletWorldOffset(world);
132
133 /// create . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
134 for (int i=0; i < scn->sc->objects.size(); ++i)
135 {
136 Object& o = scn->sc->objects[i];
137 String s = toStr(i); // counter for names
138 o.dyn = objHasBlt[o.name];
139 #ifndef SR_EDITOR
140 if (o.dyn && !pSet->game.dyn_objects) continue;
141 #endif
142
143 // add to ogre
144 bool no = !objExists[o.name];
145 o.ent = mSceneMgr->createEntity("oE"+s, (no ? "sphere" : o.name) + ".mesh");
146 o.nd = mSceneMgr->getRootSceneNode()->createChildSceneNode("oN"+s);
147 o.SetFromBlt();
148 o.nd->attachObject(o.ent); o.ent->setVisibilityFlags(RV_Objects);
149 o.nd->setScale(o.scale);
150 if (no) continue;
151
152 // add to bullet world (in game)
153 if (!o.dyn)
154 {
155 /// static . . . . . . . . . . . .
156 Vector3 posO = Axes::toOgre(o.pos);
157 Quaternion rotO = Axes::toOgreW(o.rot);
158
159 Matrix4 tre; tre.makeTransform(posO,o.scale,rotO);
160 BtOgre::StaticMeshToShapeConverter converter(o.ent, tre);
161 btCollisionShape* shape = converter.createTrimesh(); //=new x2 todo:del?...
162 shape->setUserPointer((void*)SU_ObjectStatic); // mark
163
164 btCollisionObject* bco = new btCollisionObject();
165 btTransform tr; tr.setIdentity(); //tr.setOrigin(btVector3(pos.x,-pos.z,pos.y));
166 bco->setActivationState(DISABLE_SIMULATION); // WANTS_DEACTIVATION
167 bco->setCollisionShape(shape); bco->setWorldTransform(tr);
168 bco->setFriction(0.7f); //+
169 bco->setRestitution(0.f);
170 bco->setCollisionFlags(bco->getCollisionFlags() |
171 btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/);
172 world->addCollisionObject(bco);
173 #ifndef SR_EDITOR
174 o.co = bco; o.ms = 0; o.rb = 0;
175 pGame->collision.shapes.push_back(shape);
176 #endif
177 }
178 else /// dynamic . . . . . . . . . . . .
179 {
180 // .bullet load
181 fileLoader->mTrOfs.setOrigin(btVector3(o.pos[0],o.pos[1],o.pos[2]));
182 fileLoader->mTrOfs.setRotation(btQuaternion(o.rot[0],o.rot[1],o.rot[2],o.rot[3]));
183 //fileLoader->setVerboseMode(true);//
184 std::string file = PATHMANAGER::Data()+"/objects/"+o.name+".bullet";
185
186 if (fileLoader->loadFile(file.c_str()))
187 {
188 o.ms = fileLoader->ms; // 1 only
189 o.rb = fileLoader->rb; // 1 only
190
191 /*int nshp = fileLoader->getNumCollisionShapes();
192 for (int i=0; i < nshp; ++i)
193 pGame->collision.shapes.push_back(
194 fileLoader->getCollisionShapeByIndex(i));/**/
195
196 #ifndef SR_EDITOR
197 btTransform t1; // save 1st pos for reset
198 o.ms->getWorldTransform(t1);
199 o.tr1 = new btTransform(t1);
200 #endif
201 #if 0
202 LogO(".bullet: "+o.name+
203 " shapes:"+toStr(fileLoader->getNumCollisionShapes())+
204 " bodies:"+toStr(fileLoader->getNumRigidBodies())+
205 " constr:"+toStr(fileLoader->getNumConstraints())); /**/
206 #endif
207 }else
208 LogO(".bullet: Load Error: "+o.name);
209 }
210 }
211 delete fileLoader;
212
213 #ifdef SR_EDITOR
214 iObjLast = scn->sc->objects.size();
215 #endif
216 }
217
218 /// destroy
DestroyObjects(bool clear)219 void App::DestroyObjects(bool clear)
220 {
221 for (int i=0; i < scn->sc->objects.size(); ++i)
222 {
223 Object& o = scn->sc->objects[i];
224 delete o.tr1; o.tr1 = 0;
225
226 // ogre
227 if (o.nd) mSceneMgr->destroySceneNode(o.nd); o.nd = 0;
228 #ifdef SR_EDITOR // game has destroyAll
229 if (o.ent) mSceneMgr->destroyEntity(o.ent); o.ent = 0;
230 #endif
231
232 #ifdef SR_EDITOR
233 // bullet
234 if (o.co)
235 { delete o.co->getCollisionShape();
236 #ifdef SR_EDITOR
237 world->removeCollisionObject(o.co);
238 #else
239 pGame->collision.world->removeCollisionObject(o.co);
240 #endif
241 delete o.co; o.co = 0;
242 }
243 if (o.rb)
244 { delete o.rb->getCollisionShape();
245 delete o.ms; o.ms = 0;
246 #ifdef SR_EDITOR
247 world->removeRigidBody(o.rb);
248 #else
249 pGame->collision.world->removeCollisionObject(o.rb);
250 #endif
251 delete o.rb; o.rb = 0;
252 }
253 #endif
254 }
255 if (clear)
256 scn->sc->objects.clear();
257 }
258
ResetObjects()259 void App::ResetObjects()
260 {
261 for (int i=0; i < scn->sc->objects.size(); ++i)
262 {
263 Object& o = scn->sc->objects[i];
264 if (o.dyn && o.ms && o.tr1)
265 {
266 o.rb->clearForces();
267 o.rb->setHitFraction(0.f);
268 o.rb->setLinearVelocity(btVector3(0,0,0));
269 o.rb->setAngularVelocity(btVector3(0,0,0));
270 o.rb->setActivationState(WANTS_DEACTIVATION);
271 o.rb->setWorldTransform(*o.tr1);
272 o.ms->setWorldTransform(*o.tr1);
273 o.SetFromBlt();
274 } }
275 }
276
277
278 // Pick
279 //-------------------------------------------------------------------------------------------------------
280
281 #ifdef SR_EDITOR
UpdObjPick()282 void App::UpdObjPick()
283 {
284 if (ndStBox)
285 ndStBox->setVisible(edMode == ED_Start && !bMoveCam);
286
287 int objs = scn->sc->objects.size();
288 bool bObjects = edMode == ED_Objects && !bMoveCam && objs > 0 && iObjCur >= 0;
289 if (objs > 0)
290 iObjCur = std::min(iObjCur, objs-1);
291
292 if (!ndObjBox) return;
293 ndObjBox->setVisible(bObjects);
294 if (!bObjects) return;
295
296 const Object& o = scn->sc->objects[iObjCur];
297 const AxisAlignedBox& ab = o.nd->getAttachedObject(0)->getBoundingBox();
298 Vector3 s = o.scale * ab.getSize(); // * sel obj's node aabb
299
300 Vector3 posO = Axes::toOgre(o.pos);
301 Quaternion rotO = Axes::toOgreW(o.rot);
302
303 Vector3 scaledCenter = ab.getCenter() * o.scale;
304 posO += (rotO * scaledCenter);
305
306 ndObjBox->setPosition(posO);
307 ndObjBox->setOrientation(rotO);
308 ndObjBox->setScale(s);
309 }
310
PickObject()311 void App::PickObject()
312 {
313 if (scn->sc->objects.empty()) return;
314
315 iObjCur = -1;
316 const MyGUI::IntPoint& mp = MyGUI::InputManager::getInstance().getMousePosition();
317 Real mx = Real(mp.left)/mWindow->getWidth(), my = Real(mp.top)/mWindow->getHeight();
318 Ray ray = mCamera->getCameraToViewportRay(mx,my); // 0..1
319 const Vector3& pos = mCamera->getDerivedPosition(), dir = ray.getDirection();
320
321 // query scene (aabbs are enough)
322 RaySceneQuery* rq = mSceneMgr->createRayQuery(ray);
323 rq->setSortByDistance(true);
324 RaySceneQueryResult& res = rq->execute();
325
326 Real distC = 100000.f;
327 int io = -1;
328 for (RaySceneQueryResult::iterator it = res.begin(); it != res.end(); ++it)
329 {
330 const String& s = (*it).movable->getName();
331 if (StringUtil::startsWith(s,"oE",false))
332 {
333 //LogO("RAY "+s+" "+fToStr((*it).distance,2,4)+" n "+toStr(n)+" nn "+toStr(nn));
334 int i = -1;
335 // find obj with same ent name
336 for (int o=0; o < scn->sc->objects.size(); ++o)
337 if (s == scn->sc->objects[o].ent->getName())
338 { i = o; break; }
339
340 // pick
341 if (i != -1)
342 {
343 //AxisAlignedBox ab = sc->objects[i].ent->getBoundingBox();
344 //ab.getCenter(); ab.getSize();
345
346 // closest to obj center
347 const Vector3 posSph = scn->sc->objects[i].nd->getPosition();
348 const Vector3 ps = pos - posSph;
349 Vector3 crs = ps.crossProduct(dir);
350 Real dC = crs.length() / dir.length();
351
352 //if ((*it).distance < dist) // closest aabb
353 if (dC < distC) // closest center
354 {
355 io = i;
356 //dist = (*it).distance;
357 distC = dC;
358 } }
359 } }
360
361 if (io != -1) // if none picked
362 if (iObjCur == -1)
363 iObjCur = io;
364
365 //rq->clearResults();
366 mSceneMgr->destroyQuery(rq);
367 }
368
369 // upd obj selected glow
UpdObjSel()370 void App::UpdObjSel()
371 {
372 int objs = scn->sc->objects.size();
373 for (int i=0; i < objs; ++i)
374 { bool bSel = vObjSel.find(i) != vObjSel.end();
375 scn->sc->objects[i].ent->getSubEntity(0)->setCustomParameter(1, Vector4(bSel ? 1 : 0, 0,0,0));
376 }
377 }
378
379 // selection center pos, or picked pos for multi rotate and scale
GetObjPos0()380 Vector3 App::GetObjPos0()
381 {
382 Vector3 pos0(0,0,0);
383 if (iObjCur>=0)
384 {
385 MATHVECTOR<float,3> p = scn->sc->objects[iObjCur].pos;
386 pos0 = Vector3(p[0],p[2],-p[1]);
387 }
388 else if (!vObjSel.empty())
389 {
390 for (std::set<int>::iterator it = vObjSel.begin(); it != vObjSel.end(); ++it)
391 {
392 MATHVECTOR<float,3> p = scn->sc->objects[(*it)].pos;
393 pos0 += Vector3(p[0],p[2],-p[1]);
394 }
395 pos0 /= Real(vObjSel.size());
396 }
397 return pos0;
398 }
399
400
401 /// toggle objects simulation (bullet world)
402 //-------------------------------------------------------------------------------------------------------
ToggleObjSim()403 void App::ToggleObjSim()
404 {
405 if (gui->objPan) gui->objPan->setVisible(objSim);
406
407 DestroyObjects(false);
408
409 if (!objSim) // off sim
410 {
411 // Destroy blt world
412 for(int i = world->getNumCollisionObjects() - 1; i >= 0; i--)
413 {
414 btCollisionObject* obj = world->getCollisionObjectArray()[i];
415 delete obj->getCollisionShape();
416
417 btRigidBody* body = btRigidBody::upcast(obj);
418 if (body && body->getMotionState())
419 delete body->getMotionState();
420
421 if (obj->getUserPointer() != (void*)111)
422 {
423 ShapeData* sd = static_cast<ShapeData*>(obj->getUserPointer());
424 delete sd;
425 }
426 world->removeCollisionObject(obj);
427 delete obj;
428 }
429 }
430 else // on sim
431 {
432 // Create blt world
433 scn->CreateBltTerrain();
434 scn->road->RebuildRoadInt(false,true);
435 }
436 CreateObjects();
437 UpdObjPick();
438 }
439
440
441 /// add new object
AddNewObj(bool getName)442 void App::AddNewObj(bool getName) //App..
443 {
444 ::Object o = objNew;
445 if (getName)
446 o.name = vObjNames[iObjTNew];
447 ++iObjLast;
448 String s = toStr(iObjLast); // counter for names
449 ///TODO: ?dyn objs size, !?get center,size, rmb height..
450
451 // pos, rot
452 if (getName)
453 { // one new
454 const Vector3& v = scn->road->posHit;
455 o.pos[0] = v.x; o.pos[1] =-v.z; o.pos[2] = v.y + objNew.pos[2];
456 }else // many
457 { // offset for cursor pos..
458 //o.pos[0] = v.x; o.pos[1] =-v.z; o.pos[2] = v.y + objNew.pos[2];
459 }
460
461 // create object
462 o.ent = mSceneMgr->createEntity("oE"+s, o.name + ".mesh");
463 o.nd = mSceneMgr->getRootSceneNode()->createChildSceneNode("oN"+s);
464 o.SetFromBlt();
465 o.nd->setScale(o.scale);
466 o.nd->attachObject(o.ent); o.ent->setVisibilityFlags(RV_Vegetation);
467
468 o.dyn = PATHMANAGER::FileExists(PATHMANAGER::Data()+"/objects/"+ o.name + ".bullet");
469 scn->sc->objects.push_back(o);
470 }
471
472
473 // change obj to insert
listObjsChng(MyGUI::List * l,size_t t)474 void CGui::listObjsChng(MyGUI::List* l, size_t t)
475 {
476 // unselect other
477 if (l != objListDyn) objListDyn->setIndexSelected(ITEM_NONE);
478 if (l != objListSt) objListSt->setIndexSelected(ITEM_NONE);
479 if (l != objListRck) objListRck->setIndexSelected(ITEM_NONE);
480 if (l != objListBld) objListBld->setIndexSelected(ITEM_NONE);
481
482 if (t == ITEM_NONE) // sel default
483 { /*l = objListDyn;*/ t = 0; l->setIndexSelected(t); }
484
485 std::string s = l->getItemNameAt(t).substr(7);
486 for (int i=0; i < app->vObjNames.size(); ++i)
487 if (s == app->vObjNames[i])
488 {
489 app->SetObjNewType(i);
490 Upd3DView(s+".mesh");
491 return;
492 }
493 }
494
listObjsNext(int rel)495 void CGui::listObjsNext(int rel)
496 {
497 Li li = 0;
498 if (objListDyn->getIndexSelected()!= ITEM_NONE) li = objListDyn; //else
499 if (objListSt->getIndexSelected() != ITEM_NONE) li = objListSt;
500 if (objListRck->getIndexSelected()!= ITEM_NONE) li = objListRck;
501 if (objListBld->getIndexSelected()!= ITEM_NONE) li = objListBld;
502 if (li)
503 {
504 size_t cnt = li->getItemCount();
505 if (cnt == 0) return;
506 int i = std::max(0, std::min((int)cnt-1, (int)li->getIndexSelected()+rel ));
507 li->setIndexSelected(i);
508 li->beginToItemAt(std::max(0, i-11)); // center
509 listObjsChng(li, li->getIndexSelected());
510 }
511 }
512
513
514 // change category, fill buildings list
listObjsCatChng(Li li,size_t id)515 void CGui::listObjsCatChng(Li li, size_t id)
516 {
517 if (id == ITEM_NONE || id >= li->getItemCount()) id = 0;
518 if (li->getItemCount()==0) return;
519 string cat = li->getItemNameAt(id).substr(7);
520
521 objListBld->removeAllItems();
522 for (size_t i=0; i < app->vBuildings.size(); ++i)
523 {
524 const string& s = app->vBuildings[i];
525 if (//id == 0 ||/*all*/
526 s.length() > 4 && s.substr(0,4) == cat)
527 objListBld->addItem("#E0E080"+s);
528 }
529 }
530
531
532 // preview model for insert
SetObjNewType(int tnew)533 void App::SetObjNewType(int tnew)
534 {
535 iObjTNew = tnew;
536 if (objNew.nd) { mSceneMgr->destroySceneNode(objNew.nd); objNew.nd = 0; }
537 if (objNew.ent) { mSceneMgr->destroyEntity(objNew.ent); objNew.ent = 0; }
538
539 String name = vObjNames[iObjTNew];
540 objNew.dyn = PATHMANAGER::FileExists(PATHMANAGER::Data()+"/objects/"+ name + ".bullet");
541 if (objNew.dyn) objNew.scale = Vector3::UNIT_SCALE; // dyn no scale
542 objNew.ent = mSceneMgr->createEntity("-oE", name + ".mesh");
543 objNew.nd = mSceneMgr->getRootSceneNode()->createChildSceneNode("-oN");
544 objNew.nd->attachObject(objNew.ent); objNew.ent->setVisibilityFlags(RV_Vegetation);
545 UpdObjNewNode();
546 }
547
UpdObjNewNode()548 void App::UpdObjNewNode()
549 {
550 if (!scn->road || !objNew.nd) return;
551
552 bool vis = scn->road->bHitTer && bEdit() && iObjCur == -1 && edMode == ED_Objects;
553 objNew.nd->setVisible(vis);
554 if (!vis) return;
555
556 Vector3 p = scn->road->posHit; p.y += objNew.pos[2];
557 objNew.SetFromBlt();
558 objNew.nd->setPosition(p);
559 objNew.nd->setScale(objNew.scale);
560 }
561
562 #endif
563