MissionGeometry.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. //============================================================================================
  2. // Spirenkov Maxim, 2004
  3. //============================================================================================
  4. // Mission objects
  5. //============================================================================================
  6. // MissionGeometry
  7. //============================================================================================
  8. #include "MissionGeometry.h"
  9. #define GLUE_DISTANCE 3950.0f
  10. //============================================================================================
  11. const MissionGeometry::PGroup MissionGeometry::pgroups[] =
  12. {
  13. {ConstString("World"), phys_world},
  14. {ConstString("Character"), phys_character},
  15. {ConstString("Player"), phys_player},
  16. {ConstString("Particles"), phys_particles},
  17. {ConstString("Ships"), phys_ship},
  18. {ConstString("Blood"), phys_bloodpatch},
  19. {ConstString("Boss"), phys_boss}
  20. };
  21. MissionGeometry::MissionGeometry()
  22. {
  23. bUseDistanceHack = false;
  24. rigidBody = null;
  25. model = null;
  26. events = null;
  27. shadow = null;
  28. fadeAlpha = 1.0f;
  29. alpha = 1.0f;
  30. fade = fd_none;
  31. fadeTime = 0.0f;
  32. isCheckLod = false;
  33. isPrevLodAlpha = false;
  34. bNotUseFog = false;
  35. h_density = 0.0f;
  36. h_min = 0.0f;
  37. h_max = 0.0f;
  38. d_density = 0.0f;
  39. d_min = 0.0f;
  40. d_max = 0.0f;
  41. fog_color = Color(0.0f);
  42. }
  43. MissionGeometry::~MissionGeometry()
  44. {
  45. if(events)
  46. {
  47. delete events;
  48. events = null;
  49. }
  50. if(rigidBody) rigidBody->Release();
  51. rigidBody = null;
  52. UnloadModel();
  53. }
  54. //============================================================================================
  55. //Инициализировать объект
  56. bool MissionGeometry::Create(MOPReader & reader)
  57. {
  58. if(!GeometryObject::Create(reader)) return false;
  59. if(rigidBody) rigidBody->Release();
  60. rigidBody = null;
  61. if(!events)
  62. {
  63. delete events;
  64. events = null;
  65. }
  66. bool res = LoadModel(model, reader.String());
  67. res |= LoadModel(shadow, reader.String());
  68. if(!res) return false;
  69. //Назначаемая анимация
  70. const char * ani = reader.String().c_str();
  71. if(ani[0] && model)
  72. {
  73. events = NEW AnimationStdEvents();
  74. events->Init(&Sound(), &Particles(), &Mission());
  75. model->SetAnimationFile(ani);
  76. }
  77. //Позиция
  78. Vector pos = reader.Position();
  79. Vector ang = reader.Angles();
  80. modelMatrix.Build(ang, pos);
  81. //К кому присоединять
  82. connectToName = reader.String();
  83. connectToPtr.Reset();
  84. if(!reader.Bool())
  85. {
  86. connectToName.Empty();
  87. }
  88. if( EditMode_IsOn() && connectToName.NotEmpty())
  89. FindObject(connectToName, connectToPtr);
  90. //Использование рутовой кости
  91. bUseRootBone = reader.Bool();
  92. //Видимость, коллижен
  93. bool show = reader.Bool();
  94. bool act = reader.Bool();
  95. //Группа коллизии
  96. ConstString gid = reader.Enum();
  97. PhysicsCollisionGroup physGroup = phys_world;
  98. for(dword i = 0; i < ARRSIZE(pgroups); i++)
  99. {
  100. if(gid == pgroups[i].name)
  101. {
  102. physGroup = pgroups[i].group;
  103. break;
  104. }
  105. }
  106. Assert(i < ARRSIZE(MissionGeometry::pgroups));
  107. bNotUseFog = reader.Bool();
  108. //Уровень отрисовки
  109. level = reader.Long();
  110. //Цвет
  111. color = reader.Colors();
  112. if(model)
  113. {
  114. model->SetUserColor(color);
  115. }
  116. //Делаем "мягкую" альфу
  117. bool bSmoothAlpha = reader.Bool();
  118. if(bSmoothAlpha && model)
  119. {
  120. model->SetFloatAlphaReference(0.003921f);
  121. }
  122. enableRender = reader.Bool();
  123. //Уровень отрисовки
  124. if(!reader.Bool())
  125. {
  126. level = (ML_GEOMETRY3 - ML_GEOMETRY1)*level/100 + ML_GEOMETRY1;
  127. }else{
  128. level = (ML_ALPHA3 - ML_ALPHA1)*level/100 + ML_ALPHA1;
  129. }
  130. //Освещение
  131. dynamicLighting = reader.Bool();
  132. if(model)
  133. {
  134. model->SetDynamicLightState(dynamicLighting);
  135. }
  136. //Теневые дела
  137. shadowCast = reader.Bool();
  138. shadowReceive = reader.Bool();
  139. //Отражение в море
  140. seaReflection = reader.Bool();
  141. //Преломление в море
  142. seaRefraction = reader.Bool();
  143. //Прятать при скрывании в редакторе
  144. hideInEditor = reader.Bool();
  145. //Качатся или нет
  146. noSwing = reader.Bool();
  147. //Дистанция лодирования
  148. float lodDistanceMin = reader.Float();
  149. float lodDistanceDelta = reader.Float();
  150. //Использовать distance hack или нет
  151. bUseDistanceHack = reader.Bool();
  152. lodDistanceDelta = Clampf(lodDistanceDelta, 0.001f, 1000.0f);
  153. isPrevLodAlpha = false;
  154. if(lodDistanceMin > 1e-5f)
  155. {
  156. float lodDistanceMax = lodDistanceMin + lodDistanceDelta;
  157. lodDistanceMin2 = lodDistanceMin*lodDistanceMin;
  158. lodDistanceK2 = 1.0f/(lodDistanceMax*lodDistanceMax - lodDistanceMin*lodDistanceMin);
  159. isCheckLod = true;
  160. }else{
  161. lodDistanceMin2 = 0.0f;
  162. lodDistanceK2 = 0.0f;
  163. isCheckLod = false;
  164. }
  165. //Инициализация
  166. if(!EditMode_IsOn() && events) events->SetScene(model, modelMatrix);
  167. //Установим матрицу
  168. if(model)
  169. {
  170. model->SetTransform(modelMatrix);
  171. model->SetShadowReceiveState(shadowReceive);
  172. rigidBody = model->CreatePhysicsActor(Physics(), false);
  173. if(rigidBody)
  174. {
  175. rigidBody->SetGroup(physGroup);
  176. rigidBody->SetTransform(modelMatrix);
  177. }
  178. }
  179. //Применение флажков
  180. fade = fd_none;
  181. fadeAlpha = 1.0f;
  182. alpha = 1.0f;
  183. Show(show);
  184. Activate(act);
  185. return true;
  186. }
  187. //Вызываеться, когда все объекты созданны но ещё не началось исполнение миссии
  188. void MissionGeometry::PostCreate()
  189. {
  190. if(connectToName.NotEmpty())
  191. {
  192. FindObject(connectToName, connectToPtr);
  193. }
  194. }
  195. /*
  196. //Пересоздать объект
  197. void MissionGeometry::Restart()
  198. {
  199. ReCreate();
  200. }
  201. */
  202. //Обработчик команд для объекта
  203. void MissionGeometry::Command(const char * id, dword numParams, const char ** params)
  204. {
  205. if(string::IsEmpty(id)) return;
  206. const ConstString cmd(id);
  207. //Список команд
  208. static const ConstString cmd_postdraw("postdraw");
  209. static const ConstString cmd_teleport("teleport");
  210. static const ConstString cmd_startnode("startnode");
  211. static const ConstString cmd_actlink("actlink");
  212. static const ConstString cmd_fadeout("fadeout");
  213. static const ConstString cmd_fadein("fadein");
  214. static const ConstString cmd_fade("fade");
  215. static const ConstString cmd_shadow_cast("shadow_cast");
  216. static const ConstString cmd_shadow_receive("shadow_receive");
  217. static const ConstString cmd_collapse("collapse");
  218. static const ConstString cmd_reset("reset");
  219. static const ConstString cmd_pause("pause");
  220. static const ConstString cmd_unpause("unpause");
  221. static const ConstString cmd_RedirectSoundEvent("RedirectSoundEvent");
  222. //Исполняем команду
  223. if(cmd == cmd_postdraw)
  224. {
  225. Draw(0.0f, 0);
  226. }else
  227. if(cmd == cmd_teleport)
  228. {
  229. if(numParams < 1) return;
  230. MOSafePointer obj;
  231. if(FindObject(ConstString(params[0]), obj))
  232. {
  233. obj.Ptr()->GetMatrix(modelMatrix);
  234. if(model) model->SetTransform(modelMatrix);
  235. if(rigidBody)
  236. {
  237. rigidBody->SetTransform(modelMatrix);
  238. }
  239. LogicDebug("Teleport geometry \"%s\" to mission object \"%s\"", GetObjectID().c_str(), obj.Ptr()->GetObjectID().c_str());
  240. }else{
  241. LogicDebugError("Can't teleport geometry \"%s\" to mission object \"%s\", object not found...", GetObjectID().c_str(), params[0]);
  242. }
  243. }else
  244. if(cmd == cmd_startnode)
  245. {
  246. if(numParams < 1 || !model) return;
  247. float blendTime = 0.0f;
  248. if(numParams >= 2)
  249. {
  250. char * pos = null;
  251. blendTime = (float)strtod(params[1], &pos);
  252. blendTime = Clampf(blendTime, 0.0f, 100.0f);
  253. }
  254. IAnimation * a = model->GetAnimation();
  255. if(a)
  256. {
  257. if(!a->Goto(params[0], blendTime))
  258. {
  259. LogicDebugError("Can't start animation node \"%s\" in geometry \"%s\".", params[0], GetObjectID().c_str());
  260. }
  261. a->Release();
  262. }else{
  263. LogicDebugError("Can't start animation node \"%s\" in geometry \"%s\", geometry not animated.", params[0], GetObjectID().c_str());
  264. }
  265. }else
  266. if(cmd == cmd_actlink)
  267. {
  268. if(numParams < 1 || !model) return;
  269. IAnimation * a = model->GetAnimation();
  270. if(a)
  271. {
  272. if(!ActivateAnimationLink(params[0]))
  273. {
  274. LogicDebugError("Can't start animation link \"%s\" in geometry \"%s\".", params[0], GetObjectID().c_str());
  275. }
  276. a->Release();
  277. }else{
  278. LogicDebugError("Can't start animation node \"%s\" in geometry \"%s\", geometry not animated.", params[0], GetObjectID().c_str());
  279. }
  280. }else
  281. if(cmd == cmd_fadeout)
  282. {
  283. if(fade != fd_hide)
  284. {
  285. LogicDebug("Fadeout");
  286. fade = fd_fadeout;
  287. fadeTime = 0.0f;
  288. }else{
  289. LogicDebugError("Fadeout ignore, course work \"Fade\"");
  290. }
  291. }else
  292. if(cmd == cmd_fadein)
  293. {
  294. if(fade != fd_hide)
  295. {
  296. LogicDebug("Fadein");
  297. fade = fd_fadein;
  298. fadeTime = 0.0f;
  299. }else{
  300. LogicDebugError("Fadein ignore, course work \"Fade\"");
  301. }
  302. }else
  303. if(cmd == cmd_fade)
  304. {
  305. if(fade != fd_hide)
  306. {
  307. LogicDebug("Fade");
  308. fade = fd_hide;
  309. fadeTime = 0.0f;
  310. }else{
  311. LogicDebugError("Ignore fade already work \"Fade\"");
  312. }
  313. }else
  314. if(cmd == cmd_shadow_cast)
  315. {
  316. if(numParams >= 1 && params[0][0])
  317. {
  318. shadowCast = params[0][0] != '0';
  319. Show(IsShow());
  320. LogicDebug("%s state shadow_cast in geometry \"%s\"", shadowCast ? "Enable" : "Disable", GetObjectID().c_str());
  321. }else{
  322. LogicDebugError("Can't change shadow_cast state in geometry \"%s\", because no params", GetObjectID().c_str());
  323. }
  324. }else
  325. if(cmd == cmd_shadow_receive)
  326. {
  327. if(numParams >= 1 && params[0][0])
  328. {
  329. shadowReceive = params[0][0] != '0';
  330. Show(IsShow());
  331. LogicDebug("%s state shadow_receive in geometry \"%s\"", shadowReceive ? "Enable" : "Disable", GetObjectID().c_str());
  332. }else{
  333. LogicDebugError("Can't change shadow_receive state in geometry \"%s\", because no params", GetObjectID().c_str());
  334. }
  335. }else
  336. if(cmd == cmd_collapse)
  337. {
  338. if(numParams >= 1 && params[0][0])
  339. {
  340. if(model)
  341. {
  342. IAnimation * ani = model->GetAnimation();
  343. if(ani)
  344. {
  345. const char * prms[2];
  346. static const char * collapse = "Collapse";
  347. static const char * restore = "Restore";
  348. if(numParams >= 2)
  349. {
  350. prms[0] = (params[1][0] == 't' || params[1][0] == 'T') ? collapse : restore;
  351. }else{
  352. prms[0] = collapse;
  353. }
  354. prms[1] = params[0];
  355. LogicDebug("%s bone: %s", prms[0], params[0]);
  356. if(events)
  357. {
  358. events->BoneCollapse(ani, "BoneCollapse", prms, 2);
  359. }else{
  360. LogicDebugError("Can't collapse bone in geometry \"%s\", because events not created", GetObjectID().c_str());
  361. }
  362. ani->Release();
  363. }else{
  364. LogicDebugError("Can't collapse bone in geometry \"%s\", because animation isn't set", GetObjectID().c_str());
  365. }
  366. }else{
  367. LogicDebugError("Can't collapse bone in geometry \"%s\", because model not loaded", GetObjectID().c_str());
  368. }
  369. }else{
  370. LogicDebugError("Can't collapse bone in geometry \"%s\", because no params", GetObjectID().c_str());
  371. }
  372. }else
  373. if(cmd == cmd_reset)
  374. {
  375. LogicDebug("Reset events");
  376. if(events)
  377. {
  378. events->ResetParticles();
  379. events->ResetSounds();
  380. events->ResetCollapser();
  381. }
  382. fadeAlpha = 1.0f;
  383. alpha = 1.0f;
  384. fade = fd_none;
  385. IAnimation * ani = model->GetAnimation();
  386. if(ani)
  387. {
  388. ani->Start();
  389. ani->Release();
  390. }else{
  391. LogicDebugError("Can't reset animation, because it's not set");
  392. }
  393. Show(IsShow());
  394. }else
  395. if(cmd == cmd_pause)
  396. {
  397. IAnimation * ani = model->GetAnimation();
  398. if(ani)
  399. {
  400. LogicDebug("Pause");
  401. ani->Pause(true);
  402. ani->Release();
  403. }
  404. }else
  405. if(cmd == cmd_unpause)
  406. {
  407. IAnimation * ani = model->GetAnimation();
  408. if(ani)
  409. {
  410. LogicDebug("Unpause");
  411. ani->Pause(false);
  412. ani->Release();
  413. }
  414. }else
  415. if(cmd == cmd_RedirectSoundEvent)
  416. {
  417. LogicDebug("RedirectSoundEvent");
  418. IAnimation * ani = model->GetAnimation();
  419. if(ani && events)
  420. {
  421. events->PlaySound(ani, "Snd", params, numParams);
  422. ani->Release();
  423. }else{
  424. LogicDebugError("Animation not set for this geometry");
  425. }
  426. }else{
  427. LogicDebugError("Unknown command: %s", id);
  428. }
  429. }
  430. //Инициализировать объект
  431. bool MissionGeometry::EditMode_Create(MOPReader & reader)
  432. {
  433. Create(reader);
  434. return true;
  435. }
  436. //Обновить параметры
  437. bool MissionGeometry::EditMode_Update(MOPReader & reader)
  438. {
  439. DelUpdate();
  440. Unregistry(MG_SHADOWCAST);
  441. Unregistry(MG_SHADOWRECEIVE);
  442. // Unregistry(MG_DOF);
  443. Unregistry(MG_SHADOWDONTRECEIVE);
  444. Create(reader);
  445. return true;
  446. }
  447. //Получить размеры описывающего ящика
  448. void MissionGeometry::EditMode_GetSelectBox(Vector & min, Vector & max)
  449. {
  450. if(model || shadow)
  451. {
  452. GetBox(min, max);
  453. return;
  454. }
  455. min = -0.5f;
  456. max = 0.5f;
  457. }
  458. //Получить бокс, описывающий объект в локальных координатах
  459. void MissionGeometry::GetBox(Vector & min, Vector & max)
  460. {
  461. if(model)
  462. {
  463. min = model->GetLocalBound().vMin;
  464. max = model->GetLocalBound().vMax;
  465. if(bUseRootBone)
  466. {
  467. IAnimation * ani = model->GetAnimation();
  468. if(ani)
  469. {
  470. max = (max - min)*0.5f;
  471. min = -max;
  472. ani->Release();
  473. }
  474. }
  475. return;
  476. }else
  477. if(shadow)
  478. {
  479. min = shadow->GetLocalBound().vMin;
  480. max = shadow->GetLocalBound().vMax;
  481. return;
  482. }
  483. min = 0.0f;
  484. max = 0.0f;
  485. }
  486. //Получить матрицу объекта
  487. Matrix & MissionGeometry::GetMatrix(Matrix & mtx)
  488. {
  489. if(bUseRootBone && model)
  490. {
  491. IAnimation * a = model->GetAnimation();
  492. if(a)
  493. {
  494. mtx = a->GetBoneMatrix(0)*modelMatrix;
  495. a->Release();
  496. return mtx;
  497. }
  498. }else{
  499. mtx = modelMatrix;
  500. }
  501. if(connectToPtr.Validate())
  502. {
  503. mtx = mtx*connectToPtr.Ptr()->GetMatrix(Matrix());
  504. }
  505. return mtx;
  506. };
  507. //Показать/скрыть объект
  508. void MissionGeometry::Show(bool isShow)
  509. {
  510. GeometryObject::Show(isShow);
  511. if(IsShow())
  512. {
  513. LogicDebug("Show");
  514. PauseAnimation(false);
  515. long curLevel = level;
  516. bool isTransp = false;
  517. if(alpha < 1.0f || fade != fd_none)
  518. {
  519. curLevel = c_fadelevel;
  520. isTransp = true;
  521. }
  522. DelUpdate(&MissionGeometry::Draw);
  523. if(enableRender)
  524. {
  525. SetUpdate(&MissionGeometry::Draw, curLevel);
  526. }
  527. if(EditMode_IsOn())
  528. {
  529. DelUpdate(&MissionGeometry::DrawTransparency);
  530. }
  531. if(shadowCast)
  532. {
  533. Registry(MG_SHADOWCAST, (MOF_EVENT)&MissionGeometry::ShadowInfo, curLevel);
  534. }else{
  535. Unregistry(MG_SHADOWCAST);
  536. }
  537. if(shadowReceive)
  538. {
  539. Unregistry(MG_SHADOWDONTRECEIVE);
  540. if(!isTransp)
  541. {
  542. Registry(MG_SHADOWRECEIVE, (MOF_EVENT)&MissionGeometry::ShadowRecive, curLevel);
  543. }else{
  544. Unregistry(MG_SHADOWRECEIVE);
  545. }
  546. }else{
  547. Unregistry(MG_SHADOWRECEIVE);
  548. if(curLevel < ML_ALPHA1 && enableRender) Registry(MG_SHADOWDONTRECEIVE, (MOF_EVENT)&MissionGeometry::ShadowRecive, curLevel);
  549. }
  550. if(seaReflection)
  551. {
  552. Registry(MG_SEAREFLECTION, (MOF_EVENT)&MissionGeometry::SeaReflection, curLevel);
  553. }else{
  554. Unregistry(MG_SEAREFLECTION);
  555. }
  556. if(seaRefraction)
  557. {
  558. Registry(MG_SEAREFRACTION, (MOF_EVENT)&MissionGeometry::SeaRefraction, curLevel);
  559. }else{
  560. Unregistry(MG_SEAREFRACTION);
  561. }
  562. // Registry(MG_DOF, (MOF_EVENT)&MissionGeometry::SeaReflection, curLevel);
  563. }else{
  564. LogicDebug("Hide");
  565. PauseAnimation(true);
  566. if(events)
  567. {
  568. events->ResetParticles();
  569. }
  570. DelUpdate(&MissionGeometry::Draw);
  571. if(EditMode_IsOn() && !hideInEditor)
  572. {
  573. SetUpdate(&MissionGeometry::DrawTransparency, ML_ALPHA4);
  574. }
  575. // Unregistry(MG_DOF);
  576. Unregistry(MG_SHADOWCAST);
  577. Unregistry(MG_SHADOWRECEIVE);
  578. Unregistry(MG_SEAREFLECTION);
  579. Unregistry(MG_SEAREFRACTION);
  580. Unregistry(MG_SHADOWDONTRECEIVE);
  581. }
  582. }
  583. //Активировать/деактивировать объект
  584. void MissionGeometry::Activate(bool isActive)
  585. {
  586. GeometryObject::Activate(isActive);
  587. if(EditMode_IsOn())
  588. {
  589. return;
  590. }
  591. if(rigidBody)
  592. {
  593. rigidBody->Activate(IsActive());
  594. if(IsActive())
  595. {
  596. LogicDebug("Activate");
  597. }else{
  598. LogicDebug("Deactivate");
  599. }
  600. }else{
  601. if(isActive)
  602. {
  603. LogicDebugError("Can't activate collision -> no present collision data in file \"%s\"", (model ? model->GetFileName() : ""));
  604. }else{
  605. LogicDebug("Deactivate");
  606. }
  607. }
  608. }
  609. //Нарисовать модельку
  610. void _cdecl MissionGeometry::Draw(float dltTime, long level)
  611. {
  612. if(!EditMode_IsVisible()) return;
  613. if(!model) return;
  614. if(fade != fd_none)
  615. {
  616. if(fadeTime <= 1e-10f)
  617. {
  618. if(level == c_fadelevel)
  619. {
  620. static const float fadeSpeed = 2.0f;
  621. static const float hideSpeed = 0.7f;
  622. switch(fade)
  623. {
  624. case fd_fadeout:
  625. fadeAlpha -= dltTime*fadeSpeed;
  626. if(fadeAlpha < 0.3f)
  627. {
  628. fadeAlpha = 0.3f;
  629. fade = fd_none;
  630. }
  631. break;
  632. case fd_fadein:
  633. fadeAlpha += dltTime*fadeSpeed;
  634. if(fadeAlpha > 1.0f)
  635. {
  636. fadeAlpha = 1.0f;
  637. fade = fd_none;
  638. if(!isCheckLod)
  639. {
  640. alpha = 1.0f;
  641. Show(false);
  642. Show(true);
  643. }else{
  644. if(!isPrevLodAlpha)
  645. {
  646. alpha = 1.0f;
  647. Show(false);
  648. Show(true);
  649. }
  650. }
  651. }
  652. break;
  653. case fd_hide:
  654. fadeAlpha -= dltTime*hideSpeed;
  655. if(fadeAlpha < 0.0f)
  656. {
  657. fadeAlpha = 0.0f;
  658. Show(false);
  659. return;
  660. }
  661. break;
  662. }
  663. }else{
  664. Show(false);
  665. Show(true);
  666. return;
  667. }
  668. }else{
  669. fadeTime -= dltTime;
  670. }
  671. }
  672. Matrix view(false);
  673. if(isCheckLod)
  674. {
  675. const GMXBoundBox & gbb = model->GetLocalBound();
  676. Vector center = (gbb.vMin + gbb.vMax)*0.5f;
  677. center = GetMatrix(view)*center;
  678. float k = (Render().GetView().GetCamPos() - center).GetAttenuation2(lodDistanceMin2, lodDistanceK2);
  679. if(k < 1.0f)
  680. {
  681. alpha = k*fadeAlpha;
  682. if(!isPrevLodAlpha)
  683. {
  684. isPrevLodAlpha = true;
  685. Show(IsShow());
  686. }
  687. }else{
  688. alpha = fadeAlpha;
  689. if(isPrevLodAlpha)
  690. {
  691. isPrevLodAlpha = false;
  692. Show(IsShow());
  693. }
  694. }
  695. }else{
  696. alpha = fadeAlpha;
  697. }
  698. float a = color.a*alpha;
  699. if(a < 1e-5f)
  700. {
  701. return;
  702. }
  703. if(noSwing)
  704. {
  705. view = Render().GetView();
  706. Render().SetView((Mission().GetInverseSwingMatrix()*Matrix(view).Inverse()).Inverse());
  707. }
  708. model->SetUserColor(Color(color.r, color.g, color.b, a));
  709. Matrix drawMtx;
  710. BuildViewMatrix(drawMtx);
  711. if(bUseRootBone)
  712. {
  713. Matrix mtx;
  714. GetMatrix(mtx);
  715. if(events)
  716. {
  717. events->Update(mtx, dltTime);
  718. }
  719. model->SetTransform(drawMtx);
  720. FogParamsSave();
  721. model->Draw();
  722. FogParamsRestore();
  723. }else{
  724. if(events)
  725. {
  726. events->Update(drawMtx, dltTime);
  727. }
  728. if (bUseDistanceHack)
  729. {
  730. Matrix mModelMatrix;
  731. CalculateGluedMatrix(drawMtx, mModelMatrix);
  732. model->SetTransform(mModelMatrix);
  733. } else
  734. {
  735. model->SetTransform(drawMtx);
  736. }
  737. FogParamsSave();
  738. model->Draw();
  739. FogParamsRestore();
  740. }
  741. if(noSwing)
  742. {
  743. Render().SetView(view);
  744. }
  745. };
  746. //Нарисовать прозрачную модельку
  747. void _cdecl MissionGeometry::DrawTransparency(float dltTime, long level)
  748. {
  749. if(!EditMode_IsVisible()) return;
  750. if(!Mission().EditMode_IsAdditionalDraw()) return;
  751. if(model)
  752. {
  753. Matrix drawMtx;
  754. BuildViewMatrix(drawMtx);
  755. if (bUseDistanceHack)
  756. {
  757. const Matrix & mProj = Render().GetProjection();
  758. const GMXBoundBox & bbox = model->GetLocalBound();
  759. const GMXBoundSphere& bsphere = model->GetLocalBoundSphere();
  760. Vector vCamPos = Render().GetView().GetCamPos();
  761. Matrix mModelMatrix;
  762. CalculateGluedMatrix(drawMtx, mModelMatrix);
  763. model->SetTransform(mModelMatrix);
  764. } else
  765. {
  766. model->SetTransform(drawMtx);
  767. }
  768. if(bUseRootBone && events)
  769. {
  770. Matrix mtx;
  771. GetMatrix(mtx);
  772. events->Update(mtx, dltTime);
  773. }
  774. model->SetUserColor(Color(color.r, color.g, color.b, color.a*0.1f));
  775. Matrix view(false);
  776. if(noSwing)
  777. {
  778. view = Render().GetView();
  779. Render().SetView((Mission().GetInverseSwingMatrix()*Matrix(view).Inverse()).Inverse());
  780. }
  781. FogParamsSave();
  782. model->Draw();
  783. FogParamsRestore();
  784. if(noSwing)
  785. {
  786. Render().SetView(view);
  787. }
  788. model->SetUserColor(color);
  789. }
  790. };
  791. //Нарисовать модельку для тени
  792. void _cdecl MissionGeometry::ShadowInfo(const char * group, MissionObject * sender)
  793. {
  794. if(!EditMode_IsVisible() || !IsShow()) return;
  795. if(shadow)
  796. {
  797. Matrix drawMtx;
  798. BuildViewMatrix(drawMtx);
  799. shadow->SetTransform(drawMtx);
  800. const Vector & vMin = shadow->GetBound().vMin;
  801. const Vector & vMax = shadow->GetBound().vMax;
  802. ((MissionShadowCaster *)sender)->AddObject(this, &MissionGeometry::ShadowCast, vMin, vMax);
  803. }else{
  804. if(model)
  805. {
  806. Matrix drawMtx;
  807. BuildViewMatrix(drawMtx);
  808. model->SetTransform(drawMtx);
  809. const Vector & vMin = model->GetBound().vMin;
  810. const Vector & vMax = model->GetBound().vMax;
  811. ((MissionShadowCaster *)sender)->AddObject(this, &MissionGeometry::ShadowCast, vMin, vMax);
  812. }
  813. }
  814. }
  815. //Нарисовать модельку для тени
  816. void _cdecl MissionGeometry::ShadowCast(const char * group, MissionObject * sender)
  817. {
  818. if(shadow)
  819. {
  820. Matrix drawMtx;
  821. BuildViewMatrix(drawMtx);
  822. shadow->SetTransform(drawMtx);
  823. shadow->Draw();
  824. }else{
  825. if(model)
  826. {
  827. Matrix drawMtx;
  828. BuildViewMatrix(drawMtx);
  829. model->SetTransform(drawMtx);
  830. model->Draw();
  831. }
  832. }
  833. }
  834. //Нарисовать модельку для тени
  835. void _cdecl MissionGeometry::ShadowRecive(const char * group, MissionObject * sender)
  836. {
  837. if(!EditMode_IsVisible() || !IsShow()) return;
  838. if(model)
  839. {
  840. Matrix drawMtx;
  841. BuildViewMatrix(drawMtx);
  842. model->SetTransform(drawMtx);
  843. model->Draw();
  844. }
  845. }
  846. void _cdecl MissionGeometry::SeaReflection(const char * group, MissionObject * sender)
  847. {
  848. if(!EditMode_IsVisible() || !IsShow()) return;
  849. if(model)
  850. {
  851. Matrix view(false);
  852. if(noSwing)
  853. {
  854. view = Render().GetView();
  855. Render().SetView((Mission().GetInverseSwingMatrix()*Matrix(view).Inverse()).Inverse());
  856. }
  857. Matrix drawMtx;
  858. BuildViewMatrix(drawMtx);
  859. if (bUseDistanceHack)
  860. {
  861. const Matrix & mProj = Render().GetProjection();
  862. const GMXBoundBox & bbox = model->GetLocalBound();
  863. const GMXBoundSphere& bsphere = model->GetLocalBoundSphere();
  864. Vector vCamPos = Render().GetView().GetCamPos();
  865. Matrix mModelMatrix;
  866. CalculateGluedMatrix(drawMtx, mModelMatrix);
  867. model->SetTransform(mModelMatrix);
  868. } else
  869. {
  870. model->SetTransform(drawMtx);
  871. }
  872. FogParamsSave();
  873. model->Draw();
  874. FogParamsRestore();
  875. if(noSwing)
  876. {
  877. Render().SetView(view);
  878. }
  879. }
  880. }
  881. void _cdecl MissionGeometry::SeaRefraction(const char * group, MissionObject * sender)
  882. {
  883. if(!EditMode_IsVisible() || !IsShow()) return;
  884. if(model)
  885. {
  886. Matrix view(false);
  887. if(noSwing)
  888. {
  889. view = Render().GetView();
  890. Render().SetView((Mission().GetInverseSwingMatrix()*Matrix(view).Inverse()).Inverse());
  891. }
  892. Matrix drawMtx;
  893. BuildViewMatrix(drawMtx);
  894. if (bUseDistanceHack)
  895. {
  896. const Matrix & mProj = Render().GetProjection();
  897. const GMXBoundBox & bbox = model->GetLocalBound();
  898. const GMXBoundSphere& bsphere = model->GetLocalBoundSphere();
  899. Vector vCamPos = Render().GetView().GetCamPos();
  900. Matrix mModelMatrix;
  901. CalculateGluedMatrix(drawMtx, mModelMatrix);
  902. model->SetTransform(mModelMatrix);
  903. } else
  904. {
  905. model->SetTransform(drawMtx);
  906. }
  907. FogParamsSave();
  908. model->Draw();
  909. FogParamsRestore();
  910. if(noSwing)
  911. {
  912. Render().SetView(view);
  913. }
  914. }
  915. }
  916. //Сгенерировать матрицу отрисовки
  917. inline void MissionGeometry::BuildViewMatrix(Matrix & m)
  918. {
  919. if(!connectToPtr.Validate())
  920. {
  921. m = modelMatrix;
  922. }else{
  923. m = modelMatrix*connectToPtr.Ptr()->GetMatrix(Matrix());
  924. }
  925. }
  926. //Загрузить модельку
  927. bool MissionGeometry::LoadModel(IGMXScene * & m, const ConstString & fileName)
  928. {
  929. //Создаём новую модельку
  930. IGMXScene * mdl = Geometry().CreateGMX(fileName.c_str(), &Animation(), &Particles(), &Sound());
  931. //Удаляем модельку
  932. if(m) m->Release();
  933. m = mdl;
  934. return (m != null);
  935. };
  936. //Удалить модельку
  937. void MissionGeometry::UnloadModel()
  938. {
  939. if(model) model->Release();
  940. model = null;
  941. if(shadow) shadow->Release();
  942. shadow = null;
  943. };
  944. //Остановить - продолжить проигрывание анимации
  945. void MissionGeometry::PauseAnimation(bool isPause)
  946. {
  947. if(!model) return;
  948. IAnimation * ani = model->GetAnimation();
  949. if(ani)
  950. {
  951. ani->Pause(isPause);
  952. ani->Release();
  953. }
  954. }
  955. //Получить сцену
  956. IGMXScene * MissionGeometry::GetScene()
  957. {
  958. return model;
  959. }
  960. void MissionGeometry::CalculateGluedMatrix(const Matrix & matrixIn, Matrix & matrixOut)
  961. {
  962. float fGlueDistance = GLUE_DISTANCE;
  963. const Matrix & mProjection = Render().GetProjection();
  964. const GMXBoundBox & boundBox = model->GetLocalBound();
  965. const GMXBoundSphere& localBoundSphere = model->GetLocalBoundSphere();
  966. Vector vCamPos = Render().GetView().GetCamPos();
  967. Vector vCenter = matrixIn * localBoundSphere.vCenter;
  968. Vector vDir = vCenter - vCamPos;
  969. float fDist = vDir.GetLength();
  970. vDir.y = 0.0f;
  971. vDir.Normalize();
  972. float fDistToCompleteVisible = (fGlueDistance-localBoundSphere.fRadius);
  973. if(fDist < fDistToCompleteVisible)
  974. {
  975. matrixOut = matrixIn;
  976. return;
  977. }
  978. Vector4 down = Vector4 (0.0f, boundBox.vMin.y, fDist, 1.0f);
  979. Vector4 up = Vector4 (0.0f, boundBox.vMax.y, fDist, 1.0f);
  980. Vector4 down_proj = mProjection.MulVertex(down);
  981. Vector4 up_proj = mProjection.MulVertex(up);
  982. down_proj.y = down_proj.y / down_proj.w;
  983. up_proj.y = up_proj.y / up_proj.w;
  984. float sizeMustBe = up_proj.y - down_proj.y;
  985. //ставим нужную дистанцию
  986. fDist = fDistToCompleteVisible;
  987. down = Vector4 (0.0f, boundBox.vMin.y, fDist, 1.0f);
  988. up = Vector4 (0.0f, boundBox.vMax.y, fDist, 1.0f);
  989. down_proj = mProjection.MulVertex(down);
  990. up_proj = mProjection.MulVertex(up);
  991. down_proj.y = down_proj.y / down_proj.w;
  992. up_proj.y = up_proj.y / up_proj.w;
  993. float sizeCurrent = up_proj.y - down_proj.y;
  994. float fScaleK = 0.00000000001f;
  995. if (sizeCurrent > 0.00001f)
  996. {
  997. fScaleK = Clampf (sizeMustBe / sizeCurrent);
  998. }
  999. Vector vNewCenter = vCamPos + (vDir * fDistToCompleteVisible);
  1000. vNewCenter.y = vCenter.y;
  1001. // pRS->DrawSphere(vNewCenter, 100.0f, 0xFFFF0000);
  1002. Vector vDeltaCenter = vCenter - vNewCenter;
  1003. Matrix matTransform = matrixIn;
  1004. matTransform.pos -= vDeltaCenter;
  1005. //Надо матрицу которая центрирует по боксу, скейлит и потом обратно сдвигает...
  1006. Matrix mScale;
  1007. mScale.BuildScale(fScaleK, fScaleK, fScaleK);
  1008. Matrix mWorldToBound;
  1009. mWorldToBound.pos = -localBoundSphere.vCenter;
  1010. Matrix mBoundToWorld;
  1011. mBoundToWorld = mWorldToBound;
  1012. mBoundToWorld.Inverse();
  1013. Matrix mScaleAroundPivot = (mWorldToBound * mScale) * mBoundToWorld;
  1014. matrixOut = mScaleAroundPivot * matTransform;
  1015. //т.к. скейлим относительно центра а не относительно нижней плоскости bound Box пододвигаем...
  1016. matrixOut.pos.y = (matrixIn.pos.y * fScaleK);
  1017. }
  1018. inline void MissionGeometry::FogParamsSave()
  1019. {
  1020. if(bNotUseFog == false) return;
  1021. Render().getFogParams(h_density, h_min, h_max, d_density, d_min, d_max, fog_color);
  1022. Render().setFogParams(0.0f, h_min, h_max, 0.0f, d_min, d_max, fog_color);
  1023. }
  1024. inline void MissionGeometry::FogParamsRestore()
  1025. {
  1026. if (bNotUseFog == false) return;
  1027. Render().setFogParams(h_density, h_min, h_max, d_density, d_min, d_max, fog_color);
  1028. }
  1029. //============================================================================================
  1030. //Параметры инициализации
  1031. //============================================================================================
  1032. const char * MissionGeometry::comment =
  1033. "Commands list:\n"
  1034. "----------------------------------------\n"
  1035. " Teleport geometry to position of some\n"
  1036. " mission object\n"
  1037. "----------------------------------------\n"
  1038. " command: teleport\n"
  1039. " parm: name of mission object\n"
  1040. " \n"
  1041. "----------------------------------------\n"
  1042. " Start of any animation node\n"
  1043. "----------------------------------------\n"
  1044. " command: startnode\n"
  1045. " parm: name of animation node\n"
  1046. " [parm: blend time in seconds]\n"
  1047. " * if no blend time, then start node without blend\n"
  1048. " \n"
  1049. "----------------------------------------\n"
  1050. " Move to animation link from\n"
  1051. " current node\n"
  1052. "----------------------------------------\n"
  1053. " command: actlink\n"
  1054. " parm: name of animation link\n"
  1055. " \n"
  1056. "----------------------------------------\n"
  1057. " Fade out model to transparence draw\n"
  1058. "----------------------------------------\n"
  1059. " command: fadeout\n"
  1060. " \n"
  1061. "----------------------------------------\n"
  1062. " Fade in model to solid draw\n"
  1063. "----------------------------------------\n"
  1064. " command: fadein\n"
  1065. " \n"
  1066. "----------------------------------------\n"
  1067. " Fade out model and hide after\n"
  1068. "----------------------------------------\n"
  1069. " command: fade\n"
  1070. " [parm: waiting time before fade]\n"
  1071. " \n"
  1072. "----------------------------------------\n"
  1073. " Change shadow states\n"
  1074. "----------------------------------------\n"
  1075. " command: shadow_cast\n"
  1076. " parm: 0 = disable or 1 = enable\n"
  1077. " \n"
  1078. " command: shadow_receive\n"
  1079. " parm: 0 = disable or 1 = enable\n"
  1080. " \n"
  1081. "----------------------------------------\n"
  1082. " Collapse bone\n"
  1083. "----------------------------------------\n"
  1084. " command: collapse\n"
  1085. " parm: bone name or postfix bone name\n"
  1086. " [parm: true or false] default is true\n"
  1087. " \n"
  1088. "----------------------------------------\n"
  1089. " Reset uncliiapse all bones,\n"
  1090. " restart animation\n"
  1091. "----------------------------------------\n"
  1092. " command: reset\n"
  1093. " \n"
  1094. "----------------------------------------\n"
  1095. " Pause animation\n"
  1096. "----------------------------------------\n"
  1097. " command: pause\n"
  1098. " \n"
  1099. "----------------------------------------\n"
  1100. " UnPause animation\n"
  1101. "----------------------------------------\n"
  1102. " command: unpause\n"
  1103. " \n"
  1104. " ";
  1105. MOP_BEGINLISTCG(MissionGeometry, "Geometry", '1.00', 0, MissionGeometry::comment, "Geometry")
  1106. MOP_ENUMBEG("PhysGroup")
  1107. for(dword i = 0; i < ARRSIZE(MissionGeometry::pgroups); i++)
  1108. {
  1109. MOP_ENUMELEMENT(MissionGeometry::pgroups[i].name.c_str())
  1110. }
  1111. MOP_ENUMEND
  1112. MOP_STRINGC("Name", "", "Name of model file (.gmx)")
  1113. MOP_STRINGC("Shadow", "", "Name of model file (.gmx) for shadow cast")
  1114. MOP_STRINGC("Animation", "", "Name of animation file (.anx) for replace current animation")
  1115. MOP_POSITIONC("Position", Vector(0.0f), "Model position in world")
  1116. MOP_ANGLESC("Angles", Vector(0.0f), "Model orientation in world")
  1117. MOP_STRINGC("Connect to", "", "Connect geometry to object (not for collision)")
  1118. MOP_BOOLC("Make connection", false, "Make connection to object into Edit Mode")
  1119. MOP_BOOLC("Use root bone", false, "Addition root bone transformation for current. (detector's and other using)")
  1120. MOP_BOOLC("Show", true, "Show or hide geometry in start mission time")
  1121. MOP_BOOLC("Active (collision)", false, "Wiht active geometry can collision some objects")
  1122. MOP_ENUM("PhysGroup", "Collision groups")
  1123. MOP_GROUPBEG("Render params")
  1124. MOP_BOOLC("Disable fog", false, "Fog don't affect to this geometry")
  1125. MOP_LONGEXC("Level", 0, 0, 100, "Order of geometry draw")
  1126. MOP_COLOR("Color", Color(0.0f, 0.0f, 0.0f, 1.0f))
  1127. MOP_BOOLC("Smooth alpha", false, "Disable alpha test (Make smooth alpha)")
  1128. MOP_BOOLC("Render", true, "Enable primary render")
  1129. MOP_BOOLC("Transparency", false, "Geometry draw as transparency (i.e. light rays)")
  1130. MOP_BOOL("Dynamic lighting", false)
  1131. MOP_BOOLC("Shadow cast", false, "Geometry can is shadow cast by some objects")
  1132. MOP_BOOLC("Shadow receive", false, "Geometry can is shadow receive from casting objects")
  1133. MOP_BOOLC("Sea reflection", false, "Geometry can reflect in sea")
  1134. MOP_BOOLC("Sea refraction", false, "Geometry can refract in sea")
  1135. MOP_BOOLC("Hide in editor", true, "Hide invisible geometry in editor")
  1136. MOP_BOOLC("No swing", false, "No swing geometry in swing machine")
  1137. MOP_FLOATC("Hide distance", -1.0f, "If distance less 0, then ignore this feature")
  1138. MOP_FLOATEXC("Fade distance", 5.0f, 0.001f, 1000.0f, "When distance for camera great then Hide + Fade, geometry is hidden")
  1139. MOP_BOOLC("Distance hack", false, "Use distance hack to far-far-far-far-far objects")
  1140. MOP_GROUPEND()
  1141. MOP_ENDLIST(MissionGeometry)