Subversion Repositories Games.Carmageddon

Rev

Rev 20 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "world.h"
2
#include <stdlib.h>
3
 
20 pmbaty 4
#include "brender/brender.h"
1 pmbaty 5
#include "brucetrk.h"
6
#include "car.h"
7
#include "depth.h"
8
#include "displays.h"
9
#include "drmem.h"
10
#include "errors.h"
11
#include "finteray.h"
12
#include "flicplay.h"
13
#include "globvars.h"
14
#include "globvrpb.h"
15
#include "graphics.h"
16
#include "harness/trace.h"
17
#include "input.h"
18
#include "loading.h"
19
#include "opponent.h"
20
#include "pd/sys.h"
21
#include "pedestrn.h"
22
#include "piping.h"
23
#include "replay.h"
24
#include "spark.h"
25
#include "trig.h"
26
#include "utility.h"
27
 
28
#include <float.h>
29
#include <string.h>
30
 
11 pmbaty 31
static const br_scalar viewdistance_surmultiplier = 2.5; // Pierre-Marie Baty -- view distance surmultiplier addition
32
 
1 pmbaty 33
int gFunkotronics_array_size;
34
int gGroovidelics_array_size;
35
int gSpec_vol_mode;
36
tFunkotronic_spec* gFunkotronics_array;
37
tGroovidelic_spec* gGroovidelics_array;
38
char* gFunk_type_names[] = { "spin", "rock", "throb", "slither", "roll" };
39
char* gFunk_anim_names[] = { "frames", "flic" };
40
char* gTime_mode_names[] = { "approximate", "accurate" };
41
char* gFunk_move_names[] = { "linear", "harmonic", "flash", "controlled", "absolute", "continuous" };
42
char* gFunk_nature_names[] = { "constant", "distance", "lastlap", "otherlaps" };
43
char* gGroove_nature_names[] = { "constant", "distance" };
44
char* gAxis_names[] = { "x", "y", "z" };
45
char* gLollipop_names[] = { "xlollipop", "ylollipop", "zlollipop" };
46
char* gGroove_path_names[] = { "straight", "circular" };
47
char* gGroove_object_names[] = { "spin", "rock", "throb", "shear" };
48
char* gDepth_effect_names[] = { "dark", "fog" };
49
br_actor* gGroove_by_proxy_actor;
50
tRotate_mode gCurrent_rotate_mode = eRotate_mode_y;
51
tScale_mode gCurrent_scale_mode = eScale_mode_all;
52
int gNumber_of_additional_models;
53
tRoad_texturing_level gRoad_texturing_level = eRTL_full;
54
tWall_texturing_level gWall_texturing_level = eWTL_full;
55
tCar_texturing_level gCar_texturing_level = eCTL_full;
56
int gRendering_accessories;
57
int gNumber_of_actors;
58
int gNumber_of_lights;
59
br_actor* gActor_array[500];
60
float* gGroove_funk_bindings[960];
61
br_actor* gDelete_list[500];
62
br_actor* gLight_array[50];
63
br_model* gAdditional_models[1000];
64
br_actor* gSpec_vol_actors[100];
65
tPath_name gAdditional_actor_path;
66
tPath_name gAdditional_model_path;
67
tU32 gPrevious_groove_times[2];
68
int gRace_file_version;
69
br_vector3 gActor_centre;
70
float gTemp;
71
br_actor* gLast_actor;
72
br_actor* gKnown_actor;
73
br_actor* gAdditional_actors;
74
int gDelete_count;
75
br_scalar gNearest_distance;
76
br_actor* gNearest_actor;
77
br_actor* gStandard_lamp;
78
br_scalar gSight_distance_squared;
79
 
80
// IDA: float __cdecl MapSawToTriangle(float pNumber)
81
float MapSawToTriangle(float pNumber) {
82
    LOG_TRACE("(%f)", pNumber);
83
 
84
    if (pNumber >= 0.5) {
85
        return 3.0 - pNumber * 4.0;
86
    } else {
87
        return pNumber * 4.0 - 1.0;
88
    }
89
}
90
 
91
// IDA: void __cdecl SetSightDistance(br_scalar pYon)
92
void SetSightDistance(br_scalar pYon) {
93
    gSight_distance_squared = pYon * 1.02f * (pYon * 1.02f);
94
}
95
 
96
// IDA: br_actor* __usercall FindActorInArray@<EAX>(char *pThe_name@<EAX>)
97
br_actor* FindActorInArray(char* pThe_name) {
98
    int i;
99
    LOG_TRACE("(\"%s\")", pThe_name);
100
 
101
    for (i = 0; i < gNumber_of_actors; i++) {
102
        if (strcmp(gActor_array[i]->identifier, pThe_name) == 0) {
103
            return gActor_array[i];
104
        }
105
    }
106
    return NULL;
107
}
108
 
109
// IDA: br_actor* __usercall FindLightInArray@<EAX>(char *pThe_name@<EAX>)
110
br_actor* FindLightInArray(char* pThe_name) {
111
    int i;
112
    LOG_TRACE("(\"%s\")", pThe_name);
113
 
114
    for (i = 0; i < gNumber_of_lights; i++) {
115
        if (strcmp(gLight_array[i]->identifier, pThe_name) == 0) {
116
            return gLight_array[i];
117
        }
118
    }
119
    return NULL;
120
}
121
 
122
// IDA: br_actor* __usercall CloneActor@<EAX>(br_actor *pSource_actor@<EAX>)
123
br_actor* CloneActor(br_actor* pSource_actor) {
124
    br_actor* new_actor;
125
    br_actor* child_actor;
126
    br_actor* new_child_actor;
127
    LOG_TRACE("(%p)", pSource_actor);
128
 
129
    new_actor = BrActorAllocate(pSource_actor->type, pSource_actor->type_data);
130
    new_actor->model = pSource_actor->model;
131
    new_actor->material = pSource_actor->material;
132
    if (pSource_actor->identifier != NULL) {
133
        if (new_actor->identifier != NULL) {
134
            BrResFree(new_actor->identifier);
135
        }
136
        new_actor->identifier = BrResStrDup(new_actor, pSource_actor->identifier);
137
    }
138
    new_actor->t = pSource_actor->t;
139
    for (child_actor = pSource_actor->children; child_actor != NULL; child_actor = child_actor->next) {
140
        new_child_actor = CloneActor(child_actor);
141
        BrActorAdd(new_actor, new_child_actor);
142
    }
143
    return new_actor;
144
}
145
 
146
// IDA: void __usercall InitialiseStorageSpace(tBrender_storage *pStorage_space@<EAX>, int pMax_pixelmaps@<EDX>, int pMax_shade_tables@<EBX>, int pMax_materials@<ECX>, int pMax_models)
147
void InitialiseStorageSpace(tBrender_storage* pStorage_space, int pMax_pixelmaps, int pMax_shade_tables, int pMax_materials, int pMax_models) {
148
    LOG_TRACE("(%p, %d, %d, %d, %d)", pStorage_space, pMax_pixelmaps, pMax_shade_tables, pMax_materials, pMax_models);
149
 
150
    pStorage_space->pixelmaps_count = 0;
151
    pStorage_space->shade_tables_count = 0;
152
    pStorage_space->materials_count = 0;
153
    pStorage_space->models_count = 0;
154
    pStorage_space->max_pixelmaps = pMax_pixelmaps;
155
    pStorage_space->max_shade_tables = pMax_shade_tables;
156
    pStorage_space->max_materials = pMax_materials;
157
    pStorage_space->max_models = pMax_models;
158
    pStorage_space->pixelmaps = BrMemCalloc(pMax_pixelmaps, sizeof(br_pixelmap*), kMem_stor_space_pix);
159
    pStorage_space->shade_tables = BrMemCalloc(pMax_shade_tables, sizeof(br_pixelmap*), kMem_stor_space_tab);
160
    pStorage_space->materials = BrMemCalloc(pMax_materials, sizeof(br_material*), kMem_stor_space_mat);
161
    pStorage_space->models = BrMemCalloc(pMax_models, sizeof(br_model*), kMem_stor_space_mod);
162
    pStorage_space->saved_colour_maps = BrMemCalloc(pMax_materials, sizeof(br_pixelmap*), kMem_stor_space_save);
163
}
164
 
165
// IDA: void __usercall DisposeStorageSpace(tBrender_storage *pStorage_space@<EAX>)
166
void DisposeStorageSpace(tBrender_storage* pStorage_space) {
167
    BrMemFree(pStorage_space->pixelmaps);
168
    BrMemFree(pStorage_space->shade_tables);
169
    BrMemFree(pStorage_space->materials);
170
    BrMemFree(pStorage_space->models);
171
    BrMemFree(pStorage_space->saved_colour_maps);
172
}
173
 
174
// IDA: void __usercall ClearOutStorageSpace(tBrender_storage *pStorage_space@<EAX>)
175
void ClearOutStorageSpace(tBrender_storage* pStorage_space) {
176
    int i;
177
    LOG_TRACE("(%p)", pStorage_space);
178
 
179
    for (i = 0; pStorage_space->pixelmaps_count > i; ++i) {
180
        if (pStorage_space->pixelmaps[i] != NULL) {
181
            BrMapRemove(pStorage_space->pixelmaps[i]);
182
            BrPixelmapFree(pStorage_space->pixelmaps[i]);
183
        }
184
    }
185
    pStorage_space->pixelmaps_count = 0;
186
    for (i = 0; pStorage_space->shade_tables_count > i; ++i) {
187
        if (pStorage_space->shade_tables[i] != NULL) {
188
            BrTableRemove(pStorage_space->shade_tables[i]);
189
            BrPixelmapFree(pStorage_space->shade_tables[i]);
190
        }
191
    }
192
    pStorage_space->shade_tables_count = 0;
193
    for (i = 0; pStorage_space->materials_count > i; ++i) {
194
        if (pStorage_space->materials[i] != NULL) {
195
            BrMaterialRemove(pStorage_space->materials[i]);
196
            BrMaterialFree(pStorage_space->materials[i]);
197
        }
198
    }
199
    pStorage_space->materials_count = 0;
200
    for (i = 0; pStorage_space->models_count > i; ++i) {
201
        if (pStorage_space->models[i] != NULL) {
202
            BrModelRemove(pStorage_space->models[i]);
203
            BrModelFree(pStorage_space->models[i]);
204
        }
205
    }
206
    pStorage_space->models_count = 0;
207
}
208
 
209
// IDA: tAdd_to_storage_result __usercall AddPixelmapToStorage@<EAX>(tBrender_storage *pStorage_space@<EAX>, br_pixelmap **pThe_pm@<EDX>)
210
// This seems like the signature should be `br_pixelmap* pThe_pm`
211
tAdd_to_storage_result AddPixelmapToStorage(tBrender_storage* pStorage_space, br_pixelmap** pThe_pm) {
212
    int i;
213
    LOG_TRACE("(%p, %p)", pStorage_space, pThe_pm);
214
 
215
    if (pStorage_space->pixelmaps_count >= pStorage_space->max_pixelmaps) {
216
        return eStorage_not_enough_room;
217
    }
218
 
219
    for (i = 0; i < pStorage_space->pixelmaps_count; i++) {
220
        if (pStorage_space->pixelmaps[i]->identifier
221
            && ((br_pixelmap*)pThe_pm)->identifier
222
            && strcmp(pStorage_space->pixelmaps[i]->identifier, ((br_pixelmap*)pThe_pm)->identifier) == 0) {
223
            return eStorage_duplicate;
224
        }
225
    }
226
    pStorage_space->pixelmaps[pStorage_space->pixelmaps_count] = (br_pixelmap*)pThe_pm;
227
    pStorage_space->pixelmaps_count++;
228
    return eStorage_allocated;
229
}
230
 
231
// IDA: tAdd_to_storage_result __usercall AddShadeTableToStorage@<EAX>(tBrender_storage *pStorage_space@<EAX>, br_pixelmap *pThe_st@<EDX>)
232
tAdd_to_storage_result AddShadeTableToStorage(tBrender_storage* pStorage_space, br_pixelmap* pThe_st) {
233
    int i;
234
    LOG_TRACE("(%p, %p)", pStorage_space, pThe_st);
235
 
236
    if (pStorage_space->shade_tables_count >= pStorage_space->max_shade_tables) {
237
        return eStorage_not_enough_room;
238
    }
239
 
240
    for (i = 0; i < pStorage_space->shade_tables_count; i++) {
241
        if (pStorage_space->shade_tables[i]->identifier
242
            && pThe_st->identifier
243
            && !strcmp(pStorage_space->shade_tables[i]->identifier, pThe_st->identifier)) {
244
            return eStorage_duplicate;
245
        }
246
    }
247
    pStorage_space->shade_tables[pStorage_space->shade_tables_count++] = pThe_st;
248
    return eStorage_allocated;
249
}
250
 
251
// IDA: tAdd_to_storage_result __usercall AddMaterialToStorage@<EAX>(tBrender_storage *pStorage_space@<EAX>, br_material *pThe_mat@<EDX>)
252
tAdd_to_storage_result AddMaterialToStorage(tBrender_storage* pStorage_space, br_material* pThe_mat) {
253
    int i;
254
    LOG_TRACE("(%p, %p)", pStorage_space, pThe_mat);
255
 
256
    if (pStorage_space->materials_count >= pStorage_space->max_materials) {
257
        return eStorage_not_enough_room;
258
    }
259
    for (i = 0; i < pStorage_space->materials_count; i++) {
260
        if (pStorage_space->materials[i]->identifier
261
            && pThe_mat->identifier
262
            && !strcmp(pStorage_space->materials[i]->identifier, pThe_mat->identifier)) {
263
            return eStorage_duplicate;
264
        }
265
    }
266
    pStorage_space->saved_colour_maps[pStorage_space->materials_count] = 0;
267
    pStorage_space->materials[pStorage_space->materials_count++] = pThe_mat;
268
    return eStorage_allocated;
269
}
270
 
271
// IDA: tAdd_to_storage_result __usercall AddModelToStorage@<EAX>(tBrender_storage *pStorage_space@<EAX>, br_model *pThe_mod@<EDX>)
272
tAdd_to_storage_result AddModelToStorage(tBrender_storage* pStorage_space, br_model* pThe_mod) {
273
    int i;
274
    LOG_TRACE("(%p, %p)", pStorage_space, pThe_mod);
275
 
276
    if (pStorage_space->materials_count >= pStorage_space->max_models) {
277
        return eStorage_not_enough_room;
278
    }
279
    for (i = 0; i < pStorage_space->models_count; i++) {
280
        if (pStorage_space->models[i]
281
            && pStorage_space->models[i]->identifier
282
            && pThe_mod->identifier
283
            && !strcmp(pStorage_space->models[i]->identifier, pThe_mod->identifier)) {
284
            return eStorage_duplicate;
285
        }
286
    }
287
    pStorage_space->models[pStorage_space->models_count] = pThe_mod;
288
    pStorage_space->models_count++;
289
    return eStorage_allocated;
290
}
291
 
292
// IDA: int __usercall LoadNPixelmaps@<EAX>(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>, int pCount@<EBX>)
293
int LoadNPixelmaps(tBrender_storage* pStorage_space, FILE* pF, int pCount) {
294
    tPath_name the_path;
295
    int i;
296
    int j;
297
    int new_ones;
298
    int total;
299
    char s[256];
300
    char* str;
301
    br_pixelmap* temp_array[200];
302
    LOG_TRACE("(%p, %p, %d)", pStorage_space, pF, pCount);
303
 
304
    new_ones = 0;
305
    for (i = 0; i < pCount; ++i) {
306
        PossibleService();
307
        GetALineAndDontArgue(pF, s);
308
        str = strtok(s, "\t ,/");
309
        PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
310
        PathCat(the_path, the_path, "PIXELMAP");
311
        PathCat(the_path, the_path, str);
312
        AllowOpenToFail();
313
        total = DRPixelmapLoadMany(the_path, temp_array, COUNT_OF(temp_array));
314
        if (total == 0) {
315
            PathCat(the_path, gApplication_path, "PIXELMAP");
316
            PathCat(the_path, the_path, str);
317
            total = DRPixelmapLoadMany(the_path, temp_array, COUNT_OF(temp_array));
318
            if (total == 0) {
319
                FatalError(kFatalError_LoadPixelmapFile_S, str);
320
            }
321
        }
322
        for (j = 0; j < total; j++) {
323
            if (temp_array[j] != NULL) {
324
                switch (AddPixelmapToStorage(pStorage_space, (br_pixelmap**)temp_array[j])) {
325
                case eStorage_not_enough_room:
326
                    FatalError(kFatalError_InsufficientPixelmapSlots);
327
                    break;
328
                case eStorage_duplicate:
329
                    BrPixelmapFree(temp_array[j]);
330
                    break;
331
                case eStorage_allocated:
332
                    BrMapAdd(temp_array[j]);
333
                    ++new_ones;
334
                    break;
335
                }
336
            }
337
        }
338
    }
339
    return new_ones;
340
}
341
 
342
// IDA: br_pixelmap* __usercall LoadSinglePixelmap@<EAX>(tBrender_storage *pStorage_space@<EAX>, char *pName@<EDX>)
343
br_pixelmap* LoadSinglePixelmap(tBrender_storage* pStorage_space, char* pName) {
344
    br_pixelmap* temp;
345
    LOG_TRACE("(%p, \"%s\")", pStorage_space, pName);
346
 
347
    temp = LoadPixelmap(pName);
348
    if (!temp) {
349
        return BrMapFind(pName);
350
    }
351
 
352
    switch (AddPixelmapToStorage(pStorage_space, (br_pixelmap**)temp)) {
353
    case eStorage_not_enough_room:
354
        FatalError(kFatalError_InsufficientPixelmapSlots);
355
        break;
356
 
357
    case eStorage_duplicate:
358
        BrPixelmapFree(temp);
359
        return BrMapFind(pName);
360
 
361
    case eStorage_allocated:
362
        BrMapAdd(temp);
363
        return temp;
364
    }
365
 
366
    return NULL;
367
}
368
 
369
// IDA: br_material* __usercall LoadSingleMaterial@<EAX>(tBrender_storage *pStorage_space@<EAX>, char *pName@<EDX>)
370
br_material* LoadSingleMaterial(tBrender_storage* pStorage_space, char* pName) {
371
    br_material* temp;
372
    LOG_TRACE("(%p, \"%s\")", pStorage_space, pName);
373
 
374
    temp = LoadMaterial(pName);
375
    if (!temp) {
376
        return BrMaterialFind(pName);
377
    }
378
 
379
    switch (AddMaterialToStorage(pStorage_space, temp)) {
380
    case eStorage_not_enough_room:
381
        FatalError(kFatalError_InsufficientMaterialSlots);
382
        break;
383
 
384
    case eStorage_duplicate:
385
        BrMaterialFree(temp);
386
        return BrMaterialFind(pName);
387
 
388
    case eStorage_allocated:
389
        BrMaterialAdd(temp);
390
        return temp;
391
    }
392
 
393
    return NULL;
394
}
395
 
396
// IDA: int __usercall LoadNShadeTables@<EAX>(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>, int pCount@<EBX>)
397
int LoadNShadeTables(tBrender_storage* pStorage_space, FILE* pF, int pCount) {
398
    tPath_name the_path;
399
    int i;
400
    int j;
401
    int new_ones;
402
    int total;
403
    char s[256];
404
    char* str;
405
    br_pixelmap* temp_array[50];
406
    LOG_TRACE("(%p, %p, %d)", pStorage_space, pF, pCount);
407
 
408
    new_ones = 0;
409
    for (i = 0; i < pCount; i++) {
410
        PossibleService();
411
        GetALineAndDontArgue(pF, s);
412
        str = strtok(s, "\t ,/");
413
        PathCat(the_path, gApplication_path, "SHADETAB");
414
        PathCat(the_path, the_path, str);
415
        total = DRPixelmapLoadMany(the_path, temp_array, 50);
416
        if (total == 0) {
417
            FatalError(kFatalError_LoadShadeTableFile_S, str);
418
        }
419
        for (j = 0; j < total; j++) {
420
            if (temp_array[j]) {
421
                switch (AddShadeTableToStorage(pStorage_space, temp_array[j])) {
422
                case eStorage_not_enough_room:
423
                    FatalError(kFatalError_InsufficientShadeTableSlots);
424
                    break;
425
 
426
                case eStorage_duplicate:
427
                    BrPixelmapFree(temp_array[j]);
428
                    break;
429
                case eStorage_allocated:
430
                    BrTableAdd(temp_array[j]);
431
                    new_ones++;
432
                    break;
433
                }
434
            }
435
        }
436
    }
437
    return new_ones;
438
}
439
 
440
// IDA: br_pixelmap* __usercall LoadSingleShadeTable@<EAX>(tBrender_storage *pStorage_space@<EAX>, char *pName@<EDX>)
441
br_pixelmap* LoadSingleShadeTable(tBrender_storage* pStorage_space, char* pName) {
442
    br_pixelmap* temp;
443
    LOG_TRACE("(%p, \"%s\")", pStorage_space, pName);
444
 
445
    temp = LoadShadeTable(pName);
446
    if (!temp) {
447
        return BrTableFind(pName);
448
    }
449
 
450
    switch (AddShadeTableToStorage(pStorage_space, temp)) {
451
    case eStorage_not_enough_room:
452
        FatalError(kFatalError_InsufficientShadeTableSlots);
453
        break;
454
 
455
    case eStorage_duplicate:
456
        BrPixelmapFree(temp);
457
        return BrTableFind(pName);
458
 
459
    case eStorage_allocated:
460
        BrTableAdd(temp);
461
        return temp;
462
    }
463
 
464
    return NULL;
465
}
466
 
467
// IDA: int __usercall LoadNMaterials@<EAX>(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>, int pCount@<EBX>)
468
int LoadNMaterials(tBrender_storage* pStorage_space, FILE* pF, int pCount) {
469
    tPath_name the_path;
470
    int i;
471
    int j;
472
    int new_ones;
473
    int total;
474
    char s[256];
475
    char* str;
476
    br_material* temp_array[200];
477
    LOG_TRACE("(%p, %p, %d)", pStorage_space, pF, pCount);
478
 
479
    new_ones = 0;
480
    for (i = 0; i < pCount; ++i) {
481
        PossibleService();
482
        GetALineAndDontArgue(pF, s);
483
        str = strtok(s, "\t ,/");
484
        PathCat(the_path, gApplication_path, "MATERIAL");
485
        PathCat(the_path, the_path, str);
486
        total = BrMaterialLoadMany(the_path, temp_array, 200);
487
        if (total == 0) {
488
            FatalError(kFatalError_LoadMaterialFile_S, str);
489
        }
490
        for (j = 0; j < total; j++) {
491
            if (temp_array[j]) {
492
                switch (AddMaterialToStorage(pStorage_space, temp_array[j])) {
493
                case eStorage_not_enough_room:
494
                    FatalError(kFatalError_InsufficientMaterialSlots);
495
                    break;
496
                case eStorage_duplicate:
497
                    BrMaterialFree(temp_array[j]);
498
                    break;
499
                case eStorage_allocated:
500
                    BrMaterialAdd(temp_array[j]);
501
                    new_ones++;
502
                }
503
            }
504
        }
505
    }
506
    return new_ones;
507
}
508
 
509
// IDA: int __usercall LoadNModels@<EAX>(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>, int pCount@<EBX>)
510
int LoadNModels(tBrender_storage* pStorage_space, FILE* pF, int pCount) {
511
    tPath_name the_path;
512
    int i;
513
    int j;
514
    int new_ones;
515
    int total;
516
    char s[256];
517
    char* str;
518
    br_model* temp_array[2000];
519
    //v11model* prepared; // Pierre-Marie Baty -- unused variable
520
    //int group; // Pierre-Marie Baty -- unused variable
521
    LOG_TRACE("(%p, %p, %d)", pStorage_space, pF, pCount);
522
 
523
    new_ones = 0;
524
    for (i = 0; i < pCount; i++) {
525
        PossibleService();
526
        GetALineAndDontArgue(pF, s);
527
        str = strtok(s, "\t ,/");
528
        PathCat(the_path, gApplication_path, "MODELS");
529
        PathCat(the_path, the_path, str);
530
        total = BrModelLoadMany(the_path, temp_array, 2000);
531
        if (total == 0) {
532
            FatalError(kFatalError_LoadModelFile_S, str);
533
        }
534
        for (j = 0; j < total; j++) {
535
            if (temp_array[j]) {
536
                switch (AddModelToStorage(pStorage_space, temp_array[j])) {
537
                case eStorage_not_enough_room:
538
                    FatalError(kFatalError_InsufficientModelSlots);
539
                    break;
540
                case eStorage_duplicate:
541
                    BrModelFree(temp_array[j]);
542
                    break;
543
                case eStorage_allocated:
544
                    temp_array[j]->flags |= 0x80u;
545
                    RemoveDoubleSided(temp_array[j]);
546
                    BrModelAdd(temp_array[j]);
547
                    ++new_ones;
548
                    break;
549
                }
550
            }
551
        }
552
    }
553
 
554
    return new_ones;
555
}
556
 
557
// IDA: void __usercall DodgyModelUpdate(br_model *pM@<EAX>)
558
void DodgyModelUpdate(br_model* pM) {
559
    LOG_TRACE("(%p)", pM);
560
 
561
    BrResFree(pM->faces);
562
    BrResFree(pM->vertices);
563
    pM->nfaces = 0;
564
    pM->nvertices = 0;
565
    pM->faces = NULL;
566
    pM->vertices = NULL;
567
}
568
 
569
// IDA: br_material* __usercall SuffixedMaterial@<EAX>(br_material *pOld@<EAX>, char *pSuffix@<EDX>)
570
br_material* SuffixedMaterial(br_material* pOld, char* pSuffix) {
571
    br_material* new_mat;
572
    char* new_id;
573
    LOG_TRACE("(%p, \"%s\")", pOld, pSuffix);
574
 
575
    new_id = BrMemAllocate(strlen(pOld->identifier) + strlen(pSuffix) + 1, kMem_new_mat_id);
576
    sprintf(new_id, "%s%s", pOld->identifier, pSuffix);
577
    new_mat = BrMaterialFind(new_id);
578
    if (new_mat == NULL) {
579
        new_mat = BrMaterialAllocate(NULL);
580
        MaterialCopy(new_mat, pOld);
581
        new_mat->identifier = new_id;
582
        BrMaterialAdd(new_mat);
583
    } else {
584
        BrMemFree(new_id);
585
    }
586
    return new_mat;
587
}
588
 
589
// IDA: int __usercall FaceIsRoad@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
590
int FaceIsRoad(br_model* pModel, tU16 pFace) {
591
    br_vector3 v0;
592
    br_vector3 v1;
593
    br_vector3 cross;
594
    LOG_TRACE("(%p, %d)", pModel, pFace);
595
 
596
    BrVector3Sub(&v0, &pModel->vertices[pModel->faces[pFace].vertices[0]].p, &pModel->vertices[pModel->faces[pFace].vertices[1]].p);
597
    BrVector3Sub(&v1, &pModel->vertices[pModel->faces[pFace].vertices[1]].p, &pModel->vertices[pModel->faces[pFace].vertices[2]].p);
598
    BrVector3Cross(&cross, &v0, &v1);
599
    return sqrtf(cross.v[0] * cross.v[0] + cross.v[2] * cross.v[2]) < 0.7f * cross.v[1];
600
}
601
 
602
// IDA: br_material* __usercall RoadPerspToUntex@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
603
br_material* RoadPerspToUntex(br_model* pModel, tU16 pFace) {
604
    br_material* old_mat;
605
    br_material* new_mat;
606
    LOG_TRACE("(%p, %d)", pModel, pFace);
607
 
608
    old_mat = pModel->faces[pFace].material;
609
    if (old_mat->colour_map == NULL || !FaceIsRoad(pModel, pFace)) {
610
        return NULL;
611
    }
612
    new_mat = SuffixedMaterial(old_mat, ".road");
613
    if (new_mat->colour_map != NULL) {
614
        new_mat->colour_map = NULL;
615
        BrMaterialUpdate(new_mat, BR_MATU_ALL);
616
    }
617
    return new_mat;
618
}
619
 
620
// IDA: br_material* __usercall WallPerspToLinear@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
621
br_material* WallPerspToLinear(br_model* pModel, tU16 pFace) {
622
    br_material* old_mat;
623
    br_material* new_mat;
624
    LOG_TRACE("(%p, %d)", pModel, pFace);
625
 
626
    old_mat = pModel->faces[pFace].material;
627
    if (old_mat->colour_map == NULL || !(old_mat->flags & BR_MATF_PERSPECTIVE) || FaceIsRoad(pModel, pFace)) {
628
        return NULL;
629
    }
630
    new_mat = SuffixedMaterial(old_mat, ".pwall");
631
    if (new_mat->flags & BR_MATF_PERSPECTIVE) {
632
        new_mat->flags &= ~BR_MATF_PERSPECTIVE;
633
        BrMaterialUpdate(new_mat, BR_MATU_ALL);
634
    }
635
    return new_mat;
636
}
637
 
638
// IDA: br_material* __usercall WallPerspToUntex@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
639
br_material* WallPerspToUntex(br_model* pModel, tU16 pFace) {
640
    br_material* old_mat;
641
    br_material* new_mat;
642
    LOG_TRACE("(%p, %d)", pModel, pFace);
643
 
644
    old_mat = pModel->faces[pFace].material;
645
    if (old_mat->colour_map == NULL || FaceIsRoad(pModel, pFace)) {
646
        return NULL;
647
    }
648
    if (old_mat->flags & BR_MATF_PERSPECTIVE) {
649
        new_mat = SuffixedMaterial(old_mat, ".pwall");
650
    } else {
651
        new_mat = SuffixedMaterial(old_mat, ".lwall");
652
    }
653
    if (new_mat->colour_map != NULL) {
654
        new_mat->colour_map = NULL;
655
        BrMaterialUpdate(new_mat, BR_MATU_ALL);
656
    }
657
    return new_mat;
658
}
659
 
660
// IDA: void __usercall ProcessModelFaceMaterials2(br_model *pModel@<EAX>, tPMFM2CB pCallback@<EDX>)
661
void ProcessModelFaceMaterials2(br_model* pModel, tPMFM2CB pCallback) {
662
    //tU16 f; // Pierre-Marie Baty -- unused variable
663
    //tU16 group; // Pierre-Marie Baty -- unused variable
664
    //br_material* old_mat; // Pierre-Marie Baty -- unused variable
665
    LOG_TRACE("(%p, %d)", pModel, pCallback);
666
    NOT_IMPLEMENTED();
667
}
668
 
669
// IDA: void __usercall ProcessModelFaceMaterials(br_model *pModel@<EAX>, tPMFMCB pCallback@<EDX>)
670
void ProcessModelFaceMaterials(br_model* pModel, tPMFMCB pCallback) {
671
    tU16 f;
672
    br_material* possible_mat;
673
    br_material* new_mat;
674
    LOG_TRACE("(%p, %d)", pModel, pCallback);
675
 
676
    new_mat = NULL;
677
    for (f = 0; f < pModel->nfaces; f++) {
678
        if (pModel->faces[f].material != NULL) {
679
            possible_mat = (*pCallback)(pModel, f);
680
            if (possible_mat != NULL) {
681
                pModel->faces[f].material = possible_mat;
682
                new_mat = possible_mat;
683
            }
684
        }
685
    }
686
    if (new_mat != NULL) {
687
        BrModelUpdate(pModel, BR_MATU_ALL);
688
    }
689
}
690
 
691
// IDA: int __usercall LoadNTrackModels@<EAX>(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>, int pCount@<EBX>)
692
int LoadNTrackModels(tBrender_storage* pStorage_space, FILE* pF, int pCount) {
693
    tPath_name the_path;
694
    int i;
695
    int j;
696
    int new_ones;
697
    int total;
698
    //int group; // Pierre-Marie Baty -- unused variable
699
    char s[256];
700
    char* str;
701
    br_model* temp_array[2000];
702
    //v11model* prepared; // Pierre-Marie Baty -- unused variable
703
    LOG_TRACE("(%p, %p, %d)", pStorage_space, pF, pCount);
704
 
705
    new_ones = 0;
706
    for (i = 0; i < pCount; i++) {
707
        GetALineAndDontArgue(pF, s);
708
        str = strtok(s, "\t ,/");
709
        PathCat(the_path, gApplication_path, "MODELS");
710
        PathCat(the_path, the_path, str);
711
        total = BrModelLoadMany(the_path, temp_array, 2000);
712
        if (total == 0) {
713
            FatalError(kFatalError_LoadModelFile_S, str);
714
        }
715
        for (j = 0; j < total; j++) {
716
            if (temp_array[j]) {
717
                switch (AddModelToStorage(pStorage_space, temp_array[j])) {
718
                case eStorage_not_enough_room:
719
                    FatalError(kFatalError_InsufficientModelSlots);
720
                    break;
721
                case eStorage_duplicate:
722
                    BrModelFree(temp_array[j]);
723
                    break;
724
                case eStorage_allocated:
725
                    temp_array[j]->flags |= BR_MODF_UPDATEABLE;
726
                    if (gRoad_texturing_level == eRTL_none) {
727
                        ProcessModelFaceMaterials(temp_array[j], RoadPerspToUntex);
728
                    }
729
                    switch (gWall_texturing_level) {
730
                    case eWTL_none:
731
                        ProcessModelFaceMaterials(temp_array[j], WallPerspToUntex);
732
                        break;
733
                    case eWTL_linear:
734
                        ProcessModelFaceMaterials(temp_array[j], WallPerspToLinear);
735
                        break;
736
                    default:
737
                        break;
738
                    }
739
                    RemoveDoubleSided(temp_array[j]);
740
                    BrModelAdd(temp_array[j]);
741
                    new_ones++;
742
                }
743
            }
744
        }
745
    }
746
    return new_ones;
747
}
748
 
749
// IDA: void __usercall LoadSomePixelmaps(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>)
750
void LoadSomePixelmaps(tBrender_storage* pStorage_space, FILE* pF) {
751
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
752
    //int i; // Pierre-Marie Baty -- unused variable
753
    //int j; // Pierre-Marie Baty -- unused variable
754
    int count;
755
    //int new_ones; // Pierre-Marie Baty -- unused variable
756
    char s[256];
757
    char* str;
758
    //br_pixelmap* temp_array[200]; // Pierre-Marie Baty -- unused variable
759
    LOG_TRACE("(%p, %p)", pStorage_space, pF);
760
 
761
    GetALineAndDontArgue(pF, s);
762
    str = strtok(s, "\t ,/");
763
    sscanf(str, "%d", &count);
764
    LoadNPixelmaps(pStorage_space, pF, count);
765
}
766
 
767
// IDA: void __usercall LoadSomeShadeTables(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>)
768
void LoadSomeShadeTables(tBrender_storage* pStorage_space, FILE* pF) {
769
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
770
    //int i; // Pierre-Marie Baty -- unused variable
771
    //int j; // Pierre-Marie Baty -- unused variable
772
    int count;
773
    //int new_ones; // Pierre-Marie Baty -- unused variable
774
    char s[256];
775
    char* str;
776
    //br_pixelmap* temp_array[50]; // Pierre-Marie Baty -- unused variable
777
    LOG_TRACE("(%p, %p)", pStorage_space, pF);
778
 
779
    GetALineAndDontArgue(pF, s);
780
    str = strtok(s, "\t ,/");
781
    sscanf(str, "%d", &count);
782
    LoadNShadeTables(pStorage_space, pF, count);
783
}
784
 
