ConvexAreaDetector.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. //===========================================================================================================================
  2. // Spirenkov Maxim, 2003
  3. //===========================================================================================================================//
  4. // Mission objects
  5. //===========================================================================================================================
  6. // ConvexAreaDetector
  7. //============================================================================================
  8. #include "ConvexAreaDetector.h"
  9. //============================================================================================
  10. ConvexAreaDetector::ConvexAreaDetector() : targets(_FL_)
  11. {
  12. previewPoints = null;
  13. }
  14. ConvexAreaDetector::~ConvexAreaDetector()
  15. {
  16. if(previewPoints)
  17. {
  18. delete previewPoints;
  19. }
  20. }
  21. //============================================================================================
  22. //Инициализировать объект
  23. bool ConvexAreaDetector::Create(MOPReader & reader)
  24. {
  25. targets.DelAll();
  26. eventEnter.Init(reader);
  27. eventExit.Init(reader);
  28. long objectsCount = reader.Array();
  29. targets.AddElements(objectsCount);
  30. for(long i = 0; i < objectsCount; i++)
  31. {
  32. targets[i].target.Reset();
  33. targets[i].targetID = reader.String();
  34. targets[i].isInside = false;
  35. targets[i].eventEnter.Init(reader);
  36. targets[i].eventExit.Init(reader);
  37. }
  38. Vector pos = reader.Position();
  39. Vector ang = reader.Angles();
  40. matrix.Build(ang, pos);
  41. connectID = reader.String();
  42. connect.Reset();
  43. pCount = reader.Array();
  44. planesCount = 0;
  45. Assert(pCount <= ARRSIZE(plane));
  46. Vector p0, prev;
  47. float s = 0.0f;
  48. for(long i = 0; i <= pCount; i++)
  49. {
  50. Vector pnt = (i < pCount) ? reader.Position() : p0;
  51. if(i)
  52. {
  53. Vector edge = (pnt - prev).GetXZ();
  54. if(edge.NormalizeXZ() > 1e-5f)
  55. {
  56. plane[planesCount].n.x = -edge.z;
  57. plane[planesCount].n.y = 0.0f;
  58. plane[planesCount].n.z = edge.x;
  59. plane[planesCount].d = plane[planesCount].n | pnt;
  60. planesCount++;
  61. }
  62. }else{
  63. p0 = pnt;
  64. }
  65. if(previewPoints)
  66. {
  67. previewPoints[i*2].pos = pnt;
  68. }
  69. if(i == 2)
  70. {
  71. s = (p0.x - prev.x)*(pnt.z - prev.z) - (p0.z - prev.z)*(pnt.x - prev.x);
  72. }
  73. prev = pnt;
  74. }
  75. if(planesCount < 3)
  76. {
  77. planesCount = 0;
  78. }else{
  79. if(s < 0.0f)
  80. {
  81. for(long i = 0; i < planesCount; i++)
  82. {
  83. plane[i].n = -plane[i].n;
  84. plane[i].d = -plane[i].d;
  85. }
  86. }
  87. }
  88. hmin = reader.Float();
  89. hmax = reader.Float();
  90. if(hmax <= hmin)
  91. {
  92. float t = hmax;
  93. hmax = hmin + 1e-10f;
  94. hmin = t - 1e-10f;
  95. }
  96. //eventEnter.Init(reader);
  97. //eventExit.Init(reader);
  98. isCheckVisible = reader.Bool();
  99. isCheckActive = reader.Bool();
  100. thisTriggers = reader.Bool();
  101. //Активация
  102. Activate(reader.Bool());
  103. isDebug = reader.Bool();
  104. return planesCount != 0;
  105. }
  106. //Получить матрицу объекта
  107. Matrix & ConvexAreaDetector::GetMatrix(Matrix & mtx)
  108. {
  109. if(connectID.NotEmpty())
  110. {
  111. if(!connect.Validate())
  112. {
  113. FindObject(connectID, connect);
  114. }
  115. }
  116. if(connect.Validate())
  117. {
  118. mtx = matrix*connect.Ptr()->GetMatrix(Matrix());
  119. }else{
  120. mtx = matrix;
  121. }
  122. return mtx;
  123. }
  124. //Активировать
  125. void ConvexAreaDetector::Activate(bool isActive)
  126. {
  127. MissionObject::Activate(isActive);
  128. if(!EditMode_IsOn())
  129. {
  130. if(IsActive())
  131. {
  132. LogicDebug("Activate");
  133. SetUpdate(&ConvexAreaDetector::Work, ML_TRIGGERS);
  134. for(long i = 0; i < targets; i++)
  135. {
  136. targets[i].isInside = false;
  137. }
  138. }else{
  139. LogicDebug("Deactivate");
  140. DelUpdate(&ConvexAreaDetector::Work);
  141. Unregistry(MG_ACTIVEACCEPTOR);
  142. eventExit.Activate(Mission(), false);
  143. }
  144. }
  145. }
  146. //Инициализировать объект
  147. bool ConvexAreaDetector::EditMode_Create(MOPReader & reader)
  148. {
  149. SetUpdate(&ConvexAreaDetector::EditModeWork, ML_ALPHA5);
  150. previewPoints = NEW Vertex[(ARRSIZE(plane) + 1)*4];
  151. EditMode_Update(reader);
  152. return true;
  153. }
  154. //Обновить параметры
  155. bool ConvexAreaDetector::EditMode_Update(MOPReader & reader)
  156. {
  157. Create(reader);
  158. DelUpdate(&ConvexAreaDetector::Work);
  159. //Формируем буфер для рисования тригера
  160. center = 0.0f;
  161. Vertex * backPoints = previewPoints + (pCount + 1)*2;
  162. float sgn = 0.0f;
  163. if(pCount >= 3)
  164. {
  165. sgn = (previewPoints[0].pos.x - previewPoints[2].pos.x)*(previewPoints[4].pos.z - previewPoints[2].pos.z);
  166. sgn -= (previewPoints[0].pos.z - previewPoints[2].pos.z)*(previewPoints[4].pos.x - previewPoints[2].pos.x);
  167. }
  168. for(long i = 0; i <= pCount; i++)
  169. {
  170. //Считаем среднюю точку
  171. if(i)
  172. {
  173. center += previewPoints[i*2].pos;
  174. }
  175. //Определяем выпуклость
  176. long prev = (i > 0) ? (i - 1)*2 : (pCount - 1)*2;
  177. long next = (i < pCount) ? (i + 1)*2 : 2;
  178. Vector v1 = previewPoints[prev].pos - previewPoints[i*2].pos;
  179. Vector v2 = previewPoints[next].pos - previewPoints[i*2].pos;
  180. float s = v1.x*v2.z - v1.z*v2.x;
  181. //Заполняем вершины
  182. previewPoints[i*2].pos.y = hmin;
  183. previewPoints[i*2].color = 0L;
  184. previewPoints[i*2].color.r = (s*sgn >= 0.0f) ? 0x00 : 0xff;
  185. previewPoints[i*2].color.a = (sgn >= 0.0f) ? 0x40 : 0xc0;
  186. previewPoints[i*2 + 1] = previewPoints[i*2];
  187. previewPoints[i*2 + 1].pos.y = hmax;
  188. backPoints[i*2] = previewPoints[i*2 + 1];
  189. backPoints[i*2].color.a = (sgn >= 0.0f) ? 0xc0 : 0x40;
  190. backPoints[i*2 + 1] = previewPoints[i*2];
  191. backPoints[i*2 + 1].color.a = backPoints[i*2].color.a;
  192. }
  193. //Центральная точка
  194. if(pCount)
  195. {
  196. center /= (float)pCount;
  197. }
  198. pCount = pCount*4 + 2;
  199. center.y = (hmin + hmax)*0.5f;
  200. return true;
  201. }
  202. //Получить размеры описывающего ящика
  203. void ConvexAreaDetector::EditMode_GetSelectBox(Vector & min, Vector & max)
  204. {
  205. if(previewPoints)
  206. {
  207. min = max = previewPoints[0].pos;
  208. for(long i = 0; i < pCount + 2; i++)
  209. {
  210. min.Min(previewPoints[i].pos);
  211. max.Max(previewPoints[i].pos);
  212. }
  213. }else{
  214. min = 0.0f;
  215. max = 0.0f;
  216. }
  217. }
  218. //============================================================================================
  219. //Работа детектора
  220. void _cdecl ConvexAreaDetector::Work(float dltTime, long level)
  221. {
  222. Matrix mtx, trgMtx;
  223. GetMatrix(mtx);
  224. //Анализируем
  225. bool currentInside = false;
  226. bool isAnyInside = false;
  227. for(long i = 0; i < targets; i++)
  228. {
  229. Target & trg = targets[i];
  230. currentInside |= trg.isInside;
  231. if(!trg.target.Validate())
  232. {
  233. if(trg.targetID.NotEmpty())
  234. {
  235. trg.isInside = false;
  236. FindObject(trg.targetID, trg.target);
  237. trg.targetID.Empty();
  238. }else{
  239. trg.target.Reset();
  240. }
  241. }
  242. if(!trg.target.Validate())
  243. {
  244. continue;
  245. }
  246. if(isCheckVisible)
  247. {
  248. if(!trg.target.Ptr()->IsShow())
  249. {
  250. trg.actEnter = false;
  251. trg.actExit = false;
  252. continue;
  253. }
  254. }
  255. if(isCheckActive)
  256. {
  257. if(!trg.target.Ptr()->IsActive())
  258. {
  259. trg.actEnter = false;
  260. trg.actExit = false;
  261. continue;
  262. }
  263. }
  264. Vector targetPos = mtx.MulVertexByInverse(trg.target.Ptr()->GetMatrix(trgMtx).pos);
  265. bool isInside = false;
  266. if(targetPos.y >= hmin && targetPos.y <= hmax)
  267. {
  268. for(long j = 0; j < planesCount; j++)
  269. {
  270. if((plane[j].n | targetPos) > plane[j].d)
  271. {
  272. break;
  273. }
  274. }
  275. isInside = (j >= planesCount);
  276. }
  277. if(trg.isInside != isInside)
  278. {
  279. trg.actEnter = isInside;
  280. trg.actExit = !isInside;
  281. trg.isInside = isInside;
  282. }else{
  283. trg.actEnter = false;
  284. trg.actExit = false;
  285. }
  286. isAnyInside |= isInside;
  287. }
  288. for(long i = 0; i < targets; i++)
  289. {
  290. Target & trg = targets[i];
  291. if(!trg.target.Validate()) continue;
  292. if(trg.actEnter)
  293. {
  294. LogicDebug("Enter object \"%s\"", trg.target.Ptr()->GetObjectID().c_str());
  295. trg.eventEnter.Activate(Mission(), false, trg.target.Ptr());
  296. if(thisTriggers)
  297. {
  298. LogicDebug("Triggering enter event for *this* = \"%s\"", trg.target.Ptr()->GetObjectID().c_str());
  299. eventEnter.Activate(Mission(), false, trg.target.Ptr());
  300. }
  301. }
  302. if(trg.actExit)
  303. {
  304. LogicDebug("Exit object \"%s\"", trg.target.Ptr()->GetObjectID().c_str());
  305. trg.eventExit.Activate(Mission(), false, trg.target.Ptr());
  306. if(thisTriggers)
  307. {
  308. LogicDebug("Triggering exit event for *this* = \"%s\"", trg.target.Ptr()->GetObjectID().c_str());
  309. eventExit.Activate(Mission(), false, trg.target.Ptr());
  310. }
  311. }
  312. }
  313. if(!thisTriggers && currentInside != isAnyInside)
  314. {
  315. if(isAnyInside)
  316. {
  317. LogicDebug("Triggering enter event");
  318. eventEnter.Activate(Mission(), false);
  319. }else{
  320. LogicDebug("Triggering exit event");
  321. eventExit.Activate(Mission(), false);
  322. }
  323. }
  324. }
  325. //Работа детектора в режиме редактирования
  326. void _cdecl ConvexAreaDetector::EditModeWork(float dltTime, long level)
  327. {
  328. if(!Mission().EditMode_IsAdditionalDraw()) return;
  329. if(!EditMode_IsVisible()) return;
  330. //Обновляем состояние
  331. bool res = true;
  332. for(long i = 0; i < targets; i++)
  333. {
  334. Target & trg = targets[i];
  335. if(!trg.target.Validate())
  336. {
  337. trg.isInside = false;
  338. if(!FindObject(trg.targetID, trg.target))
  339. {
  340. res = false;
  341. }
  342. }
  343. }
  344. byte g = 0;
  345. byte b = 0;
  346. if(res)
  347. {
  348. if(IsActive())
  349. {
  350. g = 0xff;
  351. b = 0x00;
  352. }else{
  353. g = 0x00;
  354. b = 0x80;
  355. }
  356. }
  357. Matrix mtx;
  358. GetMatrix(mtx);
  359. if(isDebug)
  360. {
  361. Vector targetPos = mtx.MulVertexByInverse(Render().GetView().GetCamPos());
  362. bool isInside = false;
  363. if(targetPos.y >= hmin && targetPos.y <= hmax)
  364. {
  365. for(long j = 0; j < planesCount; j++)
  366. {
  367. if((plane[j].n | targetPos) > plane[j].d)
  368. {
  369. break;
  370. }
  371. }
  372. isInside = (j >= planesCount);
  373. }
  374. if(isInside)
  375. {
  376. g = 0xff;
  377. b = 0xff;
  378. }
  379. }
  380. for(long i = 0; i < pCount + 2; i++)
  381. {
  382. previewPoints[i].color.g = g;
  383. previewPoints[i].color.b = b;
  384. }
  385. //Рисуем
  386. Render().SetWorld(mtx);
  387. ShaderId id;
  388. Render().GetShaderId("ShowDetector", id);
  389. Render().DrawPrimitiveUP(id, PT_TRIANGLESTRIP, pCount, previewPoints, sizeof(Vertex));
  390. if(EditMode_IsSelect())
  391. {
  392. Render().Print(mtx*center, -1.0f, -1.0f, 0xffffffff, "Object id: %s", GetObjectID().c_str());
  393. Render().Print(mtx*center, -1.0f, 1.0f, 0xffffffff, IsActive() ? "State: on" : "State: off");
  394. }
  395. }
  396. //============================================================================================
  397. //Параметры инициализации
  398. //============================================================================================
  399. MOP_BEGINLISTCG(ConvexAreaDetector, "Convex area detector", '1.00', 0x0fffffff, "Detector check area for some mission objects", "Logic")
  400. MOP_MISSIONTRIGGERG("Enter trigger", "Enter.")
  401. MOP_MISSIONTRIGGERG("Exit trigger", "Exit.")
  402. MOP_ARRAYBEG("Objects", 1, 1000)
  403. MOP_STRING("Object id", "Player")
  404. MOP_MISSIONTRIGGER("Enter.")
  405. MOP_MISSIONTRIGGER("Exit.")
  406. MOP_ARRAYEND
  407. MOP_POSITION("Position", Vector(0.0f))
  408. MOP_ANGLES("Angle", Vector(0.0f))
  409. MOP_STRING("Connect to object", "")
  410. MOP_ARRAYBEG("Points", 3, 16)
  411. MOP_POSITION("Point", Vector(0.0f))
  412. MOP_ARRAYEND
  413. MOP_FLOAT("Height min", -2.0f)
  414. MOP_FLOAT("Height max", 5.0f)
  415. MOP_BOOL("Check visible flag", false)
  416. MOP_BOOL("Check active flag", false)
  417. MOP_BOOLC("This triggers", false, "Activate enter/exit trigger for any object with *this* param,\nor once for any enter and once when all exit")
  418. MOP_BOOL("Active", true)
  419. MOP_BOOLC("Debug", false, "Check detector in editor with camera position")
  420. MOP_ENDLIST(ConvexAreaDetector)