Subversion Repositories Games.Carmageddon

Rev

Rev 11 | Rev 20 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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