785
// IDA: void __usercall LoadSomeMaterials(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>)
786
void LoadSomeMaterials(tBrender_storage* pStorage_space, FILE* pF) {
787
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
788
    //int i; // Pierre-Marie Baty -- unused variable
789
    //int j; // Pierre-Marie Baty -- unused variable
790
    int count;
791
    //int new_ones; // Pierre-Marie Baty -- unused variable
792
    char s[256];
793
    char* str;
794
    //br_material* temp_array[200]; // Pierre-Marie Baty -- unused variable
795
    LOG_TRACE("(%p, %p)", pStorage_space, pF);
796
 
797
    GetALineAndDontArgue(pF, s);
798
    str = strtok(s, "\t ,/");
799
    sscanf(str, "%d", &count);
800
    LoadNMaterials(pStorage_space, pF, count);
801
}
802
 
803
// IDA: void __usercall LoadSomeModels(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>)
804
void LoadSomeModels(tBrender_storage* pStorage_space, FILE* pF) {
805
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
806
    //int i; // Pierre-Marie Baty -- unused variable
807
    //int j; // Pierre-Marie Baty -- unused variable
808
    int count;
809
    //int new_ones; // Pierre-Marie Baty -- unused variable
810
    char s[256];
811
    char* str;
812
    //br_model* temp_array[2000]; // Pierre-Marie Baty -- unused variable
813
    LOG_TRACE("(%p, %p)", pStorage_space, pF);
814
 
815
    GetALineAndDontArgue(pF, s);
816
    str = strtok(s, "\t ,/");
817
    sscanf(str, "%d", &count);
818
    LoadNModels(pStorage_space, pF, count);
819
}
820
 
821
// IDA: void __usercall LoadSomeTrackModels(tBrender_storage *pStorage_space@<EAX>, FILE *pF@<EDX>)
822
void LoadSomeTrackModels(tBrender_storage* pStorage_space, FILE* pF) {
823
    //tPath_name the_path; // Pierre-Marie Baty -- unused variable
824
    //int i;               // Pierre-Marie Baty -- unused variable
825
    //int j;               // Pierre-Marie Baty -- unused variable
826
    int count;
827
    //int new_ones; // Pierre-Marie Baty -- unused variable
828
    char s[256];
829
    char* str;
830
    //br_model* temp_array[2000]; // Pierre-Marie Baty -- unused variable
831
    LOG_TRACE("(%p, %p)", pStorage_space, pF);
832
 
833
    GetALineAndDontArgue(pF, s);
834
    str = strtok(s, "\t ,/");
835
    sscanf(str, "%d", &count);
836
    LoadNTrackModels(pStorage_space, pF, count);
837
}
838
 
839
// IDA: void __usercall AddFunkGrooveBinding(int pSlot_number@<EAX>, float *pPeriod_address@<EDX>)
840
void AddFunkGrooveBinding(int pSlot_number, float* pPeriod_address) {
841
    LOG_TRACE("(%d, %p)", pSlot_number, pPeriod_address);
842
 
843
    if (pSlot_number < 0 || pSlot_number >= COUNT_OF(gGroove_funk_bindings)) {
844
        FatalError(kFatalError_DefinedRefNumGrooveFunkOutOfRange);
845
    }
846
 
847
    gGroove_funk_bindings[pSlot_number] = pPeriod_address;
848
    *pPeriod_address = 0.0f;
849
}
850
 
851
// IDA: void __usercall ControlBoundFunkGroove(int pSlot_number@<EAX>, float pValue)
852
void ControlBoundFunkGroove(int pSlot_number, float pValue) {
853
    LOG_TRACE("(%d, %f)", pSlot_number, pValue);
854
 
855
    if (pSlot_number < 0) {
856
        return;
857
    }
858
    if (pSlot_number >= COUNT_OF(gGroove_funk_bindings)) {
859
        FatalError(kFatalError_UsedRefNumGrooveFunkOutOfRange);
860
    }
861
    *gGroove_funk_bindings[pSlot_number] = pValue;
862
}
863
 
864
// IDA: float __usercall ControlBoundFunkGroovePlus@<ST0>(int pSlot_number@<EAX>, float pValue)
865
float ControlBoundFunkGroovePlus(int pSlot_number, float pValue) {
866
    LOG_TRACE("(%d, %f)", pSlot_number, pValue);
867
 
868
    if (pSlot_number < 0) {
869
        return 0.f;
870
    }
871
    if (pSlot_number >= COUNT_OF(gGroove_funk_bindings)) {
872
        FatalError(kFatalError_UsedRefNumGrooveFunkOutOfRange);
873
    }
874
    *gGroove_funk_bindings[pSlot_number] = fmodf(*gGroove_funk_bindings[pSlot_number] + pValue, 1.f);
875
    return *gGroove_funk_bindings[pSlot_number];
876
}
877
 
878
// IDA: void __usercall ShiftBoundGrooveFunks(char *pStart@<EAX>, char *pEnd@<EDX>, int pDelta@<EBX>)
879
void ShiftBoundGrooveFunks(char* pStart, char* pEnd, ptrdiff_t pDelta) {
880
    int i;
881
    LOG_TRACE("(\"%s\", \"%s\", %d)", pStart, pEnd, pDelta);
882
 
883
    for (i = 0; i < COUNT_OF(gGroove_funk_bindings); i++) {
884
        if (pStart <= (char*)gGroove_funk_bindings[i] && (char*)gGroove_funk_bindings[i] < pEnd) {
885
            gGroove_funk_bindings[i] = (float*)((char*)gGroove_funk_bindings[i] + (pDelta & ~(sizeof(void*) - 1))); // original code is (pDelta & 0xFFFFFFFC) but this caused problems;
886
        }
887
    }
888
}
889
 
890
// IDA: tFunkotronic_spec* __cdecl AddNewFunkotronic()
891
tFunkotronic_spec* AddNewFunkotronic(void) {
892
    void* new_array;
893
    int i;
894
    LOG_TRACE("()");
895
 
896
    for (i = 0; i < gFunkotronics_array_size; i++) {
897
        if (gFunkotronics_array[i].owner == -999) {
898
            memset(&gFunkotronics_array[i], 0, sizeof(tFunkotronic_spec));
899
            return &gFunkotronics_array[i];
900
        }
901
    }
902
    gFunkotronics_array_size += 16;
903
    new_array = BrMemCalloc(gFunkotronics_array_size, sizeof(tFunkotronic_spec), kMem_funk_spec);
904
    if (gFunkotronics_array != NULL) {
905
        memcpy(new_array, gFunkotronics_array, (gFunkotronics_array_size - 16) * sizeof(tFunkotronic_spec));
906
        ShiftBoundGrooveFunks(
907
            (char*)gFunkotronics_array,
908
            (char*)&gFunkotronics_array[gFunkotronics_array_size - 16],
909
            (char*)new_array - (char*)gFunkotronics_array);
910
        BrMemFree(gFunkotronics_array);
911
    }
912
    gFunkotronics_array = new_array;
913
    for (i = 0; i < 16; i++) {
914
        gFunkotronics_array[gFunkotronics_array_size - 16 + i].owner = -999;
915
    }
916
    return &gFunkotronics_array[gFunkotronics_array_size - 16];
917
}
918
 
919
// IDA: void __usercall DisposeFunkotronics(int pOwner@<EAX>)
920
void DisposeFunkotronics(int pOwner) {
921
    int i;
922
    tFunkotronic_spec* the_funk;
923
    LOG_TRACE("(%d)", pOwner);
924
 
925
    if (gFunkotronics_array == NULL) {
926
        return;
927
    }
928
    for (i = 0; i < gFunkotronics_array_size; i++) {
929
        the_funk = &gFunkotronics_array[i];
930
        PossibleService();
931
        if (the_funk->owner == pOwner) {
932
            the_funk->owner = -999;
933
            if (the_funk->proximity_array != NULL) {
934
                BrMemFree(the_funk->proximity_array);
935
            }
936
            if (the_funk->texture_animation_type == eTexture_animation_flic) {
937
                BrMemFree(the_funk->texture_animation_data.flic_info.flic_data);
938
                EndFlic(&the_funk->texture_animation_data.flic_info.flic_descriptor);
939
                BrMemFree(the_funk->material->colour_map->pixels);
940
                the_funk->material->colour_map->pixels = NULL;
941
                BrPixelmapFree(the_funk->material->colour_map);
942
                the_funk->material->colour_map = NULL;
943
            }
944
        }
945
    }
946
}
947
 
948
// IDA: void __usercall AddProximityVertex(br_vector3 *pV@<EAX>, tFunkotronic_spec *pThe_funk@<EDX>)
949
void AddProximityVertex(br_vector3* pV, tFunkotronic_spec* pThe_funk) {
950
    LOG_TRACE("(%p, %p)", pV, pThe_funk);
951
 
952
    pThe_funk->proximity_array[pThe_funk->proximity_count] = *pV;
953
    pThe_funk->proximity_count++;
954
}
955
 
956
// IDA: void __cdecl AddProximityVertexXYZ(br_scalar pX, br_scalar pY, br_scalar pZ, tFunkotronic_spec *pThe_funk)
957
void AddProximityVertexXYZ(br_scalar pX, br_scalar pY, br_scalar pZ, tFunkotronic_spec* pThe_funk) {
958
    br_vector3 v;
959
    LOG_TRACE("(%f, %f, %f, %p)", pX, pY, pZ, pThe_funk);
960
 
961
    v.v[0] = pX;
962
    v.v[1] = pY;
963
    v.v[2] = pZ;
964
    AddProximityVertex(&v, pThe_funk);
965
}
966
 
967
// IDA: br_uint_32 __usercall CalcProximities@<EAX>(br_actor *pActor@<EAX>, br_material *pMat@<EDX>, tFunkotronic_spec *pThe_funk@<EBX>)
968
br_uint_32 CalcProximities(br_actor* pActor, br_material* pMat, tFunkotronic_spec* pThe_funk) {
969
    br_face* the_face;
970
    int i;
971
    LOG_TRACE("(%p, %p, %p)", pActor, pMat, pThe_funk);
972
 
973
    if (pActor->model != NULL) {
974
        if (pThe_funk->material == pMat) {
975
            pThe_funk->proximity_count += 8;
976
        } else {
977
            for (i = 0; i < pActor->model->nfaces; i++) {
978
                the_face = &pActor->model->faces[i];
979
                if (pThe_funk->material == the_face->material) {
980
                    pThe_funk->proximity_count += 3;
981
                }
982
            }
983
        }
984
    }
985
    return 0;
986
}
987
 
988
// IDA: br_uint_32 __usercall AddProximities@<EAX>(br_actor *pActor@<EAX>, br_material *pMat@<EDX>, tFunkotronic_spec *pThe_funk@<EBX>)
989
br_uint_32 AddProximities(br_actor* pActor, br_material* pMat, tFunkotronic_spec* pThe_funk) {
990
    br_face* the_face;
991
    int i;
992
    LOG_TRACE("(%p, %p, %p)", pActor, pMat, pThe_funk);
993
 
994
    if (pActor->model != NULL) {
995
        if (pThe_funk->material == pMat) {
996
            AddProximityVertexXYZ(
997
                pActor->model->bounds.min.v[0],
998
                pActor->model->bounds.min.v[1],
999
                pActor->model->bounds.min.v[2],
1000
                pThe_funk);
1001
            AddProximityVertexXYZ(
1002
                pActor->model->bounds.min.v[0],
1003
                pActor->model->bounds.min.v[1],
1004
                pActor->model->bounds.max.v[2],
1005
                pThe_funk);
1006
            AddProximityVertexXYZ(
1007
                pActor->model->bounds.min.v[0],
1008
                pActor->model->bounds.max.v[1],
1009
                pActor->model->bounds.min.v[2],
1010
                pThe_funk);
1011
            AddProximityVertexXYZ(
1012
                pActor->model->bounds.min.v[0],
1013
                pActor->model->bounds.max.v[1],
1014
                pActor->model->bounds.max.v[2],
1015
                pThe_funk);
1016
            AddProximityVertexXYZ(
1017
                pActor->model->bounds.max.v[0],
1018
                pActor->model->bounds.min.v[1],
1019
                pActor->model->bounds.min.v[2],
1020
                pThe_funk);
1021
            AddProximityVertexXYZ(
1022
                pActor->model->bounds.max.v[0],
1023
                pActor->model->bounds.min.v[1],
1024
                pActor->model->bounds.max.v[2],
1025
                pThe_funk);
1026
            AddProximityVertexXYZ(
1027
                pActor->model->bounds.max.v[0],
1028
                pActor->model->bounds.max.v[1],
1029
                pActor->model->bounds.min.v[2],
1030
                pThe_funk);
1031
            AddProximityVertexXYZ(
1032
                pActor->model->bounds.max.v[0],
1033
                pActor->model->bounds.max.v[1],
1034
                pActor->model->bounds.max.v[2],
1035
                pThe_funk);
1036
        } else {
1037
            for (i = 0; i < pActor->model->nfaces; i++) {
1038
                the_face = &pActor->model->faces[i];
1039
                if (pThe_funk->material == the_face->material) {
1040
                    AddProximityVertex(&pActor->model->vertices[the_face->vertices[0]].p, pThe_funk);
1041
                    AddProximityVertex(&pActor->model->vertices[the_face->vertices[1]].p, pThe_funk);
1042
                    AddProximityVertex(&pActor->model->vertices[the_face->vertices[2]].p, pThe_funk);
1043
                }
1044
            }
1045
        }
1046
    }
1047
    return 0;
1048
}
1049
 
1050
// IDA: void __usercall Adjust2FloatsForExceptions(float *pVictim1@<EAX>, float *pVictim2@<EDX>, br_pixelmap *pCulprit@<EBX>)
1051
void Adjust2FloatsForExceptions(float* pVictim1, float* pVictim2, br_pixelmap* pCulprit) {
1052
    //tException_list e; // Pierre-Marie Baty -- unused variable
1053
    LOG_TRACE("(%p, %p, %p)", pVictim1, pVictim2, pCulprit);
1054
    NOT_IMPLEMENTED();
1055
}
1056
 
1057
// IDA: void __usercall AddFunkotronics(FILE *pF@<EAX>, int pOwner@<EDX>, int pRef_offset@<EBX>)
1058
void AddFunkotronics(FILE* pF, int pOwner, int pRef_offset) {
1059
    char s[256];
1060
    char* str;
1061
    int first_time;
1062
    int i;
1063
    int j;
1064
    tFunkotronic_spec* the_funk;
1065
    float speed1;
1066
    float speed2;
1067
    float a_min;
1068
    float d_min;
1069
    float s_min;
1070
    float a_max;
1071
    float d_max;
1072
    float s_max;
1073
    void* the_pixels;
1074
    br_pixelmap* the_pixelmap;
1075
    float x_0;
1076
    float x_1;
1077
    int d_0;
1078
    int d_1;
1079
    LOG_TRACE("(%p, %d, %d)", pF, pOwner, pRef_offset);
1080
 
1081
    first_time = 1;
1082
    while (!feof(pF)) {
1083
        PossibleService();
1084
        GetALineAndDontArgue(pF, s);
1085
        if (strcmp(s, "END OF FUNK") == 0) {
1086
            break;
1087
        }
1088
 
1089
        if (!first_time) {
1090
            if (strcmp(s, "NEXT FUNK") != 0) {
1091
                FatalError(kFatalError_FunkotronicFile);
1092
            }
1093
            GetALineAndDontArgue(pF, s);
1094
        }
1095
        first_time = 0;
1096
 
1097
        the_funk = AddNewFunkotronic();
1098
        the_funk->owner = pOwner;
1099
        str = strtok(s, "\t ,/");
1100
        the_funk->material = BrMaterialFind(str);
1101
        if (the_funk->material == NULL) {
1102
            FatalError(kFatalError_FindMaterialUsedByFunkotronicFile_S, str);
1103
        }
1104
        the_funk->mode = GetALineAndInterpretCommand(pF, gFunk_nature_names, COUNT_OF(gFunk_nature_names));
1105
        the_funk->matrix_mod_type = GetALineAndInterpretCommand(pF, gFunk_type_names, COUNT_OF(gFunk_type_names));
1106
        if (the_funk->matrix_mod_type != eMatrix_mod_none) {
1107
            the_funk->matrix_mode = GetALineAndInterpretCommand(pF, gFunk_move_names, COUNT_OF(gFunk_move_names));
1108
        }
1109
        switch (the_funk->matrix_mod_type) {
1110
        case eMatrix_mod_spin:
1111
            if (the_funk->matrix_mode == eMove_controlled || the_funk->matrix_mode == eMove_absolute) {
1112
                i = GetAnInt(pF);
1113
                AddFunkGrooveBinding(i + pRef_offset, &the_funk->matrix_mod_data.spin_info.period);
1114
            } else {
1115
                x_0 = GetAFloat(pF);
1116
                the_funk->matrix_mod_data.spin_info.period = (x_0 == 0.0f) ? 0.0f : 1000.0f / x_0;
1117
            }
1118
            break;
1119
        case eMatrix_mod_rock: // rock
1120
            if (the_funk->matrix_mode == eMove_controlled || the_funk->matrix_mode == eMove_absolute) {
1121
                d_0 = GetAnInt(pF);
1122
                AddFunkGrooveBinding(d_0 + pRef_offset, &the_funk->matrix_mod_data.rock_info.period);
1123
            } else {
1124
                x_0 = GetAFloat(pF);
1125
                the_funk->matrix_mod_data.rock_info.period = (x_0 == 0.0f) ? 0.0f : 1000.0f / x_0;
1126
            }
1127
 
1128
            the_funk->matrix_mod_data.rock_info.rock_angle = GetAFloat(pF);
1129
            GetPairOfFloats(pF, &x_0, &x_1);
1130
            the_funk->matrix_mod_data.rock_info.x_centre = x_0 / 100.0f;
1131
            the_funk->matrix_mod_data.rock_info.y_centre = x_1 / 100.0f;
1132
            break;
1133
        case eMatrix_mod_throb: // throb
1134
            if (the_funk->matrix_mode == eMove_controlled || the_funk->matrix_mode == eMove_absolute) {
1135
                GetPairOfInts(pF, &d_0, &d_1);
1136
                if (d_0 >= 0) {
1137
                    AddFunkGrooveBinding(d_0 + pRef_offset, &the_funk->matrix_mod_data.throb_info.x_period);
1138
                }
1139
                if (d_1 >= 0) {
1140
                    AddFunkGrooveBinding(d_1 + pRef_offset, &the_funk->matrix_mod_data.throb_info.y_period);
1141
                }
1142
            } else {
1143
                GetPairOfFloats(pF, &speed1, &speed2);
1144
                the_funk->matrix_mod_data.throb_info.x_period = (speed1 == 0.0f) ? 0.0f : 1000.0f / speed1;
1145
                the_funk->matrix_mod_data.throb_info.y_period = (speed2 == 0.0f) ? 0.0f : 1000.0f / speed2;
1146
            }
1147
            GetPairOfFloatPercents(
1148
                pF,
1149
                &the_funk->matrix_mod_data.throb_info.x_magnitude,
1150
                &the_funk->matrix_mod_data.throb_info.y_magnitude);
1151
            GetPairOfFloats(pF, &x_0, &x_1);
1152
            the_funk->matrix_mod_data.throb_info.x_centre = x_0 / 100.0f;
1153
            the_funk->matrix_mod_data.throb_info.y_centre = x_1 / 100.0f;
1154
            if (the_funk->matrix_mode != eMove_controlled) {
1155
                if (the_funk->matrix_mod_data.throb_info.x_period == 0.0f) {
1156
                    the_funk->matrix_mod_data.throb_info.x_period = 1.0f;
1157
                    the_funk->matrix_mod_data.throb_info.x_magnitude = 0.0f;
1158
                }
1159
                if (the_funk->matrix_mod_data.throb_info.y_period == 0.0f) {
1160
                    the_funk->matrix_mod_data.throb_info.y_period = 1.0f;
1161
                    the_funk->matrix_mod_data.throb_info.y_magnitude = 0.0f;
1162
                }
1163
            }
1164
            break;
1165
        case eMatrix_mod_slither: // slither
1166
            if (the_funk->matrix_mode == eMove_controlled || the_funk->matrix_mode == eMove_absolute) {
1167
                GetPairOfInts(pF, &d_0, &d_1);
1168
                if (d_0 >= 0) {
1169
                    AddFunkGrooveBinding(d_0 + pRef_offset, &the_funk->matrix_mod_data.slither_info.x_period);
1170
                }
1171
                if (d_1 >= 0) {
1172
                    AddFunkGrooveBinding(d_1 + pRef_offset, &the_funk->matrix_mod_data.slither_info.y_period);
1173
                }
1174
            } else {
1175
                GetPairOfFloats(pF, &speed1, &speed2);
1176
                the_funk->matrix_mod_data.slither_info.x_period = (speed1 == 0.0f) ? 0.0f : 1000.0f / speed1;
1177
                the_funk->matrix_mod_data.slither_info.y_period = (speed2 == 0.0f) ? 0.0f : 1000.0f / speed2;
1178
            }
1179
            GetPairOfFloatPercents(
1180
                pF,
1181
                &the_funk->matrix_mod_data.slither_info.x_magnitude,
1182
                &the_funk->matrix_mod_data.slither_info.y_magnitude);
1183
            if (the_funk->matrix_mode != eMove_controlled) {
1184
                if (the_funk->matrix_mod_data.slither_info.x_period == 0.0f) {
1185
                    the_funk->matrix_mod_data.slither_info.x_period = 1.0f;
1186
                    the_funk->matrix_mod_data.slither_info.x_magnitude = 0.0f;
1187
                }
1188
                if (the_funk->matrix_mod_data.slither_info.y_period == 0.0f) {
1189
                    the_funk->matrix_mod_data.slither_info.y_period = 1.0f;
1190
                    the_funk->matrix_mod_data.slither_info.y_magnitude = 0.0f;
1191
                }
1192
            }
1193
            break;
1194
        case eMatrix_mod_roll: // roll
1195
            if (the_funk->matrix_mode == eMove_controlled || the_funk->matrix_mode == eMove_absolute) {
1196
                GetPairOfInts(pF, &d_0, &d_1);
1197
                if (d_0 >= 0) {
1198
                    AddFunkGrooveBinding(d_0 + pRef_offset, &the_funk->matrix_mod_data.roll_info.x_period);
1199
                }
1200
                if (d_1 >= 0) {
1201
                    AddFunkGrooveBinding(d_1 + pRef_offset, &the_funk->matrix_mod_data.roll_info.y_period);
1202
                }
1203
            } else {
1204
                GetPairOfFloats(pF, &speed1, &speed2);
1205
                the_funk->matrix_mod_data.roll_info.x_period = speed1 == 0.0f ? 0.0f : 1000.0f / speed1;
1206
                the_funk->matrix_mod_data.roll_info.y_period = speed2 == 0.0f ? 0.0f : 1000.0f / speed2;
1207
            }
1208
            break;
1209
        default:
1210
            break;
1211
        }
1212
        the_funk->lighting_animation_type = GetALineAndInterpretCommand(pF, gFunk_move_names, COUNT_OF(gFunk_move_names));
1213
        if (the_funk->lighting_animation_type != eMove_none) {
1214
            if (the_funk->lighting_animation_type == eMove_controlled || the_funk->lighting_animation_type == eMove_absolute) {
1215
                d_0 = GetAnInt(pF);
1216
                AddFunkGrooveBinding(d_0 + pRef_offset, &the_funk->lighting_animation_period);
1217
            } else {
1218
                x_0 = GetAFloat(pF);
1219
                the_funk->lighting_animation_period = (x_0 == 0.0f) ? 0.0f : 1000.0f / x_0;
1220
            }
1221
            GetThreeFloatPercents(pF, &a_min, &d_min, &s_min);
1222
            GetThreeFloatPercents(pF, &a_max, &d_max, &s_max);
1223
            the_funk->ambient_base = (a_min + a_max) / 2.0f;
1224
            the_funk->direct_base = (d_min + d_max) / 2.0f;
1225
            the_funk->specular_base = (s_min + s_max) / 2.0f;
1226
            the_funk->ambient_delta = (a_max - a_min) / 2.0f;
1227
            the_funk->direct_delta = (d_max - d_min) / 2.0f;
1228
            the_funk->specular_delta = (s_max - s_min) / 2.0f;
1229
        }
1230
        the_funk->texture_animation_type = GetALineAndInterpretCommand(pF, gFunk_anim_names, COUNT_OF(gFunk_anim_names));
1231
        if (the_funk->texture_animation_type != eTexture_animation_none) {
1232
            the_funk->time_mode = GetALineAndInterpretCommand(pF, gTime_mode_names, COUNT_OF(gTime_mode_names));
1233
        }
1234
        if (the_funk->texture_animation_type == eTexture_animation_flic && gAusterity_mode) {
1235
            the_funk->texture_animation_type = eTexture_animation_none;
1236
            GetALineAndDontArgue(pF, s);
1237
        }
1238
        the_funk->last_frame = 0.0f;
1239
 
1240
        if (the_funk->texture_animation_type == eTexture_animation_flic) {
1241
            GetAString(pF, s);
1242
            the_funk->texture_animation_data.flic_info.flic_data = 0;
1243
            if (LoadFlicData(
1244
                    s,
1245
                    &the_funk->texture_animation_data.flic_info.flic_data,
1246
                    &the_funk->texture_animation_data.flic_info.flic_data_length)) {
1247
                the_funk->texture_animation_data.flic_info.flic_descriptor.data_start = NULL;
1248
                StartFlic(
1249
                    s,
1250
                    -1,
1251
                    &the_funk->texture_animation_data.flic_info.flic_descriptor,
1252
                    the_funk->texture_animation_data.flic_info.flic_data_length,
1253
                    (tS8*)the_funk->texture_animation_data.flic_info.flic_data,
1254
                    0,
1255
                    0,
1256
                    0,
1257
                    0);
1258
                the_funk->last_frame = 0.0f;
1259
                the_pixels = BrMemAllocate(
1260
                    the_funk->texture_animation_data.flic_info.flic_descriptor.height
1261
                        * ((the_funk->texture_animation_data.flic_info.flic_descriptor.width + 3) & ~3),
1262
                    kMem_video_pixels);
1263
                if (gScreen->row_bytes < 0) {
1264
                    BrFatal(
1265
                        "C:\\Msdev\\Projects\\DethRace\\World.c",
1266
                        1729,
1267
                        "Bruce bug at line %d, file C:\\Msdev\\Projects\\DethRace\\World.c",
1268
                        193);
1269
                }
1270
                the_pixelmap = DRPixelmapAllocate(
1271
                    gScreen->type,
1272
                    the_funk->texture_animation_data.flic_info.flic_descriptor.width,
1273
                    the_funk->texture_animation_data.flic_info.flic_descriptor.height,
1274
                    the_pixels,
1275
                    0);
1276
                AssertFlicPixelmap(&the_funk->texture_animation_data.flic_info.flic_descriptor, the_pixelmap);
1277
                the_funk->material->colour_map = the_pixelmap;
1278
                BrMaterialUpdate(the_funk->material, BR_MATU_ALL);
1279
            } else {
1280
                the_funk->texture_animation_type = eTexture_animation_none;
1281
            }
1282
        } else if (the_funk->texture_animation_type == eTexture_animation_frames) {
1283
            i = GetALineAndInterpretCommand(pF, gFunk_move_names, COUNT_OF(gFunk_move_names));
1284
            the_funk->texture_animation_data.frames_info.mode = i;
1285
            if (the_funk->texture_animation_data.frames_info.mode == eMove_controlled
1286
                || the_funk->texture_animation_data.frames_info.mode == eMove_absolute) {
1287
                d_0 = GetAnInt(pF);
1288
                AddFunkGrooveBinding(d_0 + pRef_offset, &the_funk->texture_animation_data.frames_info.period);
1289
            } else {
1290
                x_0 = GetAFloat(pF);
1291
                the_funk->texture_animation_data.frames_info.period = (x_0 == 0.0f) ? 0.0f : 1000.0F / x_0;
1292
            }
1293
 
1294
            the_funk->texture_animation_data.frames_info.texture_count = (int)GetAFloat(pF);
1295
            for (i = 0; i < the_funk->texture_animation_data.frames_info.texture_count; i++) {
1296
                GetAString(pF, s);
1297
                the_funk->texture_animation_data.frames_info.textures[i] = BrMapFind(s);
1298
                if (the_funk->texture_animation_data.frames_info.textures[i] == NULL) {
1299
                    FatalError(kFatalError_AnimationFramePixelmapUsedByFunkotronicFile);
1300
                }
1301
            }
1302
        }
1303
        the_funk->proximity_count = 0;
1304
        the_funk->proximity_array = 0;
1305
        if (the_funk->mode == eFunk_mode_distance) {
1306
            DRActorEnumRecurseWithMat(gUniverse_actor, NULL, (recurse_with_mat_cbfn*)CalcProximities, the_funk);
1307
            the_funk->proximity_array = BrMemAllocate(sizeof(br_vector3) * the_funk->proximity_count, kMem_funk_prox_array);
1308
            the_funk->proximity_count = 0;
1309
            DRActorEnumRecurseWithMat(gUniverse_actor, 0, (recurse_with_mat_cbfn*)AddProximities, the_funk);
1310
            for (i = 0; i < the_funk->proximity_count; i++) {
1311
                for (j = i + 1; j < the_funk->proximity_count; j++) {
1312
                    if (the_funk->proximity_array[j].v[0] == the_funk->proximity_array[i].v[0]
1313
                        && the_funk->proximity_array[j].v[1] == the_funk->proximity_array[i].v[1]
1314
                        && the_funk->proximity_array[j].v[2] == the_funk->proximity_array[i].v[2]) {
1315
                        memmove(
1316
                            &the_funk->proximity_array[j],
1317
                            &the_funk->proximity_array[j + 1],
1318
                            sizeof(br_vector3) * (the_funk->proximity_count - j - 1));
1319
                        the_funk->proximity_count--;
1320
                        j--;
1321
                    }
1322
                }
1323
            }
1324
        }
1325
    }
1326
}
1327
 
1328
// IDA: void __usercall DisposeGroovidelics(int pOwner@<EAX>)
1329
void DisposeGroovidelics(int pOwner) {
1330
    int i;
1331
    tGroovidelic_spec* the_groove;
1332
    LOG_TRACE("(%d)", pOwner);
1333
 
1334
    if (gGroovidelics_array == NULL) {
1335
        return;
1336
    }
1337
    for (i = 0; i < gGroovidelics_array_size; i++) {
1338
        the_groove = &gGroovidelics_array[i];
1339
        PossibleService();
1340
        if (the_groove->owner == pOwner) {
1341
            the_groove->owner = -999;
1342
        }
1343
    }
1344
}
1345
 
1346
// IDA: tGroovidelic_spec* __cdecl AddNewGroovidelic()
1347
tGroovidelic_spec* AddNewGroovidelic(void) {
1348
    void* new_array;
1349
    int i;
1350
    LOG_TRACE("()");
1351
 
1352
    for (i = 0; i < gGroovidelics_array_size; i++) {
1353
        if (gGroovidelics_array[i].owner == -999) {
1354
            memset(&gGroovidelics_array[i], 0, sizeof(tGroovidelic_spec));
1355
            return &gGroovidelics_array[i];
1356
        }
1357
    }
1358
    gGroovidelics_array_size += 16;
1359
    new_array = BrMemCalloc(gGroovidelics_array_size, sizeof(tGroovidelic_spec), kMem_groove_spec);
1360
    if (gGroovidelics_array != NULL) {
1361
        memcpy(new_array, gGroovidelics_array, (gGroovidelics_array_size - 16) * sizeof(tGroovidelic_spec));
1362
        ShiftBoundGrooveFunks(
1363
            (char*)gGroovidelics_array,
1364
            (char*)&gGroovidelics_array[gGroovidelics_array_size - 16],
1365
            (char*)new_array - (char*)gGroovidelics_array);
1366
        BrMemFree(gGroovidelics_array);
1367
    }
1368
    gGroovidelics_array = new_array;
1369
    for (i = 0; i < 16; i++) {
1370
        gGroovidelics_array[i + gGroovidelics_array_size - 16].owner = -999;
1371
    }
1372
    return &gGroovidelics_array[gGroovidelics_array_size - 16];
1373
}
1374
 
