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