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 }