1375
// IDA: void __usercall AddGroovidelics(FILE *pF@<EAX>, int pOwner@<EDX>, br_actor *pParent_actor@<EBX>, int pRef_offset@<ECX>, int pAllowed_to_be_absent)
1376
void AddGroovidelics(FILE* pF, int pOwner, br_actor* pParent_actor, int pRef_offset, int pAllowed_to_be_absent) {
1377
    char s[256];
1378
    char* str;
1379
    int first_time;
1380
    //int i; // Pierre-Marie Baty -- unused variable
1381
    //int j; // Pierre-Marie Baty -- unused variable
1382
    tGroovidelic_spec* the_groove;
1383
    float x_0;
1384
    float x_1;
1385
    float x_2;
1386
    int d_0;
1387
    int d_1;
1388
    int d_2;
1389
    LOG_TRACE("(%p, %d, %p, %d, %d)", pF, pOwner, pParent_actor, pRef_offset, pAllowed_to_be_absent);
1390
 
1391
    first_time = 1;
1392
 
1393
    while (!feof(pF)) {
1394
        PossibleService();
1395
        GetALineAndDontArgue(pF, s);
1396
        if (strcmp(s, "END OF GROOVE") == 0) {
1397
            break;
1398
        }
1399
 
1400
        if (!first_time) {
1401
            if (strcmp(s, "NEXT GROOVE") != 0) {
1402
                FatalError(kFatalError_GroovidelicFile);
1403
            }
1404
            GetALineAndDontArgue(pF, s);
1405
        }
1406
        first_time = 0;
1407
        str = strtok(s, "\t ,/");
1408
        the_groove = AddNewGroovidelic();
1409
        the_groove->owner = pOwner;
1410
        the_groove->actor = DRActorFindRecurse(pParent_actor, str);
1411
 
1412
        if (the_groove->actor == NULL) {
1413
            if (!pAllowed_to_be_absent && !gAusterity_mode) {
1414
                FatalError(kFatalError_FindActorUsedByGroovidelicFile_S, str);
1415
            }
1416
            if (gGroove_by_proxy_actor == NULL) {
1417
                gGroove_by_proxy_actor = BrActorAllocate(BR_ACTOR_MODEL, NULL);
1418
                gGroove_by_proxy_actor->model = LoadModel("PROXY.DAT");
1419
                BrModelAdd(gGroove_by_proxy_actor->model);
1420
                BrActorAdd(gDont_render_actor, gGroove_by_proxy_actor);
1421
            }
1422
            the_groove->actor = gGroove_by_proxy_actor;
1423
        }
1424
        the_groove->lollipop_mode = GetALineAndInterpretCommand(pF, gLollipop_names, COUNT_OF(gLollipop_names));
1425
        the_groove->mode = GetALineAndInterpretCommand(pF, gGroove_nature_names, COUNT_OF(gGroove_nature_names));
1426
 
1427
        the_groove->path_type = GetALineAndInterpretCommand(pF, gGroove_path_names, COUNT_OF(gGroove_path_names));
1428
        the_groove->path_interrupt_status = eInterrupt_none;
1429
        the_groove->object_interrupt_status = eInterrupt_none;
1430
        if (the_groove->path_type != eGroove_path_none) {
1431
            the_groove->path_mode = GetALineAndInterpretCommand(pF, gFunk_move_names, COUNT_OF(gFunk_move_names));
1432
        }
1433
 
1434
        if (the_groove->path_type == eGroove_path_circular) {
1435
            TELL_ME_IF_WE_PASS_THIS_WAY();
1436
            // GetThreeFloats(pF, &v90, &v89, &v88);
1437
            // the_groove->path_data.circular_info.centre.v[0] = v90;
1438
            // the_groove->path_data.circular_info.centre.v[1] = v89;
1439
            // the_groove->path_data.circular_info.centre.v[2] = v88;
1440
            // if (the_groove->path_data.circular_info.centre.v[2] == 0.0
1441
            //     && *(float*)&the_groove->path_data.circular_info.axis == 0.0
1442
            //     && *((float*)&the_groove->path_data.circular_info + 6) == 0.0) {
1443
            //     v25 = (_DWORD*)the_groove->actor->t.t.translate.t.v;
1444
            //     v26 = (_DWORD*)&the_groove->path_data.circular_info.centre.v[2];
1445
            //     *v26 = *v25;
1446
            //     v26[1] = v25[1];
1447
            //     v26[2] = v25[2];
1448
            // }
1449
            // if (the_groove->path_mode != 3 && the_groove->path_mode != 4) {
1450
            //     v29 = GetAFloat(pF);
1451
            //     x_0 = v29;
1452
            //     if (v31) {
1453
            //         v62 = 0.0;
1454
            //     } else {
1455
            //         v62 = 1000.0 / x_0;
1456
            //     }
1457
            //     the_groove->path_data.circular_info.period = v62;
1458
            // } else {
1459
            //     v27 = &the_groove->path_data.circular_info.period;
1460
            //     v28 = GetAnInt(pF);
1461
            //     AddFunkGrooveBinding(v28 + pRef_offset, v27);
1462
            // }
1463
            // v32 = GetAFloat(pF);
1464
            // the_groove->path_data.circular_info.radius = v32;
1465
            // v33 = GetALineAndInterpretCommand(pF, gAxis_names, 3);
1466
            // the_groove->path_data.circular_info.axis = v33;
1467
 
1468
        } else if (the_groove->path_type == eGroove_path_straight) {
1469
            GetThreeFloats(pF,
1470
                &the_groove->path_data.straight_info.centre.v[0],
1471
                &the_groove->path_data.straight_info.centre.v[1],
1472
                &the_groove->path_data.straight_info.centre.v[2]);
1473
 
1474
            if (Vector3IsZero(&the_groove->path_data.straight_info.centre)) {
1475
                BrVector3Copy(&the_groove->path_data.straight_info.centre,
1476
                    &the_groove->actor->t.t.translate.t);
1477
            }
1478
            if (the_groove->path_mode == eMove_controlled || the_groove->path_mode == eMove_absolute) {
1479
                AddFunkGrooveBinding(pRef_offset + GetAnInt(pF), &the_groove->path_data.straight_info.period);
1480
            } else {
1481
                x_0 = GetAFloat(pF);
1482
                the_groove->path_data.straight_info.period = x_0 == 0.0f ? 0.0f : 1000.0 / x_0;
1483
            }
1484
            GetThreeFloats(
1485
                pF,
1486
                &the_groove->path_data.straight_info.x_delta,
1487
                &the_groove->path_data.straight_info.y_delta,
1488
                &the_groove->path_data.straight_info.z_delta);
1489
        }
1490
        the_groove->object_type = GetALineAndInterpretCommand(pF, gGroove_object_names, COUNT_OF(gGroove_object_names));
1491
        BrVector3Copy(&the_groove->object_position, &the_groove->actor->t.t.translate.t);
1492
        if (the_groove->object_type != eGroove_object_none) {
1493
            the_groove->object_mode = GetALineAndInterpretCommand(pF, gFunk_move_names, COUNT_OF(gFunk_move_names));
1494
        }
1495
        switch (the_groove->object_type) {
1496
        case eGroove_object_spin:
1497
            if (the_groove->object_mode == eMove_controlled || the_groove->object_mode == eMove_absolute) {
1498
                AddFunkGrooveBinding(pRef_offset + GetAnInt(pF), &the_groove->object_data.spin_info.period);
1499
            } else {
1500
                x_0 = GetAFloat(pF);
1501
                the_groove->object_data.spin_info.period = (x_0 == 0.0f) ? 0.0f : (1000.0f / x_0);
1502
            }
1503
            GetThreeFloats(pF,
1504
                &the_groove->object_centre.v[0],
1505
                &the_groove->object_centre.v[1],
1506
                &the_groove->object_centre.v[2]);
1507
            the_groove->object_data.spin_info.axis = GetALineAndInterpretCommand(pF, gAxis_names, COUNT_OF(gAxis_names));
1508
            break;
1509
        case eGroove_object_rock:
1510
            if (the_groove->object_mode == eMove_controlled || the_groove->object_mode == eMove_absolute) {
1511
                AddFunkGrooveBinding(pRef_offset + GetAnInt(pF), &the_groove->object_data.rock_info.period);
1512
            } else {
1513
                x_0 = GetAFloat(pF);
1514
                the_groove->object_data.rock_info.period = (x_0 == 0.0f) ? 0.0f : (1000.0f / x_0);
1515
            }
1516
            GetThreeFloats(pF,
1517
                &the_groove->object_centre.v[0],
1518
                &the_groove->object_centre.v[1],
1519
                &the_groove->object_centre.v[2]);
1520
            the_groove->object_data.rock_info.axis = GetALineAndInterpretCommand(pF, gAxis_names, COUNT_OF(gAxis_names));
1521
            the_groove->object_data.rock_info.max_angle = GetAFloat(pF);
1522
            break;
1523
        case eGroove_object_throb:
1524
            if (the_groove->object_mode == eMove_controlled || the_groove->object_mode == eMove_absolute) {
1525
                GetThreeInts(pF, &d_0, &d_1, &d_2);
1526
                if (d_0 >= 0) {
1527
                    AddFunkGrooveBinding(pRef_offset + d_0, &the_groove->object_data.throb_info.x_period);
1528
                }
1529
                if (d_1 >= 0) {
1530
                    AddFunkGrooveBinding(pRef_offset + d_1, &the_groove->object_data.throb_info.y_period);
1531
                }
1532
                if (d_2 >= 0) {
1533
                    AddFunkGrooveBinding(pRef_offset + d_2, &the_groove->object_data.throb_info.z_period);
1534
                }
1535
            } else {
1536
                GetThreeFloats(pF, &x_0, &x_1, &x_2);
1537
                the_groove->object_data.throb_info.x_period = (x_0 == 0.0f) ? 0.0f : (1000.0f / x_0);
1538
                the_groove->object_data.throb_info.y_period = (x_1 == 0.0f) ? 0.0f : (1000.0f / x_1);
1539
                the_groove->object_data.throb_info.z_period = (x_2 == 0.0f) ? 0.0f : (1000.0f / x_2);
1540
            }
1541
            GetThreeFloats(pF,
1542
                &the_groove->object_centre.v[0],
1543
                &the_groove->object_centre.v[1],
1544
                &the_groove->object_centre.v[2]);
1545
            GetThreeFloatPercents(
1546
                pF,
1547
                &the_groove->object_data.throb_info.x_magnitude,
1548
                &the_groove->object_data.throb_info.y_magnitude,
1549
                &the_groove->object_data.throb_info.z_magnitude);
1550
            break;
1551
        case eGroove_object_shear:
1552
            if (the_groove->object_mode == eMove_controlled || the_groove->object_mode == eMove_absolute) {
1553
                GetThreeInts(pF, &d_0, &d_1, &d_2);
1554
                if (d_0 >= 0) {
1555
                    AddFunkGrooveBinding(pRef_offset + d_0, &the_groove->object_data.shear_info.x_period);
1556
                }
1557
                if (d_1 >= 0) {
1558
                    AddFunkGrooveBinding(pRef_offset + d_1, &the_groove->object_data.shear_info.y_period);
1559
                }
1560
                if (d_2 >= 0) {
1561
                    AddFunkGrooveBinding(pRef_offset + d_2, &the_groove->object_data.shear_info.z_period);
1562
                }
1563
            } else {
1564
                GetThreeFloats(pF, &x_0, &x_1, &x_2);
1565
                the_groove->object_data.shear_info.x_period = x_0 == 0.0f ? 0.0f : 1000.0 / x_0;
1566
                the_groove->object_data.shear_info.y_period = x_1 == 0.0f ? 0.0f : 1000.0 / x_1;
1567
                the_groove->object_data.shear_info.z_period = x_2 == 0.0f ? 0.0f : 1000.0 / x_2;
1568
            }
1569
            GetThreeFloats(pF,
1570
                &the_groove->object_centre.v[0],
1571
                &the_groove->object_centre.v[1],
1572
                &the_groove->object_centre.v[2]);
1573
            GetThreeFloatPercents(
1574
                pF,
1575
                &the_groove->object_data.shear_info.x_magnitude,
1576
                &the_groove->object_data.shear_info.y_magnitude,
1577
                &the_groove->object_data.shear_info.z_magnitude);
1578
 
1579
            break;
1580
        default:
1581
            break;
1582
        }
1583
    }
1584
}
1585
 
1586
// IDA: void __usercall KillGroovadelic(int pOwner@<EAX>)
1587
void KillGroovadelic(int pOwner) {
1588
    int i;
1589
    tGroovidelic_spec* the_groove;
1590
    LOG_TRACE("(%d)", pOwner);
1591
 
1592
    if (gGroovidelics_array == NULL) {
1593
        return;
1594
    }
1595
    for (i = 0; i < gGroovidelics_array_size; i++) {
1596
        the_groove = &gGroovidelics_array[i];
1597
        if (the_groove->owner != pOwner) {
1598
            continue;
1599
        }
1600
        if (the_groove->path_mode == eMove_controlled) {
1601
            continue;
1602
        }
1603
        if (the_groove->path_mode == eMove_absolute) {
1604
            continue;
1605
        }
1606
        if (the_groove->object_mode == eMove_controlled) {
1607
            continue;
1608
        }
1609
        if (the_groove->object_mode == eMove_absolute) {
1610
            continue;
1611
        }
1612
        the_groove->owner = -999;
1613
    }
1614
}
1615
 
1616
// IDA: void __usercall KillFunkotronic(int pOwner@<EAX>)
1617
void KillFunkotronic(int pOwner) {
1618
    int i;
1619
    tFunkotronic_spec* the_funk;
1620
    LOG_TRACE("(%d)", pOwner);
1621
 
1622
    if (gFunkotronics_array == NULL) {
1623
        return;
1624
    }
1625
    for (i = 0; i < gFunkotronics_array_size; i++) {
1626
        the_funk = &gFunkotronics_array[i];
1627
        if (the_funk->owner != pOwner) {
1628
            continue;
1629
        }
1630
        if (the_funk->matrix_mode == eMove_controlled) {
1631
            continue;
1632
        }
1633
        if (the_funk->matrix_mode == eMove_absolute) {
1634
            continue;
1635
        }
1636
        if (the_funk->lighting_animation_type == eMove_controlled) {
1637
            continue;
1638
        }
1639
        if (the_funk->lighting_animation_type == eMove_absolute) {
1640
            continue;
1641
        }
1642
        if (the_funk->texture_animation_data.frames_info.mode == eMove_controlled && the_funk->texture_animation_type == eTexture_animation_frames) {
1643
            continue;
1644
        }
1645
        the_funk->owner = -999;
1646
    }
1647
}
1648
 
1649
// IDA: br_uint_32 __usercall DeleteBastards@<EAX>(br_actor *pActor@<EAX>, br_matrix34 *pMatrix@<EDX>, void *pArg@<EBX>)
1650
br_uint_32 DeleteBastards(br_actor* pActor, br_matrix34* pMatrix, void* pArg) {
1651
    int i;
1652
    int parent_already_doomed;
1653
    LOG_TRACE("(%p, %p, %p)", pActor, pMatrix, pArg);
1654
 
1655
    if ((gAdditional_actors != pActor && (pActor->identifier == NULL || pActor->identifier[0] == '&') && Vector3IsZero((br_vector3*)pMatrix->m[3])) || (pActor->model == NULL && pActor->type == BR_ACTOR_MODEL)) {
1656
        parent_already_doomed = 0;
1657
        for (i = 0; i < gDelete_count; i++) {
1658
            if (gDelete_list[i] == pActor) {
1659
                parent_already_doomed = 1;
1660
                break;
1661
            }
1662
        }
1663
        if (!parent_already_doomed) {
1664
            gDelete_list[gDelete_count] = pActor;
1665
            gDelete_count++;
1666
        }
1667
    }
1668
    return 0;
1669
}
1670
 
1671
// IDA: void __cdecl DeleteAnyZeroBastards()
1672
void DeleteAnyZeroBastards(void) {
1673
    int i;
1674
    LOG_TRACE("()");
1675
 
1676
    gDelete_count = 0;
1677
    DRActorEnumRecurseWithTrans(gAdditional_actors, NULL, DeleteBastards, NULL);
1678
    for (i = 0; i < gDelete_count; i++) {
1679
        BrActorRemove(gDelete_list[i]);
1680
    }
1681
}
1682
 
1683
// IDA: br_uint_32 __usercall ApplyTransToModels@<EAX>(br_actor *pActor@<EAX>, br_matrix34 *pMatrix@<EDX>, void *pArg@<EBX>)
1684
br_uint_32 ApplyTransToModels(br_actor* pActor, br_matrix34* pMatrix, void* pArg) {
1685
    int i;
1686
    br_vector3 temp_point;
1687
    LOG_TRACE("(%p, %p, %p)", pActor, pMatrix, pArg);
1688
 
1689
    if (pActor->identifier == NULL || pActor->identifier[0] == '&') {
1690
        return 0;
1691
    }
1692
    if (pActor->model != NULL) {
1693
        for (i = 0; i < pActor->model->nvertices; i++) {
1694
            BrVector3Copy(&temp_point, &pActor->model->vertices[i].p);
1695
            BrMatrix34ApplyP(&pActor->model->vertices[i].p, &temp_point, pMatrix);
1696
        }
1697
        BrModelUpdate(pActor->model, BR_MATU_ALL);
1698
    }
1699
    BrMatrix34Identity(&pActor->t.t.mat);
1700
    pActor->t.type = BR_TRANSFORM_IDENTITY;
1701
    return 0;
1702
}
1703
 
1704
// IDA: int __usercall FindSpecVolIndex@<EAX>(br_actor *pActor@<EAX>)
1705
int FindSpecVolIndex(br_actor* pActor) {
1706
    int i;
1707
    //tSpecial_volume* v; // Pierre-Marie Baty -- unused variable
1708
    LOG_TRACE("(%p)", pActor);
1709
 
1710
    for (i = 0; i < gProgram_state.special_volume_count; i++) {
1711
        if (gSpec_vol_actors[i] == pActor) {
1712
            return i;
1713
        }
1714
    }
1715
    return -1;
1716
}
1717
 
1718
// IDA: void __usercall MungeMaterial(br_matrix34 *pMat@<EAX>, br_material *pMat_1@<EDX>, br_material *pMat_2@<EBX>, int pAxis_0@<ECX>, int pAxis_1)
1719
void MungeMaterial(br_matrix34* pMat, br_material* pMat_1, br_material* pMat_2, int pAxis_0, int pAxis_1) {
1720
    LOG_TRACE("(%p, %p, %p, %d, %d)", pMat, pMat_1, pMat_2, pAxis_0, pAxis_1);
1721
 
1722
    pMat_1->map_transform.m[0][0] = 6.f * BrVector3Length((br_vector3*)pMat->m[pAxis_0]);
1723
    pMat_1->map_transform.m[1][1] = 6.f * BrVector3Length((br_vector3*)pMat->m[pAxis_1]);
1724
    BrMatrix23Copy(&pMat_2->map_transform, &pMat_1->map_transform);
1725
}
1726
 
1727
// IDA: void __usercall SetSpecVolMatSize(br_actor *pActor@<EAX>)
1728
void SetSpecVolMatSize(br_actor* pActor) {
1729
    br_model* model;
1730
    LOG_TRACE("(%p)", pActor);
1731
 
1732
    model = pActor->model;
1733
    MungeMaterial(&pActor->t.t.mat, model->faces[5].material, model->faces[17].material, 0, 1);
1734
    MungeMaterial(&pActor->t.t.mat, model->faces[11].material, model->faces[23].material, 1, 2);
1735
    MungeMaterial(&pActor->t.t.mat, model->faces[7].material, model->faces[19].material, 0, 2);
1736
}
1737
 
1738
// IDA: void __usercall FindInverseAndWorldBox(tSpecial_volume *pSpec@<EAX>)
1739
void FindInverseAndWorldBox(tSpecial_volume* pSpec) {
1740
    br_bounds bnds;
1741
    LOG_TRACE("(%p)", pSpec);
1742
 
1743
    bnds.min.v[0] = -1.0;
1744
    bnds.min.v[1] = -1.0;
1745
    bnds.min.v[2] = -1.0;
1746
    bnds.max.v[0] = 1.0;
1747
    bnds.max.v[1] = 1.0;
1748
    bnds.max.v[2] = 1.0;
1749
    GetNewBoundingBox(&pSpec->bounds, &bnds, &pSpec->mat);
1750
    BrMatrix34Inverse(&pSpec->inv_mat, &pSpec->mat);
1751
}
1752
 
1753
// IDA: void __cdecl UpdateSpecVol()
1754
void UpdateSpecVol(void) {
1755
    int index;
1756
    tSpecial_volume* v;
1757
    LOG_TRACE("()");
1758
 
1759
    index = FindSpecVolIndex(gLast_actor);
1760
    if (index >= 0) {
1761
        v = &gProgram_state.special_volumes[index];
1762
        BrMatrix34Copy(&v->mat, &gLast_actor->t.t.mat);
1763
        FindInverseAndWorldBox(v);
1764
        SetSpecVolMatSize(gLast_actor);
1765
    }
1766
}
1767
 
1768
// IDA: void __cdecl SaveSpecialVolumes()
1769
void SaveSpecialVolumes(void) {
1770
    tPath_name the_path;
1771
    FILE* f;
1772
    int i;
1773
    tSpecial_volume* v;
1774
    LOG_TRACE("()");
1775
 
1776
    PathCat(the_path, gApplication_path, "SPECSAVE.TXT");
1777
    f = DRfopen(the_path, "wt");
1778
    if (f == NULL) {
1779
        return;
1780
    }
1781
    fprintf(f, "// SPECIAL EFFECTS VOLUMES\n\n");
1782
    fprintf(f, "%d\t\t\t\t// # special effects volumes\n\n", gProgram_state.special_volume_count);
1783
    for (i = 0; i < gProgram_state.special_volume_count; i++) {
1784
        v = &gProgram_state.special_volumes[i];
1785
        if (v->no_mat) {
1786
            fprintf(f, "%s\n", "DEFAULT WATER");
1787
        } else {
1788
            fprintf(f, "NEW IMPROVED!\n");
1789
            fprintf(f, "%.3f, %.3f, %.3f\n", v->mat.m[0][0], v->mat.m[0][1], v->mat.m[0][2]);
1790
            fprintf(f, "%.3f, %.3f, %.3f\n", v->mat.m[1][0], v->mat.m[1][1], v->mat.m[1][2]);
1791
            fprintf(f, "%.3f, %.3f, %.3f\n", v->mat.m[2][0], v->mat.m[2][1], v->mat.m[2][2]);
1792
            fprintf(f, "%.3f, %.3f, %.3f\n", v->mat.m[3][0], v->mat.m[3][1], v->mat.m[3][2]);
1793
        }
1794
        fprintf(f, "%.0f\t\t\t\t// gravity multiplier\n", v->gravity_multiplier);
1795
        fprintf(f, "%.0f\t\t\t\t// viscosity multiplier\n", v->viscosity_multiplier);
1796
        fprintf(f, "%.0f\t\t\t\t// Car damage per millisecond\n", v->car_damage_per_ms);
1797
        fprintf(f, "%.0f\t\t\t\t// Pedestrian damage per millisecond\n", v->ped_damage_per_ms);
1798
        fprintf(f, "%d\t\t\t\t\t// camera effect index\n", v->camera_special_effect_index);
1799
        fprintf(f, "%d\t\t\t\t\t// sky colour\n", v->sky_col);
1800
        fprintf(f, "%s\t\t\t\t// Windscreen material to use\n", (v->screen_material != NULL) ? v->screen_material->identifier : "none");
1801
        fprintf(f, "%d\t\t\t\t\t// Sound ID of entry noise\n", v->entry_noise);
1802
        fprintf(f, "%d\t\t\t\t\t// Sound ID of exit noise\n", v->exit_noise);
1803
        fprintf(f, "%d\t\t\t\t\t// Engine noise index\n", v->engine_noise_index);
1804
        fprintf(f, "%d\t\t\t\t\t// material index\n", v->material_modifier_index);
1805
        fprintf(f, "\n");
1806
    }
1807
    fclose(f);
1808
}
1809
 
1810
// IDA: void __cdecl SaveAdditionalStuff()
1811
void SaveAdditionalStuff(void) {
1812
    LOG_TRACE("()");
1813
 
1814
    if (gSpec_vol_mode) {
1815
        UpdateSpecVol();
1816
        SaveSpecialVolumes();
1817
    } else {
1818
        DeleteAnyZeroBastards();
1819
        if (gLast_actor != NULL) {
1820
            DRActorEnumRecurseWithTrans(gLast_actor, NULL, ApplyTransToModels, NULL);
1821
        }
1822
        BrActorSave(gAdditional_actor_path, gAdditional_actors);
1823
        BrModelSaveMany(gAdditional_model_path, gAdditional_models, gNumber_of_additional_models);
1824
    }
1825
}
1826
 
1827
// IDA: br_uint_32 __cdecl ProcessMaterials(br_actor *pActor, tPMFM2CB pCallback)
1828
br_uint_32 ProcessMaterials(br_actor* pActor, tPMFM2CB pCallback) {
1829
    LOG_TRACE("(%p, %d)", pActor, pCallback);
1830
    NOT_IMPLEMENTED();
1831
}
1832
 
1833
// IDA: br_uint_32 __cdecl ProcessFaceMaterials2(br_actor *pActor, tPMFM2CB pCallback)
1834
br_uint_32 ProcessFaceMaterials2(br_actor* pActor, tPMFM2CB pCallback) {
1835
    LOG_TRACE("(%p, %d)", pActor, pCallback);
1836
    NOT_IMPLEMENTED();
1837
}
1838
 
1839
// IDA: void __usercall ChangePerspToSubdivCB(br_material *pMaterial@<EAX>)
1840
void ChangePerspToSubdivCB(br_material* pMaterial) {
1841
    LOG_TRACE("(%p)", pMaterial);
1842
    NOT_IMPLEMENTED();
1843
}
1844
 
1845
// IDA: void __cdecl ChangePerspToSubdiv()
1846
void ChangePerspToSubdiv(void) {
1847
    LOG_TRACE("()");
1848
    NOT_IMPLEMENTED();
1849
}
1850
 
1851
// IDA: void __usercall ChangeSubdivToPerspCB(br_material *pMaterial@<EAX>)
1852
void ChangeSubdivToPerspCB(br_material* pMaterial) {
1853
    LOG_TRACE("(%p)", pMaterial);
1854
    NOT_IMPLEMENTED();
1855
}
1856
 
1857
// IDA: void __cdecl ChangeSubdivToPersp()
1858
void ChangeSubdivToPersp(void) {
1859
    LOG_TRACE("()");
1860
    NOT_IMPLEMENTED();
1861
}
1862
 
1863
// IDA: br_uint_32 __cdecl ProcessFaceMaterials(br_actor *pActor, tPMFMCB pCallback)
20 pmbaty 1864
intptr_t ProcessFaceMaterials(br_actor* pActor, tPMFMCB pCallback) {
1 pmbaty 1865
    LOG_TRACE("(%p, %d)", pActor, pCallback);
1866
 
1867
    if (pActor->identifier == NULL || pActor->identifier[0] != '&') {
1868
        if (pActor->type == BR_ACTOR_MODEL && pActor->model != NULL) {
1869
            ProcessModelFaceMaterials(pActor->model, pCallback);
1870
        }
1871
        return BrActorEnum(pActor, (br_actor_enum_cbfn*)ProcessFaceMaterials, pCallback);
1872
    } else {
1873
        return 0;
1874
    }
1875
}
1876
 
1877
// IDA: int __usercall DRPixelmapHasZeros@<EAX>(br_pixelmap *pm@<EAX>)
1878
int DRPixelmapHasZeros(br_pixelmap* pm) {
1879
    int x;
1880
    int y;
1881
    char* row_ptr;
1882
    char* pp;
1883
    //int i; // Pierre-Marie Baty -- unused variable
1884
 
1885
    if (pm->flags & BR_PMF_NO_ACCESS) {
1886
        return 1;
1887
    }
1888
    row_ptr = (char*)pm->pixels + (pm->row_bytes * pm->base_y) + pm->base_x;
1889
    for (y = 0; y < pm->height; y++) {
1890
        pp = row_ptr;
1891
        for (x = 0; x < pm->width; x++) {
1892
            if (!pp)
1893
                return 1;
1894
            pp++;
1895
        }
1896
        row_ptr += pm->row_bytes;
1897
    }
1898
    return 0;
1899
}
1900
 
1901
// IDA: int __usercall StorageContainsPixelmap@<EAX>(tBrender_storage *pStorage@<EAX>, br_pixelmap *pMap@<EDX>)
1902
int StorageContainsPixelmap(tBrender_storage* pStorage, br_pixelmap* pMap) {
1903
    int i;
1904
 
1905
    for (i = 0; i < pStorage->pixelmaps_count; i++) {
1906
        if (pMap == pStorage->pixelmaps[i]) {
1907
            return 1;
1908
        }
1909
    }
1910
    return 0;
1911
}
1912
 
1913
// IDA: void __usercall HideStoredOpaqueTextures(tBrender_storage *pStorage@<EAX>)
1914
void HideStoredOpaqueTextures(tBrender_storage* pStorage) {
1915
    int i;
1916
 
1917
    for (i = 0; i < pStorage->materials_count; i++) {
1918
        if (pStorage->materials[i]->colour_map && StorageContainsPixelmap(pStorage, pStorage->materials[i]->colour_map)) {
1919
            if (!DRPixelmapHasZeros(pStorage->materials[i]->colour_map)) {
1920
                pStorage->saved_colour_maps[i] = pStorage->materials[i]->colour_map;
1921
                pStorage->materials[i]->colour_map = NULL;
1922
                pStorage->materials[i]->flags &= 0xFDu;
1923
                BrMaterialUpdate(pStorage->materials[i], BR_MATU_ALL);
1924
            }
1925
        }
1926
    }
1927
}
1928
 
1929
// IDA: void __usercall RevealStoredTransparentTextures(tBrender_storage *pStorage@<EAX>)
1930
void RevealStoredTransparentTextures(tBrender_storage* pStorage) {
1931
    int i;
1932
 
1933
    for (i = 0; i < pStorage->materials_count; i++) {
1934
        if (pStorage->saved_colour_maps[i]) {
1935
            if (DRPixelmapHasZeros(pStorage->saved_colour_maps[i])) {
1936
                pStorage->materials[i]->colour_map = pStorage->saved_colour_maps[i];
1937
                pStorage->saved_colour_maps[i] = NULL;
1938
                pStorage->materials[i]->flags |= 2u;
1939
                BrMaterialUpdate(pStorage->materials[i], BR_MATU_ALL);
1940
            }
1941
        }
1942
    }
1943
}
1944
 
1945
// IDA: void __usercall HideStoredTextures(tBrender_storage *pStorage@<EAX>)
1946
void HideStoredTextures(tBrender_storage* pStorage) {
1947
    int i;
1948
 
1949
    for (i = 0; i < pStorage->materials_count; i++) {
1950
        if (pStorage->materials[i]->colour_map) {
1951
            if (StorageContainsPixelmap(pStorage, pStorage->materials[i]->colour_map)) {
1952
                pStorage->saved_colour_maps[i] = pStorage->materials[i]->colour_map;
1953
                pStorage->materials[i]->colour_map = NULL;
1954
                pStorage->materials[i]->flags &= 0xFDu;
1955
                BrMaterialUpdate(pStorage->materials[i], BR_MATU_ALL);
1956
            }
1957
        }
1958
    }
1959
}
1960
 
1961
// IDA: void __usercall RevealStoredTextures(tBrender_storage *pStorage@<EAX>)
1962
void RevealStoredTextures(tBrender_storage* pStorage) {
1963
    int i;
1964
 
1965
    for (i = 0; i < pStorage->materials_count; i++) {
1966
        if (pStorage->saved_colour_maps[i]) {
1967
            pStorage->materials[i]->colour_map = pStorage->saved_colour_maps[i];
1968
            pStorage->saved_colour_maps[i] = NULL;
1969
            pStorage->materials[i]->flags |= BR_MATF_PRELIT;
1970
            BrMaterialUpdate(pStorage->materials[i], BR_MATU_ALL);
1971
        }
1972
    }
1973
}
1974
 
1975
// IDA: void __usercall SetCarStorageTexturingLevel(tBrender_storage *pStorage@<EAX>, tCar_texturing_level pNew@<EDX>, tCar_texturing_level pOld@<EBX>)
1976
void SetCarStorageTexturingLevel(tBrender_storage* pStorage, tCar_texturing_level pNew, tCar_texturing_level pOld) {
1977
    LOG_TRACE("(%p, %d, %d)", pStorage, pNew, pOld);
1978
 
1979
    switch (pNew) {
1980
    case eCTL_none:
1981
        HideStoredTextures(pStorage);
1982
        break;
1983
    case eCTL_transparent:
1984
        switch (pOld) {
1985
        case eCTL_none:
1986
            RevealStoredTransparentTextures(pStorage);
1987
            break;
1988
        case eCTL_full:
1989
            HideStoredOpaqueTextures(pStorage);
1990
            break;
1991
        default:
1992
            break;
1993
        }
1994
        break;
1995
    case eCTL_full:
1996
        RevealStoredTextures(pStorage);
1997
        break;
1998
    default:
1999
        break;
2000
    }
2001
}
2002
 
2003
// IDA: tCar_texturing_level __cdecl GetCarTexturingLevel()
2004
tCar_texturing_level GetCarTexturingLevel(void) {
2005
    LOG_TRACE("()");
2006
 
2007
    return gCar_texturing_level;
2008
}
2009
 
2010
// IDA: void __usercall SetCarTexturingLevel(tCar_texturing_level pLevel@<EAX>)
2011
void SetCarTexturingLevel(tCar_texturing_level pLevel) {
2012
    LOG_TRACE("(%d)", pLevel);
2013
 
2014
    if (pLevel != gCar_texturing_level) {
2015
        if (gOur_car_storage_space.models_count != 0) {
2016
            SetCarStorageTexturingLevel(&gOur_car_storage_space, pLevel, gCar_texturing_level);
2017
        }
2018
        if (gTheir_cars_storage_space.models_count != 0) {
2019
            SetCarStorageTexturingLevel(&gTheir_cars_storage_space, pLevel, gCar_texturing_level);
2020
        }
2021
        if (gNet_cars_storage_space.models_count != 0) {
2022
            SetCarStorageTexturingLevel(&gTheir_cars_storage_space, pLevel, gCar_texturing_level);
2023
        }
2024
    }
2025
    gCar_texturing_level = pLevel;
2026
}
2027
 
2028
// IDA: int __usercall HasThisSuffix@<EAX>(char *pIdent@<EAX>, char *pSuffix@<EDX>)
2029
int HasThisSuffix(char* pIdent, char* pSuffix) {
2030
    size_t len_ident;
2031
    size_t len_suffix;
2032
    LOG_TRACE("(\"%s\", \"%s\")", pIdent, pSuffix);
2033
 
2034
    len_ident = strlen(pIdent);
2035
    len_suffix = strlen(pSuffix);
2036
    if (pIdent == NULL) {
2037
        return 0;
2038
    }
2039
    if (pIdent < pSuffix) {
2040
        return 0;
2041
    }
2042
    return strcmp(pIdent + len_ident - len_suffix, pSuffix) == 0;
2043
}
2044
 
2045
// IDA: br_material* __usercall UnsuffixedMaterial@<EAX>(char *pOld_ident@<EAX>, char *pSuffix@<EDX>)
2046
br_material* UnsuffixedMaterial(char* pOld_ident, char* pSuffix) {
2047
    br_material* result;
2048
    int unsuffixed_len;
2049
    char* new_id;
2050
    LOG_TRACE("(\"%s\", \"%s\")", pOld_ident, pSuffix);
2051
 
2052
    unsuffixed_len = strlen(pOld_ident) - strlen(pSuffix);
2053
    new_id = BrMemAllocate(unsuffixed_len + 1, kMem_new_mat_id_2);
2054
    sprintf(new_id, "%.*s", unsuffixed_len, pOld_ident);
2055
    result = BrMaterialFind(new_id);
2056
    BrMemFree(new_id);
2057
    return result;
2058
}
2059
 
2060
// IDA: br_material* __usercall RoadUntexToPersp@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
2061
br_material* RoadUntexToPersp(br_model* pModel, tU16 pFace) {
2062
    br_material* old_mat;
2063
    br_material* new_mat;
2064
    LOG_TRACE("(%p, %d)", pModel, pFace);
2065
 
2066
    old_mat = pModel->faces[pFace].material;
2067
    if (HasThisSuffix(old_mat->identifier, ".road")) {
2068
        new_mat = UnsuffixedMaterial(old_mat->identifier, ".road");
2069
    } else {
2070
        new_mat = NULL;
2071
    }
2072
    return new_mat;
2073
}
2074
 
2075
// IDA: br_material* __usercall WallLinearToUntex@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
2076
br_material* WallLinearToUntex(br_model* pModel, tU16 pFace) {
2077
    br_material* old_mat;
2078
    //br_material* new_mat; // Pierre-Marie Baty -- unused variable
2079
    LOG_TRACE("(%p, %d)", pModel, pFace);
2080
 
2081
    old_mat = pModel->faces[pFace].material;
2082
    if (HasThisSuffix(old_mat->identifier, ".pwall")) {
2083
        if (old_mat->colour_map != NULL) {
2084
            old_mat->colour_map = NULL;
2085
            BrMaterialUpdate(old_mat, BR_MATU_ALL);
2086
        }
2087
    } else {
2088
        if (!FaceIsRoad(pModel, pFace) && old_mat->identifier != NULL && old_mat->colour_map != NULL) {
2089
            old_mat = SuffixedMaterial(old_mat, ".lwall");
2090
            if (old_mat->colour_map != NULL) {
2091
                old_mat->colour_map = NULL;
2092
                BrMaterialUpdate(old_mat, BR_MATU_ALL);
2093
            }
2094
        } else {
2095
            old_mat = NULL;
2096
        }
2097
    }
2098
    return old_mat;
2099
}
2100
 
2101
// IDA: br_material* __usercall WallUntexToLinear@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
2102
br_material* WallUntexToLinear(br_model* pModel, tU16 pFace) {
2103
    br_material* old_mat;
2104
    br_material* new_mat;
2105
    LOG_TRACE("(%p, %d)", pModel, pFace);
2106
 
2107
    old_mat = pModel->faces[pFace].material;
2108
    if (HasThisSuffix(old_mat->identifier, ".lwall")) {
2109
        new_mat = UnsuffixedMaterial(old_mat->identifier, ".lwall");
2110
    } else if (HasThisSuffix(old_mat->identifier, ".pwall")) {
2111
        old_mat->colour_map = UnsuffixedMaterial(old_mat->identifier, ".pwall")->colour_map;
2112
        old_mat->flags &= ~BR_MATF_PERSPECTIVE;
2113
        BrMaterialUpdate(old_mat, BR_MATU_ALL);
2114
        new_mat = NULL;
2115
    } else {
2116
        new_mat = NULL;
2117
    }
2118
    return new_mat;
2119
}
2120
 
