1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <SDL2/SDL.h>
5
6 #include "core/gl_util.h"
7 #include "core/console.h"
8 #include "core/vmath.h"
9 #include "core/system.h"
10 #include "core/polygon.h"
11 #include "core/obb.h"
12 #include "render/frustum.h"
13 #include "physics/physics.h"
14 #include "engine.h"
15 #include "entity.h"
16 #include "mesh.h"
17 #include "trigger.h"
18 #include "room.h"
19 #include "world.h"
20
21
22 #define ROOM_LIST_SIZE_ALIGN (8)
23
24
Room_Clear(struct room_s * room)25 void Room_Clear(struct room_s *room)
26 {
27 if(!room)
28 {
29 return;
30 }
31
32 room->containers = NULL;
33 room->content = NULL;
34 room->frustum = NULL;
35
36 if(room->original_content)
37 {
38 room_content_p content = room->original_content;
39 portal_p p = content->portals;
40 if(content->portals_count)
41 {
42 for(uint16_t i = 0; i < content->portals_count; i++, p++)
43 {
44 Portal_Clear(p);
45 }
46 free(content->portals);
47 content->portals = NULL;
48 content->portals_count = 0;
49 }
50
51 if(content->mesh)
52 {
53 BaseMesh_Clear(content->mesh);
54 free(content->mesh);
55 content->mesh = NULL;
56 }
57
58 if(content->static_mesh_count)
59 {
60 for(uint32_t i = 0; i < content->static_mesh_count; i++)
61 {
62 Physics_DeleteObject(content->static_mesh[i].physics_body);
63 content->static_mesh[i].physics_body = NULL;
64
65 OBB_Delete(content->static_mesh[i].obb);
66 content->static_mesh[i].obb = NULL;
67 if(content->static_mesh[i].self)
68 {
69 content->static_mesh[i].self->room = NULL;
70 Container_Delete(content->static_mesh[i].self);
71 content->static_mesh[i].self = NULL;
72 }
73 }
74 free(content->static_mesh);
75 content->static_mesh = NULL;
76 content->static_mesh_count = 0;
77 }
78
79 Physics_DeleteObject(content->physics_body);
80 content->physics_body = NULL;
81 Physics_DeleteObject(content->physics_alt_tween);
82 content->physics_alt_tween = NULL;
83
84 if(content->sprites_count)
85 {
86 free(content->sprites);
87 content->sprites = NULL;
88 content->sprites_count = 0;
89 }
90
91 if(content->sprites_vertices)
92 {
93 free(content->sprites_vertices);
94 content->sprites_vertices = NULL;
95 }
96
97 if(content->lights_count)
98 {
99 free(content->lights);
100 content->lights = NULL;
101 content->lights_count = 0;
102 }
103
104 if(room->sectors_count)
105 {
106 room_sector_p s = content->sectors;
107 for(uint32_t i = 0; i < room->sectors_count; i++, s++)
108 {
109 if(s->trigger)
110 {
111 for(trigger_command_p current_command = s->trigger->commands; current_command; )
112 {
113 trigger_command_p next_command = current_command->next;
114 current_command->next = NULL;
115 free(current_command);
116 current_command = next_command;
117 }
118 free(s->trigger);
119 s->trigger = NULL;
120 }
121 }
122 free(content->sectors);
123 content->sectors = NULL;
124 room->sectors_count = 0;
125 room->sectors_x = 0;
126 room->sectors_y = 0;
127 }
128
129 if(content->overlapped_room_list)
130 {
131 content->overlapped_room_list_size = 0;
132 free(content->overlapped_room_list);
133 content->overlapped_room_list = NULL;
134 }
135
136 if(content->near_room_list)
137 {
138 content->near_room_list_size = 0;
139 free(content->near_room_list);
140 content->near_room_list = NULL;
141 }
142
143 free(content);
144 }
145 room->original_content = NULL;
146
147 if(room->obb)
148 {
149 OBB_Delete(room->obb);
150 room->obb = NULL;
151 }
152
153 if(room->self)
154 {
155 room->self->room = NULL;
156 Container_Delete(room->self);
157 room->self = NULL;
158 }
159 }
160
161
Room_Enable(struct room_s * room)162 void Room_Enable(struct room_s *room)
163 {
164 if(room->content->physics_body != NULL)
165 {
166 Physics_EnableObject(room->content->physics_body);
167 }
168
169 if(room->content->physics_alt_tween)
170 {
171 Physics_DisableObject(room->content->physics_alt_tween);
172 }
173
174 for(uint32_t i = 0; i < room->content->static_mesh_count; i++)
175 {
176 if(room->content->static_mesh[i].physics_body != NULL)
177 {
178 Physics_EnableObject(room->content->static_mesh[i].physics_body);
179 }
180 }
181
182 for(engine_container_p cont = room->containers; cont; cont = cont->next)
183 {
184 if(cont->collision_group == COLLISION_NONE)
185 {
186 continue;
187 }
188 switch(cont->object_type)
189 {
190 case OBJECT_ENTITY:
191 if(((entity_p)cont->object)->state_flags & ENTITY_STATE_ENABLED)
192 {
193 Physics_EnableCollision(((entity_p)cont->object)->physics);
194 }
195 break;
196 }
197 }
198 }
199
200
Room_Disable(struct room_s * room)201 void Room_Disable(struct room_s *room)
202 {
203 if(room->content->physics_body)
204 {
205 Physics_DisableObject(room->content->physics_body);
206 }
207
208 if(room->content->physics_alt_tween)
209 {
210 Physics_DisableObject(room->content->physics_alt_tween);
211 }
212
213 for(uint32_t i = 0; i < room->content->static_mesh_count; i++)
214 {
215 if(room->content->static_mesh[i].physics_body)
216 {
217 Physics_DisableObject(room->content->static_mesh[i].physics_body);
218 }
219 }
220
221 for(engine_container_p cont = room->containers; cont; cont = cont->next)
222 {
223 switch(cont->object_type)
224 {
225 case OBJECT_ENTITY:
226 if(((entity_p)cont->object)->state_flags & ENTITY_STATE_ENABLED)
227 {
228 Physics_DisableCollision(((entity_p)cont->object)->physics);
229 }
230 break;
231 }
232 }
233 }
234
235
Room_AddObject(struct room_s * room,struct engine_container_s * cont)236 int Room_AddObject(struct room_s *room, struct engine_container_s *cont)
237 {
238 engine_container_p curr = room->containers;
239
240 for(; curr; curr = curr->next)
241 {
242 if(curr == cont)
243 {
244 return 0;
245 }
246 }
247
248 cont->room = room;
249 cont->next = room->containers;
250 room->containers = cont;
251 return 1;
252 }
253
254
Room_RemoveObject(struct room_s * room,struct engine_container_s * cont)255 int Room_RemoveObject(struct room_s *room, struct engine_container_s *cont)
256 {
257 engine_container_p previous_cont, current_cont;
258
259 if(!room || !room->containers)
260 {
261 return 0;
262 }
263
264 if(room->containers == cont)
265 {
266 room->containers = cont->next;
267 cont->room = NULL;
268 return 1;
269 }
270
271 previous_cont = room->containers;
272 current_cont = previous_cont->next;
273 while(current_cont)
274 {
275 if(current_cont == cont)
276 {
277 previous_cont->next = current_cont->next;
278 cont->room = NULL;
279 return 1;
280 }
281
282 previous_cont = current_cont;
283 current_cont = current_cont->next;
284 }
285
286 return 0;
287 }
288
289
Room_SetActiveContent(struct room_s * room,struct room_s * room_with_content_from)290 void Room_SetActiveContent(struct room_s *room, struct room_s *room_with_content_from)
291 {
292 engine_container_p cont = room->containers;
293 room->containers = NULL;
294 room->content = room_with_content_from->original_content;
295 Physics_SetOwnerObject(room->content->physics_body, room->self);
296 Physics_SetOwnerObject(room->content->physics_alt_tween, room->self);
297
298 for(uint32_t i = 0; i < room->content->static_mesh_count; ++i)
299 {
300 room->content->static_mesh[i].self->room = room;
301 }
302
303 for(uint32_t i = 0; i < room->sectors_count; ++i)
304 {
305 room->content->sectors[i].owner_room = room;
306 }
307
308 if(room == room->real_room)
309 {
310 Room_Enable(room);
311 }
312 else
313 {
314 Room_Disable(room);
315 }
316
317 room->containers = cont;
318 }
319
320
Room_DoFlip(struct room_s * room1,struct room_s * room2)321 void Room_DoFlip(struct room_s *room1, struct room_s *room2)
322 {
323 if(room1 && room2 && (room1 != room2))
324 {
325 room1->frustum = NULL;
326 room2->frustum = NULL;
327
328 // swap content
329 {
330 room_content_p t = room1->content;
331 room1->content = room2->content;
332 room2->content = t;
333
334 // fix physics
335 Physics_SetOwnerObject(room1->content->physics_body, room1->self);
336 Physics_SetOwnerObject(room1->content->physics_alt_tween, room1->self);
337 Physics_SetOwnerObject(room2->content->physics_body, room2->self);
338 Physics_SetOwnerObject(room2->content->physics_alt_tween, room2->self);
339
340 // fix static meshes
341 for(uint32_t i = 0; i < room1->content->static_mesh_count; ++i)
342 {
343 room1->content->static_mesh[i].self->room = room1;
344 }
345 for(uint32_t i = 0; i < room2->content->static_mesh_count; ++i)
346 {
347 room2->content->static_mesh[i].self->room = room2;
348 }
349
350 // update enability if it is necessary
351 {
352 room_p base_room = (room1 == room1->real_room) ? room1 : NULL;
353 base_room = (room2 == room2->real_room) ? room2 : room1;
354 if(base_room)
355 {
356 engine_container_p cont = base_room->containers;
357 base_room->containers = NULL;
358 room_p alt_room = (room1 == base_room) ? room2 : room1;
359 Room_Disable(alt_room);
360 Room_Enable(base_room); // enable new collisions
361 base_room->containers = cont;
362 }
363 }
364
365 // fix sectors ownership
366 for(uint32_t i = 0; i < room1->sectors_count; ++i)
367 {
368 room1->content->sectors[i].owner_room = room1;
369 }
370
371 for(uint32_t i = 0; i < room2->sectors_count; ++i)
372 {
373 room2->content->sectors[i].owner_room = room2;
374 }
375 }
376 }
377 }
378
379
Room_GetSectorRaw(struct room_s * room,float pos[3])380 struct room_sector_s *Room_GetSectorRaw(struct room_s *room, float pos[3])
381 {
382 if(room)
383 {
384 int x = (int)(pos[0] - room->transform[12 + 0]) / TR_METERING_SECTORSIZE;
385 int y = (int)(pos[1] - room->transform[12 + 1]) / TR_METERING_SECTORSIZE;
386 if(x < 0 || x >= room->sectors_x || y < 0 || y >= room->sectors_y)
387 {
388 return NULL;
389 }
390 /*
391 * column index system
392 * X - column number, Y - string number
393 */
394 return room->content->sectors + x * room->sectors_y + y;
395 }
396
397 return NULL;
398 }
399
400
Room_GetSectorXYZ(struct room_s * room,float pos[3])401 struct room_sector_s *Room_GetSectorXYZ(struct room_s *room, float pos[3])
402 {
403 room_sector_p ret = NULL;
404 int x = (int)(pos[0] - room->transform[12 + 0]) / TR_METERING_SECTORSIZE;
405 int y = (int)(pos[1] - room->transform[12 + 1]) / TR_METERING_SECTORSIZE;
406
407 room = room->real_room;
408
409 if(x < 0 || x >= room->sectors_x || y < 0 || y >= room->sectors_y)
410 {
411 return NULL;
412 }
413 /*
414 * column index system
415 * X - column number, Y - string number
416 */
417 ret = room->content->sectors + x * room->sectors_y + y;
418
419 /*
420 * resolve Z overlapped neighboard rooms. room below has more priority.
421 */
422 if(ret->room_below && (pos[2] < ret->floor))
423 {
424 ret = Room_GetSectorRaw(ret->room_below->real_room, ret->pos);
425 }
426
427 if(ret->room_above && (pos[2] > ret->ceiling))
428 {
429 ret = Room_GetSectorRaw(ret->room_above->real_room, ret->pos);
430 }
431
432 return ret;
433 }
434
435
Room_AddToNearRoomsList(struct room_s * room,struct room_s * r)436 void Room_AddToNearRoomsList(struct room_s *room, struct room_s *r)
437 {
438 if(room && r && (r->real_room->id != room->real_room->id) &&
439 (room->bb_min[0] <= r->bb_max[0] && room->bb_max[0] >= r->bb_min[0]) &&
440 (room->bb_min[1] <= r->bb_max[1] && room->bb_max[1] >= r->bb_min[1]))
441 {
442 for(uint32_t i = 0; i < room->content->near_room_list_size; ++i)
443 {
444 if(room->content->near_room_list[i]->id == r->id)
445 {
446 return;
447 }
448 }
449
450 if(!Room_IsOverlapped(room, r))
451 {
452 if(!room->content->near_room_list)
453 {
454 room->content->near_room_list = (room_p*)malloc(ROOM_LIST_SIZE_ALIGN * sizeof(room_p));
455 }
456 else if((room->content->near_room_list_size + 1) % ROOM_LIST_SIZE_ALIGN == 0)
457 {
458 room_p *old_list = room->content->near_room_list;
459 uint16_t rooms_count = room->content->near_room_list_size + 1 + ROOM_LIST_SIZE_ALIGN;
460 room->content->near_room_list = (room_p*)malloc(rooms_count * sizeof(room_p));
461 memcpy(room->content->near_room_list, old_list, room->content->near_room_list_size * sizeof(room_p));
462 free(old_list);
463 }
464 room->content->near_room_list[room->content->near_room_list_size++] = r->real_room;
465 }
466 }
467 }
468
469
Room_AddToOverlappedRoomsList(struct room_s * room,struct room_s * r)470 void Room_AddToOverlappedRoomsList(struct room_s *room, struct room_s *r)
471 {
472 for(uint32_t i = 0; i < room->content->overlapped_room_list_size; ++i)
473 {
474 if(room->content->overlapped_room_list[i]->id == r->id)
475 {
476 return;
477 }
478 }
479
480 if(!room->content->overlapped_room_list)
481 {
482 room->content->overlapped_room_list = (room_p*)malloc(ROOM_LIST_SIZE_ALIGN * sizeof(room_p));
483 }
484 else if((room->content->overlapped_room_list_size + 1) % ROOM_LIST_SIZE_ALIGN == 0)
485 {
486 room_p *old_list = room->content->overlapped_room_list;
487 uint16_t rooms_count = room->content->overlapped_room_list_size + 1 + ROOM_LIST_SIZE_ALIGN;
488 room->content->overlapped_room_list = (room_p*)malloc(rooms_count * sizeof(room_p));
489 memcpy(room->content->overlapped_room_list, old_list, room->content->overlapped_room_list_size * sizeof(room_p));
490 free(old_list);
491 }
492 room->content->overlapped_room_list[room->content->overlapped_room_list_size++] = r->real_room;
493 }
494
495
Room_IsJoined(struct room_s * r1,struct room_s * r2)496 int Room_IsJoined(struct room_s *r1, struct room_s *r2)
497 {
498 room_sector_p rs = r1->content->sectors;
499 for(uint32_t i = 0; i < r1->sectors_count; i++, rs++)
500 {
501 if((rs->portal_to_room == r2->real_room) ||
502 (rs->room_above == r2->real_room) ||
503 (rs->room_below == r2->real_room))
504 {
505 return 1;
506 }
507 }
508
509 rs = r2->content->sectors;
510 for(uint32_t i = 0; i < r2->sectors_count; i++, rs++)
511 {
512 if((rs->portal_to_room == r1->real_room) ||
513 (rs->room_above == r1->real_room) ||
514 (rs->room_below == r1->real_room))
515 {
516 return 1;
517 }
518 }
519
520 return 0;
521 }
522
523
Room_IsOverlapped(struct room_s * r0,struct room_s * r1)524 int Room_IsOverlapped(struct room_s *r0, struct room_s *r1)
525 {
526 if((r0 == r1) || (r0->real_room == r1->real_room))
527 {
528 return 0;
529 }
530
531 if(r0->bb_min[0] >= r1->bb_max[0] || r0->bb_max[0] <= r1->bb_min[0] ||
532 r0->bb_min[1] >= r1->bb_max[1] || r0->bb_max[1] <= r1->bb_min[1] ||
533 r0->bb_min[2] >= r1->bb_max[2] || r0->bb_max[2] <= r1->bb_min[2])
534 {
535 return 0;
536 }
537
538 room_sector_p rs = r0->content->sectors;
539 for(uint32_t i = 0; i < r0->sectors_count; i++, rs++)
540 {
541 if((rs->room_above == r1->real_room) ||
542 (rs->room_below == r1->real_room))
543 {
544 return 0;
545 }
546 }
547
548 rs = r1->content->sectors;
549 for(uint32_t i = 0; i < r1->sectors_count; i++, rs++)
550 {
551 if((rs->room_above == r0->real_room) ||
552 (rs->room_below == r0->real_room))
553 {
554 return 0;
555 }
556 }
557
558 return 1;
559 }
560
561
Room_IsInNearRoomsList(struct room_s * r0,struct room_s * r1)562 int Room_IsInNearRoomsList(struct room_s *r0, struct room_s *r1)
563 {
564 if(r0 && r1)
565 {
566 if(r0->id == r1->id)
567 {
568 return 1;
569 }
570
571 for(uint16_t i = 0; i < r0->content->near_room_list_size; i++)
572 {
573 if(r0->content->near_room_list[i]->real_room->id == r1->real_room->id)
574 {
575 return 1;
576 }
577 }
578 }
579
580 return 0;
581 }
582
583
Room_IsInOverlappedRoomsList(struct room_s * r0,struct room_s * r1)584 int Room_IsInOverlappedRoomsList(struct room_s *r0, struct room_s *r1)
585 {
586 if(r0 && r1 && (r0->id != r1->id))
587 {
588 for(uint16_t i = 0; i < r0->content->overlapped_room_list_size; i++)
589 {
590 if(r0->content->overlapped_room_list[i]->real_room->id == r1->real_room->id)
591 {
592 return 1;
593 }
594 }
595 }
596
597 return 0;
598 }
599
600
Room_MoveActiveItems(struct room_s * room_to,struct room_s * room_from)601 void Room_MoveActiveItems(struct room_s *room_to, struct room_s *room_from)
602 {
603 engine_container_p t = room_from->containers;
604
605 room_from->containers = NULL;
606 for(; t; t = t->next)
607 {
608 t->room = room_to;
609 t->next = room_to->containers;
610 room_to->containers = t;
611 }
612 }
613
614
Room_GenSpritesBuffer(struct room_s * room)615 void Room_GenSpritesBuffer(struct room_s *room)
616 {
617 room->content->sprites_vertices = NULL;
618
619 if(room->content->sprites_count > 0)
620 {
621 room->content->sprites_vertices = (vertex_p)malloc(room->content->sprites_count * 4 * sizeof(vertex_t));
622 for(uint32_t i = 0; i < room->content->sprites_count; i++)
623 {
624 room_sprite_p s = room->content->sprites + i;
625 if(s->sprite)
626 {
627 vertex_p v = room->content->sprites_vertices + i * 4;
628 vec4_set_one(v[0].color);
629 vec4_set_one(v[1].color);
630 vec4_set_one(v[2].color);
631 vec4_set_one(v[3].color);
632 v[0].tex_coord[0] = s->sprite->tex_coord[0];
633 v[0].tex_coord[1] = s->sprite->tex_coord[1];
634 v[1].tex_coord[0] = s->sprite->tex_coord[2];
635 v[1].tex_coord[1] = s->sprite->tex_coord[3];
636 v[2].tex_coord[0] = s->sprite->tex_coord[4];
637 v[2].tex_coord[1] = s->sprite->tex_coord[5];
638 v[3].tex_coord[0] = s->sprite->tex_coord[6];
639 v[3].tex_coord[1] = s->sprite->tex_coord[7];
640 }
641 }
642 }
643 }
644
645
646 /*
647 * Sectors functionality
648 */
Sector_GetNextSector(struct room_sector_s * rs,float dir[3])649 struct room_sector_s *Sector_GetNextSector(struct room_sector_s *rs, float dir[3])
650 {
651 int ind_x = rs->index_x;
652 int ind_y = rs->index_y;
653 room_p r = rs->owner_room;
654
655 if(fabs(dir[0]) > fabs(dir[1]))
656 {
657 ind_x += (dir[0] > 0.0f) ? (1) : (-1);
658 ind_x = ((ind_x >= 0) && (ind_x < r->sectors_x)) ? (ind_x) : (rs->index_x);
659 }
660 else
661 {
662 ind_y += (dir[1] > 0.0f) ? (1) : (-1);
663 ind_y = ((ind_y >= 0) && (ind_y < r->sectors_y)) ? (ind_y) : (rs->index_y);
664 }
665
666 return r->content->sectors + (ind_x * r->sectors_y + ind_y);
667 }
668
669
Sector_GetPortalSectorTargetRaw(struct room_sector_s * rs)670 struct room_sector_s *Sector_GetPortalSectorTargetRaw(struct room_sector_s *rs)
671 {
672 if(rs && rs->portal_to_room)
673 {
674 room_p r = rs->portal_to_room;
675 int ind_x = (rs->pos[0] - r->transform[12 + 0]) / TR_METERING_SECTORSIZE;
676 int ind_y = (rs->pos[1] - r->transform[12 + 1]) / TR_METERING_SECTORSIZE;
677 if((ind_x >= 0) && (ind_x < r->sectors_x) && (ind_y >= 0) && (ind_y < r->sectors_y))
678 {
679 rs = r->content->sectors + (ind_x * r->sectors_y + ind_y);
680 }
681 }
682
683 return rs;
684 }
685
686
Sector_GetLowest(struct room_sector_s * sector)687 struct room_sector_s *Sector_GetLowest(struct room_sector_s *sector)
688 {
689 for(; sector && sector->room_below; sector = Room_GetSectorRaw(sector->room_below->real_room, sector->pos));
690
691 return sector;
692 }
693
694
Sector_GetHighest(struct room_sector_s * sector)695 struct room_sector_s *Sector_GetHighest(struct room_sector_s *sector)
696 {
697 for(; sector && sector->room_above; sector = Room_GetSectorRaw(sector->room_above->real_room, sector->pos));
698
699 return sector;
700 }
701
702
Sector_HighestFloorCorner(room_sector_p rs,float v[3])703 void Sector_HighestFloorCorner(room_sector_p rs, float v[3])
704 {
705 float *r1 = (rs->floor_corners[0][2] > rs->floor_corners[1][2]) ? (rs->floor_corners[0]) : (rs->floor_corners[1]);
706 float *r2 = (rs->floor_corners[2][2] > rs->floor_corners[3][2]) ? (rs->floor_corners[2]) : (rs->floor_corners[3]);
707
708 if(r1[2] > r2[2])
709 {
710 vec3_copy(v, r1);
711 }
712 else
713 {
714 vec3_copy(v, r2);
715 }
716 }
717
718
Sector_LowestCeilingCorner(room_sector_p rs,float v[3])719 void Sector_LowestCeilingCorner(room_sector_p rs, float v[3])
720 {
721 float *r1 = (rs->ceiling_corners[0][2] > rs->ceiling_corners[1][2]) ? (rs->ceiling_corners[0]) : (rs->ceiling_corners[1]);
722 float *r2 = (rs->ceiling_corners[2][2] > rs->ceiling_corners[3][2]) ? (rs->ceiling_corners[2]) : (rs->ceiling_corners[3]);
723
724 if(r1[2] < r2[2])
725 {
726 vec3_copy(v, r1);
727 }
728 else
729 {
730 vec3_copy(v, r2);
731 }
732 }
733
734
Sectors_SimilarFloor(room_sector_p s1,room_sector_p s2,int ignore_doors)735 int Sectors_SimilarFloor(room_sector_p s1, room_sector_p s2, int ignore_doors)
736 {
737 if(!s1 || !s2) return 0;
738 if( s1 == s2) return 1;
739
740 if( (s1->floor != s2->floor) ||
741 (s1->floor_penetration_config == TR_PENETRATION_CONFIG_WALL) ||
742 (s2->floor_penetration_config == TR_PENETRATION_CONFIG_WALL) ||
743 (!ignore_doors && (s1->room_below || s2->room_below)) )
744 {
745 return 0;
746 }
747
748 for(int i = 0; i < 4; i++)
749 {
750 if(s1->floor_corners[i][2] != s2->floor_corners[i][2])
751 {
752 return 0;
753 }
754 }
755
756 return 1;
757 }
758
759
Sectors_SimilarCeiling(room_sector_p s1,room_sector_p s2,int ignore_doors)760 int Sectors_SimilarCeiling(room_sector_p s1, room_sector_p s2, int ignore_doors)
761 {
762 if(!s1 || !s2) return 0;
763 if( s1 == s2) return 1;
764
765 if( (s1->ceiling != s2->ceiling) ||
766 (s1->ceiling_penetration_config == TR_PENETRATION_CONFIG_WALL) ||
767 (s2->ceiling_penetration_config == TR_PENETRATION_CONFIG_WALL) ||
768 (!ignore_doors && (s1->room_above || s2->room_above)) )
769 {
770 return 0;
771 }
772
773 for(int i = 0; i < 4; i++)
774 {
775 if(s1->ceiling_corners[i][2] != s2->ceiling_corners[i][2])
776 {
777 return 0;
778 }
779 }
780
781 return 1;
782 }
783
784
785 /////////////////////////////////////////
Room_IsBoxForPath(room_box_p curr_box,room_box_p next_box,box_validition_options_p op)786 static bool Room_IsBoxForPath(room_box_p curr_box, room_box_p next_box, box_validition_options_p op)
787 {
788 if(next_box && !next_box->is_blocked)
789 {
790 room_zone_p zone = (op->zone_alt) ? (next_box->zone + 1) : (next_box->zone);
791 int32_t step = next_box->bb_min[2] - curr_box->bb_min[2];
792 if((op->zone_type == ZONE_TYPE_FLY) || ((step >= 0) ? (step - op->step_up <= 1.0f) : (-1.0f <= step + op->step_down)))
793 {
794 switch(op->zone_type)
795 {
796 case ZONE_TYPE_ALL:
797 return true;
798
799 case ZONE_TYPE_FLY:
800 return zone->FlyZone;
801
802 case ZONE_TYPE_1:
803 return zone->GroundZone1;
804
805 case ZONE_TYPE_2:
806 return zone->GroundZone2;
807
808 case ZONE_TYPE_3:
809 return zone->GroundZone3;
810
811 case ZONE_TYPE_4:
812 return zone->GroundZone4;
813 }
814 }
815 }
816 return false;
817 }
818
819
Room_IsInBox(room_box_p box,float pos[3])820 int Room_IsInBox(room_box_p box, float pos[3])
821 {
822 return (box->bb_min[0] <= pos[0]) && (pos[0] <= box->bb_max[0]) &&
823 (box->bb_min[1] <= pos[1]) && (pos[1] <= box->bb_max[1]);
824 }
825
826
Room_FindPath(room_box_p * path_buf,uint32_t max_boxes,room_sector_p from,room_sector_p to,box_validition_options_p op)827 int Room_FindPath(room_box_p *path_buf, uint32_t max_boxes, room_sector_p from, room_sector_p to, box_validition_options_p op)
828 {
829 int ret = 0;
830 if(from->box && to->box)
831 {
832 if(from->box->id != to->box->id)
833 {
834 float pt_from[3], pt_to[3];
835 const int buf_size = sizeof(room_box_p) * max_boxes;
836 room_box_p *current_front = (room_box_p*)Sys_GetTempMem(3 * buf_size);
837 room_box_p *next_front = current_front + max_boxes;
838 room_box_p *parents = next_front + max_boxes;
839 int32_t *weights = (int32_t*)Sys_GetTempMem(max_boxes * sizeof(int32_t));
840 size_t current_front_size = 1;
841 size_t next_front_size = 0;
842
843 current_front[0] = from->box;
844 weights[current_front[0]->id] = 0;
845 memset(parents, 0x00, buf_size);
846
847 while(current_front_size > 0)
848 {
849 for(size_t i = 0; i < current_front_size; ++i)
850 {
851 room_box_p current_box = current_front[i];
852 box_overlap_p ov = current_box->overlaps;
853 if(parents[current_box->id])
854 {
855 Room_GetOverlapCenter(parents[current_box->id], current_box, pt_from);
856 }
857 else
858 {
859 vec3_copy(pt_from, from->pos);
860 }
861
862 while(ov)
863 {
864 room_box_p next_box = World_GetRoomBoxByID(ov->box);
865 Room_GetOverlapCenter(current_box, next_box, pt_to);
866 int32_t weight = (fabs(pt_to[0] - pt_from[0]) + fabs(pt_to[1] - pt_from[1]) + 1.0f) / TR_METERING_STEP;
867 if((next_box->id != from->box->id) && Room_IsBoxForPath(current_box, next_box, op) &&
868 (!parents[to->box->id] || (weights[current_box->id] + weight < weights[to->box->id])))
869 {
870 if(!parents[next_box->id])
871 {
872 next_front[next_front_size++] = next_box;
873 parents[next_box->id] = current_box;
874 weights[next_box->id] = weights[current_box->id] + weight;
875 }
876 else if(weights[next_box->id] > weights[current_box->id] + weight)
877 {
878 bool not_in_front = true;
879 parents[next_box->id] = current_box;
880 weights[next_box->id] = weights[current_box->id] + weight;
881 for(size_t j = 0; j < next_front_size; ++j)
882 {
883 if(next_front[j]->id == next_box->id)
884 {
885 not_in_front = false;
886 break;
887 }
888 }
889
890 if(not_in_front)
891 {
892 next_front[next_front_size++] = next_box;
893 }
894 }
895 }
896
897 if(ov->end)
898 {
899 break;
900 }
901 ov++;
902 }
903 }
904
905 ///SWAP FRONTS HERE
906 {
907 room_box_p *tn = current_front;
908 current_front = next_front;
909 current_front_size = next_front_size;
910 next_front = tn;
911 next_front_size = 0;
912 }
913 }
914
915 if(parents[to->box->id])
916 {
917 room_box_p p = to->box;
918 while(p)
919 {
920 path_buf[ret++] = p;
921 p = parents[p->id];
922 }
923 }
924
925 Sys_ReturnTempMem(3 * buf_size + max_boxes * sizeof(int32_t));
926 }
927 else
928 {
929 path_buf[0] = from->box;
930 ret = 1;
931 }
932 }
933
934 return ret;
935 }
936
937
Room_GetOverlapCenter(room_box_p b1,room_box_p b2,float pos[3])938 void Room_GetOverlapCenter(room_box_p b1, room_box_p b2, float pos[3])
939 {
940 pos[0] = (b1->bb_min[0] > b2->bb_min[0]) ? (b1->bb_min[0]) : (b2->bb_min[0]);
941 pos[0] += (b1->bb_max[0] > b2->bb_max[0]) ? (b2->bb_max[0]) : (b1->bb_max[0]);
942 pos[0] *= 0.5f;
943 pos[1] = (b1->bb_min[1] > b2->bb_min[1]) ? (b1->bb_min[1]) : (b2->bb_min[1]);
944 pos[1] += (b1->bb_max[1] > b2->bb_max[1]) ? (b2->bb_max[1]) : (b1->bb_max[1]);
945 pos[1] *= 0.5f;
946 pos[2] = 0.5f * (b1->bb_min[2] + b2->bb_min[2] + TR_METERING_SECTORSIZE);
947 }