1 
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <SDL2/SDL.h>
5 #include <SDL2/SDL_rwops.h>
6 
7 extern "C" {
8 #include <lua.h>
9 #include <lualib.h>
10 #include <lauxlib.h>
11 }
12 
13 #include "core/avl.h"
14 #include "core/gl_util.h"
15 #include "core/console.h"
16 #include "core/system.h"
17 #include "core/vmath.h"
18 #include "core/polygon.h"
19 #include "core/obb.h"
20 #include "render/camera.h"
21 #include "render/frustum.h"
22 #include "render/render.h"
23 #include "render/bordered_texture_atlas.h"
24 #include "audio/audio.h"
25 #include "script/script.h"
26 #include "state_control/state_control.h"
27 #include "physics/physics.h"
28 #include "gui/gui.h"
29 #include "gui/gui_inventory.h"
30 #include "vt/vt_level.h"
31 #include "room.h"
32 #include "world.h"
33 #include "mesh.h"
34 #include "skeletal_model.h"
35 #include "entity.h"
36 #include "character_controller.h"
37 #include "engine.h"
38 #include "gameflow.h"
39 #include "resource.h"
40 #include "inventory.h"
41 #include "trigger.h"
42 
43 
44  struct world_s
45 {
46     char                           *name;
47     uint32_t                        id;
48     uint32_t                        version;
49 
50     uint32_t                        rooms_count;
51     struct room_s                  *rooms;
52 
53     uint32_t                        room_boxes_count;
54     struct room_box_s              *room_boxes;
55 
56     struct box_overlap_s           *overlaps;
57     uint32_t                        overlaps_count;
58 
59     uint32_t                        flip_count;             // Number of flips
60     uint8_t                        *flip_map;               // Flipped room activity array.
61     uint8_t                        *flip_state;             // Flipped room state array.
62     uint16_t                        global_flip_state;
63 
64     bordered_texture_atlas         *tex_atlas;
65     uint32_t                        tex_count;              // Number of textures
66     GLuint                         *textures;               // OpenGL textures indexes
67 
68     uint32_t                        anim_sequences_count;   // Animated texture sequence count
69     struct anim_seq_s              *anim_sequences;         // Animated textures
70 
71     uint32_t                        meshes_count;           // Base meshes count
72     struct base_mesh_s             *meshes;                 // Base meshes data
73 
74     uint32_t                        sprites_count;          // Base sprites count
75     struct sprite_s                *sprites;                // Base sprites data
76 
77     uint32_t                        skeletal_models_count;  // number of base skeletal models
78     struct skeletal_model_s        *skeletal_models;        // base skeletal models data
79 
80     struct entity_s                *player;                 // this is an unique Lara's pointer =)
81     struct skeletal_model_s        *sky_box;                // global skybox
82 
83     struct avl_header_s             entity_tree;
84     struct avl_header_s             items_tree;
85 
86     uint32_t                        type;
87 
88     uint32_t                        cameras_sinks_count;    // Amount of cameras and sinks.
89     struct static_camera_sink_s    *cameras_sinks;          // Cameras and sinks.
90     uint32_t                        flyby_frames_count;
91     struct camera_frame_s          *flyby_frames;
92     uint32_t                        cinematic_frames_count;
93     struct camera_frame_s          *cinematic_frames;
94     struct flyby_camera_sequence_s *flyby_camera_sequences;
95 } global_world;
96 
97 
98 // private load level functions prototipes:
99 void World_SetEntityModelProperties(struct entity_s *ent);
100 void World_SetStaticMeshProperties(struct static_mesh_s *r_static);
101 void World_SetEntityFunction(struct entity_s *ent);
102 void World_ScriptsOpen(const char *path);
103 void World_AutoexecOpen();
104 // Create entity function from script, if exists.
105 bool Res_CreateEntityFunc(lua_State *lua, const char* func_name, int entity_id);
106 
107 
108 void World_GenTextures(class VT_Level *tr);
109 void World_GenAnimTextures(class VT_Level *tr);
110 void World_GenMeshes(class VT_Level *tr);
111 void World_GenSprites(class VT_Level *tr);
112 void World_GenBoxes(class VT_Level *tr);
113 void World_GenCameras(class VT_Level *tr);
114 void World_GenCinematicCameras(class VT_Level *tr);
115 void World_GenFlyByCameras(class VT_Level *tr);
116 void World_GenRoom(struct room_s *room, class VT_Level *tr);
117 void World_GenRooms(class VT_Level *tr);
118 void World_GenRoomFlipMap();
119 void World_GenSkeletalModels(class VT_Level *tr);
120 void World_GenEntities(class VT_Level *tr);
121 void World_GenBaseItems();
122 void World_GenSpritesBuffer();
123 void World_GenRoomProperties(class VT_Level *tr);
124 void World_GenRoomCollision();
125 void World_FixRooms();
126 void World_BuildNearRoomsList(struct room_s *room);
127 void World_BuildOverlappedRoomsList(struct room_s *room);
128 
AVL_DeleteEntity(void * p)129 extern "C" void AVL_DeleteEntity(void *p) { Entity_Delete((entity_p)p); }
AVL_DeleteItem(void * p)130 extern "C" void AVL_DeleteItem(void *p) { BaseItem_Delete((base_item_p)p); }
131 
World_Prepare()132 void World_Prepare()
133 {
134     global_world.id = 0;
135     global_world.name = NULL;
136     global_world.type = 0x00;
137     global_world.meshes = NULL;
138     global_world.meshes_count = 0;
139     global_world.sprites = NULL;
140     global_world.sprites_count = 0;
141     global_world.rooms_count = 0;
142     global_world.rooms = 0;
143     global_world.flip_map = NULL;
144     global_world.flip_state = NULL;
145     global_world.flip_count = 0;
146     global_world.global_flip_state = 0;
147     global_world.textures = NULL;
148     global_world.type = 0;
149     global_world.player = NULL;
150 
151     global_world.anim_sequences = NULL;
152     global_world.anim_sequences_count = 0;
153 
154     global_world.tex_count = 0;
155     global_world.textures = 0;
156     global_world.room_boxes = NULL;
157     global_world.room_boxes_count = 0;
158     global_world.overlaps = NULL;
159     global_world.overlaps_count = 0;
160     global_world.cameras_sinks = NULL;
161     global_world.cameras_sinks_count = 0;
162     global_world.flyby_frames = NULL;
163     global_world.flyby_frames_count = 0;
164     global_world.cinematic_frames = NULL;
165     global_world.cinematic_frames_count = 0;
166     global_world.flyby_camera_sequences = NULL;
167     global_world.skeletal_models = NULL;
168     global_world.skeletal_models_count = 0;
169     global_world.sky_box = NULL;
170     AVL_Init(&global_world.entity_tree);
171     global_world.entity_tree.free_data = AVL_DeleteEntity;
172     AVL_Init(&global_world.items_tree);
173     global_world.items_tree.free_data = AVL_DeleteItem;
174 }
175 
176 
World_Open(const char * path,int trv)177 void World_Open(const char *path, int trv)
178 {
179     VT_Level *tr = new VT_Level();
180     tr->read_level(path, trv);
181     tr->prepare_level();
182     //tr_level->dump_textures();
183     World_Clear();
184 
185     global_world.version = tr->game_version;
186 
187     World_ScriptsOpen(path);            // Open configuration scripts.
188     Gui_DrawLoadScreen(200);
189 
190     World_GenTextures(tr);              // Generate OGL textures
191     Gui_DrawLoadScreen(300);
192 
193     World_GenAnimTextures(tr);          // Generate animated textures
194     Gui_DrawLoadScreen(320);
195 
196     World_GenMeshes(tr);                // Generate all meshes
197     Gui_DrawLoadScreen(400);
198 
199     World_GenSprites(tr);               // Generate all sprites
200     Gui_DrawLoadScreen(420);
201 
202     World_GenBoxes(tr);                 // Generate boxes.
203     Gui_DrawLoadScreen(440);
204 
205     World_GenRooms(tr);                 // Build all rooms
206     Gui_DrawLoadScreen(480);
207 
208     World_GenCameras(tr);               // Generate cameras & sinks.
209     World_GenCinematicCameras(tr);
210     World_GenFlyByCameras(tr);
211     Gui_DrawLoadScreen(500);
212 
213     World_GenRoomFlipMap();             // Generate room flipmaps
214     Gui_DrawLoadScreen(520);
215 
216     // Build all skeletal models. Must be generated before TR_Sector_Calculate() function.
217     World_GenSkeletalModels(tr);
218     Gui_DrawLoadScreen(600);
219 
220     World_GenEntities(tr);              // Build all moveables (entities)
221     Gui_DrawLoadScreen(650);
222 
223     World_GenBaseItems();               // Generate inventory item entries.
224     Gui_DrawLoadScreen(680);
225 
226     // Generate sprite buffers. Only now because entity generation adds new sprites
227     World_GenSpritesBuffer();
228     Gui_DrawLoadScreen(700);
229 
230     // Initialize audio.
231     Audio_GenSamples(tr);
232     Gui_DrawLoadScreen(750);
233 
234     World_GenRoomProperties(tr);
235     Gui_DrawLoadScreen(800);
236 
237     World_GenRoomCollision();
238     Gui_DrawLoadScreen(850);
239 
240     // Find and set skybox.
241     global_world.sky_box = World_GetSkybox();
242     Gui_DrawLoadScreen(860);
243 
244     // Generate entity functions.
245     for(avl_node_p p = global_world.entity_tree.list; p; p = p->next)
246     {
247         World_SetEntityFunction((entity_p)p->data);
248     }
249     Gui_DrawLoadScreen(910);
250 
251     // Load entity collision flags and ID overrides from script.
252 
253     Gui_DrawLoadScreen(940);
254 
255     // Process level autoexec loading.
256     Audio_Init();
257     World_AutoexecOpen();
258     Gui_DrawLoadScreen(960);
259 
260     // Fix initial room states
261     World_FixRooms();
262     World_UpdateFlipCollisions();
263     Gui_DrawLoadScreen(970);
264 
265     if(global_world.tex_atlas)
266     {
267         delete global_world.tex_atlas;
268         global_world.tex_atlas = NULL;
269     }
270 
271     delete tr;
272 }
273 
274 
World_Clear()275 void World_Clear()
276 {
277     extern engine_container_p last_cont;
278 
279     last_cont = NULL;
280     Script_LuaClearTasks();
281     // De-initialize and destroy all audio objects.
282     Audio_DeInit();
283 
284     if(main_inventory_manager != NULL)
285     {
286         main_inventory_manager->setInventory(NULL, ENTITY_ID_NONE);
287     }
288 
289     global_world.player = NULL;
290 
291     /* entity empty must be done before rooms destroy */
292     AVL_MakeEmpty(&global_world.entity_tree);
293 
294     /* Now we can delete physics misc objects */
295     Physics_CleanUpObjects();
296 
297     for(uint32_t i = 0; i < global_world.rooms_count; i++)
298     {
299         Room_Clear(global_world.rooms + i);
300     }
301     global_world.rooms_count = 0;
302     free(global_world.rooms);
303     global_world.rooms = NULL;
304 
305     if(global_world.flip_count)
306     {
307         global_world.flip_count = 0;
308         global_world.global_flip_state = 0;
309         free(global_world.flip_map);
310         free(global_world.flip_state);
311         global_world.flip_map = NULL;
312         global_world.flip_state = NULL;
313     }
314 
315     if(global_world.room_boxes_count)
316     {
317         global_world.room_boxes_count = 0;
318         free(global_world.room_boxes);
319         global_world.room_boxes = NULL;
320     }
321 
322     if(global_world.overlaps_count)
323     {
324         global_world.overlaps_count = 0;
325         free(global_world.overlaps);
326         global_world.overlaps = NULL;
327     }
328 
329     if(global_world.cameras_sinks_count)
330     {
331         global_world.cameras_sinks_count = 0;
332         free(global_world.cameras_sinks);
333         global_world.cameras_sinks = NULL;
334     }
335 
336     if(global_world.flyby_frames_count)
337     {
338         global_world.flyby_frames_count = 0;
339         free(global_world.flyby_frames);
340         global_world.flyby_frames = NULL;
341     }
342 
343     if(global_world.cinematic_frames_count)
344     {
345         global_world.cinematic_frames_count = 0;
346         free(global_world.cinematic_frames);
347         global_world.cinematic_frames = NULL;
348     }
349 
350     for(flyby_camera_sequence_p s = global_world.flyby_camera_sequences; s;)
351     {
352         flyby_camera_sequence_p next = s->next;
353         FlyBySequence_Clear(s);
354         free(s);
355         s = next;
356     }
357     global_world.flyby_camera_sequences = NULL;
358 
359     /*sprite empty*/
360     if(global_world.sprites_count)
361     {
362         global_world.sprites_count = 0;
363         free(global_world.sprites);
364         global_world.sprites = NULL;
365     }
366 
367     /*items empty*/
368     AVL_MakeEmpty(&global_world.items_tree);
369 
370     if(global_world.skeletal_models_count)
371     {
372         for(uint32_t i = 0; i < global_world.skeletal_models_count; i++)
373         {
374             SkeletalModel_Clear(global_world.skeletal_models + i);
375         }
376         global_world.skeletal_models_count = 0;
377         free(global_world.skeletal_models);
378         global_world.skeletal_models = NULL;
379     }
380 
381     /*mesh empty*/
382     if(global_world.meshes_count)
383     {
384         for(uint32_t i = 0; i < global_world.meshes_count; i++)
385         {
386             BaseMesh_Clear(global_world.meshes+i);
387         }
388         global_world.meshes_count = 0;
389         free(global_world.meshes);
390         global_world.meshes = NULL;
391     }
392 
393     if(global_world.tex_count)
394     {
395         qglDeleteTextures(global_world.tex_count, global_world.textures);
396         global_world.tex_count = 0;
397         free(global_world.textures);
398         global_world.textures = NULL;
399     }
400 
401     if(global_world.tex_atlas)
402     {
403         delete global_world.tex_atlas;
404         global_world.tex_atlas = NULL;
405     }
406 
407     if(global_world.anim_sequences_count)
408     {
409         for(uint32_t i = 0; i < global_world.anim_sequences_count; i++)
410         {
411             if(global_world.anim_sequences[i].frames_count != 0)
412             {
413                 free(global_world.anim_sequences[i].frame_list);
414                 global_world.anim_sequences[i].frame_list = NULL;
415                 free(global_world.anim_sequences[i].frames);
416                 global_world.anim_sequences[i].frames = NULL;
417             }
418             global_world.anim_sequences[i].frames_count = 0;
419         }
420         global_world.anim_sequences_count = 0;
421         free(global_world.anim_sequences);
422         global_world.anim_sequences = NULL;
423     }
424 }
425 
426 
World_GetVersion()427 int World_GetVersion()
428 {
429     return global_world.version;
430 }
431 
432 
World_SpawnEntity(uint32_t model_id,uint32_t room_id,float pos[3],float ang[3],int32_t id)433 uint32_t World_SpawnEntity(uint32_t model_id, uint32_t room_id, float pos[3], float ang[3], int32_t id)
434 {
435     skeletal_model_p model = World_GetModelByID(model_id);
436 
437     if(model)
438     {
439         entity_p entity = World_GetEntityByID(id);
440 
441         if(entity)
442         {
443             if(pos != NULL)
444             {
445                 vec3_copy(entity->transform.M4x4 + 12, pos);
446             }
447             if(ang != NULL)
448             {
449                 vec3_copy(entity->transform.angles, ang);
450                 Entity_UpdateTransform(entity);
451             }
452             if(room_id < global_world.rooms_count)
453             {
454                 Entity_MoveToRoom(entity, global_world.rooms + room_id);
455                 entity->self->sector = Room_GetSectorRaw(entity->self->room, entity->transform.M4x4 + 12);
456             }
457             else
458             {
459                 Room_RemoveObject(entity->self->room, entity->self);
460                 entity->self->room = NULL;
461             }
462 
463             return entity->id;
464         }
465 
466         entity = Entity_Create();
467         if(id < 0)
468         {
469             avl_node_p max = global_world.entity_tree.root;
470             while(max)
471             {
472                 entity->id = max->key + 1;
473                 max = max->right;
474             }
475         }
476         else
477         {
478             entity->id = id;
479         }
480 
481         if(pos != NULL)
482         {
483             vec3_copy(entity->transform.M4x4 + 12, pos);
484         }
485         if(ang != NULL)
486         {
487             vec3_copy(entity->transform.angles, ang);
488             Entity_UpdateTransform(entity);
489         }
490         if(room_id < global_world.rooms_count)
491         {
492             entity->self->room = global_world.rooms + room_id;
493             Room_AddObject(entity->self->room, entity->self);
494             entity->self->sector = Room_GetSectorRaw(entity->self->room, entity->transform.M4x4 + 12);
495         }
496         else
497         {
498             entity->self->room = NULL;
499         }
500 
501         entity->type_flags     = ENTITY_TYPE_SPAWNED;
502         entity->state_flags    = ENTITY_STATE_ENABLED | ENTITY_STATE_ACTIVE | ENTITY_STATE_VISIBLE | ENTITY_STATE_COLLIDABLE;
503         entity->trigger_layout = 0x00;
504         entity->OCB            = 0x00;
505         entity->timer          = 0.0;
506 
507         entity->self->collision_group = COLLISION_GROUP_KINEMATIC;
508         entity->self->collision_mask = COLLISION_MASK_ALL;
509         entity->self->collision_shape = COLLISION_SHAPE_TRIMESH;
510         entity->move_type          = 0x0000;
511         entity->move_type          = 0;
512 
513         SSBoneFrame_CreateFromModel(entity->bf, model);
514         entity->bf->transform = &entity->transform;
515         Entity_SetAnimation(entity, ANIM_TYPE_BASE, 0, 0);
516         Physics_GenRigidBody(entity->physics, entity->bf);
517 
518         Entity_RebuildBV(entity);
519         if(entity->self->room != NULL)
520         {
521             Room_AddObject(entity->self->room, entity->self);
522         }
523         World_AddEntity(entity);
524         return entity->id;
525     }
526 
527     return ENTITY_ID_NONE;
528 }
529 
530 
World_GetEntityByID(uint32_t id)531 struct entity_s *World_GetEntityByID(uint32_t id)
532 {
533     avl_node_p p = AVL_SearchNode(&global_world.entity_tree, id);
534     return (p) ? ((entity_p)p->data) : (NULL);
535 }
536 
537 
World_SetPlayer(struct entity_s * entity)538 void World_SetPlayer(struct entity_s *entity)
539 {
540     int top = lua_gettop(engine_lua);
541     global_world.player = entity;
542     if(entity && entity->character)
543     {
544         lua_pushinteger(engine_lua, entity->id);
545     }
546     else
547     {
548         lua_pushinteger(engine_lua, ENTITY_ID_NONE);
549     }
550     lua_setglobal(engine_lua, "player");
551     lua_settop(engine_lua, top);
552 }
553 
554 
World_GetPlayer()555 struct entity_s *World_GetPlayer()
556 {
557     return global_world.player;
558 }
559 
560 
World_IterateAllEntities(int (* iterator)(struct entity_s * ent,void * data),void * data)561 void World_IterateAllEntities(int (*iterator)(struct entity_s *ent, void *data), void *data)
562 {
563     for(avl_node_p p = global_world.entity_tree.list; p; )
564     {
565         entity_p ent = (entity_p)p->data;
566         if(ent->state_flags & ENTITY_STATE_DELETED)
567         {
568             avl_node_p next = p->next;
569             AVL_DeleteNode(&global_world.entity_tree, p);
570             p = next;
571             continue;
572         }
573         if(iterator(ent, data))
574         {
575             break;
576         }
577         p = p->next;
578     }
579 }
580 
581 
World_GetFlyBySequences()582 struct flyby_camera_sequence_s *World_GetFlyBySequences()
583 {
584     return global_world.flyby_camera_sequences;
585 }
586 
587 
World_GetBaseItemByID(uint32_t id)588 struct base_item_s *World_GetBaseItemByID(uint32_t id)
589 {
590     avl_node_p p = AVL_SearchNode(&global_world.items_tree, id);
591     return (p) ? ((base_item_p)p->data) : (NULL);
592 }
593 
594 
World_GetBaseItemByWorldModelID(uint32_t id)595 struct base_item_s *World_GetBaseItemByWorldModelID(uint32_t id)
596 {
597     for(avl_node_p p = global_world.items_tree.list; p; p = p->next)
598     {
599         if(p->data && (id == ((base_item_p)p->data)->world_model_id))
600         {
601             return (base_item_p)p->data;
602         }
603     }
604     return NULL;
605 }
606 
607 
World_GetStaticCameraSink(uint32_t id)608 struct static_camera_sink_s *World_GetStaticCameraSink(uint32_t id)
609 {
610     if(id < global_world.cameras_sinks_count)
611     {
612         return global_world.cameras_sinks + id;
613     }
614     return NULL;
615 }
616 
617 
World_GetCinematicFrame(uint32_t id)618 struct camera_frame_s *World_GetCinematicFrame(uint32_t id)
619 {
620     if(id < global_world.cinematic_frames_count)
621     {
622         return global_world.cinematic_frames + id;
623     }
624     return NULL;
625 }
626 
627 
World_GetSkeletalModelsInfo(struct skeletal_model_s ** models,uint32_t * models_count)628 void World_GetSkeletalModelsInfo(struct skeletal_model_s **models, uint32_t *models_count)
629 {
630     *models = global_world.skeletal_models;
631     *models_count = global_world.skeletal_models_count;
632 }
633 
634 
World_GetRoomInfo(struct room_s ** rooms,uint32_t * rooms_count)635 void World_GetRoomInfo(struct room_s **rooms, uint32_t *rooms_count)
636 {
637     *rooms = global_world.rooms;
638     *rooms_count = global_world.rooms_count;
639 }
640 
641 
World_GetAnimSeqInfo(struct anim_seq_s ** seq,uint32_t * seq_count)642 void World_GetAnimSeqInfo(struct anim_seq_s **seq, uint32_t *seq_count)
643 {
644     *seq = global_world.anim_sequences;
645     *seq_count = global_world.anim_sequences_count;
646 }
647 
648 
World_GetFlipInfo(uint8_t ** flip_map,uint8_t ** flip_state,uint32_t * flip_count)649 void World_GetFlipInfo(uint8_t **flip_map, uint8_t **flip_state, uint32_t *flip_count)
650 {
651     *flip_map = global_world.flip_map;
652     *flip_state = global_world.flip_state;
653     *flip_count = global_world.flip_count;
654 }
655 
656 
World_AddAnimSeq(struct anim_seq_s * seq)657 int World_AddAnimSeq(struct anim_seq_s *seq)
658 {
659     anim_seq_p new_seqs = (anim_seq_p)realloc(global_world.anim_sequences, (global_world.anim_sequences_count + 1) * sizeof(anim_seq_t));
660     if(new_seqs)
661     {
662         new_seqs[global_world.anim_sequences_count] = *seq;
663         global_world.anim_sequences = new_seqs;
664         global_world.anim_sequences_count++;
665         return 1;
666     }
667     new_seqs = (anim_seq_p)malloc((global_world.anim_sequences_count + 1) * sizeof(anim_seq_t));
668     if(new_seqs)
669     {
670         anim_seq_p old_seq = global_world.anim_sequences;
671         if(old_seq)
672         {
673             memcpy(new_seqs, global_world.anim_sequences, global_world.anim_sequences_count * sizeof(anim_seq_t));
674         }
675         new_seqs[global_world.anim_sequences_count] = *seq;
676         global_world.anim_sequences = new_seqs;
677         global_world.anim_sequences_count++;
678         if(old_seq)
679         {
680             free(old_seq);
681         }
682         return 1;
683     }
684     return 0;
685 }
686 
687 
World_AddEntity(struct entity_s * entity)688 int World_AddEntity(struct entity_s *entity)
689 {
690     return (AVL_InsertReplace(&global_world.entity_tree, entity->id, entity)) ? (0x01) : (0x00);
691 }
692 
693 
World_DeleteEntity(uint32_t id)694 int World_DeleteEntity(uint32_t id)
695 {
696     avl_node_p p = AVL_SearchNode(&global_world.entity_tree, id);
697     if(p)
698     {
699         AVL_DeleteNode(&global_world.entity_tree, p);
700         return 1;
701     }
702     return 0;
703 }
704 
705 
World_CreateItem(uint32_t item_id,uint32_t model_id,uint32_t world_model_id,uint16_t type,uint16_t count,const char * name)706 int World_CreateItem(uint32_t item_id, uint32_t model_id, uint32_t world_model_id, uint16_t type, uint16_t count, const char *name)
707 {
708     skeletal_model_p model = World_GetModelByID(model_id);
709     if(model && (!AVL_SearchNode(&global_world.items_tree, item_id)))
710     {
711         base_item_p item = BaseItem_Create(model, item_id);
712         item->world_model_id = world_model_id;
713         item->type = type;
714         item->count = count;
715         if(name)
716         {
717             strncpy(item->name, name, sizeof(item->name));
718         }
719         return (AVL_InsertReplace(&global_world.items_tree, item_id, item)) ? (0x01) : (0x00);
720     }
721 
722     return 0;
723 }
724 
725 
World_DeleteItem(uint32_t item_id)726 int World_DeleteItem(uint32_t item_id)
727 {
728     avl_node_p p = AVL_SearchNode(&global_world.items_tree, item_id);
729     if(p)
730     {
731         AVL_DeleteNode(&global_world.items_tree, p);
732         return 1;
733     }
734     return 0;
735 }
736 
737 
World_GetSpriteByID(uint32_t ID)738 struct sprite_s *World_GetSpriteByID(uint32_t ID)
739 {
740     sprite_p sp = global_world.sprites;
741     for(uint32_t i = 0; i < global_world.sprites_count; i++, sp++)
742     {
743         if(sp->id == ID)
744         {
745             return sp;
746         }
747     }
748 
749     return NULL;
750 }
751 
752 
World_GetModelByID(uint32_t id)753 struct skeletal_model_s *World_GetModelByID(uint32_t id)
754 {
755     long int i, min, max;
756 
757     min = 0;
758     max = global_world.skeletal_models_count - 1;
759     if(global_world.skeletal_models[min].id == id)
760     {
761         return global_world.skeletal_models + min;
762     }
763     if(global_world.skeletal_models[max].id == id)
764     {
765         return global_world.skeletal_models + max;
766     }
767     do
768     {
769         i = (min + max) / 2;
770         if(global_world.skeletal_models[i].id == id)
771         {
772             return global_world.skeletal_models + i;
773         }
774 
775         if(global_world.skeletal_models[i].id < id)
776         {
777             min = i;
778         }
779         else
780         {
781             max = i;
782         }
783     }
784     while(min < max - 1);
785 
786     return NULL;
787 }
788 
789 
World_GetSkybox()790 struct skeletal_model_s* World_GetSkybox()
791 {
792     switch(global_world.version)
793     {
794         case TR_II:
795         case TR_II_DEMO:
796             return World_GetModelByID(TR_ITEM_SKYBOX_TR2);
797 
798         case TR_III:
799             return World_GetModelByID(TR_ITEM_SKYBOX_TR3);
800 
801         case TR_IV:
802         case TR_IV_DEMO:
803             return World_GetModelByID(TR_ITEM_SKYBOX_TR4);
804 
805         case TR_V:
806             return World_GetModelByID(TR_ITEM_SKYBOX_TR5);
807 
808         default:
809             return NULL;
810     };
811 }
812 
813 
World_GetRoomByID(uint32_t id)814 struct room_s *World_GetRoomByID(uint32_t id)
815 {
816     if(id < global_world.rooms_count)
817     {
818         return global_world.rooms + id;
819     }
820     return NULL;
821 }
822 
823 
World_FindRoomByPos(float pos[3])824 struct room_s *World_FindRoomByPos(float pos[3])
825 {
826     const float z_margin = TR_METERING_SECTORSIZE / 2.0f;
827     room_p r = global_world.rooms;
828     for(uint32_t i = 0; i < global_world.rooms_count; i++, r++)
829     {
830         if((r == r->real_room) &&
831            (pos[0] >= r->bb_min[0]) && (pos[0] < r->bb_max[0]) &&
832            (pos[1] >= r->bb_min[1]) && (pos[1] < r->bb_max[1]) &&
833            (pos[2] >= r->bb_min[2] - z_margin) && (pos[2] < r->bb_max[2]))
834         {
835             room_sector_p orig_sector = Room_GetSectorRaw(r->real_room, pos);
836             if(orig_sector && orig_sector->portal_to_room)
837             {
838                 return orig_sector->portal_to_room->real_room;
839             }
840             return r->real_room;
841         }
842     }
843     return NULL;
844 }
845 
846 
World_FindRoomByPosCogerrence(float pos[3],struct room_s * old_room)847 struct room_s *World_FindRoomByPosCogerrence(float pos[3], struct room_s *old_room)
848 {
849     if(old_room == NULL)
850     {
851         return World_FindRoomByPos(pos);
852     }
853 
854     old_room = old_room->real_room;
855     room_sector_p orig_sector = Room_GetSectorRaw(old_room, pos);
856     if(orig_sector && orig_sector->portal_to_room)
857     {
858         return orig_sector->portal_to_room->real_room;
859     }
860 
861     if(orig_sector &&
862        (pos[0] >= old_room->bb_min[0]) && (pos[0] < old_room->bb_max[0]) &&
863        (pos[1] >= old_room->bb_min[1]) && (pos[1] < old_room->bb_max[1]))
864     {
865         if(orig_sector->room_below && (pos[2] < orig_sector->room_below->bb_max[2]))
866         {
867             return orig_sector->room_below->real_room;
868         }
869         else if((pos[2] >= old_room->bb_min[2]) && (pos[2] < old_room->bb_max[2]))
870         {
871             return old_room;
872         }
873         else if(orig_sector->room_above && (pos[2] >= orig_sector->room_above->bb_min[2]))
874         {
875             return orig_sector->room_above->real_room;
876         }
877     }
878 
879     const float z_margin = TR_METERING_SECTORSIZE / 2.0f;
880     for(uint16_t i = 0; i < old_room->content->near_room_list_size; i++)
881     {
882         room_p r = old_room->content->near_room_list[i]->real_room;
883         if((pos[0] >= r->bb_min[0]) && (pos[0] < r->bb_max[0]) &&
884            (pos[1] >= r->bb_min[1]) && (pos[1] < r->bb_max[1]) &&
885            (pos[2] >= r->bb_min[2] - z_margin) && (pos[2] < r->bb_max[2]))
886         {
887             return r;
888         }
889     }
890 
891     return World_FindRoomByPos(pos);
892 }
893 
894 
World_GetRoomSector(int room_id,int x,int y)895 struct room_sector_s *World_GetRoomSector(int room_id, int x, int y)
896 {
897     if((room_id >= 0) && ((uint32_t)room_id < global_world.rooms_count))
898     {
899         room_p room = global_world.rooms + room_id;
900         if((x >= 0) && (y >= 0) && (x < room->sectors_x) && (y < room->sectors_y))
901         {
902             return room->content->sectors + x * room->sectors_y + y;
903         }
904     }
905 
906     return NULL;
907 }
908 
909 
World_GetRoomBoxesCount()910 uint32_t World_GetRoomBoxesCount()
911 {
912     return global_world.room_boxes_count;
913 }
914 
915 
World_GetRoomBoxByID(uint32_t id)916 struct room_box_s *World_GetRoomBoxByID(uint32_t id)
917 {
918     if(id < global_world.room_boxes_count)
919     {
920         return global_world.room_boxes + id;
921     }
922 
923     return NULL;
924 }
925 
926 
World_BuildNearRoomsList(struct room_s * room)927 void World_BuildNearRoomsList(struct room_s *room)
928 {
929     room_sector_p rs = room->content->sectors;
930     for(uint32_t i = 0; i < room->sectors_count; i++, rs++)
931     {
932         if(rs->portal_to_room)
933         {
934             Room_AddToNearRoomsList(room, rs->portal_to_room->real_room);
935         }
936     }
937 
938     int32_t list_1_size = room->content->near_room_list_size;
939     for(int32_t j = -1; j < list_1_size; j++)
940     {
941         room_p r = (j < 0) ? room : room->content->near_room_list[j];
942         rs = r->content->sectors;
943         for(uint32_t i = 0; i < r->sectors_count; i++, rs++)
944         {
945             if(rs->room_above)
946             {
947                 Room_AddToNearRoomsList(room, rs->room_above->real_room);
948             }
949 
950             if(rs->room_below)
951             {
952                 Room_AddToNearRoomsList(room, rs->room_below->real_room);
953             }
954         }
955     }
956 }
957 
958 
World_BuildOverlappedRoomsList(struct room_s * room)959 void World_BuildOverlappedRoomsList(struct room_s *room)
960 {
961     room_p r = global_world.rooms;
962     for(uint32_t i = 0; i < global_world.rooms_count; ++i, ++r)
963     {
964         if((room->real_room != r->real_room) && Room_IsOverlapped(room, r))
965         {
966             Room_AddToOverlappedRoomsList(room, r);
967             Room_AddToOverlappedRoomsList(r, room);
968         }
969     }
970 }
971 
972 /*
973  * WORLD  TRIGGERING  FUNCTIONS
974  */
975 
World_UpdateFlipCollisions()976 void World_UpdateFlipCollisions()
977 {
978     room_p r = global_world.rooms;
979     for(uint32_t i = 0; i < global_world.rooms_count; ++i, ++r)
980     {
981         if(r->real_room == r)
982         {
983             int num_tweens = r->sectors_count * 4;
984             size_t buff_size = num_tweens * sizeof(sector_tween_t);
985             sector_tween_p room_tween = (sector_tween_p)Sys_GetTempMem(buff_size);
986 
987             // Clear previous dynamic tweens
988             Physics_DeleteObject(r->content->physics_alt_tween);
989             r->content->physics_alt_tween = NULL;
990 
991             // Clear tween array.
992             for(int j = 0; j < num_tweens; j++)
993             {
994                 room_tween[j].ceiling_tween_type = TR_SECTOR_TWEEN_TYPE_NONE;
995                 room_tween[j].floor_tween_type   = TR_SECTOR_TWEEN_TYPE_NONE;
996             }
997 
998             // Most difficult task with converting floordata collision to trimesh collision is
999             // building inbetween polygons which will block out gaps between sector heights.
1000             num_tweens = Res_Sector_GenDynamicTweens(r, room_tween);
1001             if(num_tweens > 0)
1002             {
1003                 r->content->physics_alt_tween = Physics_GenRoomRigidBody(r, NULL, 0, room_tween, num_tweens);
1004                 if(r->content->physics_alt_tween)
1005                 {
1006                     Physics_EnableObject(r->content->physics_alt_tween);
1007                 }
1008             }
1009 
1010             Sys_ReturnTempMem(buff_size);
1011         }
1012     }
1013 }
1014 
1015 
World_GetGlobalFlipState()1016 uint16_t World_GetGlobalFlipState()
1017 {
1018     return global_world.global_flip_state;
1019 }
1020 
1021 
World_SetGlobalFlipState(int flip_state)1022 void World_SetGlobalFlipState(int flip_state)
1023 {
1024     room_p current_room = global_world.rooms;
1025     flip_state &= 0x00000001;
1026     for(uint32_t i = 0; i < global_world.rooms_count; i++, current_room++)
1027     {
1028         if(current_room->alternate_room_next || current_room->alternate_room_prev)
1029         {
1030             bool is_cycled = false;
1031             for(room_p room_it = current_room->alternate_room_next; room_it; room_it = room_it->alternate_room_next)
1032             {
1033                 if(room_it == current_room)
1034                 {
1035                     is_cycled = true;
1036                     break;
1037                 }
1038             }
1039             if(current_room->alternate_room_next &&
1040                (!is_cycled || (current_room->alternate_room_next != current_room->real_room)) &&
1041                (( flip_state && !current_room->is_swapped) ||
1042                 (!flip_state &&  current_room->is_swapped)))
1043             {
1044                 current_room->is_swapped = !current_room->is_swapped;
1045                 Room_DoFlip(current_room, current_room->alternate_room_next);
1046                 global_world.global_flip_state = flip_state;
1047             }
1048         }
1049     }
1050     World_UpdateFlipCollisions();
1051 }
1052 
1053 
World_SetFlipState(uint32_t flip_index,uint32_t flip_state)1054 int World_SetFlipState(uint32_t flip_index, uint32_t flip_state)
1055 {
1056     int ret = 0;
1057 
1058     if(flip_index >= global_world.flip_count)
1059     {
1060         Con_Warning("wrong flipmap index");
1061         return 0;
1062     }
1063 
1064     if((global_world.flip_map[flip_index] == 0x1F) || (flip_state & 0x02))      // Check flipmap state.
1065     {
1066         room_p current_room = global_world.rooms;
1067         bool is_global_flip = global_world.version < TR_IV;
1068         if(global_world.flip_map[flip_index] != 0x1F)
1069         {
1070             flip_state = 0;
1071         }
1072 
1073         for(uint32_t i = 0; i < global_world.rooms_count; i++, current_room++)
1074         {
1075             if(is_global_flip || (current_room->content->alternate_group == flip_index))
1076             {
1077                 bool is_cycled = false;
1078                 for(room_p room_it = current_room->alternate_room_next; room_it; room_it = room_it->alternate_room_next)
1079                 {
1080                     if(room_it == current_room)
1081                     {
1082                         is_cycled = true;
1083                         break;
1084                     }
1085                 }
1086                 if(current_room->alternate_room_next &&
1087                    (!is_cycled || (current_room->alternate_room_next != current_room->real_room)) &&
1088                    (( flip_state && !current_room->is_swapped) ||
1089                     (!flip_state &&  current_room->is_swapped)))
1090                 {
1091                     current_room->is_swapped = !current_room->is_swapped;
1092                     Room_DoFlip(current_room, current_room->alternate_room_next);
1093                     ret = 1;
1094                 }
1095             }
1096         }
1097         global_world.flip_state[flip_index] = flip_state & 0x01;
1098         global_world.global_flip_state = ret && is_global_flip && (flip_state & 0x01);
1099     }
1100 
1101     if(ret)
1102     {
1103         World_UpdateFlipCollisions();
1104     }
1105 
1106     return ret;
1107 }
1108 
1109 
World_SetFlipMap(uint32_t flip_index,uint8_t flip_mask,uint8_t flip_operation)1110 int World_SetFlipMap(uint32_t flip_index, uint8_t flip_mask, uint8_t flip_operation)
1111 {
1112     if(flip_index >= global_world.flip_count)
1113     {
1114         Con_Warning("wrong flipmap index");
1115         return 0;
1116     }
1117 
1118     if(flip_operation == TRIGGER_OP_XOR)
1119     {
1120         global_world.flip_map[flip_index] ^= flip_mask;
1121     }
1122     else if(flip_operation == TRIGGER_OP_AND_INV)
1123     {
1124         global_world.flip_map[flip_index] &= ~flip_mask;
1125     }
1126     else
1127     {
1128         global_world.flip_map[flip_index] |= flip_mask;
1129     }
1130 
1131     return 0;
1132 }
1133 
1134 
World_GetFlipMap(uint32_t flip_index)1135 uint32_t World_GetFlipMap(uint32_t flip_index)
1136 {
1137     if(flip_index >= global_world.flip_count)
1138     {
1139         return 0xFFFFFFFF;
1140     }
1141 
1142     return global_world.flip_map[flip_index];
1143 }
1144 
1145 
World_GetFlipState(uint32_t flip_index)1146 uint32_t World_GetFlipState(uint32_t flip_index)
1147 {
1148     if(flip_index >= global_world.flip_count)
1149     {
1150         return 0xFFFFFFFF;
1151     }
1152 
1153     return global_world.flip_state[flip_index];
1154 }
1155 
1156 /*
1157  * PRIVATE  WORLD  FUNCTIONS
1158  */
World_ScriptsOpen(const char * path)1159 void World_ScriptsOpen(const char *path)
1160 {
1161     if(engine_lua)
1162     {
1163         Script_DoLuaFile(engine_lua, "scripts/level_preload.lua");
1164         {
1165             char temp_script_name[1024];
1166             int top = lua_gettop(engine_lua);
1167             Engine_GetLevelScriptNameLocal(path, global_world.version, temp_script_name, sizeof(temp_script_name));
1168             int lua_err = Script_DoLuaFile(engine_lua, temp_script_name);
1169             if(lua_err)
1170             {
1171                 Sys_DebugLog("lua_out.txt", "%s", lua_tostring(engine_lua, -1));
1172                 lua_settop(engine_lua, top);
1173                 return;
1174             }
1175 
1176             lua_getglobal(engine_lua, "level_PreLoad");
1177             if(lua_isfunction(engine_lua, -1))
1178             {
1179                 lua_CallAndLog(engine_lua, 0, 0, 0);
1180             }
1181             lua_settop(engine_lua, top);
1182         }
1183     }
1184 }
1185 
1186 
World_AutoexecOpen()1187 void World_AutoexecOpen()
1188 {
1189     int top = lua_gettop(engine_lua);
1190     Script_DoLuaFile(engine_lua, "scripts/autoexec.lua");    // do standart autoexec
1191     lua_getglobal(engine_lua, "level_PostLoad");
1192     if(lua_isfunction(engine_lua, -1))
1193     {
1194         lua_CallAndLog(engine_lua, 0, 0, 0);
1195     }
1196     lua_settop(engine_lua, top);
1197 }
1198 
1199 
Res_CreateEntityFunc(lua_State * lua,const char * func_name,int entity_id)1200 bool Res_CreateEntityFunc(lua_State *lua, const char* func_name, int entity_id)
1201 {
1202     if(lua)
1203     {
1204         const char* func_template = "%s_init";
1205         char buf[256] = {0};
1206         int top = lua_gettop(lua);
1207         snprintf(buf, 256, func_template, func_name);
1208         lua_getglobal(lua, buf);
1209 
1210         if(lua_isfunction(lua, -1))
1211         {
1212             snprintf(buf, 256, "if(entity_funcs[%d]==nil) then entity_funcs[%d]={} end", entity_id, entity_id);
1213             luaL_loadstring(lua, buf);
1214             if (lua_CallAndLog(lua, 0, LUA_MULTRET, 0))
1215             {
1216                 lua_pushinteger(lua, entity_id);
1217                 lua_CallAndLog(lua, 1, 0, 0);
1218             }
1219             lua_settop(lua, top);
1220             return true;
1221         }
1222         else
1223         {
1224             lua_settop(lua, top);
1225             return false;
1226         }
1227     }
1228     return false;
1229 }
1230 
1231 
World_SetEntityModelProperties(struct entity_s * ent)1232 void World_SetEntityModelProperties(struct entity_s *ent)
1233 {
1234     if(engine_lua && ent->bf->animations.model)
1235     {
1236         int top = lua_gettop(engine_lua);
1237         lua_getglobal(engine_lua, "getEntityModelProperties");
1238         if(lua_isfunction(engine_lua, -1))
1239         {
1240             lua_pushinteger(engine_lua, global_world.version);                  // engine version
1241             lua_pushinteger(engine_lua, ent->bf->animations.model->id);         // entity model id
1242             if (lua_CallAndLog(engine_lua, 2, 3, 0))
1243             {
1244                 ent->self->collision_group = lua_tointeger(engine_lua, -3);     // get collision type flag
1245                 ent->self->collision_shape = lua_tointeger(engine_lua, -2);     // get collision shape flag
1246                 ent->bf->animations.model->hide = lua_tointeger(engine_lua, -1);// get info about model visibility
1247             }
1248         }
1249         lua_settop(engine_lua, top);
1250     }
1251 }
1252 
1253 
World_SetStaticMeshProperties(struct static_mesh_s * r_static)1254 void World_SetStaticMeshProperties(struct static_mesh_s *r_static)
1255 {
1256     if(engine_lua)
1257     {
1258         int top = lua_gettop(engine_lua);
1259         lua_getglobal(engine_lua, "getStaticMeshProperties");
1260         if(lua_isfunction(engine_lua, -1))
1261         {
1262             lua_pushinteger(engine_lua, r_static->object_id);
1263             if(lua_CallAndLog(engine_lua, 1, 3, 0))
1264             {
1265                 if(!lua_isnil(engine_lua, -3))
1266                 {
1267                     r_static->self->collision_group = lua_tointeger(engine_lua, -3);
1268                 }
1269                 if(!lua_isnil(engine_lua, -2))
1270                 {
1271                     r_static->self->collision_shape = lua_tointeger(engine_lua, -2);
1272                 }
1273                 if(!lua_isnil(engine_lua, -1))
1274                 {
1275                     r_static->hide = lua_tointeger(engine_lua, -1);
1276                 }
1277             }
1278         }
1279         lua_settop(engine_lua, top);
1280     }
1281 }
1282 
1283 
World_SetEntityFunction(struct entity_s * ent)1284 void World_SetEntityFunction(struct entity_s *ent)
1285 {
1286     if(engine_lua && ent->bf->animations.model)
1287     {
1288         int top = lua_gettop(engine_lua);
1289         lua_getglobal(engine_lua, "getEntityFunction");
1290         if(lua_isfunction(engine_lua, -1))
1291         {
1292             lua_pushinteger(engine_lua, global_world.version);                  // engine version
1293             lua_pushinteger(engine_lua, ent->bf->animations.model->id);         // entity model id
1294             if (lua_CallAndLog(engine_lua, 2, 1, 0))
1295             {
1296                 if(!lua_isnil(engine_lua, -1))
1297                 {
1298                     Res_CreateEntityFunc(engine_lua, lua_tolstring(engine_lua, -1, 0), ent->id);
1299                 }
1300             }
1301         }
1302         lua_settop(engine_lua, top);
1303     }
1304 }
1305 
1306 // Functions setting parameters from configuration scripts.
World_GenTextures(class VT_Level * tr)1307 void World_GenTextures(class VT_Level *tr)
1308 {
1309     int border_size = renderer.settings.texture_border;
1310     border_size = (border_size < 0) ? (0) : (border_size);
1311     border_size = (border_size > 128) ? (128) : (border_size);
1312     global_world.tex_atlas = new bordered_texture_atlas(border_size,
1313                                                   tr->textile32_count,
1314                                                   tr->textile32,
1315                                                   tr->object_textures_count,
1316                                                   tr->object_textures,
1317                                                   tr->sprite_textures_count,
1318                                                   tr->sprite_textures);
1319 
1320     global_world.tex_count = (uint32_t) global_world.tex_atlas->getNumAtlasPages();
1321     global_world.textures = (GLuint*)malloc(global_world.tex_count * sizeof(GLuint));
1322 
1323     qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1324     qglPixelZoom(1, 1);
1325     global_world.tex_atlas->createTextures(global_world.textures);
1326 
1327     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);   // Mag filter is always linear.
1328 
1329     // Select mipmap mode
1330     switch(renderer.settings.mipmap_mode)
1331     {
1332         case 0:
1333             qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1334             break;
1335 
1336         case 1:
1337             qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
1338             break;
1339 
1340         case 2:
1341             qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
1342             break;
1343 
1344         case 3:
1345         default:
1346             qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1347             break;
1348     };
1349 
1350     // Set mipmaps number
1351     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, renderer.settings.mipmaps);
1352 
1353     // Set anisotropy degree
1354     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, renderer.settings.anisotropy);
1355 
1356     // Read lod bias
1357     qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, renderer.settings.lod_bias);
1358 }
1359 
1360 
1361 /**   Animated textures loading.
1362   *   Natively, animated textures stored as a stream of bitu16s, which
1363   *   is then parsed on the fly. What we do is parse this stream to the
1364   *   proper structures to be used later within renderer.
1365   */
World_GenAnimTextures(class VT_Level * tr)1366 void World_GenAnimTextures(class VT_Level *tr)
1367 {
1368     uint16_t *pointer;
1369     uint16_t  num_sequences, num_uvrotates;
1370     polygon_t p0, p;
1371 
1372     p0.vertex_count = 0;
1373     p0.vertices = NULL;
1374     p.vertex_count = 0;
1375     p.vertices = NULL;
1376     Polygon_Resize(&p0, 3);
1377     Polygon_Resize(&p, 3);
1378 
1379     pointer       = tr->animated_textures;
1380     num_uvrotates = tr->animated_textures_uv_count;
1381     num_sequences = *(pointer++);   // First word in a stream is sequence count.
1382 
1383     if(num_sequences)
1384     {
1385         global_world.anim_sequences_count = num_sequences;
1386         global_world.anim_sequences = (anim_seq_p)calloc(num_sequences, sizeof(anim_seq_t));
1387 
1388         anim_seq_p seq = global_world.anim_sequences;
1389         for(uint16_t i = 0; i < num_sequences; i++, seq++)
1390         {
1391             seq->frames_count = *(pointer++) + 1;
1392             seq->frame_list   =  (uint32_t*)calloc(seq->frames_count, sizeof(uint32_t));
1393 
1394             // Fill up new sequence with frame list.
1395             seq->anim_type         = TR_ANIMTEXTURE_FORWARD;
1396             seq->frame_lock        = false; // by default anim is playing
1397             seq->uvrotate          = false; // by default uvrotate
1398             seq->reverse_direction = false; // Needed for proper reverse-type start-up.
1399             seq->frame_rate        = 0.05f; // Should be passed as 1 / FPS.
1400             seq->frame_time        = 0.0f;  // Reset frame time to initial state.
1401             seq->current_frame     = 0;     // Reset current frame to zero.
1402 
1403             for(uint16_t j = 0; j < seq->frames_count; j++)
1404             {
1405                 seq->frame_list[j] = *(pointer++);  // Add one frame.
1406             }
1407 
1408             // UVRotate textures case.
1409             // In TR4-5, it is possible to define special UVRotate animation mode.
1410             // It is specified by num_uvrotates variable. If sequence belongs to
1411             // UVRotate range, each frame will be divided in half and continously
1412             // scrolled from one part to another by shifting UV coordinates.
1413             // In OpenTomb, we can have BOTH UVRotate and classic frames mode
1414             // applied to the same sequence, but there we specify compatibility
1415             // method for TR4-5.
1416             // I need to find logic of original levels + add script functions or
1417             // other sticks for corret textures animationg.
1418             if((i < num_uvrotates) && (seq->frames_count <= 2))
1419             {
1420                 seq->uvrotate   = true;
1421                 seq->frame_rate = 0.05f * 16;
1422             }
1423             seq->frames = (tex_frame_p)calloc(seq->frames_count, sizeof(tex_frame_t));
1424             global_world.tex_atlas->getCoordinates(&p0, seq->frame_list[0], false);
1425             for(uint16_t j = 0; j < seq->frames_count; j++)
1426             {
1427                 if(seq->uvrotate)
1428                 {
1429                     seq->frames[j].uvrotate_max = 0.5 * global_world.tex_atlas->getTextureHeight(seq->frame_list[j]);
1430                     seq->frames[j].current_uvrotate = 0.0;
1431                 }
1432                 global_world.tex_atlas->getCoordinates(&p, seq->frame_list[j], false);
1433                 seq->frames[j].texture_index = p.texture_index;
1434                 if(j > 0)   // j == 0 -> d == 0;
1435                 {
1436                     ///@PARANOID: texture transformation may be not only move
1437                     GLfloat A0[2], B0[2], A[2], B[2], d;
1438                     A0[0] = p0.vertices[1].tex_coord[0] - p0.vertices[0].tex_coord[0];
1439                     A0[1] = p0.vertices[1].tex_coord[1] - p0.vertices[0].tex_coord[1];
1440                     B0[0] = p0.vertices[2].tex_coord[0] - p0.vertices[0].tex_coord[0];
1441                     B0[1] = p0.vertices[2].tex_coord[1] - p0.vertices[0].tex_coord[1];
1442 
1443                     A[0] = p.vertices[1].tex_coord[0] - p.vertices[0].tex_coord[0];
1444                     A[1] = p.vertices[1].tex_coord[1] - p.vertices[0].tex_coord[1];
1445                     B[0] = p.vertices[2].tex_coord[0] - p.vertices[0].tex_coord[0];
1446                     B[1] = p.vertices[2].tex_coord[1] - p.vertices[0].tex_coord[1];
1447 
1448                     d = A0[0] * B0[1] - A0[1] * B0[0];
1449                     seq->frames[j].mat[0 + 0 * 2] = (A[0] * B0[1] - A0[1] * B[0]) / d;
1450                     seq->frames[j].mat[1 + 0 * 2] =-(A[1] * B0[1] - A0[1] * B[1]) / d;
1451                     seq->frames[j].mat[0 + 1 * 2] =-(A0[0] * B[0] - A[0] * B0[0]) / d;
1452                     seq->frames[j].mat[1 + 1 * 2] = (A0[0] * B[1] - A[1] * B0[0]) / d;
1453                 }
1454                 else
1455                 {
1456                     seq->frames[j].mat[0 + 0 * 2] = 1.0;
1457                     seq->frames[j].mat[1 + 0 * 2] = 0.0;
1458                     seq->frames[j].mat[0 + 1 * 2] = 0.0;
1459                     seq->frames[j].mat[1 + 1 * 2] = 1.0;
1460                 }
1461 
1462                 seq->frames[j].move[0] = p.vertices[0].tex_coord[0] - (p0.vertices[0].tex_coord[0] * seq->frames[j].mat[0 + 0 * 2] + p0.vertices[0].tex_coord[1] * seq->frames[j].mat[0 + 1 * 2]);
1463                 seq->frames[j].move[1] = p.vertices[0].tex_coord[1] - (p0.vertices[0].tex_coord[0] * seq->frames[j].mat[1 + 0 * 2] + p0.vertices[0].tex_coord[1] * seq->frames[j].mat[1 + 1 * 2]);
1464             } ///end for(uint16_t j = 0; j < seq->frames_count; j++)
1465         }  ///end for(uint16_t i = 0; i < num_sequences; i++, seq++)
1466     }
1467     Polygon_Clear(&p0);
1468     Polygon_Clear(&p);
1469 }
1470 
1471 
World_GenMeshes(class VT_Level * tr)1472 void World_GenMeshes(class VT_Level *tr)
1473 {
1474     base_mesh_p base_mesh;
1475 
1476     global_world.meshes_count = tr->meshes_count;
1477     base_mesh = global_world.meshes = (base_mesh_p)calloc(global_world.meshes_count, sizeof(base_mesh_t));
1478     for(uint32_t i = 0; i < global_world.meshes_count; i++, base_mesh++)
1479     {
1480         TR_GenMesh(base_mesh, i, global_world.anim_sequences, global_world.anim_sequences_count, global_world.tex_atlas, tr);
1481         BaseMesh_GenFaces(base_mesh);
1482     }
1483 }
1484 
1485 
World_GenSprites(class VT_Level * tr)1486 void World_GenSprites(class VT_Level *tr)
1487 {
1488     sprite_p s;
1489     tr_sprite_texture_t *tr_st;
1490 
1491     if(tr->sprite_textures_count == 0)
1492     {
1493         global_world.sprites = NULL;
1494         global_world.sprites_count = 0;
1495         return;
1496     }
1497 
1498     global_world.sprites_count = tr->sprite_textures_count;
1499     s = global_world.sprites = (sprite_p)calloc(global_world.sprites_count, sizeof(sprite_t));
1500 
1501     for(uint32_t i = 0; i < global_world.sprites_count; i++, s++)
1502     {
1503         tr_st = &tr->sprite_textures[i];
1504 
1505         s->left = tr_st->left_side;
1506         s->right = tr_st->right_side;
1507         s->top = tr_st->top_side;
1508         s->bottom = tr_st->bottom_side;
1509 
1510         global_world.tex_atlas->getSpriteCoordinates(s->tex_coord, i, &s->texture_index);
1511     }
1512 
1513     for(uint32_t i = 0; i < tr->sprite_sequences_count; i++)
1514     {
1515         if((tr->sprite_sequences[i].offset >= 0) && ((uint32_t)tr->sprite_sequences[i].offset < global_world.sprites_count))
1516         {
1517             global_world.sprites[tr->sprite_sequences[i].offset].id = tr->sprite_sequences[i].object_id;
1518         }
1519     }
1520 }
1521 
1522 
World_GenBoxes(class VT_Level * tr)1523 void World_GenBoxes(class VT_Level *tr)
1524 {
1525     global_world.overlaps = NULL;
1526     global_world.overlaps_count = tr->overlaps_count;
1527 
1528     if(global_world.overlaps_count)
1529     {
1530         global_world.overlaps = (box_overlap_p)malloc(global_world.overlaps_count * sizeof(box_overlap_t));
1531         for(uint32_t i = 0; i < global_world.overlaps_count; i++)
1532         {
1533             global_world.overlaps[i].box = tr->overlaps[i] & 0x7FFF;
1534             global_world.overlaps[i].end = (tr->overlaps[i] & 0x8000) ? (1) : (0);
1535         }
1536         global_world.overlaps[global_world.overlaps_count - 1].end = 1;         // never believe user data
1537     }
1538 
1539     global_world.room_boxes = NULL;
1540     global_world.room_boxes_count = tr->boxes_count;
1541 
1542     if(global_world.room_boxes_count)
1543     {
1544         global_world.room_boxes = (room_box_p)malloc(global_world.room_boxes_count * sizeof(room_box_t));
1545         for(uint32_t i = 0; i < global_world.room_boxes_count; i++)
1546         {
1547             room_box_p r_box = global_world.room_boxes + i;
1548             uint16_t ov_index = 0x7FFF & tr->boxes[i].overlap_index;
1549             r_box->overlaps = NULL;
1550             if((tr->boxes[i].overlap_index >= 0) && (ov_index < global_world.overlaps_count))
1551             {
1552                 r_box->overlaps = global_world.overlaps + ov_index;
1553             }
1554             else
1555             {
1556                 Con_Printf("box = %d, bad overlap index = %d", i, ov_index);
1557             }
1558             r_box->id = i;
1559             r_box->is_blockable = (tr->boxes[i].overlap_index & 0x8000) ? (0x01) : (0x00);
1560             r_box->is_blocked = 0x00;
1561             r_box->bb_min[0] = tr->boxes[i].xmin;
1562             r_box->bb_min[1] =-tr->boxes[i].zmax;
1563             r_box->bb_min[2] = tr->boxes[i].true_floor;
1564             r_box->bb_max[0] = tr->boxes[i].xmax;
1565             r_box->bb_max[1] =-tr->boxes[i].zmin;
1566             r_box->bb_max[2] = tr->boxes[i].true_floor + TR_METERING_SECTORSIZE;
1567 
1568             r_box->zone[0].GroundZone1 = tr->zones[i].GroundZone1_Normal;
1569             r_box->zone[0].GroundZone2 = tr->zones[i].GroundZone2_Normal;
1570             r_box->zone[0].GroundZone3 = tr->zones[i].GroundZone3_Normal;
1571             r_box->zone[0].GroundZone4 = tr->zones[i].GroundZone4_Normal;
1572             r_box->zone[0].FlyZone = tr->zones[i].FlyZone_Normal;
1573             r_box->zone[1].GroundZone1 = tr->zones[i].GroundZone1_Alternate;
1574             r_box->zone[1].GroundZone2 = tr->zones[i].GroundZone2_Alternate;
1575             r_box->zone[1].GroundZone3 = tr->zones[i].GroundZone3_Alternate;
1576             r_box->zone[1].GroundZone4 = tr->zones[i].GroundZone4_Alternate;
1577             r_box->zone[1].FlyZone = tr->zones[i].FlyZone_Alternate;
1578         }
1579     }
1580 }
1581 
1582 
World_GenCameras(class VT_Level * tr)1583 void World_GenCameras(class VT_Level *tr)
1584 {
1585     global_world.cameras_sinks = NULL;
1586     global_world.cameras_sinks_count = tr->cameras_count;
1587 
1588     if(global_world.cameras_sinks_count)
1589     {
1590         global_world.cameras_sinks = (static_camera_sink_p)malloc(global_world.cameras_sinks_count * sizeof(static_camera_sink_t));
1591         for(uint32_t i = 0; i < global_world.cameras_sinks_count; i++)
1592         {
1593             global_world.cameras_sinks[i].pos[0]              =  tr->cameras[i].x;
1594             global_world.cameras_sinks[i].pos[1]              =  tr->cameras[i].z;
1595             global_world.cameras_sinks[i].pos[2]              = -tr->cameras[i].y;
1596             global_world.cameras_sinks[i].locked              =  0;
1597             global_world.cameras_sinks[i].room_or_strength    =  tr->cameras[i].room;
1598             global_world.cameras_sinks[i].flag_or_zone        =  tr->cameras[i].unknown1;
1599         }
1600     }
1601 }
1602 
1603 
World_GenCinematicCameras(class VT_Level * tr)1604 void World_GenCinematicCameras(class VT_Level *tr)
1605 {
1606     global_world.cinematic_frames = NULL;
1607     global_world.cinematic_frames_count = tr->cinematic_frames_count;
1608 
1609     if(global_world.cinematic_frames_count)
1610     {
1611         global_world.cinematic_frames = (camera_frame_p)calloc(global_world.cinematic_frames_count, sizeof(camera_frame_t));
1612         for(uint32_t i = 0; i < global_world.cinematic_frames_count; i++)
1613         {
1614             global_world.cinematic_frames[i].pos[0] = tr->cinematic_frames[i].posx;
1615             global_world.cinematic_frames[i].pos[1] = tr->cinematic_frames[i].posz;
1616             global_world.cinematic_frames[i].pos[2] =-tr->cinematic_frames[i].posy;
1617             global_world.cinematic_frames[i].target[0] = tr->cinematic_frames[i].targetx;
1618             global_world.cinematic_frames[i].target[1] = tr->cinematic_frames[i].targetz;
1619             global_world.cinematic_frames[i].target[2] =-tr->cinematic_frames[i].targety;
1620             global_world.cinematic_frames[i].fov = (float)(tr->cinematic_frames[i].fov) / 16384.0f * 90.0f;
1621             global_world.cinematic_frames[i].roll = (float)(tr->cinematic_frames[i].roll) / 16384.0f * 90.0f;
1622         }
1623     }
1624 }
1625 
World_GenFlyByCameras(class VT_Level * tr)1626 void World_GenFlyByCameras(class VT_Level *tr)
1627 {
1628     global_world.flyby_frames = NULL;
1629     global_world.flyby_frames_count = tr->flyby_cameras_count;
1630 
1631     if(global_world.flyby_frames_count)
1632     {
1633         uint32_t start_index = 0;
1634         flyby_camera_sequence_p *last_seq_ptr = &global_world.flyby_camera_sequences;
1635         global_world.flyby_frames = (camera_frame_p)malloc(global_world.flyby_frames_count * sizeof(camera_frame_t));
1636         for(uint32_t i = 0; i < global_world.flyby_frames_count; i++)
1637         {
1638             union
1639             {
1640                 camera_flags_t flags;
1641                 uint16_t       flags_ui;
1642             };
1643             flags_ui  =  tr->flyby_cameras[i].flags;
1644 
1645             global_world.flyby_frames[i].flags           =  flags;
1646             global_world.flyby_frames[i].pos[0]          =  tr->flyby_cameras[i].pos_x;
1647             global_world.flyby_frames[i].pos[1]          =  tr->flyby_cameras[i].pos_z;
1648             global_world.flyby_frames[i].pos[2]          = -tr->flyby_cameras[i].pos_y;
1649             global_world.flyby_frames[i].target[0]       =  tr->flyby_cameras[i].target_x;
1650             global_world.flyby_frames[i].target[1]       =  tr->flyby_cameras[i].target_z;
1651             global_world.flyby_frames[i].target[2]       = -tr->flyby_cameras[i].target_y;
1652 
1653             global_world.flyby_frames[i].fov             =  tr->flyby_cameras[i].fov;
1654             global_world.flyby_frames[i].roll            =  tr->flyby_cameras[i].roll;
1655             global_world.flyby_frames[i].timer           =  tr->flyby_cameras[i].timer;
1656             global_world.flyby_frames[i].speed           =  tr->flyby_cameras[i].speed;
1657 
1658             global_world.flyby_frames[i].sequence        =  tr->flyby_cameras[i].sequence;
1659             global_world.flyby_frames[i].index           =  tr->flyby_cameras[i].index;
1660 
1661             if((tr->flyby_cameras[i].room_id >= 0) && ((uint32_t)tr->flyby_cameras[i].room_id < global_world.rooms_count))
1662             {
1663                 global_world.flyby_frames[i].room            =  global_world.rooms + tr->flyby_cameras[i].room_id;
1664             }
1665 
1666             if((i + 1 == global_world.flyby_frames_count) || (tr->flyby_cameras[i].sequence != tr->flyby_cameras[i + 1].sequence))
1667             {
1668                 *last_seq_ptr = FlyBySequence_Create(global_world.flyby_frames + start_index, i - start_index + 1);
1669                 if(*last_seq_ptr)
1670                 {
1671                     last_seq_ptr = &(*last_seq_ptr)->next;
1672                 }
1673                 start_index = i + 1;
1674             }
1675         }
1676         *last_seq_ptr = NULL;
1677     }
1678 }
1679 
1680 
TR_vertex_to_arr(float v[3],tr5_vertex_t * tr_v)1681 __inline void TR_vertex_to_arr(float v[3], tr5_vertex_t *tr_v)
1682 {
1683     v[0] = tr_v->x;
1684     v[1] =-tr_v->z;
1685     v[2] = tr_v->y;
1686 }
1687 
World_GenRoom(struct room_s * room,class VT_Level * tr)1688 void World_GenRoom(struct room_s *room, class VT_Level *tr)
1689 {
1690     portal_p p;
1691     room_p r_dest;
1692     tr5_room_t *tr_room = &tr->rooms[room->id];
1693     tr_staticmesh_t *tr_static;
1694     static_mesh_p r_static;
1695     tr_room_portal_t *tr_portal;
1696     room_sector_p sector;
1697 
1698     room->frustum = NULL;
1699     room->containers = NULL;
1700     room->is_in_r_list = 0;
1701     room->is_swapped = 0;
1702 
1703     Mat4_E_macro(room->transform);
1704     TR_vertex_to_arr(room->transform + 12, &tr->rooms[room->id].offset);
1705 
1706     room->self = Container_Create();
1707     room->self->next = NULL;
1708     room->self->room = room;
1709     room->self->object = room;
1710     room->self->collision_group = COLLISION_GROUP_STATIC_ROOM;
1711     room->self->collision_mask = COLLISION_MASK_ALL;
1712     room->self->collision_shape = COLLISION_SHAPE_TRIMESH;
1713     room->self->object_type = OBJECT_ROOM_BASE;
1714 
1715     room->content = (room_content_p)malloc(sizeof(room_content_t));
1716     room->original_content = room->content;
1717     room->content->original_room_id = room->id;
1718     room->content->room_flags = tr->rooms[room->id].flags;
1719     room->content->near_room_list_size = 0;
1720     room->content->near_room_list = NULL;
1721     room->content->overlapped_room_list_size = 0;
1722     room->content->overlapped_room_list = NULL;
1723     room->content->physics_body = NULL;
1724     room->content->physics_alt_tween = NULL;
1725     room->content->mesh = NULL;
1726     room->content->static_mesh = NULL;
1727     room->content->sprites = NULL;
1728     room->content->sprites_vertices = NULL;
1729     room->content->lights_count = 0;
1730     room->content->lights = NULL;
1731     room->content->light_mode = tr->rooms[room->id].light_mode;
1732     room->content->reverb_info = tr->rooms[room->id].reverb_info;
1733     room->content->water_scheme = tr->rooms[room->id].water_scheme;
1734     room->content->alternate_group = tr->rooms[room->id].alternate_group;
1735     room->content->ambient_lighting[0] = tr->rooms[room->id].light_colour.r * 2;
1736     room->content->ambient_lighting[1] = tr->rooms[room->id].light_colour.g * 2;
1737     room->content->ambient_lighting[2] = tr->rooms[room->id].light_colour.b * 2;
1738 
1739     TR_GenRoomMesh(room, room->id, global_world.anim_sequences, global_world.anim_sequences_count, global_world.tex_atlas, tr);
1740     if(room->content->mesh)
1741     {
1742         BaseMesh_GenFaces(room->content->mesh);
1743     }
1744     /*
1745      * let us load sectors
1746      */
1747     room->sectors_x = tr_room->num_xsectors;
1748     room->sectors_y = tr_room->num_zsectors;
1749     room->sectors_count = room->sectors_x * room->sectors_y;
1750     room->content->sectors = (room_sector_p)malloc(room->sectors_count * sizeof(room_sector_t));
1751 
1752     /*
1753      * base sectors information loading and collisional mesh creation
1754      */
1755 
1756     // To avoid manipulating with unnecessary information, we declare simple
1757     // heightmap here, which will be operated with sector and floordata parsing,
1758     // then vertical inbetween polys will be constructed, and Bullet collisional
1759     // object will be created. Afterwards, this heightmap also can be used to
1760     // quickly detect slopes for pushable blocks and other entities that rely on
1761     // floor level.
1762     sector = room->content->sectors;
1763     for(uint32_t i = 0; i < room->sectors_count; i++, sector++)
1764     {
1765         // Filling base sectors information.
1766 
1767         sector->index_x = i / room->sectors_y;
1768         sector->index_y = i % room->sectors_y;
1769 
1770         sector->pos[0] = room->transform[12 + 0] + sector->index_x * TR_METERING_SECTORSIZE + 0.5f * TR_METERING_SECTORSIZE;
1771         sector->pos[1] = room->transform[12 + 1] + sector->index_y * TR_METERING_SECTORSIZE + 0.5f * TR_METERING_SECTORSIZE;
1772         sector->pos[2] = 0.5f * (tr_room->y_bottom + tr_room->y_top);
1773 
1774         sector->owner_room = room;
1775         sector->trigger = NULL;
1776         sector->box = NULL;
1777 
1778         if(tr->game_version < TR_III)
1779         {
1780             if(tr_room->sector_list[i].box_index < global_world.room_boxes_count)
1781             {
1782                 sector->box = global_world.room_boxes + tr_room->sector_list[i].box_index;
1783             }
1784             sector->material  = SECTOR_MATERIAL_STONE;
1785         }
1786         else
1787         {
1788             uint16_t box = (tr_room->sector_list[i].box_index & 0xFFF0) >> 4;
1789             if(box < global_world.room_boxes_count)
1790             {
1791                 sector->box = global_world.room_boxes + box;
1792             }
1793             sector->material  = (tr_room->sector_list[i].box_index & 0x000F);
1794         }
1795 
1796         sector->flags = 0;  // Clear sector flags.
1797 
1798         sector->floor      = -TR_METERING_STEP * (int)tr_room->sector_list[i].floor;
1799         sector->ceiling    = -TR_METERING_STEP * (int)tr_room->sector_list[i].ceiling;
1800         sector->trig_index = tr_room->sector_list[i].fd_index;
1801 
1802         // BUILDING CEILING HEIGHTMAP.
1803 
1804         // Penetration config is used later to build inbetween vertical collision polys.
1805         // If sector's penetration config is a wall, we simply build a vertical plane to
1806         // isolate this sector from top to bottom. Also, this allows to trick out wall
1807         // sectors inside another wall sectors to be ignored completely when building
1808         // collisional mesh.
1809         // Door penetration config means that we should either ignore sector collision
1810         // completely (classic door) or ignore one of the triangular sector parts (TR3+).
1811 
1812         if(sector->ceiling == TR_METERING_WALLHEIGHT)
1813         {
1814             room->content->sectors[i].ceiling_penetration_config = TR_PENETRATION_CONFIG_WALL;
1815         }
1816         else if(tr_room->sector_list[i].room_above != 0xFF)
1817         {
1818             room->content->sectors[i].ceiling_penetration_config = TR_PENETRATION_CONFIG_GHOST;
1819         }
1820         else
1821         {
1822             room->content->sectors[i].ceiling_penetration_config = TR_PENETRATION_CONFIG_SOLID;
1823         }
1824 
1825         // Reset some sector parameters to avoid garbaged memory issues.
1826         room->content->sectors[i].portal_to_room = NULL;
1827         room->content->sectors[i].ceiling_diagonal_type = TR_SECTOR_DIAGONAL_TYPE_NONE;
1828         room->content->sectors[i].floor_diagonal_type   = TR_SECTOR_DIAGONAL_TYPE_NONE;
1829 
1830         // Now, we define heightmap cells position and draft (flat) height.
1831         // Draft height is derived from sector's floor and ceiling values, which are
1832         // copied into heightmap cells Y coordinates. As result, we receive flat
1833         // heightmap cell, which will be operated later with floordata.
1834 
1835         room->content->sectors[i].ceiling_corners[0][0] = (float)sector->index_x * TR_METERING_SECTORSIZE;
1836         room->content->sectors[i].ceiling_corners[0][1] = (float)sector->index_y * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1837         room->content->sectors[i].ceiling_corners[0][2] = (float)sector->ceiling;
1838 
1839         room->content->sectors[i].ceiling_corners[1][0] = (float)sector->index_x * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1840         room->content->sectors[i].ceiling_corners[1][1] = (float)sector->index_y * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1841         room->content->sectors[i].ceiling_corners[1][2] = (float)sector->ceiling;
1842 
1843         room->content->sectors[i].ceiling_corners[2][0] = (float)sector->index_x * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1844         room->content->sectors[i].ceiling_corners[2][1] = (float)sector->index_y * TR_METERING_SECTORSIZE;
1845         room->content->sectors[i].ceiling_corners[2][2] = (float)sector->ceiling;
1846 
1847         room->content->sectors[i].ceiling_corners[3][0] = (float)sector->index_x * TR_METERING_SECTORSIZE;
1848         room->content->sectors[i].ceiling_corners[3][1] = (float)sector->index_y * TR_METERING_SECTORSIZE;
1849         room->content->sectors[i].ceiling_corners[3][2] = (float)sector->ceiling;
1850 
1851         // BUILDING FLOOR HEIGHTMAP.
1852 
1853         // Features same steps as for the ceiling.
1854 
1855         if(sector->floor == TR_METERING_WALLHEIGHT)
1856         {
1857             room->content->sectors[i].floor_penetration_config = TR_PENETRATION_CONFIG_WALL;
1858         }
1859         else if(tr_room->sector_list[i].room_below != 0xFF)
1860         {
1861             room->content->sectors[i].floor_penetration_config = TR_PENETRATION_CONFIG_GHOST;
1862         }
1863         else
1864         {
1865             room->content->sectors[i].floor_penetration_config = TR_PENETRATION_CONFIG_SOLID;
1866         }
1867 
1868         room->content->sectors[i].floor_corners[0][0] = (float)sector->index_x * TR_METERING_SECTORSIZE;
1869         room->content->sectors[i].floor_corners[0][1] = (float)sector->index_y * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1870         room->content->sectors[i].floor_corners[0][2] = (float)sector->floor;
1871 
1872         room->content->sectors[i].floor_corners[1][0] = (float)sector->index_x * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1873         room->content->sectors[i].floor_corners[1][1] = (float)sector->index_y * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1874         room->content->sectors[i].floor_corners[1][2] = (float)sector->floor;
1875 
1876         room->content->sectors[i].floor_corners[2][0] = (float)sector->index_x * TR_METERING_SECTORSIZE + TR_METERING_SECTORSIZE;
1877         room->content->sectors[i].floor_corners[2][1] = (float)sector->index_y * TR_METERING_SECTORSIZE;
1878         room->content->sectors[i].floor_corners[2][2] = (float)sector->floor;
1879 
1880         room->content->sectors[i].floor_corners[3][0] = (float)sector->index_x * TR_METERING_SECTORSIZE;
1881         room->content->sectors[i].floor_corners[3][1] = (float)sector->index_y * TR_METERING_SECTORSIZE;
1882         room->content->sectors[i].floor_corners[3][2] = (float)sector->floor;
1883     }
1884 
1885     /*
1886      *  load lights
1887      */
1888     room->content->lights_count = tr_room->num_lights;
1889     if(room->content->lights_count > 0)
1890     {
1891         room->content->lights = (light_p)malloc(room->content->lights_count * sizeof(light_t));
1892         for(uint16_t i = 0; i < tr_room->num_lights; i++)
1893         {
1894             Res_RoomLightCalculate(room->content->lights + i, tr_room->lights + i);
1895         }
1896     }
1897 
1898     /*
1899      * portals loading / calculation!!!
1900      */
1901     room->content->portals_count = tr_room->num_portals;
1902     p = room->content->portals = (portal_p)calloc(room->content->portals_count, sizeof(portal_t));
1903     tr_portal = tr_room->portals;
1904     for(uint16_t i = 0; i < room->content->portals_count; i++, p++, tr_portal++)
1905     {
1906         r_dest = global_world.rooms + tr_portal->adjoining_room;
1907         p->vertex_count = 4;                                                    // in original TR all portals are axis aligned rectangles
1908         p->vertex = (float*)malloc(3 * p->vertex_count * sizeof(float));
1909         p->dest_room = r_dest;
1910         TR_vertex_to_arr(p->vertex, &tr_portal->vertices[3]);
1911         vec3_add(p->vertex, p->vertex, room->transform + 12);
1912         TR_vertex_to_arr(p->vertex + 3, &tr_portal->vertices[2]);
1913         vec3_add(p->vertex + 3, p->vertex + 3, room->transform + 12);
1914         TR_vertex_to_arr(p->vertex + 6, &tr_portal->vertices[1]);
1915         vec3_add(p->vertex + 6, p->vertex + 6, room->transform + 12);
1916         TR_vertex_to_arr(p->vertex + 9, &tr_portal->vertices[0]);
1917         vec3_add(p->vertex + 9, p->vertex + 9, room->transform + 12);
1918         vec3_add(p->centre, p->vertex, p->vertex + 3);
1919         vec3_add(p->centre, p->centre, p->vertex + 6);
1920         vec3_add(p->centre, p->centre, p->vertex + 9);
1921         p->centre[0] /= 4.0f;
1922         p->centre[1] /= 4.0f;
1923         p->centre[2] /= 4.0f;
1924         Portal_GenNormale(p);
1925 
1926         /*
1927          * Portal position fix...
1928          */
1929         // X_MIN
1930         if((p->norm[0] > 0.999) && (((int)p->centre[0]) % 2))
1931         {
1932             float pos[3] = {1.0, 0.0, 0.0};
1933             Portal_Move(p, pos);
1934         }
1935 
1936         // Y_MIN
1937         if((p->norm[1] > 0.999) && (((int)p->centre[1]) % 2))
1938         {
1939             float pos[3] = {0.0, 1.0, 0.0};
1940             Portal_Move(p, pos);
1941         }
1942 
1943         // Z_MAX
1944         if((p->norm[2] <-0.999) && (((int)p->centre[2]) % 2))
1945         {
1946             float pos[3] = {0.0, 0.0, -1.0};
1947             Portal_Move(p, pos);
1948         }
1949     }
1950 
1951     /*
1952      * room borders calculation
1953      */
1954     room->bb_min[2] = tr_room->y_bottom;
1955     room->bb_max[2] = tr_room->y_top;
1956 
1957     room->bb_min[0] = room->transform[12 + 0] + TR_METERING_SECTORSIZE;
1958     room->bb_min[1] = room->transform[12 + 1] + TR_METERING_SECTORSIZE;
1959     room->bb_max[0] = room->transform[12 + 0] + TR_METERING_SECTORSIZE * room->sectors_x - TR_METERING_SECTORSIZE;
1960     room->bb_max[1] = room->transform[12 + 1] + TR_METERING_SECTORSIZE * room->sectors_y - TR_METERING_SECTORSIZE;
1961 
1962     room->obb = OBB_Create();
1963     room->obb->transform = room->transform;
1964     {
1965         float bb_min[3], bb_max[3];
1966         vec3_sub(bb_min, room->bb_min, room->transform + 12);
1967         vec3_sub(bb_max, room->bb_max, room->transform + 12);
1968         OBB_Rebuild(room->obb, bb_min, bb_max);
1969         OBB_Transform(room->obb);
1970     }
1971     /*
1972      * alternate room pointer calculation if one exists.
1973      */
1974     room->alternate_room_next = NULL;
1975     room->alternate_room_prev = NULL;
1976     room->real_room = room;
1977     if((tr_room->alternate_room >= 0) && ((uint32_t)tr_room->alternate_room < tr->rooms_count))
1978     {
1979         room->alternate_room_next = global_world.rooms + tr_room->alternate_room;
1980     }
1981 
1982     /*
1983      *  let us load static room meshes
1984      */
1985     room->content->static_mesh_count = tr_room->num_static_meshes;
1986     if(room->content->static_mesh_count)
1987     {
1988         room->content->static_mesh = (static_mesh_p)calloc(room->content->static_mesh_count, sizeof(static_mesh_t));
1989     }
1990 
1991     r_static = room->content->static_mesh;
1992     for(uint16_t i = 0; i < tr_room->num_static_meshes; i++, r_static++)
1993     {
1994         tr_static = tr->find_staticmesh_id(tr_room->static_meshes[i].object_id);
1995         if(tr_static == NULL)
1996         {
1997             room->content->static_mesh_count--;
1998             r_static--;
1999             continue;
2000         }
2001         TR_vertex_to_arr(r_static->pos, &tr_room->static_meshes[i].pos);
2002         r_static->self = Container_Create();
2003         r_static->self->room = room;
2004         r_static->self->sector = Room_GetSectorRaw(room, r_static->pos);
2005         r_static->self->object = room->content->static_mesh + i;
2006         r_static->self->object_type = OBJECT_STATIC_MESH;
2007         r_static->self->collision_group = COLLISION_GROUP_STATIC_OBLECT;
2008         r_static->self->collision_mask = COLLISION_MASK_ALL;
2009         r_static->object_id = tr_room->static_meshes[i].object_id;
2010         r_static->mesh = global_world.meshes + tr->mesh_indices[tr_static->mesh];
2011 
2012         r_static->rot[0] = tr_room->static_meshes[i].rotation;
2013         r_static->rot[1] = 0.0;
2014         r_static->rot[2] = 0.0;
2015         r_static->tint[0] = tr_room->static_meshes[i].tint.r * 2;
2016         r_static->tint[1] = tr_room->static_meshes[i].tint.g * 2;
2017         r_static->tint[2] = tr_room->static_meshes[i].tint.b * 2;
2018         r_static->tint[3] = tr_room->static_meshes[i].tint.a * 2;
2019         r_static->obb = OBB_Create();
2020 
2021         r_static->cbb_min[0] = tr_static->collision_box[0].x;
2022         r_static->cbb_min[1] =-tr_static->collision_box[0].z;
2023         r_static->cbb_min[2] = tr_static->collision_box[1].y;
2024         r_static->cbb_max[0] = tr_static->collision_box[1].x;
2025         r_static->cbb_max[1] =-tr_static->collision_box[1].z;
2026         r_static->cbb_max[2] = tr_static->collision_box[0].y;
2027 
2028         r_static->vbb_min[0] = tr_static->visibility_box[0].x;
2029         r_static->vbb_min[1] =-tr_static->visibility_box[0].z;
2030         r_static->vbb_min[2] = tr_static->visibility_box[1].y;
2031         r_static->vbb_max[0] = tr_static->visibility_box[1].x;
2032         r_static->vbb_max[1] =-tr_static->visibility_box[1].z;
2033         r_static->vbb_max[2] = tr_static->visibility_box[0].y;
2034 
2035         r_static->obb->transform = r_static->transform;
2036         r_static->obb->radius = r_static->mesh->radius;
2037         Mat4_E(r_static->transform);
2038         Mat4_Translate(r_static->transform, r_static->pos);
2039         float ang = r_static->rot[0] * M_PI / 180.0f;
2040         Mat4_RotateZ_SinCos(r_static->transform, sinf(ang), cosf(ang));
2041         OBB_Rebuild(r_static->obb, r_static->vbb_min, r_static->vbb_max);
2042         OBB_Transform(r_static->obb);
2043 
2044         r_static->physics_body = NULL;
2045         r_static->hide = 0;
2046 
2047         // Disable static mesh collision, if flag value is 3 (TR1) or all bounding box
2048         // coordinates are equal (TR2-5).
2049 
2050         if((tr_static->flags == 3) ||
2051            ((r_static->cbb_min[0] == r_static->cbb_min[1]) && (r_static->cbb_min[1] == r_static->cbb_min[2]) &&
2052             (r_static->cbb_max[0] == r_static->cbb_max[1]) && (r_static->cbb_max[1] == r_static->cbb_max[2])))
2053         {
2054             r_static->self->collision_group = COLLISION_NONE;
2055         }
2056 
2057         // Set additional static mesh properties from level script override.
2058 
2059         World_SetStaticMeshProperties(r_static);
2060 
2061         // Set static mesh collision.
2062         Physics_GenStaticMeshRigidBody(r_static);
2063     }
2064 
2065     /*
2066      * sprites loading section
2067      */
2068     room->content->sprites_count = tr_room->num_sprites;
2069     if(room->content->sprites_count != 0)
2070     {
2071         uint32_t actual_sprites_count = 0;
2072         room->content->sprites = (room_sprite_p)calloc(room->content->sprites_count, sizeof(room_sprite_t));
2073         for(uint32_t i = 0; i < room->content->sprites_count; i++)
2074         {
2075             if((tr_room->sprites[i].texture >= 0) && ((uint32_t)tr_room->sprites[i].texture < global_world.sprites_count))
2076             {
2077                 room_sprite_p rs = room->content->sprites + actual_sprites_count;
2078                 rs->sprite = global_world.sprites + tr_room->sprites[i].texture;
2079                 TR_vertex_to_arr(rs->pos, &tr_room->vertices[tr_room->sprites[i].vertex].vertex);
2080                 vec3_add(rs->pos, rs->pos, room->transform + 12);
2081                 actual_sprites_count++;
2082             }
2083         }
2084         room->content->sprites_count = actual_sprites_count;
2085         if(actual_sprites_count == 0)
2086         {
2087             free(room->content->sprites);
2088             room->content->sprites = NULL;
2089         }
2090     }
2091 }
2092 
2093 
World_GenRooms(class VT_Level * tr)2094 void World_GenRooms(class VT_Level *tr)
2095 {
2096     global_world.rooms_count = tr->rooms_count;
2097     room_p r = global_world.rooms = (room_p)malloc(global_world.rooms_count * sizeof(room_t));
2098     for(uint32_t i = 0; i < global_world.rooms_count; i++, r++)
2099     {
2100         r->id = i;
2101         World_GenRoom(r, tr);
2102     }
2103 }
2104 
2105 
World_GenRoomFlipMap()2106 void World_GenRoomFlipMap()
2107 {
2108     // Flipmap count is hardcoded, as no original levels contain such info.
2109     global_world.flip_count = FLIPMAP_MAX_NUMBER;
2110 
2111     global_world.flip_map   = (uint8_t*)malloc(global_world.flip_count * sizeof(uint8_t));
2112     global_world.flip_state = (uint8_t*)malloc(global_world.flip_count * sizeof(uint8_t));
2113 
2114     memset(global_world.flip_map,   0, global_world.flip_count);
2115     memset(global_world.flip_state, 0, global_world.flip_count);
2116 }
2117 
2118 
World_GenSkeletalModels(class VT_Level * tr)2119 void World_GenSkeletalModels(class VT_Level *tr)
2120 {
2121     skeletal_model_p smodel;
2122     tr_moveable_t *tr_moveable;
2123 
2124     global_world.skeletal_models_count = tr->moveables_count;
2125     smodel = global_world.skeletal_models = (skeletal_model_p)calloc(global_world.skeletal_models_count, sizeof(skeletal_model_t));
2126 
2127     for(uint32_t i = 0; i < global_world.skeletal_models_count; i++, smodel++)
2128     {
2129         tr_moveable = &tr->moveables[i];
2130         smodel->id = tr_moveable->object_id;
2131         smodel->mesh_count = tr_moveable->num_meshes;
2132         TR_GenSkeletalModel(smodel, i, global_world.meshes, tr);
2133         SkeletalModel_FillTransparency(smodel);
2134     }
2135 }
2136 
2137 
World_GenEntities(class VT_Level * tr)2138 void World_GenEntities(class VT_Level *tr)
2139 {
2140     int top;
2141     tr2_item_t *tr_item;
2142     entity_p entity;
2143 
2144     for(uint32_t i = 0; i < tr->items_count; i++)
2145     {
2146         tr_item = &tr->items[i];
2147         entity = Entity_Create();
2148         entity->id = i;
2149         TR_vertex_to_arr(entity->transform.M4x4 + 12, &tr_item->pos);
2150         entity->transform.angles[0] = tr_item->rotation;
2151         entity->transform.angles[1] = 0.0f;
2152         entity->transform.angles[2] = 0.0f;
2153         Entity_UpdateTransform(entity);
2154         if((tr_item->room >= 0) && ((uint32_t)tr_item->room < global_world.rooms_count))
2155         {
2156             entity->self->room = global_world.rooms + tr_item->room;
2157             entity->self->sector = Room_GetSectorRaw(entity->self->room, entity->transform.M4x4 + 12);
2158         }
2159         else
2160         {
2161             entity->self->room = NULL;
2162             entity->self->sector = NULL;
2163         }
2164 
2165         entity->trigger_layout  = (tr_item->flags & 0x3E00) >> 9;               ///@FIXME: Ignore CLEAR BODY flags for a moment.
2166         entity->OCB             = tr_item->ocb;
2167         entity->timer           = 0.0;
2168         entity->state_flags &= (tr_item->flags & 0x0100) ? (0x0000) : (0xFFFF);
2169 
2170         entity->self->collision_group = COLLISION_GROUP_KINEMATIC;
2171         entity->self->collision_mask  = COLLISION_MASK_ALL;
2172         entity->self->collision_shape = COLLISION_SHAPE_TRIMESH;
2173         entity->move_type             = MOVE_STATIC_POS;
2174 
2175         entity->bf->animations.model = World_GetModelByID(tr_item->object_id);
2176 
2177         if(engine_lua)
2178         {
2179             if(entity->bf->animations.model == NULL)
2180             {
2181                 top = lua_gettop(engine_lua);                                   // save LUA stack
2182                 lua_getglobal(engine_lua, "getOverridedID");                    // add to the up of stack LUA's function
2183                 lua_pushinteger(engine_lua, tr->game_version);                  // add to stack first argument
2184                 lua_pushinteger(engine_lua, tr_item->object_id);                // add to stack second argument
2185                 if(lua_CallAndLog(engine_lua, 2, 1, 0))                         // call that function
2186                 {
2187                     entity->bf->animations.model = World_GetModelByID(lua_tointeger(engine_lua, -1));
2188                 }
2189                 lua_settop(engine_lua, top);                                    // restore LUA stack
2190             }
2191         }
2192 
2193         if(entity->bf->animations.model == NULL)
2194         {
2195             // SPRITE LOADING
2196             sprite_p sp = World_GetSpriteByID(tr_item->object_id);
2197             if(sp && entity->self->room)
2198             {
2199                 room_sprite_p rsp;
2200                 int sz = ++entity->self->room->content->sprites_count;
2201                 entity->self->room->content->sprites = (room_sprite_p)realloc(entity->self->room->content->sprites, sz * sizeof(room_sprite_t));
2202                 rsp = entity->self->room->content->sprites + sz - 1;
2203                 rsp->sprite = sp;
2204                 rsp->pos[0] = entity->transform.M4x4[12 + 0];
2205                 rsp->pos[1] = entity->transform.M4x4[12 + 1];
2206                 rsp->pos[2] = entity->transform.M4x4[12 + 2];
2207             }
2208 
2209             Entity_Delete(entity);
2210             continue;                                                           // that entity has no model. may be it is a some trigger or look at object
2211         }
2212 
2213         SSBoneFrame_CreateFromModel(entity->bf, entity->bf->animations.model);
2214         entity->bf->transform = &entity->transform;
2215 
2216         Entity_SetAnimation(entity, ANIM_TYPE_BASE, 0, 0);                      // Set zero animation and zero frame
2217         Entity_RebuildBV(entity);
2218         Room_AddObject(entity->self->room, entity->self);
2219         entity->self->sector = Room_GetSectorRaw(entity->self->room, entity->transform.M4x4 + 12);
2220         World_AddEntity(entity);
2221         World_SetEntityModelProperties(entity);
2222         Physics_GenRigidBody(entity->physics, entity->bf);
2223         Entity_UpdateRigidBody(entity, 1);
2224 
2225         if(!(entity->state_flags & ENTITY_STATE_ENABLED) || (entity->self->collision_group == COLLISION_NONE))
2226         {
2227             Entity_DisableCollision(entity);
2228         }
2229     }
2230 }
2231 
2232 
World_GenBaseItems()2233 void World_GenBaseItems()
2234 {
2235     Script_CallVoidFunc(engine_lua, "genBaseItems");
2236 }
2237 
2238 
World_GenSpritesBuffer()2239 void World_GenSpritesBuffer()
2240 {
2241     for (uint32_t i = 0; i < global_world.rooms_count; i++)
2242     {
2243         Room_GenSpritesBuffer(&global_world.rooms[i]);
2244     }
2245 }
2246 
2247 
WorldRoom_FindRealRoomInSequence(room_p room)2248 static room_p WorldRoom_FindRealRoomInSequence(room_p room)
2249 {
2250     room_p room_with_min_id = room;
2251 
2252     for(uint16_t i = 0; i < room->content->portals_count; ++i)
2253     {
2254         room_p outer_room = room->content->portals[i].dest_room;
2255         for(uint16_t j = 0; j < outer_room->content->portals_count; ++j)
2256         {
2257             room_p real_room = outer_room->content->portals[j].dest_room;
2258             if(room == real_room)
2259             {
2260                 return real_room;
2261             }
2262 
2263             for(room_p room_it = room->alternate_room_prev; room_it; room_it = room_it->alternate_room_prev)
2264             {
2265                 if(room_it == real_room)
2266                 {
2267                     return real_room;
2268                 }
2269                 if(room_it == room)
2270                 {
2271                     break;
2272                 }
2273             }
2274 
2275             for(room_p room_it = room->alternate_room_next; room_it; room_it = room_it->alternate_room_next)
2276             {
2277                 if(room_it == real_room)
2278                 {
2279                     return real_room;
2280                 }
2281                 if(room_it == room)
2282                 {
2283                     break;
2284                 }
2285             }
2286         }
2287     }
2288 
2289     if(!room->alternate_room_prev)
2290     {
2291         return room;
2292     }
2293 
2294     for(room_p room_it = room->alternate_room_prev; room_it; room_it = room_it->alternate_room_prev)
2295     {
2296         if(!room_it->alternate_room_prev)
2297         {
2298             return room_it;
2299         }
2300         if(room_with_min_id->id > room_it->id)
2301         {
2302             room_with_min_id = room_it;
2303         }
2304         if(room_it == room)
2305         {
2306             break;
2307         }
2308     }
2309 
2310     for(room_p room_it = room->alternate_room_next; room_it; room_it = room_it->alternate_room_next)
2311     {
2312         if(room_with_min_id->id > room_it->id)
2313         {
2314             room_with_min_id = room_it;
2315         }
2316         if(room_it == room)
2317         {
2318             break;
2319         }
2320     }
2321 
2322     return room_with_min_id;
2323 }
2324 
2325 
World_GenRoomProperties(class VT_Level * tr)2326 void World_GenRoomProperties(class VT_Level *tr)
2327 {
2328     for(uint32_t i = 0; i < global_world.rooms_count; i++)
2329     {
2330         room_p r = global_world.rooms + i;
2331         if(r->alternate_room_next)
2332         {
2333             r->real_room = NULL;
2334             r->alternate_room_next->real_room = NULL;                           // HACK for next real room calculation
2335             r->alternate_room_next->alternate_room_prev = r;                    // fill base room pointers
2336         }
2337     }
2338 
2339     for(uint32_t i = 0; i < global_world.rooms_count; i++)
2340     {
2341         room_p r = global_world.rooms + i;
2342         if(!r->real_room)
2343         {
2344             room_p real_room = WorldRoom_FindRealRoomInSequence(r);             // call it once per alt rooms sequence
2345             r->real_room = real_room;
2346             for(room_p room_it = r->alternate_room_next; room_it; room_it = room_it->alternate_room_next)
2347             {
2348                 room_it->real_room = real_room;
2349                 if(room_it == r)
2350                 {
2351                     break;
2352                 }
2353             }
2354             for(room_p room_it = r->alternate_room_prev; room_it; room_it = room_it->alternate_room_prev)
2355             {
2356                 room_it->real_room = real_room;
2357                 if(room_it == r)
2358                 {
2359                     break;
2360                 }
2361             }
2362         }
2363     }
2364 
2365     for(uint32_t i = 0; i < global_world.rooms_count; i++)
2366     {
2367         room_p r = global_world.rooms + i;
2368         // Fill heightmap and translate floordata.
2369         for(uint32_t j = 0; j < r->sectors_count; j++)
2370         {
2371             room_sector_p rs = r->content->sectors + j;
2372             Res_Sector_TranslateFloorData(global_world.rooms, global_world.rooms_count, rs, tr);
2373             for(trigger_command_p cmd = (rs->trigger) ? (rs->trigger->commands) : (NULL); cmd; cmd = cmd->next)
2374             {
2375                 if(cmd->function == TR_FD_TRIGFUNC_PLAYTRACK)
2376                 {
2377                     Audio_CacheTrack(cmd->operands);
2378                 }
2379             }
2380         }
2381 
2382         // Basic sector calculations.
2383         Res_RoomSectorsCalculate(global_world.rooms, global_world.rooms_count, i, tr);
2384     }
2385 
2386     for(uint32_t i = 0; i < global_world.rooms_count; i++)
2387     {
2388         // Generate links to the overlapped rooms.
2389         World_BuildOverlappedRoomsList(global_world.rooms + i);
2390         // Generate links to the near rooms.
2391         World_BuildNearRoomsList(global_world.rooms + i);
2392     }
2393 
2394     for(uint32_t i = 0; i < global_world.rooms_count; i++)
2395     {
2396         room_p r = global_world.rooms + i;
2397         for(uint16_t j = 0; j < r->content->near_room_list_size; ++j)
2398         {
2399             Room_AddToNearRoomsList(r->content->near_room_list[j], r);
2400         }
2401     }
2402 }
2403 
2404 
World_GenRoomCollision()2405 void World_GenRoomCollision()
2406 {
2407     room_p r = global_world.rooms;
2408 
2409     if(r == NULL)
2410     {
2411         return;
2412     }
2413 
2414     for(uint32_t i = 0; i < global_world.rooms_count; i++, r++)
2415     {
2416         // Inbetween polygons array is later filled by loop which scans adjacent
2417         // sector heightmaps and fills the gaps between them, thus creating inbetween
2418         // polygon. Inbetweens can be either quad (if all four corner heights are
2419         // different), triangle (if one corner height is similar to adjacent) or
2420         // ghost (if corner heights are completely similar). In case of quad inbetween,
2421         // two triangles are added to collisional trimesh, in case of triangle inbetween,
2422         // we add only one, and in case of ghost inbetween, we ignore it.
2423 
2424         int num_tweens = r->sectors_count * 4;
2425         size_t buff_size = num_tweens * sizeof(sector_tween_t);
2426         sector_tween_p room_tween = (sector_tween_p)Sys_GetTempMem(buff_size);
2427 
2428         // Clear tween array.
2429 
2430         for(int j = 0; j < num_tweens; j++)
2431         {
2432             room_tween[j].ceiling_tween_type = TR_SECTOR_TWEEN_TYPE_NONE;
2433             room_tween[j].floor_tween_type   = TR_SECTOR_TWEEN_TYPE_NONE;
2434         }
2435 
2436         // Most difficult task with converting floordata collision to trimesh collision is
2437         // building inbetween polygons which will block out gaps between sector heights.
2438         num_tweens = Res_Sector_GenStaticTweens(r, room_tween);
2439 
2440         // Final step is sending actual sectors to Bullet collision model. We do it here.
2441         r->content->physics_body = Physics_GenRoomRigidBody(r, r->content->sectors, r->sectors_count, room_tween, num_tweens);
2442         r->self->collision_group = COLLISION_GROUP_STATIC_ROOM;                 // meshtree
2443         r->self->collision_shape = COLLISION_SHAPE_TRIMESH;
2444 
2445         Sys_ReturnTempMem(buff_size);
2446     }
2447 }
2448 
2449 
World_FixRooms()2450 void World_FixRooms()
2451 {
2452     room_p r = global_world.rooms;
2453 
2454     if(r == NULL)
2455     {
2456         return;
2457     }
2458 
2459     for(uint32_t i = 0; i < global_world.rooms_count; i++, r++)
2460     {
2461         if(r->real_room != r)
2462         {
2463             Room_Disable(r);
2464         }
2465     }
2466 }
2467