2121
// IDA: br_material* __usercall WallUntexToPersp@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
2122
br_material* WallUntexToPersp(br_model* pModel, tU16 pFace) {
2123
    br_material* old_mat;
2124
    br_material* new_mat;
2125
    LOG_TRACE("(%p, %d)", pModel, pFace);
2126
 
2127
    old_mat = pModel->faces[pFace].material;
2128
    if (HasThisSuffix(old_mat->identifier, ".lwall")) {
2129
        new_mat = UnsuffixedMaterial(old_mat->identifier, ".lwall");
2130
    } else if (HasThisSuffix(old_mat->identifier, ".pwall")) {
2131
        new_mat = UnsuffixedMaterial(old_mat->identifier, ".pwall");
2132
    } else {
2133
        new_mat = NULL;
2134
    }
2135
    return new_mat;
2136
}
2137
 
2138
// IDA: br_material* __usercall WallLinearToPersp@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
2139
br_material* WallLinearToPersp(br_model* pModel, tU16 pFace) {
2140
    br_material* old_mat;
2141
    br_material* new_mat;
2142
    LOG_TRACE("(%p, %d)", pModel, pFace);
2143
 
2144
    old_mat = pModel->faces[pFace].material;
2145
    if (HasThisSuffix(old_mat->identifier, ".pwall")) {
2146
        new_mat = UnsuffixedMaterial(old_mat->identifier, ".pwall");
2147
    } else {
2148
        new_mat = NULL;
2149
    }
2150
    return new_mat;
2151
}
2152
 
2153
// IDA: tRoad_texturing_level __cdecl GetRoadTexturingLevel()
2154
tRoad_texturing_level GetRoadTexturingLevel(void) {
2155
    return gRoad_texturing_level;
2156
}
2157
 
2158
// IDA: void __usercall SetRoadTexturingLevel(tRoad_texturing_level pLevel@<EAX>)
2159
void SetRoadTexturingLevel(tRoad_texturing_level pLevel) {
2160
    LOG_TRACE("(%d)", pLevel);
2161
    gRoad_texturing_level = pLevel;
2162
}
2163
 
2164
// IDA: void __usercall ReallySetRoadTexturingLevel(tRoad_texturing_level pLevel@<EAX>)
2165
void ReallySetRoadTexturingLevel(tRoad_texturing_level pLevel) {
2166
    LOG_TRACE("(%d)", pLevel);
2167
 
2168
    if (pLevel != gRoad_texturing_level) {
2169
        ProcessFaceMaterials(gProgram_state.track_spec.the_actor, (pLevel == eRTL_none) ? RoadUntexToPersp : RoadPerspToUntex);
2170
    }
2171
}
2172
 
2173
// IDA: tWall_texturing_level __cdecl GetWallTexturingLevel()
2174
tWall_texturing_level GetWallTexturingLevel(void) {
2175
    LOG_TRACE("()");
2176
 
2177
    return gWall_texturing_level;
2178
}
2179
 
2180
// IDA: void __usercall SetWallTexturingLevel(tWall_texturing_level pLevel@<EAX>)
2181
void SetWallTexturingLevel(tWall_texturing_level pLevel) {
2182
    LOG_TRACE("(%d)", pLevel);
2183
 
2184
    gWall_texturing_level = pLevel;
2185
}
2186
 
2187
// IDA: void __usercall ReallySetWallTexturingLevel(tWall_texturing_level pLevel@<EAX>)
2188
void ReallySetWallTexturingLevel(tWall_texturing_level pLevel) {
2189
    static tPMFMCB* tweaker[3][3] = {
2190
        {
2191
            NULL,
2192
            WallUntexToLinear,
2193
            WallUntexToPersp,
2194
        },
2195
        {
2196
            WallLinearToUntex,
2197
            NULL,
2198
            WallLinearToPersp,
2199
        },
2200
        {
2201
            WallPerspToUntex,
2202
            WallPerspToLinear,
2203
            NULL,
2204
        },
2205
    };
2206
    LOG_TRACE("(%d)", pLevel);
2207
 
2208
    if (gWall_texturing_level != pLevel) {
2209
        ProcessFaceMaterials(gProgram_state.track_spec.the_actor, tweaker[gWall_texturing_level][pLevel]);
2210
    }
2211
}
2212
 
2213
// IDA: br_material* __usercall DisposeSuffixedMaterials@<EAX>(br_model *pModel@<EAX>, tU16 pFace@<EDX>)
2214
br_material* DisposeSuffixedMaterials(br_model* pModel, tU16 pFace) {
2215
    size_t max_suffix_len;
2216
    br_material* mat;
2217
    br_material* victim;
2218
    static char* suffixes[3] = { ".road", ".pwall", ".lwall" };
2219
    int s;
2220
    char* id;
2221
    LOG_TRACE("(%p, %d)", pModel, pFace);
2222
 
2223
    mat = pModel->faces[pFace].material;
2224
    if (mat->identifier == NULL) {
2225
        return NULL;
2226
    }
2227
    max_suffix_len = 0;
2228
    for (s = 0; s < COUNT_OF(suffixes); s++) {
2229
        if (max_suffix_len < strlen(suffixes[s])) {
2230
            max_suffix_len = strlen(suffixes[s]);
2231
        }
2232
    }
2233
    id = BrMemAllocate(strlen(mat->identifier) + max_suffix_len + 1, kMem_new_mat_id_3);
2234
    for (s = 0; s < COUNT_OF(suffixes); s++) {
2235
        sprintf(id, "%s%s", mat->identifier, suffixes[s]);
2236
        victim = BrMaterialFind(id);
2237
        if (victim != NULL) {
2238
            BrMaterialRemove(victim);
2239
            BrMaterialFree(victim);
2240
        }
2241
    }
2242
    return NULL;
2243
}
2244
 
2245
// IDA: void __cdecl DisposeTexturingMaterials()
2246
void DisposeTexturingMaterials(void) {
2247
    LOG_TRACE("()");
2248
 
2249
    switch (gWall_texturing_level) {
2250
    case eWTL_linear:
2251
        ProcessFaceMaterials(gProgram_state.track_spec.the_actor, WallLinearToPersp);
2252
        break;
2253
    case eWTL_none:
2254
        ProcessFaceMaterials(gProgram_state.track_spec.the_actor, WallUntexToPersp);
2255
        break;
2256
    default:
2257
        break;
2258
    }
2259
 
2260
    switch (gRoad_texturing_level) {
2261
    case eRTL_none:
2262
        ProcessFaceMaterials(gProgram_state.track_spec.the_actor, RoadUntexToPersp);
2263
        break;
2264
    default:
2265
        break;
2266
    }
2267
 
2268
    if (gWall_texturing_level != eWTL_full || gRoad_texturing_level != eRTL_full) {
2269
        ProcessFaceMaterials(gProgram_state.track_spec.the_actor, DisposeSuffixedMaterials);
2270
    }
2271
}
2272
 
2273
// IDA: br_uint_32 __cdecl SetAccessoryRenderingCB(br_actor *pActor, void *pFlag)
20 pmbaty 2274
intptr_t SetAccessoryRenderingCB(br_actor* pActor, void* pFlag) {
1 pmbaty 2275
    if (pActor->identifier && *pActor->identifier == '&') {
2276
        pActor->render_style = *(br_uint_8*)pFlag;
2277
    }
2278
    return 0;
2279
}
2280
 
2281
// IDA: void __usercall SetAccessoryRendering(int pOn@<EAX>)
2282
void SetAccessoryRendering(int pOn) {
2283
    int style;
2284
 
2285
    LOG_TRACE("(%d)", pOn);
2286
 
2287
    if (gTrack_actor) {
2288
        if (pOn) {
2289
            style = BR_RSTYLE_FACES;
2290
        } else {
2291
            style = BR_RSTYLE_NONE;
2292
        }
2293
        DRActorEnumRecurse(gTrack_actor, (br_actor_enum_cbfn*)SetAccessoryRenderingCB, &style);
2294
    }
2295
    gRendering_accessories = pOn;
2296
}
2297
 
2298
// IDA: int __cdecl GetAccessoryRendering()
2299
int GetAccessoryRendering(void) {
2300
    LOG_TRACE("()");
2301
 
2302
    return gRendering_accessories;
2303
}
2304
 
2305
// IDA: void __usercall SetCarSimplificationLevel(int pLevel@<EAX>)
2306
void SetCarSimplificationLevel(int pLevel) {
2307
    LOG_TRACE("(%d)", pLevel);
2308
 
2309
    gCar_simplification_level = pLevel;
2310
}
2311
 
2312
// IDA: int __cdecl GetCarSimplificationLevel()
2313
int GetCarSimplificationLevel(void) {
2314
    LOG_TRACE("()");
2315
 
2316
    return gCar_simplification_level;
2317
}
2318
 
2319
// IDA: void __usercall ParseSpecialVolume(FILE *pF@<EAX>, tSpecial_volume *pSpec@<EDX>, char *pScreen_name_str@<EBX>)
2320
void ParseSpecialVolume(FILE* pF, tSpecial_volume* pSpec, char* pScreen_name_str) {
2321
    char s[256];
2322
    pSpec->gravity_multiplier = GetAScalar(pF);
2323
    pSpec->viscosity_multiplier = GetAScalar(pF);
2324
    pSpec->car_damage_per_ms = GetAScalar(pF);
2325
    pSpec->ped_damage_per_ms = GetAScalar(pF);
2326
    pSpec->camera_special_effect_index = GetAnInt(pF);
2327
    pSpec->sky_col = GetAnInt(pF);
2328
 
2329
    GetAString(pF, s);
2330
    if (pScreen_name_str) {
2331
        strcpy(pScreen_name_str, s);
2332
    } else {
2333
        pSpec->screen_material = BrMaterialFind(s);
2334
    }
2335
    pSpec->entry_noise = GetAnInt(pF);
2336
    pSpec->exit_noise = GetAnInt(pF);
2337
    pSpec->engine_noise_index = GetAnInt(pF);
2338
    pSpec->material_modifier_index = GetAnInt(pF);
2339
}
2340
 
2341
// IDA: void __usercall AddExceptionToList(tException_list *pDst@<EAX>, tException_list pNew@<EDX>)
2342
void AddExceptionToList(tException_list* pDst, tException_list pNew) {
2343
    LOG_TRACE("(%p, %d)", pDst, pNew);
2344
    NOT_IMPLEMENTED();
2345
}
2346
 
2347
// IDA: void __usercall LoadExceptionsFile(char *pName@<EAX>)
2348
void LoadExceptionsFile(char* pName) {
2349
    //FILE* f; // Pierre-Marie Baty -- unused variable
2350
    //char line[256]; // Pierre-Marie Baty -- unused variable
2351
    //char* tok; // Pierre-Marie Baty -- unused variable
2352
    //int file_version; // Pierre-Marie Baty -- unused variable
2353
    //tException_list e; // Pierre-Marie Baty -- unused variable
2354
    //char delimiters[4]; // Pierre-Marie Baty -- unused variable
2355
    LOG_TRACE("(\"%s\")", pName);
2356
    NOT_IMPLEMENTED();
2357
}
2358
 
2359
// IDA: void __usercall LoadExceptionsFileForTrack(char *pTrack_file_name@<EAX>)
2360
void LoadExceptionsFileForTrack(char* pTrack_file_name) {
2361
    //tPath_name exceptions_file_name; // Pierre-Marie Baty -- unused variable
2362
    LOG_TRACE("(\"%s\")", pTrack_file_name);
2363
    NOT_IMPLEMENTED();
2364
}
2365
 
2366
// IDA: void __cdecl FreeExceptions()
2367
void FreeExceptions(void) {
2368
    //tException_list list; // Pierre-Marie Baty -- unused variable
2369
    //tException_list next; // Pierre-Marie Baty -- unused variable
2370
    LOG_TRACE("()");
2371
    NOT_IMPLEMENTED();
2372
}
2373
 
2374
// IDA: void __usercall LoadTrack(char *pFile_name@<EAX>, tTrack_spec *pTrack_spec@<EDX>, tRace_info *pRace_info@<EBX>)
2375
void LoadTrack(char* pFile_name, tTrack_spec* pTrack_spec, tRace_info* pRace_info) {
2376
    //char temp_name[14]; // Pierre-Marie Baty -- unused variable
2377
    FILE* f;
2378
    FILE* non_car_f;
2379
    FILE* g;
2380
    int i;
2381
    int j;
2382
    int k;
2383
    int group;
2384
    //int needs_updating; // Pierre-Marie Baty -- unused variable
2385
    int killed_sky;
2386
    int line_count;
2387
    int ped_subs_index;
2388
    int sl;
2389
    int num_materials;
2390
    int count;
2391
    int num_non_cars;
2392
    int style;
2393
    int cp_rect_w[2];
2394
    int cp_rect_h[2];
2395
#if defined(DETHRACE_FIX_BUGS)
2396
    int skid_mark_cnt = 0;
2397
#endif
2398
    tPath_name the_path;
2399
    //tPath_name general_file_path; // Pierre-Marie Baty -- unused variable
2400
    char s[256];
2401
    char* str;
2402
    float temp_float;
2403
    //br_actor* new_root; // Pierre-Marie Baty -- unused variable
2404
    //br_vector3 a; // Pierre-Marie Baty -- unused variable
2405
    //br_vector3 b; // Pierre-Marie Baty -- unused variable
2406
    tU16 sky_pixels_high;
2407
    tNon_car_spec* non_car;
2408
    tSpecial_volume* spec;
2409
    br_vector3 p[3];
2410
    //br_vector3 v1; // Pierre-Marie Baty -- unused variable
2411
    //br_vector3 v2; // Pierre-Marie Baty -- unused variable
2412
    //br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
2413
    //br_bounds temp_bounds; // Pierre-Marie Baty -- unused variable
2414
    tPed_subs* ped_subs;
2415
    br_pixelmap* sky;
2416
    br_material* material;
2417
    LOG_TRACE("(\"%s\", %p, %p)", pFile_name, pTrack_spec, pRace_info);
2418
 
2419
    killed_sky = 0;
2420
    PathCat(the_path, gApplication_path, "RACES");
2421
    PathCat(the_path, the_path, pFile_name);
2422
    f = DRfopen(the_path, "rt");
2423
    if (f == NULL) {
2424
        FatalError(kFatalError_OpenRacesFile);
2425
    }
2426
    GetALineAndDontArgue(f, s);
2427
    str = strtok(s, "\t ,/");
2428
    if (strcmp(str, "VERSION") == 0) {
2429
        str = strtok(NULL, "\t ,/");
2430
        sscanf(str, "%d", &gRace_file_version);
2431
        GetALineAndDontArgue(f, s);
2432
        str = strtok(s, "\t ,/");
2433
    } else {
2434
        gRace_file_version = 0;
2435
    }
2436
    sscanf(str, "%f", &temp_float);
2437
    pRace_info->initial_position.v[0] = temp_float;
2438
    str = strtok(0, "\t ,/");
2439
    sscanf(str, "%f", &temp_float);
2440
    pRace_info->initial_position.v[1] = temp_float;
2441
    str = strtok(0, "\t ,/");
2442
    sscanf(str, "%f", &temp_float);
2443
    pRace_info->initial_position.v[2] = temp_float;
2444
    PossibleService();
2445
    GetALineAndDontArgue(f, s);
2446
    str = strtok(s, "\t ,/");
2447
    sscanf(str, "%f", &temp_float);
2448
    pRace_info->initial_yaw = temp_float;
2449
    GetThreeInts(f, pRace_info->initial_timer, &pRace_info->initial_timer[1], &pRace_info->initial_timer[2]);
2450
    pRace_info->total_laps = GetAnInt(f);
2451
    GetThreeInts(f, &pRace_info->bonus_score[0][0], &pRace_info->bonus_score[0][1], &pRace_info->bonus_score[0][2]);
2452
    GetThreeInts(f, &pRace_info->bonus_score[1][0], &pRace_info->bonus_score[1][1], &pRace_info->bonus_score[1][2]);
2453
    GetThreeInts(f, &pRace_info->bonus_score[2][0], &pRace_info->bonus_score[2][1], &pRace_info->bonus_score[2][2]);
2454
    if (gRace_file_version > 1) {
2455
        GetPairOfInts(f, &cp_rect_w[0], &cp_rect_w[1]);
2456
        GetPairOfInts(f, &cp_rect_h[0], &cp_rect_h[1]);
2457
    }
2458
    PossibleService();
2459
    pRace_info->check_point_count = GetAnInt(f);
2460
    for (i = 0; i < pRace_info->check_point_count; i++) {
2461
        PossibleService();
2462
        if (gProgram_state.sausage_eater_mode) {
2463
            GetALineAndDontArgue(f, s);
2464
            GetThreeInts(
2465
                f,
2466
                &pRace_info->checkpoints[i].time_value[0],
2467
                &pRace_info->checkpoints[i].time_value[1],
2468
                &pRace_info->checkpoints[i].time_value[2]);
2469
        } else {
2470
            GetThreeInts(
2471
                f,
2472
                &pRace_info->checkpoints[i].time_value[0],
2473
                &pRace_info->checkpoints[i].time_value[1],
2474
                &pRace_info->checkpoints[i].time_value[2]);
2475
            GetALineAndDontArgue(f, s);
2476
        }
2477
        pRace_info->checkpoints[i].quad_count = GetAnInt(f);
2478
        for (j = 0; j < pRace_info->checkpoints[i].quad_count; j++) {
2479
            for (k = 0; k < 4; ++k) {
2480
                GetThreeScalars(
2481
                    f,
2482
                    &pRace_info->checkpoints[i].vertices[j][k].v[0],
2483
                    &pRace_info->checkpoints[i].vertices[j][k].v[1],
2484
                    &pRace_info->checkpoints[i].vertices[j][k].v[2]);
2485
            }
2486
            p[0] = pRace_info->checkpoints[i].vertices[j][0];
2487
            p[1] = pRace_info->checkpoints[i].vertices[j][1];
2488
            p[2] = pRace_info->checkpoints[i].vertices[j][2];
2489
            pRace_info->checkpoints[i].normal[j].v[0] = (p[2].v[2] - p[0].v[2]) * (p[1].v[1] - p[0].v[1]) - (p[1].v[2] - p[0].v[2]) * (p[2].v[1] - p[0].v[1]);
2490
            pRace_info->checkpoints[i].normal[j].v[1] = (p[1].v[2] - p[0].v[2]) * (p[2].v[0] - p[0].v[0]) - (p[2].v[2] - p[0].v[2]) * (p[1].v[0] - p[0].v[0]);
2491
            pRace_info->checkpoints[i].normal[j].v[2] = (p[2].v[1] - p[0].v[1]) * (p[1].v[0] - p[0].v[0]) - (p[1].v[1] - p[0].v[1]) * (p[2].v[0] - p[0].v[0]);
2492
        }
2493
        if (gRace_file_version > 0) {
2494
            if (gRace_file_version == 1) {
2495
                GetPairOfInts(f, pRace_info->checkpoints[i].map_left, &pRace_info->checkpoints[i].map_left[1]);
2496
                GetPairOfInts(f, pRace_info->checkpoints[i].map_top, &pRace_info->checkpoints[i].map_top[1]);
2497
                GetPairOfInts(f, pRace_info->checkpoints[i].map_right, &pRace_info->checkpoints[i].map_right[1]);
2498
                GetPairOfInts(f, pRace_info->checkpoints[i].map_bottom, &pRace_info->checkpoints[i].map_bottom[1]);
2499
            } else {
2500
                GetPairOfInts(f, pRace_info->checkpoints[i].map_left, &pRace_info->checkpoints[i].map_left[1]);
2501
                GetPairOfInts(f, pRace_info->checkpoints[i].map_top, &pRace_info->checkpoints[i].map_top[1]);
2502
                pRace_info->checkpoints[i].map_right[0] = cp_rect_w[0] + pRace_info->checkpoints[i].map_left[0];
2503
                pRace_info->checkpoints[i].map_right[1] = cp_rect_w[0] + pRace_info->checkpoints[i].map_left[1];
2504
                pRace_info->checkpoints[i].map_bottom[0] = cp_rect_h[0] + pRace_info->checkpoints[i].map_top[0];
2505
                pRace_info->checkpoints[i].map_bottom[1] = cp_rect_h[0] + pRace_info->checkpoints[i].map_top[1];
2506
            }
2507
        }
2508
    }
2509
    if (gRace_file_version <= 3) {
2510
        LoadSomePixelmaps(&gTrack_storage_space, f);
2511
    } else if (gAusterity_mode) {
2512
        SkipNLines(f);
2513
        LoadSomePixelmaps(&gTrack_storage_space, f);
2514
    } else {
2515
        LoadSomePixelmaps(&gTrack_storage_space, f);
2516
        SkipNLines(f);
2517
    }
2518
    LoadSomeShadeTables(&gTrack_storage_space, f);
2519
    if (gRace_file_version <= 3) {
2520
        LoadSomeMaterials(&gTrack_storage_space, f);
2521
    } else if (gAusterity_mode) {
2522
        SkipNLines(f);
2523
        LoadSomeMaterials(&gTrack_storage_space, f);
2524
    } else {
2525
        LoadSomeMaterials(&gTrack_storage_space, f);
2526
        SkipNLines(f);
2527
    }
2528
    for (i = 0; gTrack_storage_space.materials_count > i; ++i) {
2529
        PossibleService();
2530
        if (gTrack_storage_space.materials[i]->flags & (BR_MATF_LIGHT | BR_MATF_PRELIT | BR_MATF_SMOOTH)) {
2531
            gTrack_storage_space.materials[i]->flags &= ~(BR_MATF_LIGHT | BR_MATF_PRELIT | BR_MATF_SMOOTH);
2532
            if (gTrack_storage_space.materials[i]->flags & BR_MATF_TWO_SIDED) {
2533
                gTrack_storage_space.materials[i]->user = DOUBLESIDED_USER_FLAG;
2534
                gTrack_storage_space.materials[i]->flags &= ~BR_MATF_TWO_SIDED;
2535
            }
2536
            BrMaterialUpdate(gTrack_storage_space.materials[i], BR_MATU_RENDERING);
2537
        }
2538
    }
2539
    if (gRace_file_version <= 5) {
2540
        LoadSomeTrackModels(&gTrack_storage_space, f);
2541
    } else if (gAusterity_mode) {
2542
        SkipNLines(f);
2543
        LoadSomeTrackModels(&gTrack_storage_space, f);
2544
    } else {
2545
        LoadSomeTrackModels(&gTrack_storage_space, f);
2546
        SkipNLines(f);
2547
    }
2548
 
2549
    PrintMemoryDump(0, "JUST LOADED IN TEXTURES/MATS/MODELS FOR TRACK");
2550
    if (gRace_file_version <= 5) {
2551
        GetALineAndDontArgue(f, s);
2552
        str = strtok(s, "\t ,/");
2553
        PathCat(the_path, gApplication_path, "ACTORS");
2554
        PathCat(the_path, the_path, str);
2555
    } else if (gAusterity_mode) {
2556
        GetALineAndDontArgue(f, s);
2557
        GetALineAndDontArgue(f, s);
2558
        str = strtok(s, "\t ,/");
2559
        PathCat(the_path, gApplication_path, "ACTORS");
2560
        PathCat(the_path, the_path, str);
2561
    } else {
2562
        GetALineAndDontArgue(f, s);
2563
        str = strtok(s, "\t ,/");
2564
        PathCat(the_path, gApplication_path, "ACTORS");
2565
        PathCat(the_path, the_path, str);
2566
        GetALineAndDontArgue(f, s);
2567
    }
2568
    pTrack_spec->the_actor = BrActorLoad(the_path);
2569
    if (gRace_file_version <= 6) {
2570
        gDefault_blend_pc = 75;
2571
    } else {
2572
        GetAString(f, s);
2573
        if (!sscanf(s, "%d", &gDefault_blend_pc) || gDefault_blend_pc < 0 || gDefault_blend_pc > 100) {
2574
            PDFatalError("Wanted a default blend percentage. Didn't get one. Old data file?");
2575
        }
2576
    }
2577
    PossibleService();
2578
    ExtractColumns(pTrack_spec);
2579
    for (i = 0; gTrack_storage_space.models_count > i; ++i) {
2580
        PossibleService();
2581
        if (gTrack_storage_space.models[i] && gTrack_storage_space.models[i]->flags & 0x82) {
2582
            gTrack_storage_space.models[i]->flags &= 0xFF7Du;
2583
            for (group = 0; group < V11MODEL(gTrack_storage_space.models[i])->ngroups; group++) {
2584
                int f = V11MODEL(gTrack_storage_space.models[i])->groups[group].face_user[0];
2585
                material = gTrack_storage_space.models[i]->faces[f].material;
20 pmbaty 2586
                V11MODEL(gTrack_storage_space.models[i])->groups[group].face_colours_material = material;
1 pmbaty 2587
                if (material && !material->index_shade) {
2588
                    material->index_shade = BrTableFind("DRRENDER.TAB");
2589
                    BrMaterialUpdate(material, 0x7FFFu);
2590
                }
2591
            }
2592
            DodgyModelUpdate(gTrack_storage_space.models[i]);
2593
        }
2594
    }
2595
    PrintMemoryDump(0, "JUST LOADED IN TRACK ACTOR AND PROCESSED COLUMNS");
2596
    gTrack_actor = pTrack_spec->the_actor;
2597
    if (!gRendering_accessories && !gNet_mode) {
2598
        PossibleService();
2599
        style = BR_RSTYLE_NONE;
2600
        DRActorEnumRecurse(gTrack_actor, (br_actor_enum_cbfn*)SetAccessoryRenderingCB, &style);
2601
    }
2602
    BrActorAdd(gUniverse_actor, pTrack_spec->the_actor);
2603
    GetALineAndDontArgue(f, s);
2604
    str = strtok(s, "\t ,/");
2605
    str = strtok(str, ".");
2606
    strcat(str, ".DAT");
2607
    PathCat(gAdditional_model_path, gApplication_path, "MODELS");
2608
    PathCat(gAdditional_model_path, gAdditional_model_path, str);
2609
    gNumber_of_additional_models = 0;
2610
    PossibleService();
2611
    str = strtok(s, "\t ,/");
2612
    str = strtok(str, ".");
2613
    strcat(str, ".ACT");
2614
    PathCat(gAdditional_actor_path, gApplication_path, "ACTORS");
2615
    PathCat(gAdditional_actor_path, gAdditional_actor_path, str);
2616
    gAdditional_actors = BrActorAllocate(BR_ACTOR_NONE, NULL);
2617
    BrActorAdd(gUniverse_actor, gAdditional_actors);
2618
    gLast_actor = NULL;
2619
    SaveAdditionalStuff();
2620
    GetAString(f, s);
2621
    sky = BrMapFind(s);
2622
    if (gAusterity_mode && sky) {
2623
        for (i = 0; gTrack_storage_space.pixelmaps_count > i; ++i) {
2624
            if (gTrack_storage_space.pixelmaps[i] == sky) {
2625
                BrMapRemove(gTrack_storage_space.pixelmaps[i]);
2626
                BrPixelmapFree(gTrack_storage_space.pixelmaps[i]);
2627
                gTrack_storage_space.pixelmaps[i] = gTrack_storage_space.pixelmaps[gTrack_storage_space.pixelmaps_count - 1];
2628
                gTrack_storage_space.pixelmaps_count--;
2629
                break;
2630
            }
2631
        }
2632
        sky = 0;
2633
        killed_sky = 1;
2634
    }
2635
    gProgram_state.default_depth_effect.sky_texture = sky;
2636
    if (sky) {
2637
        sky_pixels_high = gProgram_state.default_depth_effect.sky_texture->height;
2638
    } else {
2639
        sky_pixels_high = 100;
2640
    }
2641
    PossibleService();
2642
 
2643
    gSky_image_width = BrDegreeToAngle(360.0 / GetAnInt(f));
2644
    gSky_image_height = BrDegreeToAngle(GetAScalar(f));
2645
    gSky_image_underground = gSky_image_height * (sky_pixels_high - GetAnInt(f)) / sky_pixels_high;
2646
 
2647
    MungeRearviewSky();
2648
    PossibleService();
2649
 
2650
    gProgram_state.default_depth_effect.type = GetALineAndInterpretCommand(f, gDepth_effect_names, 2);
2651
    GetPairOfInts(f, &gProgram_state.default_depth_effect.start, &gProgram_state.default_depth_effect.end);
2652
    if (killed_sky && gProgram_state.default_depth_effect.type != eDepth_effect_fog) {
2653
        gProgram_state.default_depth_effect.type = eDepth_effect_fog;
2654
        gProgram_state.default_depth_effect.start = 7;
2655
        gProgram_state.default_depth_effect.end = 0;
2656
    }
2657
    InstantDepthChange(
2658
        gProgram_state.default_depth_effect.type,
2659
        gProgram_state.default_depth_effect.sky_texture,
2660
        gProgram_state.default_depth_effect.start,
2661
        gProgram_state.default_depth_effect.end);
2662
    gSwap_sky_texture = 0;
2663
    if (!GetSkyTextureOn()) {
2664
        ToggleSkyQuietly();
2665
    }
2666
    gSwap_depth_effect_type = -1;
2667
    if (!GetDepthCueingOn()) {
2668
        ToggleDepthCueingQuietly();
2669
    }
2670
    PossibleService();
2671
    gDefault_engine_noise_index = GetAnInt(f);
2672
    gDefault_water_spec_vol = &gDefault_default_water_spec_vol;
2673
    gProgram_state.special_volume_count = GetAnInt(f);
2674
    if (gProgram_state.special_volume_count) {
2675
        gProgram_state.special_volumes = BrMemAllocate(sizeof(tSpecial_volume) * gProgram_state.special_volume_count, kMem_special_volume);
2676
        i = 0;
2677
        spec = gProgram_state.special_volumes;
2678
        for (i = 0; i < gProgram_state.special_volume_count; i++) {
2679
            PossibleService();
2680
            spec->no_mat = 0;
2681
            GetALineAndDontArgue(f, s);
2682
            if (strcmp(s, "NEW IMPROVED!") == 0) {
2683
                GetThreeScalars(f, &spec->mat.m[0][0], &spec->mat.m[0][1], &spec->mat.m[0][2]);
2684
                GetThreeScalars(f, &spec->mat.m[1][0], &spec->mat.m[1][1], &spec->mat.m[1][2]);
2685
                GetThreeScalars(f, &spec->mat.m[2][0], &spec->mat.m[2][1], &spec->mat.m[2][2]);
2686
                GetThreeScalars(f, &spec->mat.m[3][0], &spec->mat.m[3][1], &spec->mat.m[3][2]);
2687
                FindInverseAndWorldBox(spec);
2688
                ParseSpecialVolume(f, spec, NULL);
2689
            } else if (strcmp(s, "DEFAULT WATER") == 0) {
2690
                spec->bounds.min.v[0] = 0.0;
2691
                spec->bounds.min.v[1] = 0.0;
2692
                spec->bounds.min.v[2] = 0.0;
2693
                spec->bounds.max.v[0] = 0.0;
2694
                spec->bounds.max.v[1] = 0.0;
2695
                spec->bounds.max.v[2] = 0.0;
2696
                ParseSpecialVolume(f, spec, NULL);
2697
                gDefault_water_spec_vol = spec;
2698
                spec->no_mat = 1;
2699
            } else {
2700
                TELL_ME_IF_WE_PASS_THIS_WAY();
2701
                spec->no_mat = 0;
2702
                str = strtok(s, "\t ,/");
2703
                sscanf(str, "%f", &spec->bounds.min.v[0]);
2704
                str = strtok(0, "\t ,/");
2705
                sscanf(str, "%f", &spec->bounds.min.v[1]);
2706
                str = strtok(0, "\t ,/");
2707
                sscanf(str, "%f", &spec->bounds.min.v[2]);
2708
                GetThreeScalars(f, &spec->bounds.max.v[0], &spec->bounds.max.v[1], &spec->bounds.max.v[2]);
2709
                BrMatrix34Identity(&spec->mat);
2710
                for (k = 0; k < 3; ++k) {
2711
                    // FIXME: not 100% sure this is correct
2712
                    spec->mat.m[3][k] = (spec->bounds.max.v[k] + spec->bounds.min.v[k]) / 2.f;
2713
                    spec->mat.m[k][k] = spec->bounds.max.v[k] - spec->bounds.min.v[k];
2714
                }
2715
                ParseSpecialVolume(f, spec, NULL);
2716
            }
2717
            spec++;
2718
        }
2719
    }
2720
    GetAString(f, s);
2721
    gProgram_state.standard_screen = BrMaterialFind(s);
2722
    GetAString(f, s);
2723
    gProgram_state.standard_screen_dark = BrMaterialFind(s);
2724
    GetAString(f, s);
2725
    gProgram_state.standard_screen_fog = BrMaterialFind(s);
2726
    gProgram_state.special_screens_count = GetAnInt(f);
2727
    if (gProgram_state.special_screens_count) {
2728
        gProgram_state.special_screens = BrMemAllocate(sizeof(tSpecial_screen) * gProgram_state.special_screens_count, kMem_special_screen);
2729
        for (i = 0; i < gProgram_state.special_screens_count; i++) {
2730
            GetFourScalars(
2731
                f,
2732
                &gProgram_state.special_screens[i].min_x,
2733
                &gProgram_state.special_screens[i].min_z,
2734
                &gProgram_state.special_screens[i].max_x,
2735
                &gProgram_state.special_screens[i].max_z);
2736
            GetAString(f, s);
2737
            material = BrMaterialFind(s);
2738
            gProgram_state.special_screens[i].material = material;
2739
        }
2740
    }
2741
    PossibleService();
2742
    GetAString(f, s);
2743
    pRace_info->map_image = LoadPixelmap(s);
2744
    PrintMemoryDump(0, "JUST LOADING SKY/SPEC VOLS/SCREENS/MAP");
2745
    for (i = 0; i < 4; ++i) {
2746
        GetThreeScalars(
2747
            f,
2748
            &pRace_info->map_transformation.m[i][0],
2749
            &pRace_info->map_transformation.m[i][1],
2750
            &pRace_info->map_transformation.m[i][2]);
2751
    }
2752
    GetALineAndDontArgue(f, s);
2753
    AddFunkotronics(f, -2, 720);
2754
    GetALineAndDontArgue(f, s);
2755
    AddGroovidelics(f, -2, gUniverse_actor, 720, 0);
2756
    PossibleService();
2757
    PrintMemoryDump(0, "JUST LOADING IN FUNKS AND GROOVES");
2758
    ped_subs = NULL;
2759
    count = 0;
2760
    if (gRace_file_version > 3) {
2761
        line_count = GetAnInt(f);
2762
        if (gAusterity_mode) {
2763
            if (line_count >= 0) {
2764
                PathCat(the_path, gApplication_path, "PEDSUBS.TXT");
2765
                g = DRfopen(the_path, "rt");
2766
                if (g == NULL) {
2767
                    FatalError(kFatalError_OpenRacesFile);
2768
                }
2769
                for (i = 0; i < line_count; ++i) {
2770
                    SkipNLines(g);
2771
                }
2772
                count = GetAnInt(g);
2773
                ped_subs = BrMemAllocate(sizeof(tPed_subs) * count, kMem_misc);
2774
                for (ped_subs_index = 0; ped_subs_index < count; ped_subs_index++) {
2775
                    GetPairOfInts(g, &ped_subs[i].orig, &ped_subs[i].subs);
2776
                }
2777
                fclose(g);
2778
            }
2779
        }
2780
    }
2781
    PossibleService();
2782
    LoadInPedestrians(f, count, ped_subs);
2783
    if (ped_subs != NULL) {
2784
        BrMemFree(ped_subs);
2785
    }
2786
    PrintMemoryDump(0, "JUST LOADED IN PEDS");
2787
    LoadInOppoPaths(f);
2788
    PrintMemoryDump(0, "JUST LOADED IN OPPO PATHS");
2789
    num_materials = GetAnInt(f);
2790
    for (i = 0; i < num_materials; i++) {
2791
        PossibleService();
2792
        pRace_info->material_modifiers[i].car_wall_friction = GetAScalar(f);
2793
        pRace_info->material_modifiers[i].tyre_road_friction = GetAScalar(f);
2794
        pRace_info->material_modifiers[i].down_force = GetAScalar(f);
2795
        pRace_info->material_modifiers[i].bumpiness = GetAScalar(f);
2796
        pRace_info->material_modifiers[i].tyre_noise_index = GetAnInt(f);
2797
        pRace_info->material_modifiers[i].crash_noise_index = GetAnInt(f);
2798
        pRace_info->material_modifiers[i].scrape_noise_index = GetAnInt(f);
2799
        pRace_info->material_modifiers[i].sparkiness = GetAScalar(f);
2800
        pRace_info->material_modifiers[i].smoke_type = GetAnInt(f);
2801
        GetAString(f, s);
2802
        str = strtok(s, ".");
2803
 
2804
        if (!strcmp(s, "none") || !strcmp(s, "NONE") || !strcmp(s, "0") || !strcmp(s, "1")) {
2805
            pRace_info->material_modifiers[i].skid_mark_material = NULL;
2806
        } else {
2807
            sl = strlen(str);
2808
            strcat(str, ".PIX");
2809
            LoadSinglePixelmap(&gTrack_storage_space, str);
2810
            str[sl] = 0;
2811
            strcat(str, ".MAT");
2812
            material = LoadSingleMaterial(&gTrack_storage_space, str);
2813
            pRace_info->material_modifiers[i].skid_mark_material = material;
2814
#if defined(DETHRACE_FIX_BUGS)
2815
            skid_mark_cnt++;
2816
#endif
2817
        }
2818
    }
2819
#if defined(DETHRACE_FIX_BUGS)
2820
    /* Display skidmarks even if the race has no specified skidmark material. */
2821
    if (!skid_mark_cnt && num_materials) {
2822
        LOG_WARN("Track %s has no valid skid mark material, setting the default one",
2823
            pRace_info->track_file_name);
2824
        LoadSinglePixelmap(&gTrack_storage_space, "SKIDMARK.PIX");
2825
        material = LoadSingleMaterial(&gTrack_storage_space, "SKIDMARK.MAT");
2826
        pRace_info->material_modifiers[0].skid_mark_material = material;
2827
    }
2828
#endif
2829
    for (i = num_materials; i < 10; ++i) {
2830
        pRace_info->material_modifiers[i].car_wall_friction = 1.0;
2831
        pRace_info->material_modifiers[i].tyre_road_friction = 1.0;
2832
        pRace_info->material_modifiers[i].down_force = 1.0;
2833
        pRace_info->material_modifiers[i].bumpiness = 0.0;
2834
        pRace_info->material_modifiers[i].tyre_noise_index = 0;
2835
        pRace_info->material_modifiers[i].crash_noise_index = 0;
2836
        pRace_info->material_modifiers[i].scrape_noise_index = 0;
2837
        pRace_info->material_modifiers[i].sparkiness = 1.0;
2838
        pRace_info->material_modifiers[i].smoke_type = 1;
2839
        pRace_info->material_modifiers[i].skid_mark_material = 0;
2840
    }
2841
    i = 10;
2842
    pRace_info->material_modifiers[i].car_wall_friction = 1.0;
2843
    pRace_info->material_modifiers[i].tyre_road_friction = 1.0;
2844
    pRace_info->material_modifiers[i].down_force = 0.0;
2845
    pRace_info->material_modifiers[i].bumpiness = 0.0;
2846
    pRace_info->material_modifiers[i].tyre_noise_index = -1;
2847
    pRace_info->material_modifiers[i].crash_noise_index = 0;
2848
    pRace_info->material_modifiers[i].scrape_noise_index = 0;
2849
    pRace_info->material_modifiers[i].sparkiness = 0.0;
2850
    pRace_info->material_modifiers[i].smoke_type = 1;
2851
    pRace_info->material_modifiers[i].skid_mark_material = 0;
2852
    gDefault_water_spec_vol->material_modifier_index = i;
2853
    num_non_cars = GetAnInt(f);
2854
    non_car = BrMemCalloc(num_non_cars + 5, sizeof(tNon_car_spec), kMem_non_car_spec);
2855
    if (!non_car && num_non_cars) {
2856
        FatalError(kFatalError_OpenRacesFile);
2857
    }
2858
    gProgram_state.non_cars = non_car;
2859
    gProgram_state.num_non_car_spaces = num_non_cars + NONCAR_UNUSED_SLOTS;
2860
    for (i = 0; i < COUNT_OF(gNon_car_spec_list); ++i) {
2861
        gNon_car_spec_list[i] = '\0';
2862
    }
2863
    for (i = 0; i < NONCAR_UNUSED_SLOTS; i++) {
2864
        non_car->collision_info.driver = eDriver_non_car_unused_slot;
2865
        non_car++;
2866
    }
2867
    i = 0;
2868
    for (i = 0; i < num_non_cars; i++) {
2869
        PossibleService();
2870
        GetAString(f, s);
2871
        PathCat(the_path, gApplication_path, "NONCARS");
2872
        PathCat(the_path, the_path, s);
2873
        non_car_f = DRfopen(the_path, "rt");
2874
        if (non_car_f == NULL) {
2875
            FatalError(kFatalError_Open_S, the_path);
2876
        }
2877
        ReadNonCarMechanicsData(non_car_f, non_car);
2878
        PossibleService();
2879
        ReadShrapnelMaterials(non_car_f, &non_car->collision_info);
2880
        gNon_car_spec_list[non_car->collision_info.index] = i + 1;
2881
        fclose(non_car_f);
2882
        non_car++;
2883
    }
2884
    GetSmokeShadeTables(f);
2885
    pRace_info->number_of_net_start_points = GetAnInt(f);
2886
    for (i = 0; i < pRace_info->number_of_net_start_points; i++) {
2887
        GetThreeScalars(
2888
            f,
2889
            &pRace_info->net_starts[i].pos.v[0],
2890
            &pRace_info->net_starts[i].pos.v[1],
2891
            &pRace_info->net_starts[i].pos.v[2]);
2892
        pRace_info->net_starts[i].yaw = GetAScalar(f);
2893
    }
2894
    if (gRace_file_version <= 2) {
2895
        LoadInKevStuff(NULL);
2896
    } else {
2897
        LoadInKevStuff(f);
2898
    }
2899
    if (gRace_file_version < 5) {
20 pmbaty 2900
        gYon_multiplier = viewdistance_surmultiplier * 1.0;
1 pmbaty 2901
    } else {
20 pmbaty 2902
        gYon_multiplier = viewdistance_surmultiplier * GetAScalar(f);
1 pmbaty 2903
    }
2904
    GetAString(f, s);
2905
    if (strcmp(s, pFile_name) != 0) {
2906
        FatalError(kFatalError_FileCorrupt_S, pFile_name);
2907
    }
2908
    fclose(f);
2909
}
2910
 
