Subversion Repositories Games.Carmageddon

Rev

Rev 11 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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