2911
// IDA: br_uint_32 __cdecl RemoveBounds(br_actor *pActor, void *pArg)
20 pmbaty 2912
intptr_t RemoveBounds(br_actor* pActor, void* pArg) {
1 pmbaty 2913
    LOG_TRACE("(%p, %p)", pActor, pArg);
2914
 
2915
    if (pActor->type == BR_ACTOR_BOUNDS || pActor->type == BR_ACTOR_BOUNDS_CORRECT) {
2916
        BrResFree(pActor->type_data);
2917
        pActor->type_data = NULL;
2918
    }
2919
    return 0;
2920
}
2921
 
2922
// IDA: void __usercall RemoveBoundsStructures(br_actor *pActor@<EAX>)
2923
void RemoveBoundsStructures(br_actor* pActor) {
2924
    LOG_TRACE("(%p)", pActor);
2925
 
2926
    DRActorEnumRecurse(pActor, RemoveBounds, NULL);
2927
}
2928
 
2929
// IDA: void __usercall FreeTrack(tTrack_spec *pTrack_spec@<EAX>)
2930
void FreeTrack(tTrack_spec* pTrack_spec) {
2931
    int i;
2932
    tNon_car_spec* non_car;
2933
    LOG_TRACE("(%p)", pTrack_spec);
2934
 
2935
    if (gAdditional_actors != NULL) {
2936
        BrActorRemove(gAdditional_actors);
2937
        BrActorFree(gAdditional_actors);
2938
    }
2939
    PossibleService();
2940
    DisposeTexturingMaterials();
2941
    PossibleService();
2942
    DisposeColumns(pTrack_spec);
2943
    PossibleService();
2944
    RemoveBoundsStructures(pTrack_spec->the_actor);
2945
    BrActorRemove(pTrack_spec->the_actor);
2946
    BrActorFree(pTrack_spec->the_actor);
2947
    pTrack_spec->the_actor = NULL;
2948
    gTrack_actor = NULL;
2949
    PossibleService();
2950
    DisposeFunkotronics(-2);
2951
    PossibleService();
2952
    ClearOutStorageSpace(&gTrack_storage_space);
2953
    PossibleService();
2954
    DisposeGroovidelics(-2);
2955
    PossibleService();
2956
    DisposeOpponentPaths();
2957
    PossibleService();
2958
    DisposeKevStuff();
2959
    PossibleService();
2960
    if (gCurrent_race.map_image != NULL) {
2961
        BrPixelmapFree(gCurrent_race.map_image);
2962
    }
2963
    if (gProgram_state.special_screens_count != 0) {
2964
        BrMemFree(gProgram_state.special_screens);
2965
    }
2966
    PossibleService();
2967
    for (i = 0, non_car = gProgram_state.non_cars; i < gProgram_state.num_non_car_spaces; i++, non_car++) {
2968
        PossibleService();
2969
        if (non_car->collision_info.driver == eDriver_non_car && non_car->collision_info.car_master_actor != NULL) {
2970
            BrActorRemove(non_car->collision_info.car_master_actor);
2971
            BrActorFree(non_car->collision_info.car_master_actor);
2972
        }
2973
    }
2974
    if (gProgram_state.non_cars != NULL) {
2975
        BrMemFree(gProgram_state.non_cars);
2976
    }
2977
    FreeSmokeShadeTables();
2978
}
2979
 
2980
// IDA: void __usercall ProcessTrack(br_actor *pWorld@<EAX>, tTrack_spec *pTrack_spec@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world_transform@<ECX>, int pRender_blends)
2981
void ProcessTrack(br_actor* pWorld, tTrack_spec* pTrack_spec, br_actor* pCamera, br_matrix34* pCamera_to_world_transform, int pRender_blends) {
2982
    LOG_TRACE("(%p, %p, %p, %p, %d)", pWorld, pTrack_spec, pCamera, pCamera_to_world_transform, pRender_blends);
2983
 
2984
    RenderTrack(pWorld, pTrack_spec, pCamera, pCamera_to_world_transform, pRender_blends);
2985
    if (gAdditional_actors) {
2986
        if (!pRender_blends) {
2987
            BrZbSceneRenderAdd(gAdditional_actors);
2988
        }
2989
    }
2990
}
2991
 
2992
// IDA: br_scalar __cdecl NormaliseDegreeAngle(br_scalar pAngle)
2993
br_scalar NormaliseDegreeAngle(br_scalar pAngle) {
2994
    LOG_TRACE("(%f)", pAngle);
2995
 
2996
    while (pAngle < .0f) {
2997
        pAngle += 360.f;
2998
    }
2999
    return pAngle;
3000
}
3001
 
3002
#define SAW(T, PERIOD) (fmodf((T), (PERIOD)) / (PERIOD))
3003
 
3004
#define MOVE_FUNK_PARAMETER(DEST, MODE, PERIOD, AMPLITUDE, FLASH_VALUE)                   \
3005
    do {                                                                                  \
3006
        switch (MODE) {                                                                   \
3007
        case eMove_continuous:                                                            \
3008
            if ((PERIOD) == 0.f) {                                                        \
3009
                DEST = 0.f;                                                               \
3010
            } else {                                                                      \
3011
                DEST = (AMPLITUDE)*SAW(f_the_time, (PERIOD));                             \
3012
            }                                                                             \
3013
            break;                                                                        \
3014
        case eMove_controlled:                                                            \
3015
            DEST = (PERIOD) * (AMPLITUDE);                                                \
3016
            break;                                                                        \
3017
        case eMove_absolute:                                                              \
3018
            DEST = (PERIOD);                                                              \
3019
            break;                                                                        \
3020
        case eMove_linear:                                                                \
3021
            if ((PERIOD) == 0.f) {                                                        \
3022
                DEST = 0.f;                                                               \
3023
            } else {                                                                      \
3024
                DEST = (AMPLITUDE)*MapSawToTriangle(SAW(f_the_time, (PERIOD)));           \
3025
            }                                                                             \
3026
            break;                                                                        \
3027
        case eMove_flash:                                                                 \
3028
            if (2 * fmodf(f_the_time, (PERIOD)) > (PERIOD)) {                             \
3029
                DEST = (FLASH_VALUE);                                                     \
3030
            } else {                                                                      \
3031
                DEST = -(FLASH_VALUE);                                                    \
3032
            }                                                                             \
3033
            break;                                                                        \
3034
        case eMove_harmonic:                                                              \
3035
            if ((PERIOD) == 0.f) {                                                        \
3036
                DEST = 0.f;                                                               \
3037
            } else {                                                                      \
3038
                DEST = (AMPLITUDE)*BR_SIN(BR_ANGLE_DEG(SAW(f_the_time, (PERIOD)) * 360)); \
3039
            }                                                                             \
3040
            break;                                                                        \
3041
        default:                                                                          \
3042
            TELL_ME_IF_WE_PASS_THIS_WAY();                                                \
3043
        }                                                                                 \
3044
    } while (0)
3045
 
3046
// IDA: void __cdecl FunkThoseTronics()
3047
void FunkThoseTronics(void) {
3048
    int i;
3049
    int j;
3050
    int iteration_count;
3051
    int finished;
3052
    tFunkotronic_spec* the_funk;
3053
    //br_vector3* the_proximity; // Pierre-Marie Baty -- unused variable
3054
    tS32 the_time;
3055
    //tS32 old_last_time; // Pierre-Marie Baty -- unused variable
3056
    //tS32 time_diff; // Pierre-Marie Baty -- unused variable
3057
    br_matrix23* mat_matrix;
3058
    br_material* the_material;
3059
    float f_the_time;
3060
    float rot_amount;
3061
    float f_time_diff;
3062
    br_vector2 tmp_v2;
3063
    br_pixelmap* old_colour_map;
3064
    LOG_TRACE("()");
3065
 
3066
    if (gFunkotronics_array == NULL) {
3067
        return;
3068
    }
3069
    DontLetFlicFuckWithPalettes();
3070
    the_time = GetTotalTime();
3071
    f_the_time = (float)the_time;
3072
    for (i = 0; i < gFunkotronics_array_size; i++) {
3073
        the_funk = &gFunkotronics_array[i];
3074
        if (the_funk->owner == -999) {
3075
            continue;
3076
        }
3077
        j = 0;
3078
        if (the_funk->mode == eFunk_mode_distance && the_funk->proximity_array != NULL) {
3079
            j = -2;
3080
            for (j = 0; j < the_funk->proximity_count; j++) {
3081
                if (Vector3DistanceSquared(&the_funk->proximity_array[j], gOur_pos) <= gSight_distance_squared) {
3082
                    j = -1;
3083
                    break;
3084
                }
3085
            }
3086
        }
3087
        if (j == -1 || (j != -2 && (the_funk->mode != eFunk_mode_last_lap_only || gLap >= gTotal_laps) && (the_funk->mode != eFunk_mode_all_laps_but_last || gLap < gTotal_laps))) {
3088
            the_material = the_funk->material;
3089
            mat_matrix = &the_material->map_transform;
3090
            if (!gAction_replay_mode || !ReplayIsPaused() || the_funk->matrix_mode == eMove_controlled || the_funk->matrix_mode == eMove_absolute) {
3091
                switch (the_funk->matrix_mod_type) {
3092
                case eMatrix_mod_spin:
3093
 
3094
                    BrMatrix23Identity(mat_matrix);
3095
                    the_material->map_transform.m[2][0] -= .5f;
3096
                    the_material->map_transform.m[2][1] -= .5f;
3097
                    if (the_funk->matrix_mod_data.spin_info.period > 0.f) {
3098
                        f_time_diff = 1.f - fmodf(the_funk->matrix_mod_data.spin_info.period, 1.f);
3099
                    } else {
3100
                        f_time_diff = fmodf(-the_funk->matrix_mod_data.spin_info.period, 1.f);
3101
                    }
3102
 
3103
                    MOVE_FUNK_PARAMETER(rot_amount, the_funk->matrix_mode, f_time_diff, 65536.f, 7.5f);
3104
                    DRMatrix23PostRotate(mat_matrix, (br_angle)rot_amount);
3105
 
3106
                    the_material->map_transform.m[2][0] += .5f;
3107
                    the_material->map_transform.m[2][1] += .5f;
3108
                    break;
3109
                case eMatrix_mod_rock:
3110
                    BrMatrix23Identity(mat_matrix);
3111
                    the_material->map_transform.m[2][0] -= the_funk->matrix_mod_data.rock_info.x_centre;
3112
                    the_material->map_transform.m[2][1] -= the_funk->matrix_mod_data.rock_info.y_centre;
3113
 
3114
                    MOVE_FUNK_PARAMETER(rot_amount, the_funk->matrix_mode, the_funk->matrix_mod_data.rock_info.period, the_funk->matrix_mod_data.rock_info.rock_angle, the_funk->matrix_mod_data.rock_info.rock_angle);
3115
                    DRMatrix23PostRotate(mat_matrix, BrDegreeToAngle(NormaliseDegreeAngle(rot_amount)));
3116
 
3117
                    the_material->map_transform.m[2][0] += the_funk->matrix_mod_data.rock_info.x_centre;
3118
                    the_material->map_transform.m[2][1] += the_funk->matrix_mod_data.rock_info.y_centre;
3119
                    break;
3120
                case eMatrix_mod_throb:
3121
                    BrMatrix23Identity(mat_matrix);
3122
                    the_material->map_transform.m[2][0] -= the_funk->matrix_mod_data.throb_info.x_centre;
3123
                    the_material->map_transform.m[2][1] -= the_funk->matrix_mod_data.throb_info.y_centre;
3124
 
3125
                    MOVE_FUNK_PARAMETER(tmp_v2.v[1], the_funk->matrix_mode, the_funk->matrix_mod_data.throb_info.y_period, the_funk->matrix_mod_data.throb_info.y_magnitude, the_funk->matrix_mod_data.throb_info.y_magnitude);
3126
                    MOVE_FUNK_PARAMETER(tmp_v2.v[0], the_funk->matrix_mode, the_funk->matrix_mod_data.throb_info.x_period, the_funk->matrix_mod_data.throb_info.x_magnitude, the_funk->matrix_mod_data.throb_info.x_magnitude);
3127
                    BrMatrix23PostScale(mat_matrix, tmp_v2.v[0] + 1.f, tmp_v2.v[1] + 1.f);
3128
 
3129
                    the_material->map_transform.m[2][0] += the_funk->matrix_mod_data.throb_info.x_centre;
3130
                    the_material->map_transform.m[2][1] += the_funk->matrix_mod_data.throb_info.y_centre;
3131
                    break;
3132
                case eMatrix_mod_slither:
3133
                    MOVE_FUNK_PARAMETER(the_material->map_transform.m[2][0], the_funk->matrix_mode, the_funk->matrix_mod_data.slither_info.x_period, the_funk->matrix_mod_data.slither_info.x_magnitude, the_funk->matrix_mod_data.slither_info.x_magnitude);
3134
                    MOVE_FUNK_PARAMETER(the_material->map_transform.m[2][1], the_funk->matrix_mode, the_funk->matrix_mod_data.slither_info.y_period, the_funk->matrix_mod_data.slither_info.y_magnitude, the_funk->matrix_mod_data.slither_info.y_magnitude);
3135
                    break;
3136
                case eMatrix_mod_roll:
3137
                    MOVE_FUNK_PARAMETER(the_material->map_transform.m[2][0], the_funk->matrix_mode, the_funk->matrix_mod_data.roll_info.x_period, 1.f, 1.875f);
3138
                    MOVE_FUNK_PARAMETER(the_material->map_transform.m[2][1], the_funk->matrix_mode, the_funk->matrix_mod_data.roll_info.y_period, 1.f, 1.875f);
3139
                    break;
3140
                case eMatrix_mod_none:
3141
                    break;
3142
                }
3143
                if (the_funk->matrix_mod_type != eMatrix_mod_none) {
3144
                    BrMaterialUpdate(the_funk->material, BR_MATU_MAP_TRANSFORM);
3145
                }
3146
            }
3147
            if (the_funk->lighting_animation_type != eMove_none) {
3148
                MOVE_FUNK_PARAMETER(the_material->ka, the_funk->lighting_animation_type, the_funk->lighting_animation_period, the_funk->ambient_delta, the_funk->ambient_delta);
3149
                the_material->ka += the_funk->ambient_base;
3150
 
3151
                MOVE_FUNK_PARAMETER(the_material->kd, the_funk->lighting_animation_type, the_funk->lighting_animation_period, the_funk->direct_delta, the_funk->direct_delta);
3152
                the_material->kd += the_funk->direct_base;
3153
 
3154
                MOVE_FUNK_PARAMETER(the_material->ks, the_funk->lighting_animation_type, the_funk->lighting_animation_period, the_funk->specular_delta, the_funk->specular_delta);
3155
                the_material->ks += the_funk->specular_base;
3156
            }
3157
            if (the_funk->texture_animation_type == eTexture_animation_frames) {
3158
                if (!gAction_replay_mode || !ReplayIsPaused() || the_funk->mode == eFunk_mode_all_laps_but_last || the_funk->mode == 4) {
3159
                    old_colour_map = the_material->colour_map;
3160
                    if (the_funk->time_mode == eTime_mode_accurate) {
3161
                        MOVE_FUNK_PARAMETER(rot_amount, the_funk->texture_animation_data.frames_info.mode, the_funk->texture_animation_data.frames_info.period, the_funk->texture_animation_data.frames_info.texture_count, the_funk->texture_animation_data.frames_info.texture_count);
3162
                        the_material->colour_map = the_funk->texture_animation_data.frames_info.textures[(int)rot_amount];
3163
                    } else {
3164
                        if (the_funk->texture_animation_data.frames_info.period <= fabsf(f_the_time - the_funk->last_frame)) {
3165
                            the_funk->last_frame = f_the_time;
3166
                            the_funk->texture_animation_data.frames_info.current_frame++;
3167
                            if (the_funk->texture_animation_data.frames_info.current_frame >= the_funk->texture_animation_data.frames_info.texture_count) {
3168
                                the_funk->texture_animation_data.frames_info.current_frame = 0;
3169
                            }
3170
                            the_material->colour_map = the_funk->texture_animation_data.frames_info.textures[the_funk->texture_animation_data.frames_info.current_frame];
3171
                        }
3172
                    }
3173
                    if (the_material->colour_map != old_colour_map) {
3174
                        BrMaterialUpdate(the_funk->material, BR_MATU_COLOURMAP);
3175
                    }
3176
                }
3177
            } else if (the_funk->texture_animation_type == eTexture_animation_flic && (!gAction_replay_mode || !ReplayIsPaused())) {
3178
                f_time_diff = f_the_time;
3179
                if (f_time_diff < the_funk->last_frame) {
3180
                    f_time_diff = 2 * the_funk->last_frame - f_time_diff;
3181
                }
3182
                if (the_funk->time_mode == eTime_mode_accurate) {
3183
                    if (the_funk->last_frame) {
3184
                        iteration_count = (f_time_diff - the_funk->last_frame) / the_funk->texture_animation_data.flic_info.flic_descriptor.frame_period;
3185
                    } else {
3186
                        iteration_count = 1;
3187
                    }
3188
                } else {
3189
                    if (f_time_diff - the_funk->last_frame > the_funk->texture_animation_data.flic_info.flic_descriptor.frame_period) {
3190
                        iteration_count = 1;
3191
                    } else {
3192
                        iteration_count = 0;
3193
                    }
3194
                }
3195
                for (j = 0; j < iteration_count; j++) {
3196
                    finished = PlayNextFlicFrame(&the_funk->texture_animation_data.flic_info.flic_descriptor);
3197
                    BrMapUpdate(the_funk->material->colour_map, BR_MAPU_ALL);
3198
                    BrMaterialUpdate(the_funk->material, BR_MATU_COLOURMAP);
3199
                    if (finished) {
3200
                        EndFlic(&the_funk->texture_animation_data.flic_info.flic_descriptor);
3201
                        StartFlic(
3202
                            the_funk->texture_animation_data.flic_info.flic_descriptor.file_name,
3203
                            -1,
3204
                            &the_funk->texture_animation_data.flic_info.flic_descriptor,
3205
                            the_funk->texture_animation_data.flic_info.flic_data_length,
3206
                            (tS8*)the_funk->texture_animation_data.flic_info.flic_data,
3207
                            the_material->colour_map, 0, 0, 0);
3208
                    }
3209
                    the_funk->last_frame = f_the_time;
3210
                }
3211
            }
3212
        }
3213
    }
3214
    LetFlicFuckWithPalettes();
3215
}
3216
 
3217
// IDA: void __usercall LollipopizeActor(br_actor *pSubject_actor@<EAX>, br_matrix34 *ref_to_world@<EDX>, tLollipop_mode pWhich_axis@<EBX>)
3218
void LollipopizeActor(br_actor* pSubject_actor, br_matrix34* ref_to_world, tLollipop_mode pWhich_axis) {
3219
    br_vector3 ref_to_subject;
3220
    br_vector3 fixed_axis;
3221
    br_vector3 vector_a;
3222
    br_vector3 vector_b;
3223
    br_matrix34 subject_to_world;
3224
    br_matrix34 mat;
3225
    LOG_TRACE("(%p, %p, %d)", pSubject_actor, ref_to_world, pWhich_axis);
3226
 
3227
    BrActorToActorMatrix34(&subject_to_world, pSubject_actor, gNon_track_actor);
3228
    BrVector3Sub(&ref_to_subject, (br_vector3*)ref_to_world->m[3], (br_vector3*)subject_to_world.m[3]);
3229
    switch (pWhich_axis) {
3230
    case eLollipop_none:
3231
        TELL_ME_IF_WE_PASS_THIS_WAY();
3232
        break;
3233
    case eLollipop_x_match:
3234
        BrVector3SetFloat(&vector_a, 1.f, 0.f, 0.f);
3235
        break;
3236
    case eLollipop_y_match:
3237
        BrVector3SetFloat(&vector_a, 0.f, 1.f, 0.f);
3238
        break;
3239
    case eLollipop_z_match:
3240
        BrVector3SetFloat(&vector_a, 0.f, 0.f, 1.f);
3241
        break;
3242
    }
3243
    BrVector3Cross(&vector_b, &ref_to_subject, &vector_a);
3244
    BrVector3Normalise(&vector_b, &vector_b);
3245
 
3246
    BrVector3Cross(&fixed_axis, &vector_a, &vector_b);
3247
 
3248
    switch (pWhich_axis) {
3249
    case eLollipop_none:
3250
        break;
3251
    case eLollipop_x_match:
3252
        mat.m[0][0] = vector_a.v[0];
3253
        mat.m[1][0] = vector_a.v[1];
3254
        mat.m[2][0] = vector_a.v[2];
3255
        mat.m[0][1] = vector_b.v[0];
3256
        mat.m[1][1] = vector_b.v[1];
3257
        mat.m[2][1] = vector_b.v[2];
3258
        mat.m[0][2] = fixed_axis.v[0];
3259
        mat.m[1][2] = fixed_axis.v[1];
3260
        mat.m[2][2] = fixed_axis.v[2];
3261
        mat.m[3][0] = 0.f;
3262
        mat.m[3][1] = 0.f;
3263
        mat.m[3][2] = 0.f;
3264
        break;
3265
    case eLollipop_y_match:
3266
        mat.m[0][0] = vector_b.v[0];
3267
        mat.m[1][0] = vector_b.v[1];
3268
        mat.m[2][0] = vector_b.v[2];
3269
        mat.m[0][1] = vector_a.v[0];
3270
        mat.m[1][1] = vector_a.v[1];
3271
        mat.m[2][1] = vector_a.v[2];
3272
        mat.m[0][2] = fixed_axis.v[0];
3273
        mat.m[1][2] = fixed_axis.v[1];
3274
        mat.m[2][2] = fixed_axis.v[2];
3275
        mat.m[3][0] = 0.f;
3276
        mat.m[3][1] = 0.f;
3277
        mat.m[3][2] = 0.f;
3278
        break;
3279
    case eLollipop_z_match:
3280
        mat.m[0][0] = vector_b.v[0];
3281
        mat.m[1][0] = vector_b.v[1];
3282
        mat.m[2][0] = vector_b.v[2];
3283
        mat.m[0][1] = vector_a.v[0];
3284
        mat.m[1][1] = vector_a.v[1];
3285
        mat.m[2][1] = vector_a.v[2];
3286
        mat.m[0][2] = fixed_axis.v[0];
3287
        mat.m[1][2] = fixed_axis.v[1];
3288
        mat.m[2][2] = fixed_axis.v[2];
3289
        mat.m[3][0] = 0.f;
3290
        mat.m[3][1] = 0.f;
3291
        mat.m[3][2] = 0.f;
3292
        break;
3293
    }
3294
    BrMatrix34Pre(&pSubject_actor->t.t.mat, &mat);
3295
}
3296
 
3297
// IDA: void __usercall CalcActorGlobalPos(br_vector3 *pResult@<EAX>, br_actor *pActor@<EDX>)
3298
void CalcActorGlobalPos(br_vector3* pResult, br_actor* pActor) {
3299
    LOG_TRACE("(%p, %p)", pResult, pActor);
3300
 
3301
    pResult->v[0] = 0.0;
3302
    pResult->v[1] = 0.0;
3303
    pResult->v[2] = 0.0;
3304
    while (pActor && pActor != gNon_track_actor) {
3305
        pResult->v[0] = pActor->t.t.mat.m[3][0] + pResult->v[0];
3306
        pResult->v[1] = pActor->t.t.mat.m[3][1] + pResult->v[1];
3307
        pResult->v[2] = pActor->t.t.mat.m[3][2] + pResult->v[2];
3308
        pActor = pActor->parent;
3309
    }
3310
}
3311
 
3312
// IDA: int __usercall PointOutOfSight@<EAX>(br_vector3 *pPoint@<EAX>, br_scalar pMax_distance)
3313
int PointOutOfSight(br_vector3* pPoint, br_scalar pMax_distance) {
3314
    br_vector3 distance_vector;
3315
    LOG_TRACE("(%p, %f)", pPoint, pMax_distance);
3316
 
3317
    if (gMirror_on__graphics) {
3318
        distance_vector.v[0] = pPoint->v[0] - gRearview_camera_to_world.m[3][0];
3319
        distance_vector.v[1] = pPoint->v[1] - gRearview_camera_to_world.m[3][1];
3320
        distance_vector.v[2] = pPoint->v[2] - gRearview_camera_to_world.m[3][2];
3321
        if (distance_vector.v[0] * distance_vector.v[0]
3322
                    + distance_vector.v[1] * distance_vector.v[1]
3323
                    + distance_vector.v[2] * distance_vector.v[2]
3324
                < pMax_distance
3325
            && gRearview_camera_to_world.m[2][2] * distance_vector.v[2]
3326
                    + gRearview_camera_to_world.m[2][1] * distance_vector.v[1]
3327
                    + gRearview_camera_to_world.m[2][0] * distance_vector.v[0]
3328
                < 0.0) {
3329
            return 0;
3330
        }
3331
    }
3332
    distance_vector.v[0] = pPoint->v[0] - gCamera_to_world.m[3][0];
3333
    distance_vector.v[1] = pPoint->v[1] - gCamera_to_world.m[3][1];
3334
    distance_vector.v[2] = pPoint->v[2] - gCamera_to_world.m[3][2];
3335
    return distance_vector.v[0] * distance_vector.v[0] + distance_vector.v[1] * distance_vector.v[1] + distance_vector.v[2] * distance_vector.v[2] >= pMax_distance
3336
        || gCamera_to_world.m[2][2] * distance_vector.v[2] + gCamera_to_world.m[2][1] * distance_vector.v[1] + gCamera_to_world.m[2][0] * distance_vector.v[0] >= 0.0;
3337
}
3338
 
3339
// IDA: void __usercall PathGrooveBastard(tGroovidelic_spec *pGroove@<EAX>, tU32 pTime@<EDX>, br_matrix34 *pMat@<EBX>, int pInterrupt_it@<ECX>)
3340
void PathGrooveBastard(tGroovidelic_spec* pGroove, tU32 pTime, br_matrix34* pMat, int pInterrupt_it) {
3341
    br_scalar pos;
3342
    LOG_TRACE("(%p, %d, %p, %d)", pGroove, pTime, pMat, pInterrupt_it);
3343
 
3344
    if (pGroove->path_type == eGroove_path_straight) {
3345
        if (pGroove->path_data.straight_info.x_delta != 0.0f) {
3346
 
3347
            switch (pGroove->path_mode) {
3348
            case eMove_continuous:
3349
                if (pGroove->path_data.straight_info.period == 0.0f) {
3350
                    pos = 0.f;
3351
                } else {
3352
                    pos = fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period * pGroove->path_data.straight_info.x_delta;
3353
                }
3354
                break;
3355
            case eMove_controlled:
3356
                pos = pGroove->path_data.straight_info.period * pGroove->path_data.straight_info.x_delta;
3357
                break;
3358
            case eMove_absolute:
3359
                pos = pGroove->path_data.straight_info.period;
3360
                break;
3361
            case eMove_flash:
3362
                if (fmodf(pTime, pGroove->path_data.straight_info.period) * 2.0f <= pGroove->path_data.straight_info.period) {
3363
                    pos = pGroove->path_data.straight_info.x_delta;
3364
                } else {
3365
                    pos = -pGroove->path_data.straight_info.x_delta;
3366
                }
3367
                break;
3368
            case eMove_harmonic:
3369
                if (pGroove->path_data.straight_info.period == 0.0f) {
3370
                    pos = 0.f;
3371
                } else {
3372
                    pos = sinf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period * 360.0f)))
3373
                        * pGroove->path_data.straight_info.x_delta;
3374
                }
3375
                break;
3376
            case eMove_linear:
3377
                if (pGroove->path_data.straight_info.period == 0.0f) {
3378
                    pos = 0.f;
3379
                } else {
3380
                    pos = MapSawToTriangle(fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period)
3381
                        * pGroove->path_data.straight_info.x_delta;
3382
                }
3383
                break;
3384
            default:
3385
                TELL_ME_IF_WE_PASS_THIS_WAY();
3386
            }
3387
 
3388
            pos += pGroove->path_data.straight_info.centre.v[0];
3389
            if (pInterrupt_it) {
3390
                pGroove->path_resumption_value = pos;
3391
                if (pMat->m[3][0] <= pos) {
3392
                    pGroove->path_interrupt_status = eInterrupt_greater_than;
3393
                } else {
3394
                    pGroove->path_interrupt_status = eInterrupt_less_than;
3395
                }
3396
            } else if (pGroove->path_interrupt_status == eInterrupt_none) {
3397
                BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3398
                pMat->m[3][0] = pos;
3399
            } else if (pGroove->path_interrupt_status == eInterrupt_less_than) {
3400
                if (pGroove->path_resumption_value > pos) {
3401
                    pGroove->path_interrupt_status = eInterrupt_none;
3402
                    BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3403
                    pMat->m[3][0] = pos;
3404
                }
3405
            } else if (pGroove->path_resumption_value < pos) {
3406
                pGroove->path_interrupt_status = eInterrupt_none;
3407
                BrVector3Copy(&pGroove->actor->t.t.euler.t, &pGroove->path_data.straight_info.centre);
3408
                pMat->m[3][0] = pos;
3409
            }
3410
        }
3411
 
3412
        if (pGroove->path_data.straight_info.y_delta != 0.0f) {
3413
            switch (pGroove->path_mode) {
3414
            case eMove_continuous:
3415
                if (pGroove->path_data.straight_info.period == 0.0f) {
3416
                    pos = 0.f;
3417
                } else {
3418
                    pos = fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period * pGroove->path_data.straight_info.y_delta;
3419
                }
3420
                break;
3421
            case eMove_controlled:
3422
                pos = pGroove->path_data.straight_info.period * pGroove->path_data.straight_info.y_delta;
3423
                break;
3424
            case eMove_absolute:
3425
                pos = pGroove->path_data.straight_info.period;
3426
                break;
3427
            case eMove_flash:
3428
                if (fmodf(pTime, pGroove->path_data.straight_info.period) * 2.0f <= pGroove->path_data.straight_info.period) {
3429
                    pos = pGroove->path_data.straight_info.y_delta;
3430
                } else {
3431
                    pos = -pGroove->path_data.straight_info.y_delta;
3432
                }
3433
                break;
3434
            case eMove_harmonic:
3435
                if (pGroove->path_data.straight_info.period == 0.0) {
3436
                    pos = 0.f;
3437
                } else {
3438
                    pos = sinf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period * 360.0f)))
3439
                        * pGroove->path_data.straight_info.y_delta;
3440
                }
3441
                break;
3442
            case eMove_linear:
3443
                if (pGroove->path_data.straight_info.period == 0.0f) {
3444
                    pos = 0.f;
3445
                } else {
3446
                    pos = MapSawToTriangle(fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period)
3447
                        * pGroove->path_data.straight_info.y_delta;
3448
                }
3449
                break;
3450
            default:
3451
                TELL_ME_IF_WE_PASS_THIS_WAY();
3452
            }
3453
 
3454
            pos += pGroove->path_data.straight_info.centre.v[1];
3455
            if (pInterrupt_it) {
3456
                pGroove->path_resumption_value = pos;
3457
                if (pMat->m[3][1] <= pos) {
3458
                    pGroove->path_interrupt_status = eInterrupt_greater_than;
3459
                } else {
3460
                    pGroove->path_interrupt_status = eInterrupt_less_than;
3461
                }
3462
            } else if (pGroove->path_interrupt_status == eInterrupt_none) {
3463
                BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3464
                pMat->m[3][1] = pos;
3465
            } else if (pGroove->path_interrupt_status == eInterrupt_less_than) {
3466
                if (pGroove->path_resumption_value > pos) {
3467
                    pGroove->path_interrupt_status = eInterrupt_none;
3468
                    BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3469
                    pMat->m[3][1] = pos;
3470
                }
3471
            } else if (pGroove->path_resumption_value < pos) {
3472
                pGroove->path_interrupt_status = eInterrupt_none;
3473
                pGroove->actor->t.t.euler.t = pGroove->path_data.straight_info.centre;
3474
                pMat->m[3][1] = pos;
3475
            }
3476
        }
3477
 
3478
        if (pGroove->path_data.straight_info.z_delta != 0.0f) {
3479
            switch (pGroove->path_mode) {
3480
            case eMove_continuous:
3481
                if (pGroove->path_data.straight_info.period == 0.0f) {
3482
                    pos = 0.f;
3483
                } else {
3484
                    pos = fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period * pGroove->path_data.straight_info.z_delta;
3485
                }
3486
                break;
3487
            case eMove_controlled:
3488
                pos = pGroove->path_data.straight_info.period * pGroove->path_data.straight_info.z_delta;
3489
                break;
3490
            case eMove_absolute:
3491
                pos = pGroove->path_data.straight_info.period;
3492
                break;
3493
            case eMove_flash:
3494
                if (fmodf(pTime, pGroove->path_data.straight_info.period) * 2.0f <= pGroove->path_data.straight_info.period) {
3495
                    pos = pGroove->path_data.straight_info.z_delta;
3496
                } else {
3497
                    pos = -pGroove->path_data.straight_info.z_delta;
3498
                }
3499
                break;
3500
            case eMove_harmonic:
3501
                if (pGroove->path_data.straight_info.period == 0.0f) {
3502
                    pos = 0.f;
3503
                } else {
3504
                    pos = sinf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period * 360.0f)))
3505
                        * pGroove->path_data.straight_info.z_delta;
3506
                }
3507
                break;
3508
            case eMove_linear:
3509
                if (pGroove->path_data.straight_info.period == 0.0f) {
3510
                    pos = 0.f;
3511
                } else {
3512
                    pos = MapSawToTriangle(fmodf(pTime, pGroove->path_data.straight_info.period) / pGroove->path_data.straight_info.period)
3513
                        * pGroove->path_data.straight_info.z_delta;
3514
                }
3515
                break;
3516
            default:
3517
                TELL_ME_IF_WE_PASS_THIS_WAY();
3518
            }
3519
 
3520
            pos += pGroove->path_data.straight_info.centre.v[1];
3521
            if (pInterrupt_it) {
3522
                pGroove->path_resumption_value = pos;
3523
                if (pMat->m[3][2] <= pos) {
3524
                    pGroove->path_interrupt_status = eInterrupt_greater_than;
3525
                } else {
3526
                    pGroove->path_interrupt_status = eInterrupt_less_than;
3527
                }
3528
            } else {
3529
                if (pGroove->path_interrupt_status == eInterrupt_none) {
3530
                    BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3531
                    pMat->m[3][2] = pos;
3532
                } else if (pGroove->path_interrupt_status == eInterrupt_less_than) {
3533
                    if (pGroove->path_resumption_value > pos) {
3534
                        pGroove->path_interrupt_status = eInterrupt_none;
3535
                        BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3536
                        pMat->m[3][2] = pos;
3537
                    }
3538
                } else if (pGroove->path_resumption_value < pos) {
3539
                    pGroove->path_interrupt_status = eInterrupt_none;
3540
                    BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.straight_info.centre);
3541
                    pMat->m[3][2] = pos;
3542
                }
3543
            }
3544
        }
3545
        BrVector3Copy(&pGroove->object_position, &pGroove->actor->t.t.translate.t);
3546
    } else if (pGroove->path_type == eGroove_path_circular) {
3547
        BrVector3Copy(&pGroove->actor->t.t.translate.t, &pGroove->path_data.circular_info.centre);
3548
        if (pGroove->path_data.circular_info.axis == eGroove_axis_y) {
3549
            if (pGroove->path_data.circular_info.period == 0.0f) {
3550
                pos = 0.f;
3551
            } else {
3552
                pos = cosf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.circular_info.period) / pGroove->path_data.circular_info.period * 360.0f))) * pGroove->path_data.circular_info.radius;
3553
            }
3554
            pMat->m[3][0] = pGroove->path_data.circular_info.centre.v[0] + pos;
3555
        } else if (pGroove->path_data.circular_info.axis == eGroove_axis_z) {
3556
            if (pGroove->path_data.circular_info.period == 0.0f) {
3557
                pos = 0.f;
3558
            } else {
3559
                pos = sinf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.circular_info.period) / pGroove->path_data.circular_info.period * 360.0f))) * pGroove->path_data.circular_info.radius;
3560
            }
3561
            pMat->m[3][0] = pGroove->path_data.circular_info.centre.v[0] + pos;
3562
        }
3563
 
3564
        if (pGroove->path_data.circular_info.axis == eGroove_axis_x) {
3565
            if (pGroove->path_data.circular_info.period == 0.0f) {
3566
                pos = 0.f;
3567
            } else {
3568
                pos = sinf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.circular_info.period) / pGroove->path_data.circular_info.period * 360.0f))) * pGroove->path_data.circular_info.radius;
3569
            }
3570
            pMat->m[3][1] = pGroove->path_data.circular_info.centre.v[1] + pos;
3571
        } else if (pGroove->path_data.circular_info.axis == eGroove_axis_z) {
3572
            if (pGroove->path_data.circular_info.period == 0.0f) {
3573
                pos = 0.f;
3574
            } else {
3575
                pos = cosf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.circular_info.period) / pGroove->path_data.circular_info.period * 360.0f))) * pGroove->path_data.circular_info.radius;
3576
            }
3577
            pMat->m[3][1] = pGroove->path_data.circular_info.centre.v[1] + pos;
3578
        }
3579
 
3580
        if (pGroove->path_data.circular_info.axis == eGroove_axis_x) {
3581
            if (pGroove->path_data.circular_info.period == 0.0f) {
3582
                pos = 0.f;
3583
            } else {
3584
                pos = cosf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.circular_info.period) / pGroove->path_data.circular_info.period * 360.0f))) * pGroove->path_data.circular_info.radius;
3585
            }
3586
            pMat->m[3][2] = pGroove->path_data.circular_info.centre.v[1] + pos;
3587
        } else if (pGroove->path_data.circular_info.axis == eGroove_axis_z) {
3588
            if (pGroove->path_data.circular_info.period == 0.0f) {
3589
                pos = 0.f;
3590
            } else {
3591
                pos = sinf(BrAngleToRadian(BrDegreeToAngle(fmodf(pTime, pGroove->path_data.circular_info.period) / pGroove->path_data.circular_info.period * 360.0f))) * pGroove->path_data.circular_info.radius;
3592
            }
3593
            pMat->m[3][2] = pGroove->path_data.circular_info.centre.v[1] + pos;
3594
        }
3595
        BrVector3Copy(&pGroove->object_position, &pGroove->actor->t.t.translate.t);
3596
    }
3597
}
3598
 
3599
// IDA: void __usercall ObjectGrooveBastard(tGroovidelic_spec *pGroove@<EAX>, tU32 pTime@<EDX>, br_matrix34 *pMat@<EBX>, int pInterrupt_it@<ECX>)
3600
void ObjectGrooveBastard(tGroovidelic_spec* pGroove, tU32 pTime, br_matrix34* pMat, int pInterrupt_it) {
3601
    int rock_it;
3602
    br_scalar x_size;
3603
    br_scalar y_size;
3604
    br_scalar z_size;
3605
    br_scalar pos;
3606
    br_bounds* bounds;
3607
    LOG_TRACE("(%p, %d, %p, %d)", pGroove, pTime, pMat, pInterrupt_it);
3608
 
3609
    x_size = 0;
3610
    y_size = 0;
3611
    z_size = 0;
3612
    pos = 0;
3613
 
3614
    switch (pGroove->object_type) {
3615
    case eGroove_object_spin:
3616
        if (pGroove->object_data.spin_info.axis == eGroove_axis_y) {
3617
            if (pGroove->object_mode == eMove_continuous) {
3618
                if (pGroove->object_data.spin_info.period != 0.0) {
3619
                    pos = fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period * 360.0;
3620
                }
3621
            } else if (pGroove->object_mode == eMove_controlled) {
3622
                pos = pGroove->object_data.spin_info.period * 360.0;
3623
            } else if (pGroove->object_mode == eMove_absolute) {
3624
                pos = pGroove->object_data.spin_info.period;
3625
            } else if (pGroove->object_mode == eMove_flash) {
3626
                if (fmod(pTime, pGroove->object_data.spin_info.period) * 2.0 <= pGroove->object_data.spin_info.period) {
3627
                    pos = (br_scalar) 3.85156; // Pierre-Marie Baty -- added type cast
3628
                } else {
3629
                    pos = (br_scalar) -3.85156; // Pierre-Marie Baty -- added type cast
3630
                }
3631
            } else if (pGroove->object_mode == eMove_harmonic) {
3632
                if (pGroove->object_data.spin_info.period != 0.0) {
3633
                    pos = sin(
3634
                              BrAngleToRadian(
3635
                                  BrDegreeToAngle(
3636
                                      fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period * 360.0)))
3637
                        * 360.0;
3638
                }
3639
            } else {
3640
                if (pGroove->object_data.spin_info.period != 0.0) {
3641
                    pos = fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period;
3642
                    pos = MapSawToTriangle(pos) * 360.0;
3643
                }
3644
            }
3645
            DRMatrix34PostRotateY(pMat, BrDegreeToAngle(pos));
3646
        } else if (pGroove->object_data.spin_info.axis == eGroove_axis_z) {
3647
            if (pGroove->object_mode == eMove_continuous) {
3648
                if (pGroove->object_data.spin_info.period != 0.0) {
3649
                    pos = fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period * 360.0;
3650
                }
3651
            } else if (pGroove->object_mode == eMove_controlled) {
3652
                pos = pGroove->object_data.spin_info.period * 360.0;
3653
            } else if (pGroove->object_mode == eMove_absolute) {
3654
                pos = pGroove->object_data.spin_info.period;
3655
            } else if (pGroove->object_mode == eMove_flash) {
3656
                if (fmod(pTime, pGroove->object_data.spin_info.period) * 2.0 <= pGroove->object_data.spin_info.period) {
3657
                    pos = (br_scalar) 3.85156; // Pierre-Marie Baty -- added type cast
3658
                } else {
3659
                    pos = (br_scalar) -3.85156; // Pierre-Marie Baty -- added type cast
3660
                }
3661
            } else if (pGroove->object_mode == eMove_harmonic) {
3662
                if (pGroove->object_data.spin_info.period != 0.0) {
3663
                    pos = sin(
3664
                              BrAngleToRadian(
3665
                                  BrDegreeToAngle(
3666
                                      fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period * 360.0)))
3667
                        * 360.0;
3668
                }
3669
            } else {
3670
                if (pGroove->object_data.spin_info.period != 0.0) {
3671
                    pos = fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period;
3672
                    pos = MapSawToTriangle(pos) * 360.0;
3673
                }
3674
            }
3675
            DRMatrix34PostRotateZ(pMat, BrDegreeToAngle(pos));
3676
        } else if (pGroove->object_data.spin_info.axis == eGroove_axis_x) {
3677
            if (pGroove->object_mode == eMove_continuous) {
3678
                if (pGroove->object_data.spin_info.period != 0.0) {
3679
                    pos = fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period * 360.0;
3680
                }
3681
            } else if (pGroove->object_mode == eMove_controlled) {
3682
                pos = pGroove->object_data.spin_info.period * 360.0;
3683
            } else if (pGroove->object_mode == eMove_absolute) {
3684
                pos = pGroove->object_data.spin_info.period;
3685
            } else if (pGroove->object_mode == eMove_flash) {
3686
                if (fmod(pTime, pGroove->object_data.spin_info.period) * 2.0 <= pGroove->object_data.spin_info.period) {
3687
                    pos = (br_scalar) 3.85156; // Pierre-Marie Baty -- added type cast
3688
                } else {
3689
                    pos = (br_scalar) -3.85156; // Pierre-Marie Baty -- added type cast
3690
                }
3691
            } else if (pGroove->object_mode == eMove_harmonic) {
3692
                if (pGroove->object_data.spin_info.period != 0.0) {
3693
                    pos = sin(
3694
                              BrAngleToRadian(
3695
                                  BrDegreeToAngle(
3696
                                      fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period * 360.0)))
3697
                        * 360.0;
3698
                }
3699
            } else {
3700
                if (pGroove->object_data.spin_info.period != 0.0) {
3701
                    pos = fmod(pTime, pGroove->object_data.spin_info.period) / pGroove->object_data.spin_info.period;
3702
                    pos = MapSawToTriangle(pos) * 360.0;
3703
                }
3704
            }
3705
            DRMatrix34PostRotateX(pMat, BrDegreeToAngle(pos));
3706
        }
3707
        break;
3708
    case eGroove_object_rock:
3709
        rock_it = 1;
3710
        if (pGroove->object_mode == eMove_continuous) {
3711
            if (pGroove->object_data.rock_info.period != 0.0) {
3712
                pos = fmod(pTime, pGroove->object_data.rock_info.period) / pGroove->object_data.rock_info.period * pGroove->object_data.rock_info.max_angle;
3713
            }
3714
        } else if (pGroove->object_mode == eMove_controlled) {
3715
            pos = pGroove->object_data.rock_info.period * pGroove->object_data.rock_info.max_angle;
3716
        } else if (pGroove->object_mode == eMove_absolute) {
3717
            pos = pGroove->object_data.rock_info.period;
3718
        } else if (pGroove->object_mode == eMove_flash) {
3719
            if (fmod(pTime, pGroove->object_data.rock_info.period) * 2.0 <= pGroove->object_data.rock_info.period) {
3720
                pos = pGroove->object_data.rock_info.max_angle;
3721
            } else {
3722
                pos = -pGroove->object_data.rock_info.max_angle;
3723
            }
3724
        } else if (pGroove->object_mode == eMove_harmonic) {
3725
            if (pGroove->object_data.rock_info.period != 0.0) {
3726
                pos = sin(
3727
                          BrAngleToRadian(
3728
                              BrDegreeToAngle(
3729
                                  fmod(pTime, pGroove->object_data.rock_info.period) / pGroove->object_data.rock_info.period * 360.0)))
3730
                    * pGroove->object_data.rock_info.max_angle;
3731
            }
3732
        } else {
3733
            if (pGroove->object_data.rock_info.period != 0.0) {
3734
                pos = fmod(pTime, pGroove->object_data.rock_info.period) / pGroove->object_data.rock_info.period;
3735
                pos = MapSawToTriangle(pos) * pGroove->object_data.rock_info.max_angle;
3736
            }
3737
        }
3738
 
3739
        if (pInterrupt_it) {
3740
            pGroove->object_resumption_value = pos;
3741
            if (pGroove->object_data.rock_info.current_angle <= pos) {
3742
                pGroove->object_interrupt_status = eInterrupt_greater_than;
3743
            } else {
3744
                pGroove->object_interrupt_status = eInterrupt_less_than;
3745
            }
3746
        } else if (pGroove->object_interrupt_status == eInterrupt_less_than) {
3747
            if (pGroove->object_resumption_value <= pos || gAction_replay_mode) {
3748
                rock_it = 0;
3749
            } else {
3750
                pGroove->object_interrupt_status = eInterrupt_none;
3751
            }
3752
        } else if (pGroove->object_interrupt_status == eInterrupt_greater_than) {
3753
            if (pGroove->object_resumption_value >= pos || gAction_replay_mode) {
3754
                rock_it = 0;
3755
            } else {
3756
                pGroove->object_interrupt_status = eInterrupt_none;
3757
            }
3758
        }
3759
        if (rock_it) {
3760
            pGroove->object_data.rock_info.current_angle = pos;
3761
        }
3762
 
3763
        if (pGroove->object_data.rock_info.axis == eGroove_axis_y) {
3764
            DRMatrix34PostRotateY(pMat, BrDegreeToAngle(pGroove->object_data.rock_info.current_angle));
3765
        } else if (pGroove->object_data.rock_info.axis == eGroove_axis_z) {
3766
            DRMatrix34PostRotateZ(pMat, BrDegreeToAngle(pGroove->object_data.rock_info.current_angle));
3767
        } else if (pGroove->object_data.rock_info.axis == eGroove_axis_x) {
3768
            DRMatrix34PostRotateX(pMat, BrDegreeToAngle(pGroove->object_data.rock_info.current_angle));
3769
        }
3770
        break;
3771
    case eGroove_object_throb:
3772
        if (pGroove->object_mode == eMove_continuous) {
3773
            if (pGroove->object_data.throb_info.z_period != 0.0) {
3774
                z_size = fmod(pTime, pGroove->object_data.throb_info.z_period) / pGroove->object_data.throb_info.z_period * pGroove->object_data.throb_info.z_magnitude;
3775
            }
3776
        } else if (pGroove->object_mode == eMove_controlled) {
3777
            z_size = pGroove->object_data.throb_info.z_magnitude * pGroove->object_data.throb_info.z_period;
3778
        } else if (pGroove->object_mode == eMove_absolute) {
3779
            z_size = pGroove->object_data.throb_info.z_period;
3780
        } else if (pGroove->object_mode == eMove_flash) {
3781
            if (fmod(pTime, pGroove->object_data.throb_info.z_period) * 2.0 <= pGroove->object_data.throb_info.z_period) {
3782
                z_size = pGroove->object_data.throb_info.z_magnitude;
3783
            } else {
3784
                z_size = -pGroove->object_data.throb_info.z_magnitude;
3785
            }
3786
        } else if (pGroove->object_mode == eMove_harmonic) {
3787
            if (pGroove->object_data.throb_info.z_period != 0.0) {
3788
                z_size = sin(
3789
                             BrAngleToRadian(
3790
                                 BrDegreeToAngle(
3791
                                     fmod(pTime, pGroove->object_data.throb_info.z_period) / pGroove->object_data.throb_info.z_period * 360.0)))
3792
                    * pGroove->object_data.throb_info.z_magnitude;
3793
            }
3794
        } else {
3795
            if (pGroove->object_data.throb_info.z_period != 0.0) {
3796
                z_size = fmod(pTime, pGroove->object_data.throb_info.z_period) / pGroove->object_data.throb_info.z_period;
3797
                z_size = MapSawToTriangle(z_size) * pGroove->object_data.throb_info.z_magnitude;
3798
            }
3799
        }
3800
 
3801
        if (pGroove->object_mode == eMove_continuous) {
3802
            if (pGroove->object_data.throb_info.x_period != 0.0) {
3803
                x_size = fmod(pTime, pGroove->object_data.throb_info.x_period) / pGroove->object_data.throb_info.x_period * pGroove->object_data.throb_info.x_magnitude;
3804
            }
3805
        } else if (pGroove->object_mode == eMove_controlled) {
3806
            x_size = pGroove->object_data.throb_info.x_magnitude * pGroove->object_data.throb_info.x_period;
3807
        } else if (pGroove->object_mode == eMove_absolute) {
3808
            x_size = pGroove->object_data.throb_info.x_period;
3809
        } else if (pGroove->object_mode == eMove_flash) {
3810
            if (fmod(pTime, pGroove->object_data.throb_info.x_period) * 2.0 <= pGroove->object_data.throb_info.x_period) {
3811
                x_size = pGroove->object_data.throb_info.x_magnitude;
3812
            } else {
3813
                x_size = -pGroove->object_data.throb_info.x_magnitude;
3814
            }
3815
        } else if (pGroove->object_mode == eMove_harmonic) {
3816
            if (pGroove->object_data.throb_info.x_period != 0.0) {
3817
                x_size = sin(
3818
                             BrAngleToRadian(
3819
                                 BrDegreeToAngle(
3820
                                     fmod(pTime, pGroove->object_data.throb_info.x_period) / pGroove->object_data.throb_info.x_period * 360.0)))
3821
                    * pGroove->object_data.throb_info.x_magnitude;
3822
            }
3823
        } else {
3824
            if (pGroove->object_data.throb_info.x_period != 0.0) {
3825
                x_size = fmod(pTime, pGroove->object_data.throb_info.x_period) / pGroove->object_data.throb_info.x_period;
3826
                x_size = MapSawToTriangle(x_size) * pGroove->object_data.throb_info.x_magnitude;
3827
            }
3828
        }
3829
 
3830
        if (pGroove->object_mode == eMove_continuous) {
3831
            if (pGroove->object_data.throb_info.y_period != 0.0) {
3832
                y_size = fmod(pTime, pGroove->object_data.throb_info.y_period) / pGroove->object_data.throb_info.y_period * pGroove->object_data.throb_info.y_magnitude;
3833
            }
3834
        } else if (pGroove->object_mode == eMove_controlled) {
3835
            y_size = pGroove->object_data.throb_info.y_magnitude * pGroove->object_data.throb_info.y_period;
3836
        } else if (pGroove->object_mode == eMove_absolute) {
3837
            y_size = pGroove->object_data.throb_info.y_period;
3838
        } else if (pGroove->object_mode == eMove_flash) {
3839
            if (fmod(pTime, pGroove->object_data.throb_info.y_period) * 2.0 <= pGroove->object_data.throb_info.y_period) {
3840
                y_size = pGroove->object_data.throb_info.y_magnitude;
3841
            } else {
3842
                y_size = -pGroove->object_data.throb_info.y_magnitude;
3843
            }
3844
        } else if (pGroove->object_mode == eMove_harmonic) {
3845
            if (pGroove->object_data.throb_info.y_period != 0.0) {
3846
                y_size = sin(
3847
                             BrAngleToRadian(
3848
                                 BrDegreeToAngle(
3849
                                     fmod(pTime, pGroove->object_data.throb_info.y_period) / pGroove->object_data.throb_info.y_period * 360.0)))
3850
                    * pGroove->object_data.throb_info.y_magnitude;
3851
            }
3852
        } else {
3853
            if (pGroove->object_data.throb_info.y_period != 0.0) {
3854
                y_size = fmod(pTime, pGroove->object_data.throb_info.y_period) / pGroove->object_data.throb_info.y_period;
3855
                y_size = MapSawToTriangle(y_size) * pGroove->object_data.throb_info.y_magnitude;
3856
            }
3857
        }
3858
 
3859
        BrMatrix34PostScale(pMat, x_size + 1.0, y_size + 1.0, z_size + 1.0);
3860
        /* FALLTHROUGH */
3861
    case eGroove_object_shear:
3862
        bounds = &pGroove->actor->model->bounds;
3863
        if (pGroove->object_data.shear_info.x_magnitude == 0.0) {
3864
            if (pGroove->object_mode == eMove_continuous) {
3865
                if (pGroove->object_data.shear_info.z_period != 0.0) {
3866
                    z_size = fmod(pTime, pGroove->object_data.shear_info.z_period) / pGroove->object_data.shear_info.z_period * pGroove->object_data.shear_info.z_magnitude;
3867
                }
3868
            } else if (pGroove->object_mode == eMove_controlled) {
3869
                z_size = pGroove->object_data.shear_info.z_magnitude * pGroove->object_data.shear_info.z_period;
3870
            } else if (pGroove->object_mode == eMove_absolute) {
3871
                z_size = pGroove->object_data.shear_info.z_period;
3872
            } else if (pGroove->object_mode == eMove_flash) {
3873
                if (fmod(pTime, pGroove->object_data.shear_info.z_period) * 2.0 <= pGroove->object_data.shear_info.z_period) {
3874
                    z_size = pGroove->object_data.shear_info.z_magnitude;
3875
                } else {
3876
                    z_size = -pGroove->object_data.shear_info.z_magnitude;
3877
                }
3878
            } else if (pGroove->object_mode == eMove_harmonic) {
3879
                if (pGroove->object_data.shear_info.z_period != 0.0) {
3880
                    z_size = sin(
3881
                                 BrAngleToRadian(
3882
                                     BrDegreeToAngle(
3883
                                         fmod(pTime, pGroove->object_data.shear_info.z_period) / pGroove->object_data.shear_info.z_period * 360.0)))
3884
                        * pGroove->object_data.shear_info.z_magnitude;
3885
                }
3886
            } else {
3887
                if (pGroove->object_data.shear_info.z_period != 0.0) {
3888
                    z_size = fmod(pTime, pGroove->object_data.shear_info.z_period) / pGroove->object_data.shear_info.z_period;
3889
                    z_size = MapSawToTriangle(z_size) * pGroove->object_data.shear_info.z_magnitude;
3890
                }
3891
            }
3892
 
3893
            if (pGroove->object_mode == eMove_continuous) {
3894
                if (pGroove->object_data.shear_info.y_period != 0.0) {
3895
                    y_size = fmod(pTime, pGroove->object_data.shear_info.y_period) / pGroove->object_data.shear_info.y_period * pGroove->object_data.shear_info.y_magnitude;
3896
                }
3897
            } else if (pGroove->object_mode == eMove_controlled) {
3898
                y_size = pGroove->object_data.shear_info.y_magnitude * pGroove->object_data.shear_info.y_period;
3899
            } else if (pGroove->object_mode == eMove_absolute) {
3900
                y_size = pGroove->object_data.shear_info.y_period;
3901
            } else if (pGroove->object_mode == eMove_flash) {
3902
                if (fmod(pTime, pGroove->object_data.shear_info.y_period) * 2.0 <= pGroove->object_data.shear_info.y_period) {
3903
                    y_size = pGroove->object_data.shear_info.y_magnitude;
3904
                } else {
3905
                    y_size = -pGroove->object_data.shear_info.y_magnitude;
3906
                }
3907
            } else if (pGroove->object_mode == eMove_harmonic) {
3908
                if (pGroove->object_data.shear_info.y_period != 0.0) {
3909
                    y_size = sin(
3910
                                 BrAngleToRadian(
3911
                                     BrDegreeToAngle(
3912
                                         fmod(pTime, pGroove->object_data.shear_info.y_period) / pGroove->object_data.shear_info.y_period * 360.0)))
3913
                        * pGroove->object_data.shear_info.y_magnitude;
3914
                }
3915
            } else {
3916
                if (pGroove->object_data.shear_info.y_period != 0.0) {
3917
                    y_size = fmod(pTime, pGroove->object_data.shear_info.y_period) / pGroove->object_data.shear_info.y_period;
3918
                    y_size = MapSawToTriangle(y_size) * pGroove->object_data.shear_info.y_magnitude;
3919
                }
3920
            }
3921
            BrMatrix34PostShearX(pMat, y_size / (bounds->max.v[1] - bounds->min.v[1]), z_size / bounds->max.v[2] - bounds->min.v[2]);
3922
        } else if (pGroove->object_data.shear_info.y_magnitude == 0.0) {
3923
 
3924
            if (pGroove->object_mode == eMove_continuous) {
3925
                if (pGroove->object_data.shear_info.z_period != 0.0) {
3926
                    z_size = fmod(pTime, pGroove->object_data.shear_info.z_period) / pGroove->object_data.shear_info.z_period * pGroove->object_data.shear_info.z_magnitude;
3927
                }
3928
            } else if (pGroove->object_mode == eMove_controlled) {
3929
                z_size = pGroove->object_data.shear_info.z_magnitude * pGroove->object_data.shear_info.z_period;
3930
            } else if (pGroove->object_mode == eMove_absolute) {
3931
                z_size = pGroove->object_data.shear_info.z_period;
3932
            } else if (pGroove->object_mode == eMove_flash) {
3933
                if (fmod(pTime, pGroove->object_data.shear_info.z_period) * 2.0 <= pGroove->object_data.shear_info.z_period) {
3934
                    z_size = pGroove->object_data.shear_info.z_magnitude;
3935
                } else {
3936
                    z_size = -pGroove->object_data.shear_info.z_magnitude;
3937
                }
3938
            } else if (pGroove->object_mode == eMove_harmonic) {
3939
                if (pGroove->object_data.shear_info.z_period != 0.0) {
3940
                    z_size = sin(
3941
                                 BrAngleToRadian(
3942
                                     BrDegreeToAngle(
3943
                                         fmod(pTime, pGroove->object_data.shear_info.z_period) / pGroove->object_data.shear_info.z_period * 360.0)))
3944
                        * pGroove->object_data.shear_info.z_magnitude;
3945
                }
3946
            } else {
3947
                if (pGroove->object_data.shear_info.z_period != 0.0) {
3948
                    z_size = fmod(pTime, pGroove->object_data.shear_info.z_period) / pGroove->object_data.shear_info.z_period;
3949
                    z_size = MapSawToTriangle(z_size) * pGroove->object_data.shear_info.z_magnitude;
3950
                }
3951
            }
3952
 
3953
            if (pGroove->object_mode == eMove_continuous) {
3954
                if (pGroove->object_data.shear_info.x_period != 0.0) {
3955
                    x_size = fmod(pTime, pGroove->object_data.shear_info.x_period) / pGroove->object_data.shear_info.x_period * pGroove->object_data.shear_info.x_magnitude;
3956
                }
3957
            } else if (pGroove->object_mode == eMove_controlled) {
3958
                x_size = pGroove->object_data.shear_info.x_magnitude * pGroove->object_data.shear_info.x_period;
3959
            } else if (pGroove->object_mode == eMove_absolute) {
3960
                x_size = pGroove->object_data.shear_info.x_period;
3961
            } else if (pGroove->object_mode == eMove_flash) {
3962
                if (fmod(pTime, pGroove->object_data.shear_info.x_period) * 2.0 <= pGroove->object_data.shear_info.x_period) {
3963
                    x_size = pGroove->object_data.shear_info.x_magnitude;
3964
                } else {
3965
                    x_size = -pGroove->object_data.shear_info.x_magnitude;
3966
                }
3967
            } else if (pGroove->object_mode == eMove_harmonic) {
3968
                if (pGroove->object_data.shear_info.x_period != 0.0) {
3969
                    x_size = sin(
3970
                                 BrAngleToRadian(
3971
                                     BrDegreeToAngle(
3972
                                         fmod(pTime, pGroove->object_data.shear_info.x_period) / pGroove->object_data.shear_info.x_period * 360.0)))
3973
                        * pGroove->object_data.shear_info.x_magnitude;
3974
                }
3975
            } else { // linear
3976
                if (pGroove->object_data.shear_info.x_period != 0.0) {
3977
                    x_size = fmod(pTime, pGroove->object_data.shear_info.x_period) / pGroove->object_data.shear_info.x_period;
3978
                    x_size = MapSawToTriangle(x_size) * pGroove->object_data.shear_info.x_magnitude;
3979
                }
3980
            }
3981
 
3982
            BrMatrix34PostShearY(pMat, x_size / (bounds->max.v[0] - bounds->min.v[0]), z_size / (bounds->max.v[2] - bounds->min.v[2]));
3983
        } else { // x_magnitude == 0
3984
            if (pGroove->object_mode == eMove_continuous) {
3985
                if (pGroove->object_data.shear_info.y_period != 0.0) {
3986
                    y_size = fmod(pTime, pGroove->object_data.shear_info.y_period) / pGroove->object_data.shear_info.y_period * pGroove->object_data.shear_info.y_magnitude;
3987
                }
3988
            } else if (pGroove->object_mode == eMove_controlled) {
3989
                y_size = pGroove->object_data.shear_info.y_magnitude * pGroove->object_data.shear_info.y_period;
3990
            } else if (pGroove->object_mode == eMove_absolute) {
3991
                y_size = pGroove->object_data.shear_info.y_period;
3992
            } else if (pGroove->object_mode == eMove_flash) {
3993
                if (fmod(pTime, pGroove->object_data.shear_info.y_period) * 2.0 <= pGroove->object_data.shear_info.y_period) {
3994
                    y_size = pGroove->object_data.shear_info.y_magnitude;
3995
                } else {
3996
                    y_size = -pGroove->object_data.shear_info.y_magnitude;
3997
                }
3998
            } else if (pGroove->object_mode == eMove_harmonic) {
3999
                if (pGroove->object_data.shear_info.y_period != 0.0) {
4000
                    y_size = sin(
4001
                                 BrAngleToRadian(
4002
                                     BrDegreeToAngle(
4003
                                         fmod(pTime, pGroove->object_data.shear_info.y_period) / pGroove->object_data.shear_info.y_period * 360.0)))
4004
                        * pGroove->object_data.shear_info.y_magnitude;
4005
                }
4006
            } else {
4007
                if (pGroove->object_data.shear_info.y_period != 0.0) {
4008
                    y_size = fmod(pTime, pGroove->object_data.shear_info.y_period) / pGroove->object_data.shear_info.y_period;
4009
                    y_size = MapSawToTriangle(y_size) * pGroove->object_data.shear_info.y_magnitude;
4010
                }
4011
            }
4012
 
4013
            if (pGroove->object_mode == eMove_continuous) {
4014
                if (pGroove->object_data.shear_info.x_period != 0.0) {
4015
                    x_size = fmod(pTime, pGroove->object_data.shear_info.x_period) / pGroove->object_data.shear_info.x_period * pGroove->object_data.shear_info.x_magnitude;
4016
                }
4017
            } else if (pGroove->object_mode == eMove_controlled) {
4018
                x_size = pGroove->object_data.shear_info.x_magnitude * pGroove->object_data.shear_info.x_period;
4019
            } else if (pGroove->object_mode == eMove_absolute) {
4020
                x_size = pGroove->object_data.shear_info.x_period;
4021
            } else if (pGroove->object_mode == eMove_flash) {
4022
                if (fmod(pTime, pGroove->object_data.shear_info.x_period) * 2.0 <= pGroove->object_data.shear_info.x_period) {
4023
                    x_size = pGroove->object_data.shear_info.x_magnitude;
4024
                } else {
4025
                    x_size = -pGroove->object_data.shear_info.x_magnitude;
4026
                }
4027
            } else if (pGroove->object_mode == eMove_harmonic) {
4028
                if (pGroove->object_data.shear_info.x_period != 0.0) {
4029
                    x_size = sin(
4030
                                 BrAngleToRadian(
4031
                                     BrDegreeToAngle(
4032
                                         fmod(pTime, pGroove->object_data.shear_info.x_period) / pGroove->object_data.shear_info.x_period * 360.0)))
4033
                        * pGroove->object_data.shear_info.x_magnitude;
4034
                }
4035
            } else {
4036
                if (pGroove->object_data.shear_info.x_period != 0.0) {
4037
                    x_size = fmod(pTime, pGroove->object_data.shear_info.x_period) / pGroove->object_data.shear_info.x_period;
4038
                    x_size = MapSawToTriangle(x_size) * pGroove->object_data.shear_info.x_magnitude;
4039
                }
4040
            }
4041
            BrMatrix34PostShearZ(pMat, x_size / (bounds->max.v[0] - bounds->min.v[0]), y_size / (bounds->max.v[1] - bounds->min.v[1]));
4042
        }
4043
        break;
4044
    default:
4045
        return;
4046
    }
4047
}
4048
 
4049
// IDA: void __usercall GrooveThisDelic(tGroovidelic_spec *pGroove@<EAX>, tU32 pTime@<EDX>, int pInterrupt_it@<EBX>)
4050
void GrooveThisDelic(tGroovidelic_spec* pGroove, tU32 pTime, int pInterrupt_it) {
4051
    br_actor* the_actor;
4052
    br_vector3 actor_pos;
4053
    br_matrix34* the_mat;
4054
    tInterrupt_status old_path_interrupt;
4055
    tInterrupt_status old_object_interrupt;
4056
    LOG_TRACE8("(%p, %d, %d)", pGroove, pTime, pInterrupt_it);
4057
 
4058
    old_path_interrupt = pGroove->path_interrupt_status;
4059
    old_object_interrupt = pGroove->object_interrupt_status;
4060
    the_actor = pGroove->actor;
4061
    pGroove->done_this_frame = 1;
4062
    CalcActorGlobalPos(&actor_pos, the_actor);
4063
    if (PointOutOfSight(&actor_pos, pGroove->mode == eGroove_mode_distance ? gYon_squared : 36.f)) {
4064
        return;
4065
    }
4066
 
4067
    the_mat = &the_actor->t.t.mat;
4068
    if (!gAction_replay_mode
4069
        || !ReplayIsPaused()
4070
        || pGroove->path_mode == eMove_controlled
4071
        || pGroove->path_mode == eMove_absolute) {
4072
        PathGrooveBastard(pGroove, pTime, the_mat, pInterrupt_it);
4073
    }
4074
    if ((pGroove->object_type != eGroove_object_none || pGroove->lollipop_mode != eLollipop_none)
4075
        && (!gAction_replay_mode
4076
            || !ReplayIsPaused()
4077
            || pGroove->object_mode == eMove_controlled
4078
            || pGroove->object_mode == eMove_absolute)) {
4079
        the_mat->m[0][0] = 1.0f;
4080
        the_mat->m[0][1] = 0.0f;
4081
        the_mat->m[0][2] = 0.0f;
4082
        the_mat->m[1][0] = 0.0f;
4083
        the_mat->m[1][1] = 1.0f;
4084
        the_mat->m[1][2] = 0.0f;
4085
        the_mat->m[2][0] = 0.0f;
4086
        the_mat->m[2][1] = 0.0f;
4087
        the_mat->m[2][2] = 1.0f;
4088
        the_mat->m[3][0] = -pGroove->object_centre.v[0];
4089
        the_mat->m[3][1] = -pGroove->object_centre.v[1];
4090
        the_mat->m[3][2] = -pGroove->object_centre.v[2];
4091
        ObjectGrooveBastard(pGroove, pTime, the_mat, pInterrupt_it);
4092
        the_actor->t.t.mat.m[3][0] += pGroove->object_position.v[0] + pGroove->object_centre.v[0];
4093
        the_actor->t.t.mat.m[3][1] += pGroove->object_position.v[1] + pGroove->object_centre.v[1];
4094
        the_actor->t.t.mat.m[3][2] += pGroove->object_position.v[2] + pGroove->object_centre.v[2];
4095
        if (pGroove->lollipop_mode != eLollipop_none) {
4096
            LollipopizeActor(pGroove->actor, &gCamera_to_world, pGroove->lollipop_mode);
4097
        }
4098
    }
4099
    if (pGroove->path_interrupt_status != old_path_interrupt || pGroove->object_interrupt_status != old_object_interrupt) {
4100
        PipeSingleGrooveStop(
4101
            pGroove - gGroovidelics_array,
4102
            the_mat,
4103
            pGroove->path_interrupt_status,
4104
            pGroove->object_interrupt_status,
4105
            pGroove->path_resumption_value,
4106
            pGroove->object_resumption_value);
4107
    }
4108
}
4109
 
4110
// IDA: void __cdecl GrooveThoseDelics()
4111
void GrooveThoseDelics(void) {
4112
    int i;
4113
    tGroovidelic_spec* the_groove;
4114
    float f_the_time;
4115
    LOG_TRACE("()");
4116
 
4117
    if (gGroovidelics_array != NULL) {
4118
        f_the_time = (double)GetTotalTime();
4119
        gPrevious_groove_times[1] = gPrevious_groove_times[0];
4120
        gPrevious_groove_times[0] = f_the_time;
4121
 
4122
        for (i = 0; i < gGroovidelics_array_size; i++) {
4123
            the_groove = &gGroovidelics_array[i];
4124
            if (the_groove->owner != -999 && !the_groove->done_this_frame) {
4125
                GrooveThisDelic(the_groove, f_the_time, 0);
4126
            }
4127
        }
4128
    }
4129
}
4130
 
4131
// IDA: void __usercall StopGroovidelic(br_actor *pActor@<EAX>)
4132
void StopGroovidelic(br_actor* pActor) {
4133
    int i;
4134
    tGroovidelic_spec* the_groove;
4135
    LOG_TRACE("(%p)", pActor);
4136
 
4137
    for (i = 0; i < gGroovidelics_array_size; i++) {
4138
        the_groove = &gGroovidelics_array[i];
4139
        if (the_groove->actor == pActor) {
4140
            if (the_groove->path_interrupt_status == eInterrupt_none && the_groove->object_interrupt_status == eInterrupt_none) {
4141
                GrooveThisDelic(the_groove, gPrevious_groove_times[1], 1);
4142
            }
4143
            return;
4144
        }
4145
    }
4146
}
4147
 
4148
// IDA: void __usercall SetGrooveInterrupt(int pGroove_index@<EAX>, br_matrix34 *pMatrix@<EDX>, int pPath_interrupt@<EBX>, int pObject_interrupt@<ECX>, float pPath_resumption, float pObject_resumption)
4149
void SetGrooveInterrupt(int pGroove_index, br_matrix34* pMatrix, int pPath_interrupt, int pObject_interrupt, float pPath_resumption, float pObject_resumption) {
4150
    tGroovidelic_spec* the_groove;
4151
    LOG_TRACE("(%d, %p, %d, %d, %f, %f)", pGroove_index, pMatrix, pPath_interrupt, pObject_interrupt, pPath_resumption, pObject_resumption);
4152
 
4153
    the_groove = &gGroovidelics_array[pGroove_index];
4154
    the_groove->path_interrupt_status = pPath_interrupt;
4155
    the_groove->object_interrupt_status = pObject_interrupt;
4156
    the_groove->path_resumption_value = pPath_resumption;
4157
    the_groove->object_resumption_value = pObject_resumption;
4158
    BrMatrix34Copy(&the_groove->actor->t.t.mat, pMatrix);
4159
}
4160
 
4161
// IDA: void __cdecl ResetGrooveFlags()
4162
void ResetGrooveFlags(void) {
4163
    int i;
4164
    tGroovidelic_spec* the_groove;
4165
    LOG_TRACE("()");
4166
 
4167
    the_groove = gGroovidelics_array;
4168
    for (i = 0; i < gGroovidelics_array_size; i++) {
4169
        the_groove->done_this_frame = 0;
4170
        the_groove++;
4171
    }
4172
}
4173
 
4174
// IDA: tSpecial_volume* __cdecl GetDefaultSpecialVolumeForWater()
4175
tSpecial_volume* GetDefaultSpecialVolumeForWater(void) {
4176
    LOG_TRACE("()");
4177
 
4178
    return gDefault_water_spec_vol;
4179
}
4180
 
4181
// IDA: tSpecial_volume* __usercall FindSpecialVolume@<EAX>(br_vector3 *pP@<EAX>, tSpecial_volume *pLast_vol@<EDX>)
4182
tSpecial_volume* FindSpecialVolume(br_vector3* pP, tSpecial_volume* pLast_vol) {
4183
    int i;
4184
    tSpecial_volume* v;
4185
    br_vector3 p;
4186
    LOG_TRACE("(%p, %p)", pP, pLast_vol);
4187
 
4188
    for (i = 0, v = gProgram_state.special_volumes; i < gProgram_state.special_volume_count; i++, v++) {
4189
        if (!v->no_mat && v->bounds.min.v[0] < pP->v[0] && pP->v[0] < v->bounds.max.v[0] && v->bounds.min.v[1] < pP->v[1] && pP->v[1] < v->bounds.max.v[1] && v->bounds.min.v[2] < pP->v[2] && pP->v[2] < v->bounds.max.v[2]) {
4190
            BrMatrix34ApplyP(&p, pP, &v->inv_mat);
4191
            if (-1.f < p.v[0] && p.v[0] < 1.f && -1.f < p.v[1] && p.v[1] < 1.f && -1.f < p.v[2] && p.v[2] < 1.f) {
4192
                return v;
4193
            }
4194
        }
4195
    }
4196
    return NULL;
4197
}
4198
 
4199
// IDA: void __cdecl SaveAdditionalActors()
4200
void SaveAdditionalActors(void) {
4201
    LOG_TRACE("()");
4202
 
4203
    if (gAdditional_actors != NULL) {
4204
        SaveAdditionalStuff();
4205
    }
4206
}
4207
 
4208
// IDA: br_scalar __usercall DistanceFromFace@<ST0>(br_vector3 *pPos@<EAX>, tFace_ref *pFace@<EDX>)
4209
br_scalar DistanceFromFace(br_vector3* pPos, tFace_ref* pFace) {
4210
    //br_vector3 normal; // Pierre-Marie Baty -- unused variable
4211
    LOG_TRACE("(%p, %p)", pPos, pFace);
4212
 
4213
    return BrVector3Dot(&pFace->normal, pPos) - pFace->d;
4214
}
4215
 
4216
// IDA: br_uint_32 __cdecl CalcHighestID(br_actor *pActor, int *pHighest)
4217
br_uint_32 CalcHighestID(br_actor* pActor, int* pHighest) {
4218
    char s[256];
4219
    int number;
4220
    LOG_TRACE("(%p, %p)", pActor, pHighest);
4221
 
4222
    if (pActor->identifier == NULL || pActor->identifier[0] == '@') {
4223
        return 0;
4224
    }
4225
    strcpy(s, &pActor->identifier[4]);
4226
    s[4] = '\0';
4227
    sscanf(s, "%d", &number);
4228
    if (*pHighest < number) {
4229
        *pHighest = number;
4230
    }
4231
    return 0;
4232
}
4233
 
4234
// IDA: br_uint_32 __cdecl SetID(br_actor *pActor, void *pArg)
4235
br_uint_32 SetID(br_actor* pActor, void* pArg) {
4236
    char s[256];
4237
    LOG_TRACE("(%p, %p)", pActor, pArg);
4238
 
4239
    if (pActor->identifier == NULL) {
4240
        return 0;
4241
    }
4242
    strcpy(s, pActor->identifier);
4243
    strtok(s, ".");
4244
    strcat(s, "0000");
4245
    sprintf(&s[4], "%04d", (int)(intptr_t)pArg);
4246
    strcat(s, ".ACT");
4247
    BrResFree(pActor->identifier);
4248
    pActor->identifier = BrResStrDup(pActor, s);
4249
    return 0;
4250
}
4251
 
4252
// IDA: void __usercall UniquificateActorsName(br_actor *pUniverse_actor@<EAX>, br_actor *pActor@<EDX>)
4253
void UniquificateActorsName(br_actor* pUniverse_actor, br_actor* pActor) {
4254
    int highest;
4255
    LOG_TRACE("(%p, %p)", pUniverse_actor, pActor);
4256
 
4257
    if (pActor->identifier == NULL || pActor->identifier[0] == '@') {
4258
        return;
4259
    }
4260
    highest = 0;
4261
    DRActorEnumRecurse(pUniverse_actor, (br_actor_enum_cbfn*)CalcHighestNonAmID, &highest);
4262
    DRActorEnumRecurse(pActor, (br_actor_enum_cbfn*)SetID, (void*)(uintptr_t)(highest + 1));
4263
}
4264
 
4265
// IDA: void __usercall AccessoryHeadup(br_actor *pActor@<EAX>, char *pPrefix@<EDX>)
4266
void AccessoryHeadup(br_actor* pActor, char* pPrefix) {
4267
    char s[256];
4268
    //int i; // Pierre-Marie Baty -- unused variable
4269
    //br_actor* original_actor; // Pierre-Marie Baty -- unused variable
4270
    LOG_TRACE("(%p, \"%s\")", pActor, pPrefix);
4271
 
4272
    strcpy(s, pPrefix);
4273
    if (pActor->identifier != NULL) {
4274
        strcat(s, pActor->identifier);
4275
    }
21 pmbaty 4276
    NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, s);
1 pmbaty 4277
}
4278
 
4279
// IDA: br_uint_32 __cdecl CalcHighestNonAmID(br_actor *pActor, int *pHighest)
4280
br_uint_32 CalcHighestNonAmID(br_actor* pActor, int* pHighest) {
4281
    char s[256];
4282
    int number;
4283
    LOG_TRACE("(%p, %p)", pActor, pHighest);
4284
 
4285
    if (pActor->identifier == NULL || pActor->identifier[0] == '&') {
4286
        return 0;
4287
    }
4288
    if (strlen(pActor->identifier) == 12) {
4289
        strcpy(s, &pActor->identifier[4]);
4290
        strtok(s, ".");
4291
        sscanf(s, "%d", &number);
4292
    } else {
4293
        number = 0;
4294
    }
4295
    if (*pHighest < number) {
4296
        *pHighest = number;
4297
    }
4298
    return 0;
4299
}
4300
 
4301
// IDA: br_uint_32 __cdecl SetIDAndDupModel(br_actor *pActor, void *pArg)
4302
br_uint_32 SetIDAndDupModel(br_actor* pActor, void* pArg) {
4303
    char s[256];
4304
    char s2[256];
4305
    br_model* new_model;
4306
    LOG_TRACE("(%p, %p)", pActor, pArg);
4307
 
4308
    if (pActor->identifier == NULL || pActor->identifier[0] == '@') {
4309
        return 0;
4310
    }
4311
    *(int*)(uintptr_t)pArg = *(int*)(uintptr_t)pArg + 1;
4312
    strcpy(s, pActor->identifier);
4313
    s[0] = '@';
4314
    strtok(s, ".");
4315
    strcat(s, "0000");
4316
    sprintf(&s[4], "%04d", *(int*)(uintptr_t)pArg);
4317
    strcpy(s2, s);
4318
    strcat(s, ".ACT");
4319
    BrResFree(pActor->identifier);
4320
    pActor->identifier = BrResStrDup(pActor, s);
4321
    if (pActor->model != NULL) {
4322
        strcat(s2, ".DAT");
4323
        new_model = BrModelAllocate(s2, pActor->model->nvertices, pActor->model->nfaces);
4324
        memcpy(new_model->vertices, pActor->model->vertices, pActor->model->nvertices * sizeof(br_vertex));
4325
        memcpy(new_model->faces, pActor->model->faces, pActor->model->nfaces * sizeof(br_face));
20 pmbaty 4326
        new_model->flags |= 0x80; // FIXME: unknown model flag
1 pmbaty 4327
        BrModelAdd(new_model);
4328
        BrModelUpdate(new_model, BR_MODU_ALL);
4329
        pActor->model = new_model;
4330
        gAdditional_models[gNumber_of_additional_models] = new_model;
4331
        gNumber_of_additional_models++;
4332
    }
4333
    return 0;
4334
}
4335
 
4336
// IDA: void __usercall DuplicateIfNotAmpersand(br_actor *pActor@<EAX>)
4337
void DuplicateIfNotAmpersand(br_actor* pActor) {
4338
    int highest;
4339
    LOG_TRACE("(%p)", pActor);
4340
 
4341
    if (pActor->identifier != NULL && pActor->identifier[0] != '&') {
4342
        highest = 0;
4343
        DRActorEnumRecurse(gUniverse_actor, (br_actor_enum_cbfn*)CalcHighestID, &highest);
4344
        DRActorEnumRecurse(pActor, (br_actor_enum_cbfn*)SetIDAndDupModel, &highest);
4345
    }
4346
}
4347
 
4348
// IDA: void __usercall DropActor(int pIndex@<EAX>)
4349
void DropActor(int pIndex) {
4350
    FILE* f;
4351
    tPath_name the_path;
4352
    char s[256];
4353
    int i;
4354
    int face_bastard;
4355
    int face_count;
4356
    tBounds kev_bounds;
4357
    tFace_ref the_list[50];
4358
    br_scalar nearest_bastard;
4359
    br_scalar distance_bastard;
4360
    //br_scalar ts; // Pierre-Marie Baty -- unused variable
4361
    br_vector3 side_vector;
4362
    //br_angle phi; // Pierre-Marie Baty -- unused variable
4363
    //br_matrix34 mat; // Pierre-Marie Baty -- unused variable
4364
    br_transform new_transform;
4365
    br_actor* a;
4366
    br_actor* last_non_ampersand;
4367
    LOG_TRACE("(%d)", pIndex);
4368
 
4369
    if (PDKeyDown(KEY_CTRL_ANY)) {
4370
        pIndex += 20;
4371
    }
4372
    if (PDKeyDown(KEY_ALT_ANY)) {
4373
        pIndex += 10;
4374
    }
4375
    PathCat(the_path, gApplication_path, "ACCESSRY.TXT");
4376
    f = DRfopen(the_path, "rt");
4377
    for (i = 0; i <= pIndex; i++) {
4378
        if (!feof(f)) {
4379
            GetAString(f, s);
4380
        } else {
4381
            s[0] = '\0';
4382
        }
4383
    }
4384
    if (s[0] != '\0') {
4385
        gLast_actor = LoadActor(s);
4386
        if (gLast_actor != NULL && gLast_actor->model != NULL) {
4387
            BrVector3Set(&kev_bounds.original_bounds.min, -.05f, -.05f, -.05f);
4388
            BrVector3Set(&kev_bounds.original_bounds.max, .05f, .05f, .05f);
4389
            kev_bounds.mat = &gProgram_state.current_car.car_master_actor->t.t.mat;
4390
 
4391
            do {
4392
                face_count = FindFacesInBox(&kev_bounds, the_list, COUNT_OF(the_list));
4393
                BrVector3Scale(&kev_bounds.original_bounds.min, &kev_bounds.original_bounds.min, 2.f);
4394
                BrVector3Scale(&kev_bounds.original_bounds.max, &kev_bounds.original_bounds.max, 2.f);
4395
            } while (face_count == 0);
4396
 
4397
            nearest_bastard = FLT_MAX;
4398
            face_bastard = -1;
4399
            for (i = 0; i < face_count; i++) {
4400
                distance_bastard = DistanceFromFace(gOur_pos, &the_list[i]);
4401
                if (distance_bastard < nearest_bastard) {
4402
                    nearest_bastard = distance_bastard;
4403
                    face_bastard = i;
4404
                }
4405
            }
4406
 
4407
            if (face_bastard >= 0) {
4408
                BrVector3Scale(&gLast_actor->t.t.translate.t, &the_list[face_bastard].normal, -nearest_bastard);
4409
                BrVector3Accumulate(&gLast_actor->t.t.translate.t, gOur_pos);
4410
                if (!PDKeyDown(KEY_SHIFT_ANY)) {
4411
                    if (the_list[face_bastard].normal.v[1] > the_list[face_bastard].normal.v[0] && the_list[face_bastard].normal.v[2] > the_list[face_bastard].normal.v[0]) {
4412
                        BrVector3Set(&side_vector, -1.f, 0.f, 0.f);
4413
                    } else if (the_list[face_bastard].normal.v[0] > the_list[face_bastard].normal.v[1] && the_list[face_bastard].normal.v[2] > the_list[face_bastard].normal.v[1]) {
4414
                        BrVector3Set(&side_vector, 0.f, -1.f, 0.f);
4415
                    } else {
4416
                        BrVector3Set(&side_vector, 0.f, 0.f, -1.f);
4417
                    }
4418
                    new_transform.type = BR_TRANSFORM_LOOK_UP;
4419
                    BrVector3Cross(&new_transform.t.look_up.look, &the_list[face_bastard].normal, &side_vector);
4420
                    BrVector3Copy(&new_transform.t.look_up.up, &the_list[face_bastard].normal);
4421
                    BrVector3Copy(&new_transform.t.look_up.t, &gLast_actor->t.t.translate.t);
4422
                    BrTransformToTransform(&gLast_actor->t, &new_transform);
4423
                }
4424
 
4425
                gKnown_actor = gLast_actor;
4426
                BrVector3Copy(&gActor_centre, &gLast_actor->t.t.translate.t);
4427
                DuplicateIfNotAmpersand(gLast_actor);
4428
                UniquificateActorsName(gUniverse_actor, gLast_actor);
20 pmbaty 4429
                gLast_actor->model->flags |= 0x80; // FIXME: unknown flag
1 pmbaty 4430
                if (gLast_actor->identifier == NULL || gLast_actor->identifier[0] == '&') {
4431
                    last_non_ampersand = gAdditional_actors;
4432
                    for (a = gAdditional_actors->children; a != NULL; a = a->next) {
4433
                        if (a->identifier != NULL && a->identifier[0] != '&') {
4434
                            last_non_ampersand = a;
4435
                        }
4436
                    }
4437
                    BrActorAdd(last_non_ampersand, gLast_actor);
4438
                } else {
4439
                    BrActorAdd(gAdditional_actors, gLast_actor);
4440
                }
4441
                SaveAdditionalStuff();
4442
                AccessoryHeadup(gLast_actor, "Shat out ");
4443
            }
4444
        }
4445
    }
4446
    fclose(f);
4447
}
4448
 
4449
// IDA: void __cdecl DropActor0()
4450
void DropActor0(void) {
4451
    LOG_TRACE("()");
4452
 
4453
    DropActor(0);
4454
}
4455
 
4456
// IDA: void __cdecl DropActor1()
4457
void DropActor1(void) {
4458
    LOG_TRACE("()");
4459
 
4460
    DropActor(1);
4461
}
4462
 
4463
// IDA: void __cdecl DropActor2()
4464
void DropActor2(void) {
4465
    LOG_TRACE("()");
4466
 
4467
    DropActor(2);
4468
}
4469
 
4470
// IDA: void __cdecl DropActor3()
4471
void DropActor3(void) {
4472
    LOG_TRACE("()");
4473
 
4474
    DropActor(3);
4475
}
4476
 
4477
// IDA: void __cdecl DropActor4()
4478
void DropActor4(void) {
4479
    LOG_TRACE("()");
4480
 
4481
    DropActor(4);
4482
}
4483
 
4484
// IDA: void __cdecl DropActor5()
4485
void DropActor5(void) {
4486
    LOG_TRACE("()");
4487
 
4488
    DropActor(5);
4489
}
4490
 
4491
// IDA: void __cdecl DropActor6()
4492
void DropActor6(void) {
4493
    LOG_TRACE("()");
4494
 
4495
    DropActor(6);
4496
}
4497
 
4498
// IDA: void __cdecl DropActor7()
4499
void DropActor7(void) {
4500
    LOG_TRACE("()");
4501
 
4502
    DropActor(7);
4503
}
4504
 
4505
// IDA: void __cdecl DropActor8()
4506
void DropActor8(void) {
4507
    LOG_TRACE("()");
4508
 
4509
    DropActor(8);
4510
}
4511
 
4512
// IDA: void __cdecl DropActor9()
4513
void DropActor9(void) {
4514
    LOG_TRACE("()");
4515
 
4516
    DropActor(9);
4517
}
4518
 
4519
// IDA: br_uint_32 __cdecl IdentifyAccCB(br_actor *pActor, void *pArg)
4520
br_uint_32 IdentifyAccCB(br_actor* pActor, void* pArg) {
4521
    br_scalar distance;
4522
    //char s[256]; // Pierre-Marie Baty -- unused variable
4523
    br_vector3 v;
4524
    LOG_TRACE("(%p, %p)", pActor, pArg);
4525
 
4526
    if (pActor == NULL || pActor->model == NULL) {
4527
        return 0;
4528
    }
4529
    BrVector3Add(&v, &pActor->model->bounds.max, &pActor->model->bounds.min);
4530
    BrVector3InvScale(&v, &v, 2.f);
4531
    BrVector3Accumulate(&v, &pActor->t.t.translate.t);
4532
    BrVector3Sub(&v, &v, gOur_pos);
4533
    distance = BrVector3LengthSquared(&v);
4534
    if (distance < gNearest_distance) {
4535
        gNearest_actor = pActor;
4536
        gNearest_distance = distance;
4537
    }
4538
    return 0;
4539
}
4540
 
4541
// IDA: void __cdecl IdentifyAcc()
4542
void IdentifyAcc(void) {
4543
    LOG_TRACE("()");
4544
 
4545
    gNearest_distance = FLT_MAX;
4546
    gNearest_actor = NULL;
4547
    DRActorEnumRecurse(gAdditional_actors, (br_actor_enum_cbfn*)IdentifyAccCB, NULL);
4548
    if (gNearest_actor != NULL) {
4549
        gLast_actor = gNearest_actor;
4550
        AccessoryHeadup(gNearest_actor, "Locked onto ");
4551
    }
4552
}
4553
 
4554
// IDA: br_uint_32 __cdecl DelGrooveRef(br_actor *pActor, void *pArg)
4555
br_uint_32 DelGrooveRef(br_actor* pActor, void* pArg) {
4556
    tGroovidelic_spec* the_groove;
4557
    int i;
4558
    LOG_TRACE("(%p, %p)", pActor, pArg);
4559
 
4560
    for (i = 0; i < gGroovidelics_array_size; i++) {
4561
        the_groove = &gGroovidelics_array[i];
4562
        if (the_groove->actor == pActor) {
4563
            the_groove->owner = -999;
4564
        }
4565
    }
4566
    return 0;
4567
}
4568
 
4569
// IDA: br_uint_32 __cdecl DelReferencedModels(br_actor *pActor, void *pArg)
4570
br_uint_32 DelReferencedModels(br_actor* pActor, void* pArg) {
4571
    //tGroovidelic_spec* the_groove; // Pierre-Marie Baty -- unused variable
4572
    int i;
4573
    LOG_TRACE("(%p, %p)", pActor, pArg);
4574
 
4575
    for (i = 0; i < gNumber_of_additional_models; i++) {
4576
        if (pActor->model == gAdditional_models[i]) {
4577
            BrModelRemove(pActor->model);
4578
            BrModelFree(pActor->model);
4579
            memmove(&gAdditional_models[i], &gAdditional_models[i + 1], (gNumber_of_additional_models - i - 1) * sizeof(br_model*));
4580
            gNumber_of_additional_models--;
4581
        }
4582
    }
4583
    return 0;
4584
}
4585
 
4586
// IDA: void __cdecl DeleteAcc()
4587
void DeleteAcc(void) {
4588
    LOG_TRACE("()");
4589
 
4590
    if (gLast_actor == NULL) {
4591
        return;
4592
    }
4593
    AccessoryHeadup(gLast_actor, "Murdered ");
4594
    DRActorEnumRecurse(gLast_actor, (br_actor_enum_cbfn*)DelReferencedModels, NULL);
4595
    DRActorEnumRecurse(gLast_actor, (br_actor_enum_cbfn*)DelGrooveRef, NULL);
4596
    BrActorRemove(gLast_actor);
4597
    BrActorFree(gLast_actor);
4598
    gLast_actor = NULL;
4599
    SaveAdditionalStuff();
4600
}
4601
 
4602
// IDA: br_uint_32 __cdecl OffsetModel(br_actor *pActor, void *pArg)
4603
br_uint_32 OffsetModel(br_actor* pActor, void* pArg) {
4604
    int i;
4605
    LOG_TRACE("(%p, %p)", pActor, pArg);
4606
 
4607
    if (pActor->model == NULL) {
4608
        return 0;
4609
    }
4610
    for (i = 0; i < pActor->model->nvertices; i++) {
4611
        BrVector3Accumulate(&pActor->model->vertices[i].p, (br_vector3*)pArg);
4612
    }
4613
    return 0;
4614
}
4615
 
4616
// IDA: void __usercall OffsetActor(br_actor *pActor@<EAX>, br_vector3 *pOffset@<EDX>)
4617
void OffsetActor(br_actor* pActor, br_vector3* pOffset) {
4618
    LOG_TRACE("(%p, %p)", pActor, pOffset);
4619
 
4620
    DRActorEnumRecurse(pActor, (br_actor_enum_cbfn*)OffsetModel, pOffset);
4621
}
4622
 
4623
// IDA: void __usercall CentreActor(br_actor *pActor@<EAX>, br_vector3 *pOffset@<EDX>)
4624
void CentreActor(br_actor* pActor, br_vector3* pOffset) {
4625
    LOG_TRACE("(%p, %p)", pActor, pOffset);
4626
 
4627
    if (pActor->model == NULL) {
4628
        BrVector3Set(pOffset, 0.f, 0.f, 0.f);
4629
    } else if (gKnown_actor == gLast_actor) {
4630
        BrVector3Scale(pOffset, &gActor_centre, -1.f);
4631
    } else {
4632
        BrVector3Add(pOffset, &pActor->model->bounds.max, &pActor->model->bounds.min);
4633
        BrVector3Scale(pOffset, pOffset, -2.f);
4634
    }
4635
    DRActorEnumRecurse(pActor, (br_actor_enum_cbfn*)OffsetModel, pOffset);
4636
    BrVector3Scale(pOffset, pOffset, -1.f);
4637
}
4638
 
4639
// IDA: void __cdecl SnapAccToVertical()
4640
void SnapAccToVertical(void) {
4641
    LOG_TRACE("()");
4642
 
4643
    if (gLast_actor == NULL) {
4644
        return;
4645
    }
4646
    BrVector3Set((br_vector3*)gLast_actor->t.t.mat.m[0], 1.f, 0.f, 0.f);
4647
    BrVector3Set((br_vector3*)gLast_actor->t.t.mat.m[1], 0.f, 1.f, 0.f);
4648
    BrVector3Set((br_vector3*)gLast_actor->t.t.mat.m[2], 0.f, 0.f, 1.f);
4649
    SaveAdditionalStuff();
4650
}
4651
 
4652
// IDA: void __usercall RotateAccessory(br_angle pAngle@<EAX>)
4653
void RotateAccessory(br_angle pAngle) {
4654
    br_vector3 mr_offset;
4655
    LOG_TRACE("(%d)", pAngle);
4656
 
4657
    if (gLast_actor == NULL) {
4658
        return;
4659
    }
4660
    if (!gSpec_vol_mode && gLast_actor->identifier != NULL && gLast_actor->identifier[0] == '@') {
4661
        CentreActor(gLast_actor, &mr_offset);
4662
    }
4663
    switch (gCurrent_rotate_mode) {
4664
    case eRotate_mode_x:
4665
        BrMatrix34PreRotateX(&gLast_actor->t.t.mat, pAngle);
4666
        break;
4667
    case eRotate_mode_y:
4668
        BrMatrix34PreRotateY(&gLast_actor->t.t.mat, pAngle);
4669
        break;
4670
    case eRotate_mode_z:
4671
        BrMatrix34PreRotateZ(&gLast_actor->t.t.mat, pAngle);
4672
        break;
4673
    }
4674
    if (!gSpec_vol_mode && gLast_actor->identifier != NULL && gLast_actor->identifier[0] == '@') {
4675
        DRActorEnumRecurseWithTrans(gLast_actor, NULL, ApplyTransToModels, NULL);
4676
        OffsetActor(gLast_actor, &mr_offset);
4677
    }
4678
    SaveAdditionalStuff();
4679
}
4680
 
4681
// IDA: void __cdecl ScaleAccessory(float pScaling_factor)
4682
void ScaleAccessory(float pScaling_factor) {
4683
    br_vector3 mr_offset;
4684
    LOG_TRACE("(%f)", pScaling_factor);
4685
 
4686
    if (gLast_actor == NULL) {
4687
        return;
4688
    }
4689
    if (!gSpec_vol_mode && gLast_actor->identifier != NULL && gLast_actor->identifier[0] == '@') {
4690
        CentreActor(gLast_actor, &mr_offset);
4691
    }
4692
    switch (gCurrent_scale_mode) {
4693
    case eScale_mode_all:
4694
        BrMatrix34PreScale(&gLast_actor->t.t.mat, pScaling_factor, pScaling_factor, pScaling_factor);
4695
        break;
4696
    case eScale_mode_x:
4697
        BrMatrix34PreScale(&gLast_actor->t.t.mat, pScaling_factor, 1.f, 1.f);
4698
        break;
4699
    case eScale_mode_y:
4700
        BrMatrix34PreScale(&gLast_actor->t.t.mat, 1.f, pScaling_factor, 1.f);
4701
        break;
4702
    case eScale_mode_z:
4703
        BrMatrix34PreScale(&gLast_actor->t.t.mat, 1.f, 1.f, pScaling_factor);
4704
        break;
4705
    }
4706
    if (!gSpec_vol_mode && gLast_actor->identifier != NULL && gLast_actor->identifier[0] == '@') {
4707
        DRActorEnumRecurseWithTrans(gLast_actor, NULL, ApplyTransToModels, NULL);
4708
        OffsetActor(gLast_actor, &mr_offset);
4709
    }
4710
    SaveAdditionalStuff();
4711
}
4712
 
4713
// IDA: void __cdecl MoveAccessory(br_scalar pX_shift, br_scalar pY_shift, br_scalar pZ_shift)
4714
void MoveAccessory(br_scalar pX_shift, br_scalar pY_shift, br_scalar pZ_shift) {
4715
    br_vector3 v;
4716
    LOG_TRACE("(%f, %f, %f)", pX_shift, pY_shift, pZ_shift);
4717
 
4718
    if (gLast_actor == NULL) {
4719
        return;
4720
    }
4721
    BrVector3SetFloat(&v, pX_shift, pY_shift, pZ_shift);
4722
    BrVector3Accumulate(&gLast_actor->t.t.translate.t, &v);
4723
    SaveAdditionalStuff();
4724
}
4725
 
4726
// IDA: void __cdecl RotateAccL()
4727
void RotateAccL(void) {
4728
    LOG_TRACE("()");
4729
 
4730
    RotateAccessory(BrDegreeToAngle(90));
4731
}
4732
 
4733
// IDA: void __cdecl RotateAccL2()
4734
void RotateAccL2(void) {
4735
    LOG_TRACE("()");
4736
 
4737
    RotateAccessory(BrDegreeToAngle(15));
4738
}
4739
 
4740
// IDA: void __cdecl RotateAccL3()
4741
void RotateAccL3(void) {
4742
    LOG_TRACE("()");
4743
 
4744
    RotateAccessory(BrDegreeToAngle(5));
4745
}
4746
 
4747
// IDA: void __cdecl RotateAccL4()
4748
void RotateAccL4(void) {
4749
    LOG_TRACE("()");
4750
 
4751
    RotateAccessory(BrDegreeToAngle(1));
4752
}
4753
 
4754
// IDA: void __cdecl RotateAccR()
4755
void RotateAccR(void) {
4756
    LOG_TRACE("()");
4757
 
4758
    RotateAccessory(BrDegreeToAngle(270));
4759
}
4760
 
4761
// IDA: void __cdecl RotateAccR2()
4762
void RotateAccR2(void) {
4763
    LOG_TRACE("()");
4764
 
4765
    RotateAccessory(BrDegreeToAngle(345));
4766
}
4767
 
4768
// IDA: void __cdecl RotateAccR3()
4769
void RotateAccR3(void) {
4770
    LOG_TRACE("()");
4771
 
4772
    RotateAccessory(BrDegreeToAngle(355));
4773
}
4774
 
4775
// IDA: void __cdecl RotateAccR4()
4776
void RotateAccR4(void) {
4777
    LOG_TRACE("()");
4778
 
4779
    RotateAccessory(BrDegreeToAngle(359));
4780
}
4781
 
4782
// IDA: void __cdecl CycleAccRotate()
4783
void CycleAccRotate(void) {
4784
    LOG_TRACE("()");
4785
 
4786
    gCurrent_rotate_mode = (gCurrent_rotate_mode == eRotate_mode_z) ? eRotate_mode_x : (gCurrent_rotate_mode + 1);
4787
    switch (gCurrent_rotate_mode) {
4788
    case eRotate_mode_x:
21 pmbaty 4789
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Rotate mode: X");
1 pmbaty 4790
        break;
4791
    case eRotate_mode_y:
21 pmbaty 4792
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Rotate mode: Y");
1 pmbaty 4793
        break;
4794
    case eRotate_mode_z:
21 pmbaty 4795
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Rotate mode: Z");
1 pmbaty 4796
        break;
4797
    }
4798
}
4799
 
4800
// IDA: void __cdecl CycleAccScale()
4801
void CycleAccScale(void) {
4802
    LOG_TRACE("()");
4803
 
4804
    gCurrent_scale_mode = (gCurrent_scale_mode == eScale_mode_z) ? eScale_mode_all : (gCurrent_scale_mode + 1);
4805
    switch (gCurrent_scale_mode) {
4806
    case eScale_mode_all:
21 pmbaty 4807
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Scale mode: ALL");
1 pmbaty 4808
        break;
4809
    case eScale_mode_x:
21 pmbaty 4810
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Scale mode: X");
1 pmbaty 4811
        break;
4812
    case eScale_mode_y:
21 pmbaty 4813
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Scale mode: Y");
1 pmbaty 4814
        break;
4815
    case eScale_mode_z:
21 pmbaty 4816
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "Scale mode: Z");
1 pmbaty 4817
        break;
4818
    }
4819
}
4820
 
4821
// IDA: void __cdecl ScaleAccUp2()
4822
void ScaleAccUp2(void) {
4823
    LOG_TRACE("()");
4824
 
4825
    ScaleAccessory(1.2f);
4826
}
4827
 
4828
// IDA: void __cdecl ScaleAccUp3()
4829
void ScaleAccUp3(void) {
4830
    LOG_TRACE("()");
4831
 
4832
    ScaleAccessory(1.05f);
4833
}
4834
 
4835
// IDA: void __cdecl ScaleAccUp4()
4836
void ScaleAccUp4(void) {
4837
    LOG_TRACE("()");
4838
 
4839
    ScaleAccessory(1.002f);
4840
}
4841
 
4842
// IDA: void __cdecl ScaleAccDown2()
4843
void ScaleAccDown2(void) {
4844
    LOG_TRACE("()");
4845
 
4846
    ScaleAccessory(1 / 1.2f);
4847
}
4848
 
4849
// IDA: void __cdecl ScaleAccDown3()
4850
void ScaleAccDown3(void) {
4851
    LOG_TRACE("()");
4852
 
4853
    ScaleAccessory(1 / 1.05f);
4854
}
4855
 
4856
// IDA: void __cdecl ScaleAccDown4()
4857
void ScaleAccDown4(void) {
4858
    LOG_TRACE("()");
4859
 
4860
    ScaleAccessory(1 / 1.002f);
4861
}
4862
 
4863
// IDA: void __cdecl MoveXAccL()
4864
void MoveXAccL(void) {
4865
    LOG_TRACE("()");
4866
 
4867
    MoveAccessory(1.f, 0.f, 0.f);
4868
}
4869
 
4870
// IDA: void __cdecl MoveXAccL2()
4871
void MoveXAccL2(void) {
4872
    LOG_TRACE("()");
4873
 
4874
    MoveAccessory(.2f, 0.f, 0.f);
4875
}
4876
 
4877
// IDA: void __cdecl MoveXAccL3()
4878
void MoveXAccL3(void) {
4879
    LOG_TRACE("()");
4880
 
4881
    MoveAccessory(.02f, 0.f, 0.f);
4882
}
4883
 
4884
// IDA: void __cdecl MoveXAccL4()
4885
void MoveXAccL4(void) {
4886
    LOG_TRACE("()");
4887
 
4888
    MoveAccessory(.002f, 0.f, 0.f);
4889
}
4890
 
4891
// IDA: void __cdecl MoveXAccR()
4892
void MoveXAccR(void) {
4893
    LOG_TRACE("()");
4894
 
4895
    MoveAccessory(-1.f, 0.f, 0.f);
4896
}
4897
 
4898
// IDA: void __cdecl MoveXAccR2()
4899
void MoveXAccR2(void) {
4900
    LOG_TRACE("()");
4901
 
4902
    MoveAccessory(-.2f, 0.f, 0.f);
4903
}
4904
 
4905
// IDA: void __cdecl MoveXAccR3()
4906
void MoveXAccR3(void) {
4907
    LOG_TRACE("()");
4908
 
4909
    MoveAccessory(-.02f, 0.f, 0.f);
4910
}
4911
 
4912
// IDA: void __cdecl MoveXAccR4()
4913
void MoveXAccR4(void) {
4914
    LOG_TRACE("()");
4915
 
4916
    MoveAccessory(-.002f, 0.f, 0.f);
4917
}
4918
 
4919
// IDA: void __cdecl MoveYAccL()
4920
void MoveYAccL(void) {
4921
    LOG_TRACE("()");
4922
 
4923
    MoveAccessory(0.f, 1.f, 0.f);
4924
}
4925
 
4926
// IDA: void __cdecl MoveYAccL2()
4927
void MoveYAccL2(void) {
4928
    LOG_TRACE("()");
4929
 
4930
    MoveAccessory(0.f, .2f, 0.f);
4931
}
4932
 
4933
// IDA: void __cdecl MoveYAccL3()
4934
void MoveYAccL3(void) {
4935
    LOG_TRACE("()");
4936
 
4937
    MoveAccessory(0.f, .02f, 0.f);
4938
}
4939
 
4940
// IDA: void __cdecl MoveYAccL4()
4941
void MoveYAccL4(void) {
4942
    LOG_TRACE("()");
4943
 
4944
    MoveAccessory(0.f, .002f, 0.f);
4945
}
4946
 
4947
// IDA: void __cdecl MoveYAccR()
4948
void MoveYAccR(void) {
4949
    LOG_TRACE("()");
4950
 
4951
    MoveAccessory(0.f, -1.f, 0.f);
4952
}
4953
 
4954
// IDA: void __cdecl MoveYAccR2()
4955
void MoveYAccR2(void) {
4956
    LOG_TRACE("()");
4957
 
4958
    MoveAccessory(0.f, -.2f, 0.f);
4959
}
4960
 
4961
// IDA: void __cdecl MoveYAccR3()
4962
void MoveYAccR3(void) {
4963
    LOG_TRACE("()");
4964
 
4965
    MoveAccessory(0.f, -.02f, 0.f);
4966
}
4967
 
4968
// IDA: void __cdecl MoveYAccR4()
4969
void MoveYAccR4(void) {
4970
    LOG_TRACE("()");
4971
 
4972
    MoveAccessory(0.f, -.002f, 0.f);
4973
}
4974
 
4975
// IDA: void __cdecl MoveZAccL()
4976
void MoveZAccL(void) {
4977
    LOG_TRACE("()");
4978
 
4979
    MoveAccessory(0.f, 0.f, 1.f);
4980
}
4981
 
4982
// IDA: void __cdecl MoveZAccL2()
4983
void MoveZAccL2(void) {
4984
    LOG_TRACE("()");
4985
 
4986
    MoveAccessory(0.f, 0.f, .2f);
4987
}
4988
 
4989
// IDA: void __cdecl MoveZAccL3()
4990
void MoveZAccL3(void) {
4991
    LOG_TRACE("()");
4992
 
4993
    MoveAccessory(0.f, 0.f, .02f);
4994
}
4995
 
4996
// IDA: void __cdecl MoveZAccL4()
4997
void MoveZAccL4(void) {
4998
    LOG_TRACE("()");
4999
 
5000
    MoveAccessory(0.f, 0.f, .002f);
5001
}
5002
 
5003
// IDA: void __cdecl MoveZAccR()
5004
void MoveZAccR(void) {
5005
    LOG_TRACE("()");
5006
 
5007
    MoveAccessory(0.f, 0.f, -1.f);
5008
}
5009
 
5010
// IDA: void __cdecl MoveZAccR2()
5011
void MoveZAccR2(void) {
5012
    LOG_TRACE("()");
5013
 
5014
    MoveAccessory(0.f, 0.f, -.2f);
5015
}
5016
 
5017
// IDA: void __cdecl MoveZAccR3()
5018
void MoveZAccR3(void) {
5019
    LOG_TRACE("()");
5020
 
5021
    MoveAccessory(0.f, 0.f, -.02f);
5022
}
5023
 
5024
// IDA: void __cdecl MoveZAccR4()
5025
void MoveZAccR4(void) {
5026
    LOG_TRACE("()");
5027
 
5028
    MoveAccessory(0.f, 0.f, -.002f);
5029
}
5030
 
5031
// IDA: br_material* __cdecl GetInternalMat()
5032
br_material* GetInternalMat(void) {
5033
    LOG_TRACE("()");
5034
 
5035
    return BrMaterialFind("SPECVOL.MAT");
5036
}
5037
 
5038
// IDA: br_material* __cdecl GetExternalMat()
5039
br_material* GetExternalMat(void) {
5040
    LOG_TRACE("()");
5041
 
5042
    return BrMaterialFind("SPECVOL2.MAT");
5043
}
5044
 
5045
#define DrVertexSet(V, X, Y, Z) \
5046
    do {                        \
5047
        (V)[0] = (X);           \
5048
        (V)[1] = (Y);           \
5049
        (V)[2] = (Z);           \
5050
    } while (0)
5051
 
5052
// IDA: void __usercall BuildSpecVolModel(tSpecial_volume *pSpec@<EAX>, int pIndex@<EDX>, br_material *pInt_mat@<EBX>, br_material *pExt_mat@<ECX>)
5053
void BuildSpecVolModel(tSpecial_volume* pSpec, int pIndex, br_material* pInt_mat, br_material* pExt_mat) {
5054
    int i;
5055
    //int j; // Pierre-Marie Baty -- unused variable
5056
    int temp;
5057
    //tSpecial_volume* v; // Pierre-Marie Baty -- unused variable
5058
    br_actor* actor;
5059
    br_model* model;
5060
    LOG_TRACE("(%p, %d, %p, %p)", pSpec, pIndex, pInt_mat, pExt_mat);
5061
 
5062
    actor = BrActorAllocate(BR_ACTOR_MODEL, NULL);
5063
    BrMatrix34Copy(&actor->t.t.mat, &pSpec->mat);
5064
    actor->render_style = BR_RSTYLE_FACES;
5065
    model = BrModelAllocate("", 12, 24);
5066
    model->flags |= BR_MODF_KEEP_ORIGINAL | BR_MODF_DONT_WELD;
5067
    BrVector3Set(&model->vertices[0].p, 1.f, -1.f, -1.f);
5068
    BrVector2Set(&model->vertices[0].map, 1.f, 0.f);
5069
    BrVector3Set(&model->vertices[1].p, -1.f, -1.f, -1.f);
5070
    BrVector2Set(&model->vertices[1].map, 0.f, 0.f);
5071
    BrVector3Set(&model->vertices[2].p, -1.f, 1.f, -1.f);
5072
    BrVector2Set(&model->vertices[2].map, 0.f, 1.f);
5073
    BrVector3Set(&model->vertices[3].p, 1.f, 1.f, -1.f);
5074
    BrVector2Set(&model->vertices[3].map, 1.f, 1.f);
5075
    BrVector3Set(&model->vertices[4].p, 1.f, -1.f, 1.f);
5076
    BrVector2Set(&model->vertices[4].map, 1.f, 1.f);
5077
    BrVector3Set(&model->vertices[5].p, -1.f, -1.f, 1.f);
5078
    BrVector2Set(&model->vertices[5].map, 0.f, 1.f);
5079
    BrVector3Set(&model->vertices[6].p, -1.f, 1.f, 1.f);
5080
    BrVector2Set(&model->vertices[6].map, 0.f, 0.f);
5081
    BrVector3Set(&model->vertices[7].p, 1.f, 1.f, 1.f);
5082
    BrVector2Set(&model->vertices[7].map, 1.f, 0.f);
5083
    BrVector3Set(&model->vertices[8].p, 1.f, -1.f, -1.f);
5084
    BrVector2Set(&model->vertices[8].map, 0.f, 1.f);
5085
    BrVector3Set(&model->vertices[9].p, 1.f, -1.f, 1.f);
5086
    BrVector2Set(&model->vertices[9].map, 0.f, 0.f);
5087
    BrVector3Set(&model->vertices[10].p, -1.f, -1.f, -1.f);
5088
    BrVector2Set(&model->vertices[10].map, 1.f, 1.f);
5089
    BrVector3Set(&model->vertices[11].p, -1.f, -1.f, 1.f);
5090
    BrVector2Set(&model->vertices[11].map, 1.f, 0.f);
5091
 
5092
    DrVertexSet(model->faces[0].vertices, 0, 3, 1);
5093
    DrVertexSet(model->faces[1].vertices, 1, 3, 2);
5094
    DrVertexSet(model->faces[2].vertices, 3, 7, 2);
5095
    DrVertexSet(model->faces[3].vertices, 2, 7, 6);
5096
    DrVertexSet(model->faces[4].vertices, 6, 7, 4);
5097
    DrVertexSet(model->faces[5].vertices, 6, 4, 5);
5098
    DrVertexSet(model->faces[6].vertices, 0, 5, 4);
5099
    DrVertexSet(model->faces[7].vertices, 1, 5, 0);
5100
    DrVertexSet(model->faces[8].vertices, 9, 7, 8);
5101
    DrVertexSet(model->faces[9].vertices, 8, 7, 3);
5102
    DrVertexSet(model->faces[10].vertices, 11, 2, 6);
5103
    DrVertexSet(model->faces[11].vertices, 11, 10, 2);
5104
 
5105
    memcpy(&model->faces[12], model->faces, 12 * sizeof(br_face));
5106
    for (i = 12; i < 24; i++) {
5107
        temp = model->faces[i].vertices[0];
5108
        model->faces[i].vertices[0] = model->faces[i].vertices[1];
5109
        model->faces[i].vertices[1] = temp;
5110
    }
5111
    model->faces[5].material = model->faces[4].material = model->faces[1].material = model->faces[0].material = DRMaterialClone(pExt_mat);
5112
    model->faces[11].material = model->faces[10].material = model->faces[9].material = model->faces[8].material = DRMaterialClone(pExt_mat);
5113
    model->faces[7].material = model->faces[6].material = model->faces[3].material = model->faces[2].material = DRMaterialClone(pExt_mat);
5114
    model->faces[17].material = model->faces[16].material = model->faces[13].material = model->faces[12].material = DRMaterialClone(pInt_mat);
5115
    model->faces[23].material = model->faces[22].material = model->faces[21].material = model->faces[20].material = DRMaterialClone(pInt_mat);
5116
    model->faces[19].material = model->faces[18].material = model->faces[15].material = model->faces[14].material = DRMaterialClone(pInt_mat);
5117
    BrModelUpdate(model, BR_MODU_ALL);
5118
    actor->model = model;
5119
    BrActorAdd(gNon_track_actor, actor);
5120
    gSpec_vol_actors[pIndex] = actor;
5121
    SetSpecVolMatSize(actor);
5122
}
5123
 
5124
#undef DrVertexSet
5125
 
5126
// IDA: void __usercall DropSpecVol(int pIndex@<EAX>)
5127
void DropSpecVol(int pIndex) {
5128
    FILE* f;
5129
    tPath_name the_path;
5130
    int i;
5131
    int spec_count;
5132
    tSpecial_volume spec;
5133
    tSpecial_volume* new_specs;
5134
    char s[256];
5135
    LOG_TRACE("(%d)", pIndex);
5136
 
5137
    PathCat(the_path, gApplication_path, "SPECVOL.TXT");
5138
    f = DRfopen(the_path, "rt");
5139
    if (f == NULL) {
5140
        return;
5141
    }
5142
    spec_count = GetAnInt(f);
5143
    // pIndex = 1 means first special volume
5144
    if (pIndex > spec_count) {
5145
        fclose(f);
5146
        return;
5147
    }
5148
    for (i = 0; i < pIndex; i++) {
5149
        ParseSpecialVolume(f, &spec, NULL);
5150
    }
5151
    spec.no_mat = 0;
5152
    BrMatrix34Copy(&spec.mat, &gProgram_state.current_car.car_master_actor->t.t.mat);
5153
    new_specs = BrMemAllocate((gProgram_state.special_volume_count + 1) * sizeof(tSpecial_volume), kMem_new_special_vol);
5154
    memcpy(new_specs, gProgram_state.special_volumes, gProgram_state.special_volume_count * sizeof(tSpecial_volume));
5155
    memcpy(&new_specs[gProgram_state.special_volume_count], &spec, sizeof(tSpecial_volume));
5156
    gProgram_state.special_volume_count++;
5157
    BrMemFree(gProgram_state.special_volumes);
5158
    gProgram_state.special_volumes = new_specs;
5159
    BuildSpecVolModel(&spec, gProgram_state.special_volume_count - 1, GetInternalMat(), GetExternalMat());
5160
    gLast_actor = gSpec_vol_actors[gProgram_state.special_volume_count - 1];
5161
    UpdateSpecVol();
5162
    sprintf(s, "Shat out special volume #%d (type %d)", gProgram_state.special_volume_count - 1, pIndex);
21 pmbaty 5163
    NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, s);
1 pmbaty 5164
    SaveSpecialVolumes();
5165
    fclose(f);
5166
}
5167
 
5168
// IDA: void __cdecl DropSpecVol0()
5169
void DropSpecVol0(void) {
5170
    LOG_TRACE("()");
5171
}
5172
 
5173
// IDA: void __cdecl DropSpecVol1()
5174
void DropSpecVol1(void) {
5175
    LOG_TRACE("()");
5176
 
5177
    DropSpecVol(1);
5178
}
5179
 
5180
// IDA: void __cdecl DropSpecVol2()
5181
void DropSpecVol2(void) {
5182
    LOG_TRACE("()");
5183
 
5184
    DropSpecVol(2);
5185
}
5186
 
5187
// IDA: void __cdecl DropSpecVol3()
5188
void DropSpecVol3(void) {
5189
    LOG_TRACE("()");
5190
 
5191
    DropSpecVol(3);
5192
}
5193
 
5194
// IDA: void __cdecl DropSpecVol4()
5195
void DropSpecVol4(void) {
5196
    LOG_TRACE("()");
5197
 
5198
    DropSpecVol(4);
5199
}
5200
 
5201
// IDA: void __cdecl DropSpecVol5()
5202
void DropSpecVol5(void) {
5203
    LOG_TRACE("()");
5204
 
5205
    DropSpecVol(5);
5206
}
5207
 
5208
// IDA: void __cdecl DropSpecVol6()
5209
void DropSpecVol6(void) {
5210
    LOG_TRACE("()");
5211
 
5212
    DropSpecVol(6);
5213
}
5214
 
5215
// IDA: void __cdecl DropSpecVol7()
5216
void DropSpecVol7(void) {
5217
    LOG_TRACE("()");
5218
 
5219
    DropSpecVol(7);
5220
}
5221
 
5222
// IDA: void __cdecl DropSpecVol8()
5223
void DropSpecVol8(void) {
5224
    LOG_TRACE("()");
5225
 
5226
    DropSpecVol(8);
5227
}
5228
 
5229
// IDA: void __cdecl DropSpecVol9()
5230
void DropSpecVol9(void) {
5231
    LOG_TRACE("()");
5232
 
5233
    DropSpecVol(9);
5234
}
5235
 
5236
// IDA: void __cdecl IdentifySpecVol()
5237
void IdentifySpecVol(void) {
5238
    int i;
5239
    int min_index;
5240
    tSpecial_volume* v;
5241
    br_scalar min_d;
5242
    br_scalar d;
5243
    br_vector3* p;
5244
    char s[256];
5245
    LOG_TRACE("()");
5246
 
5247
    min_d = FLT_MAX;
5248
    min_index = -1;
5249
    p = &gProgram_state.current_car.pos;
5250
    for (i = 0; i < gProgram_state.special_volume_count; i++) {
5251
        v = &gProgram_state.special_volumes[i];
5252
        d = Vector3DistanceSquared((br_vector3*)v->mat.m[3], p);
5253
        if (d < min_d) {
5254
            min_index = i;
5255
            min_d = d;
5256
        }
5257
    }
5258
    if (min_index < 0) {
5259
        gLast_actor = NULL;
21 pmbaty 5260
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "No special volumes to lock onto");
1 pmbaty 5261
    } else {
5262
        sprintf(s, "Locked onto Special Volume #%d", min_index);
21 pmbaty 5263
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, s);
1 pmbaty 5264
        gLast_actor = gSpec_vol_actors[min_index];
5265
    }
5266
}
5267
 
5268
// IDA: void __usercall DelSpecVolumeGraph(int pIndex@<EAX>)
5269
void DelSpecVolumeGraph(int pIndex) {
5270
    br_actor* actor;
5271
    br_model* model;
5272
    LOG_TRACE("(%d)", pIndex);
5273
 
5274
    actor = gSpec_vol_actors[pIndex];
5275
    model = actor->model;
5276
 
5277
    BrMaterialRemove(model->faces[5].material);
5278
    BrMaterialRemove(model->faces[11].material);
5279
    BrMaterialRemove(model->faces[7].material);
5280
    BrMaterialRemove(model->faces[17].material);
5281
    BrMaterialRemove(model->faces[23].material);
5282
    BrMaterialRemove(model->faces[19].material);
5283
    BrMaterialFree(model->faces[5].material);
5284
    BrMaterialFree(model->faces[11].material);
5285
    BrMaterialFree(model->faces[7].material);
5286
    BrMaterialFree(model->faces[17].material);
5287
    BrMaterialFree(model->faces[23].material);
5288
    BrMaterialFree(model->faces[19].material);
5289
    BrModelRemove(model);
5290
    BrModelFree(model);
5291
    BrActorRemove(actor);
5292
    BrActorFree(actor);
5293
}
5294
 
5295
// IDA: void __cdecl DeleteSpecVol()
5296
void DeleteSpecVol(void) {
5297
    int index;
5298
    LOG_TRACE("()");
5299
 
5300
    index = FindSpecVolIndex(gLast_actor);
5301
    if (index < 0) {
5302
        return;
5303
    }
5304
    DelSpecVolumeGraph(index);
5305
    memmove(&gProgram_state.special_volumes[index], &gProgram_state.special_volumes[index + 1], (gProgram_state.special_volume_count - index - 1) * sizeof(tSpecial_volume));
5306
    memmove(&gSpec_vol_actors[index], &gSpec_vol_actors[index + 1], (gProgram_state.special_volume_count - index - 1) * sizeof(br_actor*));
5307
    gProgram_state.special_volume_count--;
21 pmbaty 5308
    NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -2, "There's been a special volumes MURDER!!");
1 pmbaty 5309
    gLast_actor = NULL;
5310
    if (&gProgram_state.special_volumes[index] < gDefault_water_spec_vol) {
5311
        gDefault_water_spec_vol--;
5312
    }
5313
    SaveSpecialVolumes();
5314
}
5315
 
5316
// IDA: void __cdecl RotateSpecVolL()
5317
void RotateSpecVolL(void) {
5318
    LOG_TRACE("()");
5319
 
5320
    RotateAccL();
5321
}
5322
 
5323
// IDA: void __cdecl RotateSpecVolL2()
5324
void RotateSpecVolL2(void) {
5325
    LOG_TRACE("()");
5326
 
5327
    RotateAccL2();
5328
}
5329
 
5330
// IDA: void __cdecl RotateSpecVolL3()
5331
void RotateSpecVolL3(void) {
5332
    LOG_TRACE("()");
5333
 
5334
    RotateAccL3();
5335
}
5336
 
5337
// IDA: void __cdecl RotateSpecVolL4()
5338
void RotateSpecVolL4(void) {
5339
    LOG_TRACE("()");
5340
 
5341
    RotateAccL4();
5342
}
5343
 
5344
// IDA: void __cdecl RotateSpecVolR()
5345
void RotateSpecVolR(void) {
5346
    LOG_TRACE("()");
5347
 
5348
    RotateAccR();
5349
}
5350
 
5351
// IDA: void __cdecl RotateSpecVolR2()
5352
void RotateSpecVolR2(void) {
5353
    LOG_TRACE("()");
5354
 
5355
    RotateAccR2();
5356
}
5357
 
5358
// IDA: void __cdecl RotateSpecVolR3()
5359
void RotateSpecVolR3(void) {
5360
    LOG_TRACE("()");
5361
 
5362
    RotateAccR3();
5363
}
5364
 
5365
// IDA: void __cdecl RotateSpecVolR4()
5366
void RotateSpecVolR4(void) {
5367
    LOG_TRACE("()");
5368
 
5369
    RotateAccR4();
5370
}
5371
 
5372
// IDA: void __cdecl CycleSpecVolRotate()
5373
void CycleSpecVolRotate(void) {
5374
    LOG_TRACE("()");
5375
 
5376
    CycleAccRotate();
5377
}
5378
 
5379
// IDA: void __cdecl CycleSpecVolScale()
5380
void CycleSpecVolScale(void) {
5381
    LOG_TRACE("()");
5382
 
5383
    CycleAccScale();
5384
}
5385
 
5386
// IDA: void __cdecl ScaleSpecVolUp2()
5387
void ScaleSpecVolUp2(void) {
5388
    LOG_TRACE("()");
5389
 
5390
    ScaleAccUp2();
5391
}
5392
 
5393
// IDA: void __cdecl ScaleSpecVolUp3()
5394
void ScaleSpecVolUp3(void) {
5395
    LOG_TRACE("()");
5396
 
5397
    ScaleAccUp3();
5398
}
5399
 
5400
// IDA: void __cdecl ScaleSpecVolUp4()
5401
void ScaleSpecVolUp4(void) {
5402
    LOG_TRACE("()");
5403
 
5404
    ScaleAccUp4();
5405
}
5406
 
5407
// IDA: void __cdecl ScaleSpecVolDown2()
5408
void ScaleSpecVolDown2(void) {
5409
    LOG_TRACE("()");
5410
 
5411
    ScaleAccDown2();
5412
}
5413
 
5414
// IDA: void __cdecl ScaleSpecVolDown3()
5415
void ScaleSpecVolDown3(void) {
5416
    LOG_TRACE("()");
5417
 
5418
    ScaleAccDown3();
5419
}
5420
 
5421
// IDA: void __cdecl ScaleSpecVolDown4()
5422
void ScaleSpecVolDown4(void) {
5423
    LOG_TRACE("()");
5424
 
5425
    ScaleAccDown4();
5426
}
5427
 
5428
// IDA: void __cdecl MoveXSpecVolL()
5429
void MoveXSpecVolL(void) {
5430
    LOG_TRACE("()");
5431
 
5432
    MoveXAccL();
5433
}
5434
 
5435
// IDA: void __cdecl MoveXSpecVolL2()
5436
void MoveXSpecVolL2(void) {
5437
    LOG_TRACE("()");
5438
 
5439
    MoveXAccL2();
5440
}
5441
 
5442
// IDA: void __cdecl MoveXSpecVolL3()
5443
void MoveXSpecVolL3(void) {
5444
    LOG_TRACE("()");
5445
 
5446
    MoveXAccL3();
5447
}
5448
 
5449
// IDA: void __cdecl MoveXSpecVolL4()
5450
void MoveXSpecVolL4(void) {
5451
    LOG_TRACE("()");
5452
 
5453
    MoveXAccL4();
5454
}
5455
 
5456
// IDA: void __cdecl MoveXSpecVolR()
5457
void MoveXSpecVolR(void) {
5458
    LOG_TRACE("()");
5459
 
5460
    MoveXAccR();
5461
}
5462
 
5463
// IDA: void __cdecl MoveXSpecVolR2()
5464
void MoveXSpecVolR2(void) {
5465
    LOG_TRACE("()");
5466
 
5467
    MoveXAccR2();
5468
}
5469
 
5470
// IDA: void __cdecl MoveXSpecVolR3()
5471
void MoveXSpecVolR3(void) {
5472
    LOG_TRACE("()");
5473
 
5474
    MoveXAccR3();
5475
}
5476
 
5477
// IDA: void __cdecl MoveXSpecVolR4()
5478
void MoveXSpecVolR4(void) {
5479
    LOG_TRACE("()");
5480
 
5481
    MoveXAccR4();
5482
}
5483
 
5484
// IDA: void __cdecl MoveYSpecVolL()
5485
void MoveYSpecVolL(void) {
5486
    LOG_TRACE("()");
5487
 
5488
    MoveYAccL();
5489
}
5490
 
5491
// IDA: void __cdecl MoveYSpecVolL2()
5492
void MoveYSpecVolL2(void) {
5493
    LOG_TRACE("()");
5494
 
5495
#if defined(DETHRACE_FIX_BUGS)
5496
    MoveYAccL2();
5497
#else
5498
    MoveYAccL3();
5499
#endif
5500
}
5501
 
5502
// IDA: void __cdecl MoveYSpecVolL3()
5503
void MoveYSpecVolL3(void) {
5504
    LOG_TRACE("()");
5505
 
5506
    MoveYAccL3();
5507
}
5508
 
5509
// IDA: void __cdecl MoveYSpecVolL4()
5510
void MoveYSpecVolL4(void) {
5511
    LOG_TRACE("()");
5512
 
5513
    MoveYAccL4();
5514
}
5515
 
5516
// IDA: void __cdecl MoveYSpecVolR()
5517
void MoveYSpecVolR(void) {
5518
    LOG_TRACE("()");
5519
 
5520
    MoveYAccR();
5521
}
5522
 
5523
// IDA: void __cdecl MoveYSpecVolR2()
5524
void MoveYSpecVolR2(void) {
5525
    LOG_TRACE("()");
5526
 
5527
    MoveYAccR2();
5528
}
5529
 
5530
// IDA: void __cdecl MoveYSpecVolR3()
5531
void MoveYSpecVolR3(void) {
5532
    LOG_TRACE("()");
5533
 
5534
    MoveYAccR3();
5535
}
5536
 
5537
// IDA: void __cdecl MoveYSpecVolR4()
5538
void MoveYSpecVolR4(void) {
5539
    LOG_TRACE("()");
5540
 
5541
    MoveYAccR4();
5542
}
5543
 
5544
// IDA: void __cdecl MoveZSpecVolL()
5545
void MoveZSpecVolL(void) {
5546
    LOG_TRACE("()");
5547
 
5548
    MoveZAccL();
5549
}
5550
 
5551
// IDA: void __cdecl MoveZSpecVolL2()
5552
void MoveZSpecVolL2(void) {
5553
    LOG_TRACE("()");
5554
 
5555
    MoveZAccL2();
5556
}
5557
 
5558
// IDA: void __cdecl MoveZSpecVolL3()
5559
void MoveZSpecVolL3(void) {
5560
    LOG_TRACE("()");
5561
 
5562
    MoveZAccL3();
5563
}
5564
 
5565
// IDA: void __cdecl MoveZSpecVolL4()
5566
void MoveZSpecVolL4(void) {
5567
    LOG_TRACE("()");
5568
 
5569
    MoveZAccL4();
5570
}
5571
 
5572
// IDA: void __cdecl MoveZSpecVolR()
5573
void MoveZSpecVolR(void) {
5574
    LOG_TRACE("()");
5575
 
5576
    MoveZAccR();
5577
}
5578
 
5579
// IDA: void __cdecl MoveZSpecVolR2()
5580
void MoveZSpecVolR2(void) {
5581
    LOG_TRACE("()");
5582
 
5583
    MoveZAccR2();
5584
}
5585
 
5586
// IDA: void __cdecl MoveZSpecVolR3()
5587
void MoveZSpecVolR3(void) {
5588
    LOG_TRACE("()");
5589
 
5590
    MoveZAccR3();
5591
}
5592
 
5593
// IDA: void __cdecl MoveZSpecVolR4()
5594
void MoveZSpecVolR4(void) {
5595
    LOG_TRACE("()");
5596
 
5597
    MoveZAccR4();
5598
}
5599
 
5600
// IDA: void __cdecl SnapSpecVolToVertical()
5601
void SnapSpecVolToVertical(void) {
5602
    LOG_TRACE("()");
5603
 
5604
    SnapAccToVertical();
5605
}
5606
 
5607
// IDA: void __cdecl ShowSpecialVolumes()
5608
void ShowSpecialVolumes(void) {
5609
    int i;
5610
    //int j; // Pierre-Marie Baty -- unused variable
5611
    //int temp; // Pierre-Marie Baty -- unused variable
5612
    tSpecial_volume* v;
5613
    //br_actor* actor; // Pierre-Marie Baty -- unused variable
5614
    //br_model* model; // Pierre-Marie Baty -- unused variable
5615
    br_material* internal_mat;
5616
    br_material* external_mat;
5617
    LOG_TRACE("()");
5618
 
5619
    gLast_actor = NULL;
5620
    gSpec_vol_mode = 1;
5621
    internal_mat = GetInternalMat();
5622
    external_mat = GetExternalMat();
5623
    for (i = 0; i < gProgram_state.special_volume_count; i++) {
5624
        v = &gProgram_state.special_volumes[i];
5625
        if (!v->no_mat) {
5626
            BuildSpecVolModel(v, i, internal_mat, external_mat);
5627
        } else {
5628
            gSpec_vol_actors[i] = NULL;
5629
        }
5630
    }
5631
}
5632
 
5633
// IDA: void __cdecl HideSpecialVolumes()
5634
void HideSpecialVolumes(void) {
5635
    int i;
5636
    tSpecial_volume* v;
5637
    LOG_TRACE("()");
5638
 
5639
    gSpec_vol_mode = 0;
5640
    for (i = 0; i < gProgram_state.special_volume_count; i++) {
5641
        v = &gProgram_state.special_volumes[i];
5642
        if (!v->no_mat) {
5643
            DelSpecVolumeGraph(i);
5644
        }
5645
    }
5646
}