Subversion Repositories Games.Carmageddon

Rev

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

Rev Author Line No. Line
1 pmbaty 1
#include "graphics.h"
2
 
3
#include "brender/brender.h"
4
#include "car.h"
5
#include "constants.h"
6
#include "controls.h"
7
#include "depth.h"
8
#include "displays.h"
9
#include "errors.h"
10
#include "finteray.h"
11
#include "flicplay.h"
12
#include "globvars.h"
13
#include "globvrpb.h"
14
#include "grafdata.h"
15
#include "harness/hooks.h"
16
#include "harness/os.h"
17
#include "harness/trace.h"
18
#include "init.h"
19
#include "input.h"
20
#include "loading.h"
21
#include "netgame.h"
22
#include "network.h"
23
#include "oil.h"
24
#include "opponent.h"
25
#include "pd/sys.h"
26
#include "pedestrn.h"
27
#include "piping.h"
28
#include "powerup.h"
29
#include "pratcam.h"
30
#include "replay.h"
31
#include "sound.h"
32
#include "spark.h"
33
#include "trig.h"
34
#include "utility.h"
35
#include "world.h"
36
#include <limits.h>
37
#include <stdlib.h>
38
 
39
#include <math.h>
40
 
41
int gPalette_munged;
42
int gColourValues[1];
43
int gNext_transient;
44
int gCursor_x_offsets[8] = {
45
    6,
46
    8,
47
    16,
48
    36,
49
    6,
50
    8,
51
    16,
52
    36,
53
};
54
int gCursor_y_offsets[8] = {
55
    26,
56
    19,
57
    12,
58
    5,
59
    26,
60
    19,
61
    12,
62
    5,
63
};
64
int gCursor_gib_x_offsets[8] = {
65
    82,
66
    72,
67
    66,
68
    36,
69
    82,
70
    72,
71
    66,
72
    36,
73
};
74
int gCursor_gib_y_offsets[8] = {
75
    74,
76
    86,
77
    93,
78
    106,
79
    74,
80
    86,
81
    93,
82
    106,
83
};
84
int gCursor_giblet_sequence0[7] = {
85
    6,
86
    0,
87
    1,
88
    2,
89
    3,
90
    4,
91
    5,
92
};
93
int gCursor_giblet_sequence1[5] = {
94
    4,
95
    6,
96
    7,
97
    8,
98
    9,
99
};
100
int gCursor_giblet_sequence2[5] = {
101
    4,
102
    10,
103
    11,
104
    12,
105
    13,
106
};
107
int gCursor_giblet_sequence3[5] = {
108
    4,
109
    14,
110
    15,
111
    16,
112
    17,
113
};
114
int* gCursor_giblet_sequences[4] = {
115
    gCursor_giblet_sequence0,
116
    gCursor_giblet_sequence1,
117
    gCursor_giblet_sequence2,
118
    gCursor_giblet_sequence3,
119
};
120
char* gFont_names[21] = {
121
    "TYPEABLE",
122
    "ORANGHED",
123
    "BLUEHEAD",
124
    "GREENHED",
125
    "MEDIUMHD",
126
    "TIMER",
127
    "NEWHITE",
128
    "NEWRED",
129
    "NEWBIGGR",
130
    "GRNDK",
131
    "GRNLIT",
132
    "GRYDK",
133
    "GRYLIT",
134
    "BUTTIN",
135
    "BUTTOUT",
136
    "LITPLAQ",
137
    "DRKPLAQ",
138
    "BUTTIN1",
139
    "BUTTOUT1",
140
    "LITPLAQ1",
141
    "DRKPLAQ1"
142
};
143
br_colour gRGB_colours[9] = {
144
    0u,
145
    16777215u,
146
    16711680u,
147
    65280u,
148
    255u,
149
    16776960u,
150
    65535u,
151
    16711935u,
152
    13649666u
153
};
154
br_matrix34 gSheer_mat = {
155
    { { 1.0, 0.0, 0.0 },
156
        { 0.0, 1.0, 0.0 },
157
        { 0.0, 0.0, 1.0 },
158
        { 0.0, 0.0, 0.0 } }
159
};
160
br_matrix34 gIdentity34 = {
161
    { { 1.0, 0.0, 0.0 },
162
        { 0.0, 1.0, 0.0 },
163
        { 0.0, 0.0, 1.0 },
164
        { 0.0, 0.0, 0.0 } }
165
};
166
tShadow_level gShadow_level = eShadow_us_only;
167
br_scalar gShadow_hither_z_move;
168
br_scalar gShadow_hither_min_move;
169
/* clang-format off */
170
// arrows pointing to 180, 202, 224, 246 degrees (step = 90 / 4 = 22(.5) degrees)
171
int gArrows[2][4][60] =
172
{
173
    {
174
        // inner arrow (=fill)
175
        { 10,  0,  0, -1,  0,  1,  0,  0, -1,  0, -2,  0,  1, -1,  1,  1,  1, -2,  2,  2,  2, },
176
        { 11,  0,  0, -1,  0,  1,  0,  0, -1,  1, -1,  1, -2, -2,  1, -1,  1,  0,  1,  1,  1,  1,  2, },
177
        {  9,  0,  0, -2,  0, -1,  0,  1,  0,  0, -1,  1, -1,  2, -2,  0,  1,  0,  2, },
178
        { 11,  0,  0, -1,  0,  1,  0, -2, -1, -1, -1,  0, -1,  1, -1,  2, -1, -1,  1,  0,  1, -1,  2, },
179
    },
180
    {
181
        // outer arrow (=border)
182
        { 26,  1, -3,  1, -2,  1, -1,  2, -1,  2,  0,  2,  1,  3,  1,  3,  2,  3,  3,  2,  3,  1,  3,  1,  2,  0,  2, -1,  2,
183
              -1,  3, -2,  3, -3,  3, -3,  2, -3,  1, -2,  1, -2,  0, -2, -1, -1, -1, -1, -2, -1, -3,  0, -3, },
184
        { 22,  0, -3,  1, -3,  2, -3,  2, -2,  2, -1,  2,  0,  2,  1,  2,  2,  2,  3,  1,  3,  0,  3,  0,  2, -1,  2, -2,  2,
185
              -3,  2, -3,  1, -3,  0, -2,  0, -2, -1, -1, -1, -1, -2,  0, -2, },
186
        { 24,  1, -3,  2, -3,  3, -3,  3, -2,  3, -1,  2, -1,  2,  0,  2,  1,  1,  1,  1,  2,  1,  3,  0,  3, -1,  3, -1,  2,
187
              -1,  1, -2,  1, -3,  1, -3,  0, -3, -1, -2, -1, -1, -1, -1, -2,  0, -2,  1, -2, },
188
        { 22, -3, -2, -2, -2, -1, -2,  0, -2,  1, -2,  2, -2,  3, -2,  3, -1,  3,  0,  2,  0,  2,  1,  1,  1,  1,  2,  0,  2,
189
               0,  3, -1,  3, -2,  3, -2,  2, -2,  1, -2,  0, -3,  0, -3, -1, },
190
    },
191
};
192
/* clang-format on */
193
 
194
float gMap_render_x = 80.f;
195
float gMap_render_y = 6.f;
196
float gMap_render_width = 64.f;
197
float gMap_render_height = 40.f;
198
int gMouse_started;
199
int gFaded_palette;
200
int gAR_fudge_headups;
201
br_pixelmap* gCurrent_splash;
202
br_pixelmap* gCurrent_conversion_table;
203
int gMap_colours[4] = { 4, 0, 52, 132 };
204
br_vector3 gShadow_points[8];
205
tConcussion gConcussion;
206
tClip_details gShadow_clip_planes[8];
207
br_actor* gLollipops[100];
208
tWobble_spec gWobble_array[5];
209
tSaved_table gSaved_shade_tables[100];
210
tCursor_giblet gCursor_giblets[45];
211
tTransient_bm gTransient_bitmaps[50];
212
float gCosine_array[64];
213
br_pixelmap* gCursors[8];
214
br_pixelmap* gCursor_giblet_images[18];
215
br_pixelmap* gEval_1;
216
br_pixelmap* gEval_2;
217
br_vector3 gShadow_light_z;
218
br_vector3 gShadow_light_x;
219
int gShadow_dim_amount;
220
int gNumber_of_lollipops;
221
br_vector3 gShadow_light_ray;
222
int gFancy_shadow;
223
br_model* gShadow_model;
224
br_actor* gShadow_actor;
225
int gShadow_clip_plane_count;
226
br_pixelmap* gPalette_conversion_table;
227
br_material* gShadow_material;
228
int gSaved_table_count;
229
int gCurrent_cursor_index;
230
int gPalette_index;
231
int gCursor_transient_index;
232
char* gScratch_pixels;
233
br_pixelmap* gScratch_palette;
234
int gLast_palette_change;
235
br_pixelmap* gOrig_render_palette;
236
br_pixelmap* gCurrent_palette;
237
br_pixelmap* gRender_palette;
238
float gCamera_to_horiz_angle;
239
int gColours[9];
240
br_pixelmap* gFlic_palette;
241
tDR_font gFonts[21];
242
char* gCurrent_palette_pixels;
243
int gWidth;
244
int gMap_render_height_i;
245
int gScreen_wobble_x;
246
int gScreen_wobble_y;
247
br_scalar gCurrent_ambience;
248
int gY_offset;
249
int gMap_render_width_i;
250
int gMouse_in_use;
251
int gHeight;
252
int gMouse_last_y_coord;
253
int gMouse_last_x_coord;
254
br_scalar gAmbient_adjustment;
255
int gMap_render_x_i;
256
int gX_offset;
257
int gMap_render_y_i;
258
int gMirror_on__graphics; // suffix added to avoid duplicate symbol
259
br_scalar gYon_squared;
260
 
261
#define SHADOW_D_IGNORE_FLAG 10000.0
262
 
263
// IDA: void __cdecl TurnOnPaletteConversion()
264
void TurnOnPaletteConversion(void) {
265
    LOG_TRACE("()");
266
 
267
    gCurrent_conversion_table = gPalette_conversion_table;
268
}
269
 
270
// IDA: void __cdecl TurnOffPaletteConversion()
271
void TurnOffPaletteConversion(void) {
272
    LOG_TRACE("()");
273
 
274
    gCurrent_conversion_table = NULL;
275
}
276
 
277
// IDA: void __cdecl ResetLollipopQueue()
278
void ResetLollipopQueue(void) {
279
    LOG_TRACE("()");
280
 
281
    gNumber_of_lollipops = 0;
282
}
283
 
284
// IDA: int __usercall AddToLollipopQueue@<EAX>(br_actor *pActor@<EAX>, int pIndex@<EDX>)
285
int AddToLollipopQueue(br_actor* pActor, int pIndex) {
286
    LOG_TRACE("(%p, %d)", pActor, pIndex);
287
 
288
    if (pIndex >= 0) {
289
        gLollipops[pIndex] = pActor;
290
    } else if (gNumber_of_lollipops >= 100) {
291
        pIndex = -1;
292
    } else {
293
        gLollipops[gNumber_of_lollipops] = pActor;
294
        pIndex = gNumber_of_lollipops;
295
        gNumber_of_lollipops++;
296
    }
297
    return pIndex;
298
}
299
 
300
// IDA: void __cdecl RenderLollipops()
301
void RenderLollipops(void) {
302
    int i;
303
    int must_relink;
304
    br_actor** the_actor;
305
    br_actor* old_parent;
306
    LOG_TRACE("()");
307
 
308
    for (i = 0, the_actor = gLollipops; i < gNumber_of_lollipops; i++, the_actor++) {
309
        if ((*the_actor)->render_style == BR_RSTYLE_NONE) {
310
            must_relink = (*the_actor)->parent != gDont_render_actor;
311
            if (must_relink) {
312
                old_parent = (*the_actor)->parent;
313
                BrActorRelink(gDont_render_actor, *the_actor);
314
            }
315
            (*the_actor)->render_style = BR_RSTYLE_FACES;
316
            SetPedMaterialForRender(*the_actor);
317
            BrZbSceneRenderAdd(*the_actor);
318
            (*the_actor)->render_style = BR_RSTYLE_NONE;
319
            if (must_relink) {
320
                BrActorRelink(old_parent, *the_actor);
321
            }
322
        }
323
    }
324
}
325
 
326
// IDA: void __usercall DRDrawLine(br_pixelmap *pDestn@<EAX>, int pX1@<EDX>, int pY1@<EBX>, int pX2@<ECX>, int pY2, int pColour)
327
void DRDrawLine(br_pixelmap* pDestn, int pX1, int pY1, int pX2, int pY2, int pColour) {
328
    //tU8* d_ptr; // Pierre-Marie Baty -- unused variable
329
    //tS32 y_delta; // Pierre-Marie Baty -- unused variable
330
    //tS32 x_delta; // Pierre-Marie Baty -- unused variable
331
    //tU32 current_y; // Pierre-Marie Baty -- unused variable
332
    //tU32 current_x; // Pierre-Marie Baty -- unused variable
333
    //int row_bytes; // Pierre-Marie Baty -- unused variable
334
    //int x; // Pierre-Marie Baty -- unused variable
335
    //int y; // Pierre-Marie Baty -- unused variable
336
    //int the_diff; // Pierre-Marie Baty -- unused variable
337
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pDestn, pX1, pY1, pX2, pY2, pColour);
338
 
339
    BrPixelmapLine(pDestn, pX1, pY1, pX2, pY2, pColour);
340
}
341
 
342
// IDA: void __usercall DrawDigitAt(br_pixelmap *gImage@<EAX>, int pX@<EDX>, int pY@<EBX>, int pY_pitch@<ECX>, int pValue)
343
void DrawDigitAt(br_pixelmap* gImage, int pX, int pY, int pY_pitch, int pValue) {
344
    LOG_TRACE("(%p, %d, %d, %d, %d)", gImage, pX, pY, pY_pitch, pValue);
345
 
346
    DRPixelmapRectangleMaskedCopy(gBack_screen, pX, pY, gImage, 0, pY_pitch * pValue, gImage->width, pY_pitch);
347
}
348
 
349
// IDA: void __usercall DrawNumberAt(br_pixelmap *gImage@<EAX>, int pX@<EDX>, int pY@<EBX>, int pX_pitch@<ECX>, int pY_pitch, int pValue, int pDigit_count, int pLeading_zeroes)
350
void DrawNumberAt(br_pixelmap* gImage, int pX, int pY, int pX_pitch, int pY_pitch, int pValue, int pDigit_count, int pLeading_zeroes) {
351
    int i;
352
    int the_value;
353
    LOG_TRACE("(%p, %d, %d, %d, %d, %d, %d, %d)", gImage, pX, pY, pX_pitch, pY_pitch, pValue, pDigit_count, pLeading_zeroes);
354
 
355
    for (i = pDigit_count - 1; i >= 0; i--) {
356
        the_value = pValue % 10;
357
        pValue /= 10;
358
        if (pValue || pLeading_zeroes || pDigit_count - 1 == i) {
359
            DrawDigitAt(gImage, pX + pX_pitch * i, pY, pY_pitch, the_value);
360
        }
361
    }
362
}
363
 
364
// IDA: void __usercall BuildColourTable(br_pixelmap *pPalette@<EAX>)
365
void BuildColourTable(br_pixelmap* pPalette) {
366
    int i;
367
    int j;
368
    int nearest_index = 0;
369
    int red;
370
    int green;
371
    int blue;
372
    float nearest_distance;
373
    float distance;
374
    LOG_TRACE("(%p)", pPalette);
375
 
376
#define SQR(i) i* i
377
 
378
    for (i = 0; i < COUNT_OF(gRGB_colours); i++) {
379
        nearest_distance = 196608.f;
380
        red = (gRGB_colours[i] >> 16) & 0xFF;
381
        green = (gRGB_colours[i] >> 8) & 0xFF;
382
        blue = gRGB_colours[i] & 0xFF;
383
        for (j = 0; j < 256; j++) {
384
            distance = SQR((double)(signed int)(*((br_uint_8*)pPalette->pixels + 4 * j + 2) - red));
385
            distance += SQR((double)(signed int)(*((br_uint_8*)pPalette->pixels + 4 * j) - blue));
386
            distance += SQR((double)(signed int)(*((br_uint_8*)pPalette->pixels + 4 * j + 1) - green));
387
            if (distance < nearest_distance) {
388
                nearest_index = j;
389
                nearest_distance = distance;
390
            }
391
        }
392
        gColours[i] = nearest_index;
393
    }
394
}
395
 
396
// IDA: void __cdecl ClearConcussion()
397
void ClearConcussion(void) {
398
    LOG_TRACE("()");
399
 
400
    gConcussion.concussed = 0;
401
}
402
 
403
// IDA: tS8* __usercall SkipLines@<EAX>(tS8 *pSource@<EAX>, int pCount@<EDX>)
404
tS8* SkipLines(tS8* pSource, int pCount) {
405
    int i;
406
    int j;
407
    int number_of_chunks;
408
    int chunk_length;
409
    LOG_TRACE("(%p, %d)", pSource, pCount);
410
 
411
    for (i = 0; i < pCount; ++i) {
412
        number_of_chunks = *pSource++;
413
        for (j = 0; j < number_of_chunks; j++) {
414
            chunk_length = *pSource++;
415
            if (chunk_length < 0) {
416
                pSource -= chunk_length;
417
            }
418
        }
419
    }
420
    return pSource;
421
}
422
 
423
// IDA: void __usercall CopyWords(char *pDst@<EAX>, char *pSrc@<EDX>, int pN@<EBX>)
424
void CopyWords(char* pDst, char* pSrc, int pN) {
425
    //tU16* dst; // Pierre-Marie Baty -- unused variable
426
    //tU16* src; // Pierre-Marie Baty -- unused variable
427
    LOG_TRACE("(\"%s\", \"%s\", %d)", pDst, pSrc, pN);
428
    NOT_IMPLEMENTED();
429
}
430
 
431
// IDA: void __usercall Copy8BitStripImageTo16Bit(br_pixelmap *pDest@<EAX>, br_int_16 pDest_x@<EDX>, br_int_16 pOffset_x@<EBX>, br_int_16 pDest_y@<ECX>, br_int_16 pOffset_y, tS8 *pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_uint_16 pWidth, br_uint_16 pHeight)
432
void Copy8BitStripImageTo16Bit(br_pixelmap* pDest, br_int_16 pDest_x, br_int_16 pOffset_x, br_int_16 pDest_y, br_int_16 pOffset_y, tS8* pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_uint_16 pWidth, br_uint_16 pHeight) {
433
    //int i; // Pierre-Marie Baty -- unused variable
434
    //int j; // Pierre-Marie Baty -- unused variable
435
    //int height; // Pierre-Marie Baty -- unused variable
436
    //int number_of_chunks; // Pierre-Marie Baty -- unused variable
437
    //int old_x_byte; // Pierre-Marie Baty -- unused variable
438
    //int x_byte; // Pierre-Marie Baty -- unused variable
439
    //int off_the_left; // Pierre-Marie Baty -- unused variable
440
    //int destn_width; // Pierre-Marie Baty -- unused variable
441
    //int chunk_length; // Pierre-Marie Baty -- unused variable
442
    //char* destn_ptr; // Pierre-Marie Baty -- unused variable
443
    //char* destn_ptr2; // Pierre-Marie Baty -- unused variable
444
    LOG_TRACE("(%p, %d, %d, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pOffset_x, pDest_y, pOffset_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
445
    NOT_IMPLEMENTED();
446
}
447
 
448
// IDA: void __usercall CopyStripImage(br_pixelmap *pDest@<EAX>, br_int_16 pDest_x@<EDX>, br_int_16 pOffset_x@<EBX>, br_int_16 pDest_y@<ECX>, br_int_16 pOffset_y, tS8 *pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_uint_16 pWidth, br_uint_16 pHeight)
449
void CopyStripImage(br_pixelmap* pDest, br_int_16 pDest_x, br_int_16 pOffset_x, br_int_16 pDest_y, br_int_16 pOffset_y, tS8* pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_uint_16 pWidth, br_uint_16 pHeight) {
450
    int i;
451
    int j;
452
    int height;
453
    int number_of_chunks;
454
    int old_x_byte;
455
    int x_byte;
456
    int off_the_left;
457
    //int destn_width; // Pierre-Marie Baty -- unused variable
458
    int chunk_length;
459
    char* destn_ptr;
460
    char* destn_ptr2;
461
    LOG_TRACE8("(%p, %d, %d, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pOffset_x, pDest_y, pOffset_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
462
 
463
    height = *(uint16_t*)pSource;
464
    pSource = pSource + 2;
465
    if (pDest_y + pOffset_y >= 0) {
466
        destn_ptr = (char*)pDest->pixels + pDest->row_bytes * (pDest_y + pOffset_y);
467
    } else {
468
        pSource = SkipLines(pSource, -pDest_y - pOffset_y);
469
        destn_ptr = (char*)pDest->pixels;
470
        height += pDest_y + pOffset_y;
471
        pOffset_y = 0;
472
        pDest_y = 0;
473
    }
474
 
475
    if (height + pDest_y + pOffset_y > pDest->height) {
476
        height = pDest->height - pDest_y - pOffset_y;
477
    }
478
    off_the_left = pDest_x + pOffset_x;
479
    if (off_the_left > 0) {
480
        destn_ptr += off_the_left;
481
    }
482
    for (i = 0; i < height; i++) {
483
        destn_ptr2 = destn_ptr;
484
        number_of_chunks = *pSource;
485
        pSource++;
486
        x_byte = off_the_left;
487
        for (j = 0; j < number_of_chunks; j++) {
488
            chunk_length = *pSource;
489
            pSource++;
490
            if (chunk_length >= 0) {
491
                old_x_byte = x_byte;
492
                x_byte += chunk_length;
493
                if (old_x_byte >= 0) {
494
                    destn_ptr2 += chunk_length;
495
                } else if (x_byte > 0) {
496
                    destn_ptr2 += chunk_length + old_x_byte;
497
                }
498
            } else {
499
                old_x_byte = x_byte;
500
                x_byte += -chunk_length;
501
                if (old_x_byte >= 0) {
502
                    if (pDest->width >= x_byte) {
503
                        memcpy(destn_ptr2, pSource, -chunk_length);
504
                        destn_ptr2 += -chunk_length;
505
                    } else if (old_x_byte < pDest->width) {
506
                        memcpy(destn_ptr2, pSource, pDest->width - old_x_byte);
507
                    }
508
                } else if (x_byte > 0) {
509
                    memcpy(destn_ptr2, &pSource[-old_x_byte], -chunk_length + old_x_byte);
510
                    destn_ptr2 += -chunk_length + old_x_byte;
511
                }
512
                pSource += -chunk_length;
513
            }
514
        }
515
        destn_ptr += pDest->row_bytes;
516
    }
517
}
518
 
519
// IDA: void __usercall SetBRenderScreenAndBuffers(int pX_offset@<EAX>, int pY_offset@<EDX>, int pWidth@<EBX>, int pHeight@<ECX>)
520
void SetBRenderScreenAndBuffers(int pX_offset, int pY_offset, int pWidth, int pHeight) {
521
    LOG_TRACE("(%d, %d, %d, %d)", pX_offset, pY_offset, pWidth, pHeight);
522
 
523
    PDAllocateScreenAndBack();
524
    if (!pWidth) {
525
        pWidth = gBack_screen->width;
526
    }
527
    if (!pHeight) {
528
        pHeight = gBack_screen->height;
529
    }
530
    gRender_screen = DRPixelmapAllocateSub(gBack_screen, pX_offset, pY_offset, pWidth, pHeight);
531
    gWidth = pWidth;
532
    gHeight = pHeight;
533
    gY_offset = pY_offset;
534
    gX_offset = pX_offset;
535
    if (gGraf_specs[gGraf_spec_index].doubled) {
536
        gScreen->base_x = (gGraf_specs[gGraf_spec_index].phys_width - 2 * gGraf_specs[gGraf_spec_index].total_width) / 2;
537
        gScreen->base_y = (gGraf_specs[gGraf_spec_index].phys_height - 2 * gGraf_specs[gGraf_spec_index].total_height) / 2;
538
    } else {
539
        gScreen->base_x = (gGraf_specs[gGraf_spec_index].phys_width - gGraf_specs[gGraf_spec_index].total_width) / 2;
540
        gScreen->base_y = (gGraf_specs[gGraf_spec_index].phys_height - gGraf_specs[gGraf_spec_index].total_height) / 2;
541
    }
542
 
543
    gScreen->origin_x = 0;
544
    gScreen->origin_y = 0;
545
    if (gBack_screen == NULL) {
546
        FatalError(kFatalError_AllocateOffScreenBuffer);
547
    }
548
    gDepth_buffer = BrPixelmapMatch(gBack_screen, BR_PMMATCH_DEPTH_16);
549
    if (gDepth_buffer == NULL) {
550
        FatalError(kFatalError_AllocateZBuffer);
551
    }
552
    BrZbBegin(gRender_screen->type, gDepth_buffer->type);
553
    gBrZb_initialized = 1;
554
}
555
 
556
// IDA: void __cdecl SetIntegerMapRenders()
557
void SetIntegerMapRenders(void) {
558
    LOG_TRACE("()");
559
 
560
    gMap_render_x_i = ((int)gMap_render_x) & ~3;
561
    gMap_render_y_i = ((int)gMap_render_y) & ~1;
562
    gMap_render_width_i = ((int)gMap_render_width) & ~3;
563
    gMap_render_height_i = ((int)gMap_render_height) & ~1;
564
    if (gReal_graf_data_index != 0) {
565
        gMap_render_x_i = 2 * gMap_render_x_i;
566
        gMap_render_y_i = 2 * gMap_render_y_i + 40;
567
        gMap_render_width_i = 2 * gMap_render_width_i;
568
        gMap_render_height_i = 2 * gMap_render_height_i;
569
    }
570
}
571
 
572
// IDA: void __cdecl AdjustRenderScreenSize()
573
void AdjustRenderScreenSize(void) {
574
    int switched_res;
575
    LOG_TRACE("()");
576
 
577
    switched_res = SwitchToRealResolution();
578
    ReinitialiseRenderStuff();
579
    if (gMap_mode) {
580
        gRender_screen->base_x = gMap_render_x_i;
581
        gRender_screen->base_y = gMap_render_y_i;
582
        gRender_screen->width = gMap_render_width_i;
583
        gRender_screen->height = gMap_render_height_i;
584
    } else {
585
        gRender_screen->base_x = gProgram_state.current_render_left;
586
        gRender_screen->base_y = gProgram_state.current_render_top;
587
        gRender_screen->height = gProgram_state.current_render_bottom - gProgram_state.current_render_top;
588
        gRender_screen->width = gProgram_state.current_render_right - gProgram_state.current_render_left;
589
    }
590
    if (gRender_screen->row_bytes == gRender_screen->width) {
591
        gRender_screen->flags |= BR_PMF_ROW_WHOLEPIXELS;
592
    } else {
593
        gRender_screen->flags &= ~BR_PMF_ROW_WHOLEPIXELS;
594
    }
595
    gRender_screen->origin_x = gRender_screen->width / 2;
596
    gRender_screen->origin_y = gRender_screen->height / 2;
597
    gWidth = gRender_screen->width;
598
    gHeight = gRender_screen->height;
599
    ReinitialiseForwardCamera();
600
    if (switched_res) {
601
        SwitchToLoresMode();
602
    }
603
}
604
 
605
// IDA: void __cdecl ScreenSmaller()
606
void ScreenSmaller(void) {
607
    LOG_TRACE("()");
608
 
609
    if (!gMap_mode) {
610
        if (gProgram_state.cockpit_on) {
611
            ToggleCockpit();
612
        }
613
        gRender_indent++;
614
        if (gRender_indent > 8) {
615
            gRender_indent = 8;
616
        }
617
        AdjustRenderScreenSize();
618
    }
619
}
620
 
621
// IDA: void __cdecl ScreenLarger()
622
void ScreenLarger(void) {
623
    LOG_TRACE("()");
624
 
625
    if (!gMap_mode) {
626
        if (gProgram_state.cockpit_on) {
627
            ToggleCockpit();
628
        }
629
        gRender_indent--;
630
        if (gRender_indent < 0) {
631
            gRender_indent = 0;
632
        }
633
        AdjustRenderScreenSize();
634
    }
635
}
636
 
637
// IDA: void __usercall DRSetPaletteEntries(br_pixelmap *pPalette@<EAX>, int pFirst_colour@<EDX>, int pCount@<EBX>)
638
void DRSetPaletteEntries(br_pixelmap* pPalette, int pFirst_colour, int pCount) {
639
    LOG_TRACE("(%p, %d, %d)", pPalette, pFirst_colour, pCount);
640
    if (pFirst_colour == 0) {
641
        ((br_int_32*)pPalette->pixels)[0] = 0;
642
    }
643
    memcpy(gCurrent_palette_pixels + 4 * pFirst_colour, (char*)pPalette->pixels + 4 * pFirst_colour, 4 * pCount);
644
    if (!gFaded_palette) {
645
        PDSetPaletteEntries(pPalette, pFirst_colour, pCount);
646
    }
647
    gPalette_munged = 1;
648
}
649
 
650
// IDA: void __usercall DRSetPalette3(br_pixelmap *pThe_palette@<EAX>, int pSet_current_palette@<EDX>)
651
void DRSetPalette3(br_pixelmap* pThe_palette, int pSet_current_palette) {
652
    LOG_TRACE("(%p, %d)", pThe_palette, pSet_current_palette);
653
 
654
    if (pSet_current_palette) {
655
        memcpy(gCurrent_palette_pixels, pThe_palette->pixels, 0x400u);
656
    }
657
    if (!gFaded_palette) {
658
        PDSetPalette(pThe_palette);
659
    }
660
    if (pThe_palette != gRender_palette) {
661
        gPalette_munged |= 1u;
662
    }
663
}
664
 
665
// IDA: void __usercall DRSetPalette2(br_pixelmap *pThe_palette@<EAX>, int pSet_current_palette@<EDX>)
666
void DRSetPalette2(br_pixelmap* pThe_palette, int pSet_current_palette) {
667
    ((br_int_32*)pThe_palette->pixels)[0] = 0;
668
    if (pSet_current_palette) {
669
        memcpy(gCurrent_palette_pixels, pThe_palette->pixels, 0x400u);
670
    }
671
    if (!gFaded_palette) {
672
        PDSetPalette(pThe_palette);
673
    }
674
    if (pThe_palette != gRender_palette) {
675
        gPalette_munged |= 1u;
676
    }
677
}
678
 
679
// IDA: void __usercall DRSetPalette(br_pixelmap *pThe_palette@<EAX>)
680
void DRSetPalette(br_pixelmap* pThe_palette) {
681
    DRSetPalette2(pThe_palette, 1);
682
}
683
 
684
// IDA: void __cdecl InitializePalettes()
685
void InitializePalettes(void) {
686
    //int j; // Pierre-Marie Baty -- unused variable
687
    gCurrent_palette_pixels = BrMemAllocate(0x400u, kMem_cur_pal_pixels);
688
    gCurrent_palette = DRPixelmapAllocate(BR_PMT_RGBX_888, 1u, 256, gCurrent_palette_pixels, 0);
689
    gRender_palette = BrTableFind("DRRENDER.PAL");
690
    if (gRender_palette == NULL) {
691
        FatalError(kFatalError_RequiredPalette);
692
    }
693
    gOrig_render_palette = BrPixelmapAllocateSub(gRender_palette, 0, 0, gRender_palette->width, gRender_palette->height);
694
    gOrig_render_palette->pixels = BrMemAllocate(0x400u, kMem_render_pal_pixels);
695
    memcpy(gOrig_render_palette->pixels, gRender_palette->pixels, 0x400u);
696
    gFlic_palette = BrTableFind("DRACEFLC.PAL");
697
    if (gFlic_palette == NULL) {
698
        FatalError(kFatalError_RequiredPalette);
699
    }
700
    DRSetPalette(gFlic_palette);
701
    gScratch_pixels = BrMemAllocate(0x400u, kMem_scratch_pal_pixels);
702
    gScratch_palette = DRPixelmapAllocate(BR_PMT_RGBX_888, 1u, 256, gScratch_pixels, 0);
703
    gPalette_conversion_table = BrTableFind("FLC2REND.TAB");
704
    gRender_shade_table = BrTableFind("DRRENDER.TAB");
705
    gEval_1 = LoadPixelmap("Evalu01.PIX");
706
}
707
 
708
// IDA: void __usercall SwitchToPalette(char *pPal_name@<EAX>)
709
void SwitchToPalette(char* pPal_name) {
710
    //br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
711
    LOG_TRACE("(\"%s\")", pPal_name);
712
    NOT_IMPLEMENTED();
713
}
714
 
715
// IDA: void __cdecl ClearEntireScreen()
716
void ClearEntireScreen(void) {
717
    LOG_TRACE("()");
718
 
719
    if (gScreen) {
720
        BrPixelmapFill(gScreen, gGraf_specs[gGraf_spec_index].black_value);
721
    }
722
    BrPixelmapFill(gBack_screen, gGraf_specs[gGraf_spec_index].black_value);
723
    PDScreenBufferSwap(0);
724
}
725
 
726
// IDA: void __cdecl ClearWobbles()
727
void ClearWobbles(void) {
728
    int i;
729
    LOG_TRACE("()");
730
 
731
    for (i = 0; i < COUNT_OF(gWobble_array); i++) {
732
        gWobble_array[i].time_started = 0;
733
    }
734
}
735
 
736
// IDA: void __cdecl InitWobbleStuff()
737
void InitWobbleStuff(void) {
738
    int i;
739
 
740
    ClearWobbles();
741
    for (i = 0; i < COUNT_OF(gCosine_array); i++) {
742
        gCosine_array[i] = cosf(i / 64.0f * DR_PI / 2.0f);
743
    }
744
}
745
 
746
// IDA: void __cdecl NewScreenWobble(double pAmplitude_x, double pAmplitude_y, double pPeriod)
747
void NewScreenWobble(double pAmplitude_x, double pAmplitude_y, double pPeriod) {
748
    int i;
749
    int oldest_time;
750
    int oldest_index;
751
    LOG_TRACE("(%d, %d, %d)", pAmplitude_x, pAmplitude_y, pPeriod);
752
 
753
    oldest_index = -1;
754
    oldest_time = INT_MAX;
755
    for (i = 0; i < COUNT_OF(gWobble_array); i++) {
756
        if (gWobble_array[i].time_started == 0) {
757
            oldest_index = i;
758
            break;
759
        }
760
        if (gWobble_array[i].time_started < oldest_time) {
761
            oldest_time = gWobble_array[i].time_started;
762
            oldest_index = i;
763
        }
764
    }
765
    gWobble_array[oldest_index].time_started = GetTotalTime();
766
    gWobble_array[oldest_index].amplitude_x = pAmplitude_x;
767
    gWobble_array[oldest_index].amplitude_y = pAmplitude_y;
768
    gWobble_array[oldest_index].period = pPeriod;
769
}
770
 
771
// IDA: void __usercall SetScreenWobble(int pWobble_x@<EAX>, int pWobble_y@<EDX>)
772
void SetScreenWobble(int pWobble_x, int pWobble_y) {
773
    LOG_TRACE("(%d, %d)", pWobble_x, pWobble_y);
774
 
775
    gScreen_wobble_y = pWobble_y;
776
    gScreen_wobble_x = pWobble_x;
777
}
778
 
779
// IDA: void __cdecl ResetScreenWobble()
780
void ResetScreenWobble(void) {
781
    LOG_TRACE("()");
782
 
783
    SetScreenWobble(0, 0);
784
}
785
 
786
// IDA: void __usercall CalculateWobblitude(tU32 pThe_time@<EAX>)
787
void CalculateWobblitude(tU32 pThe_time) {
788
    int i;
789
    tU32 time_going;
790
    double angle;
791
    double mod_angle;
792
    double cosine_over_angle;
793
    LOG_TRACE("(%d)", pThe_time);
794
 
795
    if (gProgram_state.new_view != eView_undefined) {
796
        return;
797
    }
798
    gScreen_wobble_x = 0;
799
    gScreen_wobble_y = 0;
800
    for (i = 0; i < COUNT_OF(gWobble_array); i++) {
801
        if (gWobble_array[i].time_started != 0) {
802
            time_going = pThe_time - gWobble_array[i].time_started;
803
            if (time_going > 1000) {
804
                gWobble_array[i].time_started = 0;
805
            } else {
806
                mod_angle = fmod(time_going / gWobble_array[i].period, TAU);
807
                if (mod_angle > DR_3PI_OVER_2) {
808
                    cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.0)];
809
                } else if (mod_angle > DR_PI) {
810
                    cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.0)];
811
                } else if (mod_angle > DR_PI_OVER_2) {
812
                    cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.0)];
813
                } else {
814
                    cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.0)];
815
                }
816
                angle = cosine_over_angle / ((double)(pThe_time - gWobble_array[i].time_started) * 0.0035f + 1.0f);
817
                gScreen_wobble_x = (gWobble_array[i].amplitude_x * angle + gScreen_wobble_x);
818
                gScreen_wobble_y = (gWobble_array[i].amplitude_y * angle + gScreen_wobble_y);
819
            }
820
        }
821
    }
822
    if (gScreen_wobble_x > gCurrent_graf_data->cock_margin_x) {
823
        gScreen_wobble_x = gCurrent_graf_data->cock_margin_x;
824
    } else if (gScreen_wobble_x < -gCurrent_graf_data->cock_margin_x) {
825
        gScreen_wobble_x = -gCurrent_graf_data->cock_margin_x;
826
    }
827
    if (gScreen_wobble_y > gCurrent_graf_data->cock_margin_y) {
828
        gScreen_wobble_y = gCurrent_graf_data->cock_margin_y;
829
    } else if (gScreen_wobble_y < -gCurrent_graf_data->cock_margin_y) {
830
        gScreen_wobble_y = -gCurrent_graf_data->cock_margin_y;
831
    }
832
    PipeSingleScreenShake(gScreen_wobble_x, gScreen_wobble_y);
833
}
834
 
835
// IDA: void __usercall CalculateConcussion(tU32 pThe_time@<EAX>)
836
void CalculateConcussion(tU32 pThe_time) {
837
    tU32 time_difference;
838
    int i;
839
    int j;
840
    float the_amplitude;
841
    float angle;
842
    float mod_angle;
843
    float cosine_over_angle;
844
    LOG_TRACE("(%d)", pThe_time);
845
 
846
    if (!gConcussion.concussed) {
847
        return;
848
    }
849
    time_difference = pThe_time - gConcussion.time_started;
850
    if (pThe_time - gConcussion.time_started > 2000) {
851
        gConcussion.concussed = 0;
852
    } else {
853
        for (i = 0; i < 3; ++i) {
854
            for (j = 0; j < 3; ++j) {
855
                the_amplitude = gConcussion.amplitudes.m[i][j];
856
                if (the_amplitude != 0.0) {
857
                    mod_angle = fmodf(time_difference / gConcussion.periods.m[i][j], (float) TAU); // Pierre-Marie Baty -- added type cast
858
                    if (mod_angle > DR_3PI_OVER_2) {
859
                        cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.f)];
860
                    } else if (mod_angle > DR_PI) {
861
                        cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.f)];
862
                    } else if (mod_angle > DR_PI_OVER_2) {
863
                        cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.f)];
864
                    } else {
865
                        cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.f)];
866
                    }
867
                    angle = cosine_over_angle / ((double)time_difference * 0.02f + 1.0f);
868
                    gCamera->t.t.mat.m[i][j] = angle * the_amplitude + gCamera->t.t.mat.m[i][j];
869
                    gRearview_camera->t.t.mat.m[i][j] = angle * the_amplitude + gRearview_camera->t.t.mat.m[i][j];
870
                }
871
            }
872
        }
873
    }
874
}
875
 
876
// IDA: void __cdecl SufferFromConcussion(float pSeriousness)
877
void SufferFromConcussion(float pSeriousness) {
878
    int i;
879
    int j;
880
    LOG_TRACE("(%f)", pSeriousness);
881
 
882
    for (i = 0; i < 3; i++) {
883
        for (j = 0; j < 3; j++) {
884
            gConcussion.amplitudes.m[i][j] = FRandomPosNeg(pSeriousness);
885
            gConcussion.periods.m[i][j] = FRandomBetween(20.f, 100.f);
886
        }
887
    }
888
    gConcussion.concussed = 1;
889
    gConcussion.time_started = GetTotalTime();
890
}
891
 
892
// IDA: void __usercall ProcessNonTrackActors(br_pixelmap *pRender_buffer@<EAX>, br_pixelmap *pDepth_buffer@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world@<ECX>, br_matrix34 *pOld_camera_matrix)
893
void ProcessNonTrackActors(br_pixelmap* pRender_buffer, br_pixelmap* pDepth_buffer, br_actor* pCamera, br_matrix34* pCamera_to_world, br_matrix34* pOld_camera_matrix) {
894
    LOG_TRACE("(%p, %p, %p, %p, %p)", pRender_buffer, pDepth_buffer, pCamera, pCamera_to_world, pOld_camera_matrix);
895
 
896
    BrZbSceneRenderAdd(gNon_track_actor);
897
}
898
 
899
// IDA: int __usercall OppositeColour@<EAX>(int pColour@<EAX>)
900
int OppositeColour(int pColour) {
901
    int brightness;
902
    LOG_TRACE("(%d)", pColour);
903
 
904
    if (pColour < 224) {
905
        if ((pColour & 0x7) < 4) {
906
            brightness = 255;
907
        } else {
908
            brightness = 0;
909
        }
910
    } else {
911
        if ((pColour & 0xf) < 8) {
912
            brightness = 255;
913
        } else {
914
            brightness = 0;
915
        }
916
    }
917
    return brightness;
918
}
919
 
920
// IDA: void __usercall DrawMapBlip(tCar_spec *pCar@<EAX>, tU32 pTime@<EDX>, br_matrix34 *pTrans@<EBX>, br_vector3 *pPos@<ECX>, int pColour)
921
void DrawMapBlip(tCar_spec* pCar, tU32 pTime, br_matrix34* pTrans, br_vector3* pPos, int pColour) {
922
    br_vector3 map_pos;
923
    int offset;
924
    int* arrow_ptr;
925
    int point_count;
926
    int colours[2];
927
    int x;
928
    int y;
929
    int colour;
930
    int i;
931
    int j;
932
    int temp;
933
    int from_x;
934
    int from_y;
935
    int to_x;
936
    int to_y;
937
    int arrow_index;
938
    tU32 time_diff;
939
    tU32 period;
940
    br_matrix34 car_in_map_space;
941
    float bearing;
942
    //float cos_factor; // Pierre-Marie Baty -- unused variable
943
    //float sin_factor; // Pierre-Marie Baty -- unused variable
944
    LOG_TRACE("(%p, %d, %p, %p, %d)", pCar, pTime, pTrans, pPos, pColour);
945
 
946
    time_diff = pTime - gMap_mode;
947
    BrMatrix34ApplyP(&map_pos, pPos, &gCurrent_race.map_transformation);
948
    switch (gReal_graf_data_index) {
949
    case 0:
950
        break;
951
    case 1:
952
        map_pos.v[0] = map_pos.v[0] * 2.f;
953
        map_pos.v[1] = map_pos.v[1] * 2.f + 40.f;
954
        break;
955
    default:
956
        TELL_ME_IF_WE_PASS_THIS_WAY();
957
    }
958
    period = 256; // Must be power of 2
959
    colours[0] = pColour;
960
    colours[1] = OppositeColour(pColour);
961
    BrMatrix34Mul(&car_in_map_space, pTrans, &gCurrent_race.map_transformation);
962
    bearing = FastScalarArcTan2(car_in_map_space.m[2][0], car_in_map_space.m[2][1]);
963
 
964
    // Calculate in which of the 16 directions, the arrow is pointing to
965
    bearing = (360.f - bearing + 12.25) / 22.5f;
966
    arrow_index = ((int)bearing) % 16;
967
 
968
    // The player's blip blinks, others are shown permanently
969
    if (pCar->driver != eDriver_local_human || (period & pTime) != 0) {
970
        for (i = 0; i < COUNT_OF(colours); i++) {
971
            colour = colours[i];
972
            point_count = gArrows[i][arrow_index & 0x3][0];
973
            arrow_ptr = &gArrows[i][arrow_index & 0x3][1];
974
            for (j = 0; j < point_count; j++, arrow_ptr += 2) {
975
                if (arrow_index & 0x8) {
976
                    x = -arrow_ptr[0];
977
                    y = -arrow_ptr[1];
978
                } else {
979
                    x = arrow_ptr[0];
980
                    y = arrow_ptr[1];
981
                }
982
                if (arrow_index & 0x4) {
983
                    temp = x;
984
                    x = -y;
985
                    y = temp;
986
                }
987
                BrPixelmapPixelSet(gBack_screen, map_pos.v[0] + x, map_pos.v[1] + y, colour);
988
            }
989
        }
990
    }
991
    // Draw a rectangle around the fox
992
    colour = colours[!!(pTime & period)];
993
    if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_foxy && gNet_players[gIt_or_fox].car == pCar) {
994
        from_x = map_pos.v[0] - 8.f;
995
        from_y = map_pos.v[1] - 8.f;
996
        to_x = map_pos.v[0] + 8.f;
997
        to_y = map_pos.v[1] + 8.f;
998
        BrPixelmapLine(gBack_screen, from_x, from_y, to_x, from_y, colour);
999
        BrPixelmapLine(gBack_screen, from_x, to_y, to_x, to_y, colour);
1000
        BrPixelmapLine(gBack_screen, from_x, from_y, from_x, to_y, colour);
1001
        BrPixelmapLine(gBack_screen, to_x, from_y, to_x, to_y, colour);
1002
    }
1003
    // To attract the player's attention, draw a rectangle around the player's position that decreases in size,
1004
    if (time_diff <= 500 && pCar->driver == eDriver_local_human) {
1005
        offset = ((500 - time_diff) * 70) / 500;
1006
        from_x = map_pos.v[0] - offset - .5f;
1007
        from_y = map_pos.v[1] - offset - .5f;
1008
        to_x = map_pos.v[0] + offset + .5f;
1009
        to_y = map_pos.v[1] + offset + .5f;
1010
        BrPixelmapLine(gBack_screen, from_x, from_y, to_x, from_y, colour);
1011
        BrPixelmapLine(gBack_screen, from_x, to_y, to_x, to_y, colour);
1012
        BrPixelmapLine(gBack_screen, from_x, from_y, from_x, to_y, colour);
1013
        BrPixelmapLine(gBack_screen, to_x, from_y, to_x, to_y, colour);
1014
    }
1015
}
1016
 
1017
// IDA: void __usercall DrawMapSmallBlip(tU32 pTime@<EAX>, br_vector3 *pPos@<EDX>, int pColour@<EBX>)
1018
void DrawMapSmallBlip(tU32 pTime, br_vector3* pPos, int pColour) {
1019
    br_vector3 map_pos;
1020
    int offset;
1021
    //tU32 time_diff; // Pierre-Marie Baty -- unused variable
1022
    LOG_TRACE("(%d, %p, %d)", pTime, pPos, pColour);
1023
 
1024
    if ((pTime & 0x100) == 0) {
1025
        BrMatrix34ApplyP(&map_pos, pPos, &gCurrent_race.map_transformation);
1026
        if (gReal_graf_data_index != 0) {
1027
            map_pos.v[0] = 2.f * map_pos.v[0];
1028
            map_pos.v[1] = 2.f * map_pos.v[1] + 40.f;
1029
        }
1030
        offset = (int)map_pos.v[0] + gBack_screen->row_bytes * (int)map_pos.v[1];
1031
        ((br_uint_8*)gBack_screen->pixels)[offset] = pColour;
1032
    }
1033
}
1034
 
1035
// IDA: void __usercall MungeClipPlane(br_vector3 *pLight@<EAX>, tCar_spec *pCar@<EDX>, br_vector3 *p1@<EBX>, br_vector3 *p2@<ECX>, br_scalar pY_offset)
1036
void MungeClipPlane(br_vector3* pLight, tCar_spec* pCar, br_vector3* p1, br_vector3* p2, br_scalar pY_offset) {
1037
    br_vector3 v1;
1038
    br_vector3 v2;
1039
    br_vector3 v3;
1040
    br_vector3 v4;
1041
    br_scalar length;
1042
    br_actor* new_clip;
1043
    LOG_TRACE("(%p, %p, %p, %p, %f)", pLight, pCar, p1, p2, pY_offset);
1044
 
1045
    BrMatrix34ApplyP(&v1, p1, &pCar->car_master_actor->t.t.mat);
1046
    BrMatrix34ApplyP(&v2, p2, &pCar->car_master_actor->t.t.mat);
1047
    BrVector3Sub(&v3, p2, p1);
1048
    BrVector3Cross(&v4, &v3, pLight);
1049
    if (fabsf(v4.v[0]) >= 0.01f || fabsf(v4.v[1]) >= 0.01f || fabsf(v4.v[2]) >= 0.01f) {
1050
        BrVector3Copy(&v3, p1);
1051
        v3.v[1] -= pY_offset;
1052
        if (BrVector3Dot(&v3, &v4) > 0.f) {
1053
            BrVector3Negate(&v4, &v4);
1054
        }
1055
        BrVector3Normalise(&v3, &v4);
1056
        BrMatrix34ApplyV(&v4, &v3, &pCar->car_master_actor->t.t.mat);
1057
        length = (v1.v[2] - v2.v[2]) * (v1.v[2] - v2.v[2]) + (v1.v[0] - v2.v[0]) * (v1.v[0] - v2.v[0]);
1058
 
1059
        new_clip = gShadow_clip_planes[gShadow_clip_plane_count].clip;
1060
        ((br_vector4*)new_clip->type_data)->v[0] = v4.v[0];
1061
        ((br_vector4*)new_clip->type_data)->v[1] = v4.v[1];
1062
        ((br_vector4*)new_clip->type_data)->v[2] = v4.v[2];
1063
        ((br_vector4*)new_clip->type_data)->v[3] = -BrVector3Dot(&v1, &v4);
1064
        gShadow_clip_planes[gShadow_clip_plane_count].length = length;
1065
        gShadow_clip_plane_count++;
1066
    }
1067
}
1068
 
1069
// IDA: void __usercall TryThisEdge(tCar_spec *pCar@<EAX>, br_vector3 *pLight@<EDX>, int pIndex_1@<EBX>, br_scalar pSign_1, int pIndex_2, br_scalar pSign_2, int pPoint_index_1, int pPoint_index_2, br_scalar pY_offset)
1070
void TryThisEdge(tCar_spec* pCar, br_vector3* pLight, int pIndex_1, br_scalar pSign_1, int pIndex_2, br_scalar pSign_2, int pPoint_index_1, int pPoint_index_2, br_scalar pY_offset) {
1071
    br_scalar dot_1;
1072
    br_scalar dot_2;
1073
    br_scalar mult;
1074
    LOG_TRACE("(%p, %p, %d, %f, %d, %f, %d, %d, %f)", pCar, pLight, pIndex_1, pSign_1, pIndex_2, pSign_2, pPoint_index_1, pPoint_index_2, pY_offset);
1075
 
1076
    dot_1 = pSign_1 * pLight->v[pIndex_1];
1077
    dot_2 = pSign_2 * pLight->v[pIndex_2];
1078
    mult = dot_1 * dot_2;
1079
    if (mult < 0 || (mult == 0 && (dot_1 > 0 || dot_2 > 0))) {
1080
        if (gShadow_clip_plane_count < 6) {
1081
            MungeClipPlane(pLight, pCar, &gShadow_points[pPoint_index_1], &gShadow_points[pPoint_index_2], pY_offset);
1082
        }
1083
    }
1084
}
1085
 
1086
// IDA: br_scalar __usercall DistanceFromPlane@<ST0>(br_vector3 *pPos@<EAX>, br_scalar pA, br_scalar pB, br_scalar pC, br_scalar pD)
1087
br_scalar DistanceFromPlane(br_vector3* pPos, br_scalar pA, br_scalar pB, br_scalar pC, br_scalar pD) {
1088
    //br_vector3 normal; // Pierre-Marie Baty -- unused variable
1089
    LOG_TRACE("(%p, %f, %f, %f, %f)", pPos, pA, pB, pC, pD);
1090
 
1091
    return fabsf((pPos->v[1] * pB + pPos->v[0] * pA + pPos->v[2] * pC + pD) / (pA * pA + pC * pC + pB * pB));
1092
}
1093
 
1094
// IDA: void __cdecl DisableLights()
1095
void DisableLights(void) {
1096
    //int i; // Pierre-Marie Baty -- unused variable
1097
    LOG_TRACE("()");
1098
    NOT_IMPLEMENTED();
1099
}
1100
 
1101
// IDA: void __cdecl EnableLights()
1102
void EnableLights(void) {
1103
    //int i; // Pierre-Marie Baty -- unused variable
1104
    LOG_TRACE("()");
1105
    NOT_IMPLEMENTED();
1106
}
1107
 
1108
// IDA: void __usercall ProcessShadow(tCar_spec *pCar@<EAX>, br_actor *pWorld@<EDX>, tTrack_spec *pTrack_spec@<EBX>, br_actor *pCamera@<ECX>, br_matrix34 *pCamera_to_world_transform, br_scalar pDistance_factor)
1109
void ProcessShadow(tCar_spec* pCar, br_actor* pWorld, tTrack_spec* pTrack_spec, br_actor* pCamera, br_matrix34* pCamera_to_world_transform, br_scalar pDistance_factor) {
1110
    int i;
1111
    //int j; // Pierre-Marie Baty -- unused variable
1112
    int face_count;
1113
    //int force_shadow; // Pierre-Marie Baty -- unused variable
1114
    //int models_used; // Pierre-Marie Baty -- unused variable
1115
    //int point_to_use; // Pierre-Marie Baty -- unused variable
1116
    int oily_count;
1117
    int f_num;
1118
    //br_vector3 pos; // Pierre-Marie Baty -- unused variable
1119
    br_vector3 light_ray_car;
1120
    //br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
1121
    br_vector3 shadow_points_world[8];
1122
    br_vector3 poly_centre;
1123
    br_vector3 car_to_poly;
1124
    br_vector3 ray;
1125
    br_vector3 ray_pos;
1126
    br_vector3 normal;
1127
    //br_vector3 the_normal; // Pierre-Marie Baty -- unused variable
1128
    br_vector3 pos_cam_space;
1129
    //br_vector3* v0; // Pierre-Marie Baty -- unused variable
1130
    br_vector3* v1;
1131
    br_vector3* v2;
1132
    br_vector4* clip_normal;
1133
    br_scalar bounds_x_min;
1134
    br_scalar bounds_x_max;
1135
    br_scalar bounds_y_min;
1136
    br_scalar bounds_y_max;
1137
    br_scalar bounds_z_min;
1138
    br_scalar bounds_z_max;
1139
    //br_scalar height; // Pierre-Marie Baty -- unused variable
1140
    br_scalar oily_size;
1141
    br_scalar highest_underneath;
1142
    br_scalar shadow_scaling_factor;
1143
    br_scalar y_offset;
1144
    //br_scalar most_neg_dotty; // Pierre-Marie Baty -- unused variable
1145
    //br_scalar mr_dotty; // Pierre-Marie Baty -- unused variable
1146
    br_scalar first_poly_below;
1147
    br_scalar distance;
1148
    br_scalar camera_hither_fudge;
1149
    br_scalar camera_angle_additional_fudge;
1150
    br_scalar ray_length;
1151
    tBounds kev_bounds;
1152
    tFace_ref the_list[100];
1153
    tFace_ref* face_ref;
1154
    tFace_ref* list_ptr;
1155
    //br_renderbounds_cbfn* old_call_back; // Pierre-Marie Baty -- unused variable
1156
    br_camera* camera_ptr;
1157
    br_actor* oily_actor;
1158
    //br_model* model; // Pierre-Marie Baty -- unused variable
1159
    br_material* material;
1160
    br_vertex verts[48];
1161
    br_face faces[16];
1162
    LOG_TRACE("(%p, %p, %p, %p, %p, %f)", pCar, pWorld, pTrack_spec, pCamera, pCamera_to_world_transform, pDistance_factor);
1163
 
1164
#if defined(DETHRACE_FIX_BUGS)
1165
    ray_length = 0.f;
1166
#endif
1167
    f_num = 0;
1168
    bounds_x_min = pCar->bounds[1].min.v[0] / WORLD_SCALE;
1169
    bounds_x_max = pCar->bounds[1].max.v[0] / WORLD_SCALE;
1170
    bounds_y_min = pCar->bounds[1].min.v[1] / WORLD_SCALE;
1171
    bounds_y_max = pCar->bounds[1].max.v[1] / WORLD_SCALE;
1172
    bounds_z_min = pCar->bounds[1].min.v[2] / WORLD_SCALE;
1173
    bounds_z_max = pCar->bounds[1].max.v[2] / WORLD_SCALE;
1174
    gShadow_points[0].v[0] = bounds_x_max;
1175
    gShadow_points[0].v[1] = bounds_y_max;
1176
    gShadow_points[0].v[2] = bounds_z_max;
1177
    gShadow_points[1].v[0] = bounds_x_max;
1178
    gShadow_points[1].v[1] = bounds_y_max;
1179
    gShadow_points[1].v[2] = bounds_z_min;
1180
    gShadow_points[2].v[0] = bounds_x_min;
1181
    gShadow_points[2].v[1] = bounds_y_max;
1182
    gShadow_points[2].v[2] = bounds_z_min;
1183
    gShadow_points[3].v[0] = bounds_x_min;
1184
    gShadow_points[3].v[1] = bounds_y_max;
1185
    gShadow_points[3].v[2] = bounds_z_max;
1186
    gShadow_points[4].v[0] = bounds_x_max;
1187
    gShadow_points[4].v[1] = bounds_y_min;
1188
    gShadow_points[4].v[2] = bounds_z_max;
1189
    gShadow_points[5].v[0] = bounds_x_max;
1190
    gShadow_points[5].v[1] = bounds_y_min;
1191
    gShadow_points[5].v[2] = bounds_z_min;
1192
    gShadow_points[6].v[0] = bounds_x_min;
1193
    gShadow_points[6].v[1] = bounds_y_min;
1194
    gShadow_points[6].v[2] = bounds_z_min;
1195
    gShadow_points[7].v[0] = bounds_x_min;
1196
    gShadow_points[7].v[1] = bounds_y_min;
1197
    gShadow_points[7].v[2] = bounds_z_max;
1198
    gShadow_clip_plane_count = 0;
1199
    BrMatrix34TApplyV(&light_ray_car, &gShadow_light_ray, &pCar->car_master_actor->t.t.mat);
1200
    y_offset = (bounds_y_max + bounds_y_min) / 2.0;
1201
    TryThisEdge(pCar, &light_ray_car, 2, 1.0, 1, 1.0, 0, 3, y_offset);
1202
    TryThisEdge(pCar, &light_ray_car, 2, -1.0, 1, 1.0, 1, 2, y_offset);
1203
    TryThisEdge(pCar, &light_ray_car, 2, -1.0, 1, -1.0, 6, 5, y_offset);
1204
    TryThisEdge(pCar, &light_ray_car, 2, 1.0, 1, -1.0, 7, 4, y_offset);
1205
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 1, 1.0, 1, 0, y_offset);
1206
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 1, 1.0, 2, 3, y_offset);
1207
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 1, -1.0, 7, 6, y_offset);
1208
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 1, -1.0, 4, 5, y_offset);
1209
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 2, 1.0, 4, 0, y_offset);
1210
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 2, 1.0, 3, 7, y_offset);
1211
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 2, -1.0, 2, 6, y_offset);
1212
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 2, -1.0, 5, 1, y_offset);
1213
    for (i = 0; i < gShadow_clip_plane_count; ++i) {
1214
        BrClipPlaneEnable(gShadow_clip_planes[i].clip);
1215
    }
1216
    face_count = GetPrecalculatedFacesUnderCar(pCar, &face_ref);
1217
 
1218
    if (!gAction_replay_mode && pCar->number_of_wheels_on_ground >= 3 && face_count != 0) {
1219
        highest_underneath = 0.0;
1220
    } else {
1221
        kev_bounds.original_bounds.min.v[0] = 1000.0;
1222
        kev_bounds.original_bounds.min.v[1] = 1000.0;
1223
        kev_bounds.original_bounds.min.v[2] = 1000.0;
1224
        kev_bounds.original_bounds.max.v[0] = -1000.0;
1225
        kev_bounds.original_bounds.max.v[1] = -1000.0;
1226
        kev_bounds.original_bounds.max.v[2] = -1000.0;
1227
        for (i = 0; i < COUNT_OF(shadow_points_world); i++) {
1228
            BrMatrix34ApplyP(&shadow_points_world[i], &gShadow_points[i], &pCar->car_master_actor->t.t.mat);
1229
            if (shadow_points_world[i].v[0] >= kev_bounds.original_bounds.min.v[0]) {
1230
                if (shadow_points_world[i].v[0] > kev_bounds.original_bounds.max.v[0]) {
1231
                    kev_bounds.original_bounds.max.v[0] = shadow_points_world[i].v[0];
1232
                }
1233
            } else {
1234
                kev_bounds.original_bounds.min.v[0] = shadow_points_world[i].v[0];
1235
            }
1236
            if (shadow_points_world[i].v[1] >= kev_bounds.original_bounds.min.v[1]) {
1237
                if (shadow_points_world[i].v[1] > kev_bounds.original_bounds.max.v[1]) {
1238
                    kev_bounds.original_bounds.max.v[1] = shadow_points_world[i].v[1];
1239
                }
1240
            } else {
1241
                kev_bounds.original_bounds.min.v[1] = shadow_points_world[i].v[1];
1242
            }
1243
            if (shadow_points_world[i].v[2] >= kev_bounds.original_bounds.min.v[2]) {
1244
                if (shadow_points_world[i].v[2] > kev_bounds.original_bounds.max.v[2]) {
1245
                    kev_bounds.original_bounds.max.v[2] = shadow_points_world[i].v[2];
1246
                }
1247
            } else {
1248
                kev_bounds.original_bounds.min.v[2] = shadow_points_world[i].v[2];
1249
            }
1250
        }
1251
        kev_bounds.original_bounds.min.v[1] = kev_bounds.original_bounds.min.v[1] - 4.4000001;
1252
        kev_bounds.mat = &gIdentity34;
1253
        face_count = FindFacesInBox(&kev_bounds, the_list, 100);
1254
        face_ref = the_list;
1255
        highest_underneath = 1000.0;
1256
        ray_length = kev_bounds.original_bounds.max.v[1] - kev_bounds.original_bounds.min.v[1];
1257
        ray.v[0] = 0.0;
1258
        ray.v[1] = -ray_length;
1259
        ray.v[2] = 0.0;
1260
        ray_pos = pCar->car_master_actor->t.t.translate.t;
1261
        ray_pos.v[1] = kev_bounds.original_bounds.max.v[1];
1262
    }
1263
    if (face_count) {
1264
        first_poly_below = -1000.0;
1265
        i = 0;
1266
        list_ptr = face_ref;
1267
        for (i = 0; i < face_count; i++) {
1268
            v1 = &list_ptr->v[1];
1269
            v2 = &list_ptr->v[2];
1270
            if (list_ptr->normal.v[1] >= -0.1 || (list_ptr->material && (list_ptr->material->flags & 0x1000) != 0)) {
1271
                if (list_ptr->normal.v[1] < 0.0 || (list_ptr->material && ((list_ptr->material->identifier && list_ptr->material->identifier[0] == '!') || list_ptr->material->index_blend))) {
1272
                    list_ptr->d = SHADOW_D_IGNORE_FLAG;
1273
                } else if ((list_ptr->v[0].v[1] > pCar->pos.v[1] || v1->v[1] > pCar->pos.v[1] || v2->v[1] > pCar->pos.v[1]) && list_ptr->normal.v[1] < 0.1) {
1274
                    list_ptr->d = SHADOW_D_IGNORE_FLAG;
1275
                }
1276
            } else {
1277
                poly_centre.v[0] = v1->v[0] + list_ptr->v[0].v[0];
1278
                poly_centre.v[1] = v1->v[1] + list_ptr->v[0].v[1];
1279
                poly_centre.v[2] = v1->v[2] + list_ptr->v[0].v[2];
1280
                poly_centre.v[0] = v2->v[0] + poly_centre.v[0];
1281
                poly_centre.v[1] = v2->v[1] + poly_centre.v[1];
1282
                poly_centre.v[2] = v2->v[2] + poly_centre.v[2];
1283
                poly_centre.v[0] = poly_centre.v[0] / 3.0;
1284
                poly_centre.v[1] = poly_centre.v[1] / 3.0;
1285
                poly_centre.v[2] = poly_centre.v[2] / 3.0;
1286
                poly_centre.v[1] = (v2->v[1] + v1->v[1] + list_ptr->v[0].v[1]) / 3.0;
1287
                if (poly_centre.v[1] > first_poly_below) {
1288
                    car_to_poly.v[0] = poly_centre.v[0] - pCar->car_master_actor->t.t.mat.m[3][0];
1289
                    car_to_poly.v[1] = poly_centre.v[1] - pCar->car_master_actor->t.t.mat.m[3][1];
1290
                    car_to_poly.v[2] = poly_centre.v[2] - pCar->car_master_actor->t.t.mat.m[3][2];
1291
 
1292
                    if (BrVector3Dot(&list_ptr->normal, &car_to_poly) > 0.0) {
1293
                        first_poly_below = poly_centre.v[1];
1294
                    }
1295
                }
1296
                list_ptr->d = SHADOW_D_IGNORE_FLAG;
1297
            }
1298
            list_ptr++;
1299
        }
1300
        list_ptr = face_ref;
1301
        for (i = 0; i < face_count; i++) {
1302
            if (list_ptr->d != 10000.0) {
1303
                if (list_ptr->v[0].v[1] >= first_poly_below || list_ptr->v[1].v[1] >= first_poly_below || list_ptr->v[2].v[1] >= first_poly_below) {
1304
                    if (gFancy_shadow) {
1305
                        faces[f_num].material = list_ptr->material;
1306
                        if (list_ptr->material && list_ptr->material->colour_map && (list_ptr->material->flags & BR_MATF_LIGHT) == 0) {
1307
                            list_ptr->material->flags |= BR_MATF_SMOOTH | BR_MATF_LIGHT;
1308
                            BrMaterialUpdate(list_ptr->material, BR_MATU_RENDERING);
1309
                        }
1310
                    } else {
1311
                        faces[f_num].material = gShadow_material;
1312
                    }
1313
 
1314
                    verts[3 * f_num].p = list_ptr->v[0];
1315
                    verts[3 * f_num].map = *list_ptr->map[0];
1316
                    verts[3 * f_num + 1].p = list_ptr->v[1];
1317
                    verts[3 * f_num + 1].map = *list_ptr->map[1];
1318
                    verts[3 * f_num + 2].p = list_ptr->v[2];
1319
                    verts[3 * f_num + 2].map = *list_ptr->map[2];
1320
                    faces[f_num].vertices[0] = 3 * f_num;
1321
                    faces[f_num].vertices[1] = 3 * f_num + 1;
1322
                    faces[f_num].vertices[2] = 3 * f_num + 2;
1323
                    f_num++;
1324
                    if (highest_underneath > 0.0) {
1325
                        CheckSingleFace(list_ptr, &ray_pos, &ray, &normal, &distance);
1326
                        if (distance < 1.0 && ray_length * distance < highest_underneath) {
1327
                            highest_underneath = ray_length * distance;
1328
                        }
1329
                    }
1330
                    if (f_num >= LEN(faces)) {
1331
                        break;
1332
                    }
1333
                }
1334
            }
1335
            list_ptr++;
1336
        }
1337
        highest_underneath = highest_underneath - (bounds_y_max - bounds_y_min);
1338
        if (highest_underneath < 2.2) {
1339
            if (highest_underneath < 0.0) {
1340
                highest_underneath = 0.0;
1341
            }
1342
        } else {
1343
            highest_underneath = (br_scalar) 2.2; // Pierre-Marie Baty -- added type cast
1344
        }
1345
        if (gFancy_shadow) {
1346
            gShadow_dim_amount = ((2.2 - highest_underneath) * 5.0 / 2.2 + 2.5);
1347
            for (i = 0; i < gSaved_table_count; i++) {
1348
                gSaved_shade_tables[i].original->height = 1;
1349
                gSaved_shade_tables[i].original->pixels = (tU8*)gDepth_shade_table->pixels + gShadow_dim_amount * gDepth_shade_table->row_bytes;
1350
 
1351
                BrTableUpdate(gSaved_shade_tables[i].original, BR_TABU_ALL);
1352
            }
1353
        }
1354
        shadow_scaling_factor = (2.2 - highest_underneath) * 0.52 / 2.2 + 0.4;
1355
        for (i = 0; i < gShadow_clip_plane_count; i++) {
1356
            clip_normal = (br_vector4*)gShadow_clip_planes[i].clip->type_data;
1357
            distance = DistanceFromPlane(&pCar->car_master_actor->t.t.euler.t, clip_normal->v[0], clip_normal->v[1], clip_normal->v[2], clip_normal->v[3]);
1358
            gShadow_clip_planes[i].clip->t.t.mat.m[3][0] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[0];
1359
            gShadow_clip_planes[i].clip->t.t.mat.m[3][1] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[1];
1360
            gShadow_clip_planes[i].clip->t.t.mat.m[3][2] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[2];
1361
        }
1362
 
1363
        camera_ptr = (br_camera*)gCamera->type_data;
1364
        DRMatrix34TApplyP(&pos_cam_space, &pCar->car_master_actor->t.t.euler.t, &gCamera_to_world);
1365
        if (pos_cam_space.v[2] >= 36.0 || pos_cam_space.v[2] >= camera_ptr->yon_z) {
1366
            camera_hither_fudge = 0.0;
1367
        } else {
1368
            camera_angle_additional_fudge = sqr(camera_ptr->yon_z - camera_ptr->hither_z);
1369
            camera_hither_fudge = camera_angle_additional_fudge * (pos_cam_space.v[2] * 1.0) / ((pos_cam_space.v[2] - camera_ptr->yon_z) * camera_ptr->yon_z * 65536.0);
1370
            if (camera_hither_fudge < 0.0002) {
1371
                camera_hither_fudge = (br_scalar) 0.0002; // Pierre-Marie Baty -- added type cast
1372
            }
1373
            camera_ptr->hither_z += camera_hither_fudge;
1374
        }
1375
        if (f_num) {
1376
            BrZbSceneRenderBegin(gUniverse_actor, gCamera, gRender_screen, gDepth_buffer);
1377
            gShadow_model->vertices = verts;
1378
            gShadow_model->faces = faces;
1379
            gShadow_model->nfaces = f_num;
1380
            gShadow_model->nvertices = 3 * f_num;
1381
            gShadow_actor->render_style = BR_RSTYLE_FACES;
1382
            BrModelAdd(gShadow_model);
1383
            BrZbSceneRenderAdd(gShadow_actor);
1384
            BrModelRemove(gShadow_model);
1385
            if (pCar->shadow_intersection_flags) {
1386
                oily_count = GetOilSpillCount();
1387
                for (i = 0; i < oily_count; ++i) {
1388
                    if (((1 << i) & pCar->shadow_intersection_flags) != 0) {
1389
                        GetOilSpillDetails(i, &oily_actor, &oily_size);
1390
                        if (oily_actor) {
1391
                            MungeIndexedOilsHeightAboveGround(i);
1392
                            BrZbSceneRenderAdd(oily_actor);
1393
                        }
1394
                    }
1395
                }
1396
            }
1397
            BrZbSceneRenderEnd();
1398
        }
1399
        camera_ptr->hither_z -= camera_hither_fudge;
1400
        for (i = 0; i < f_num; i++) {
1401
            if (gFancy_shadow) {
1402
                material = gShadow_model->faces[i].material;
1403
                if (material) {
1404
                    if (material->colour_map && (material->flags & BR_MATF_LIGHT) != 0) {
1405
                        material->flags &= ~(BR_MATF_LIGHT | BR_MATF_PRELIT | BR_MATF_SMOOTH);
1406
                        BrMaterialUpdate(material, BR_MATU_RENDERING);
1407
                    }
1408
                }
1409
            }
1410
        }
1411
    }
1412
    gShadow_actor->render_style = BR_RSTYLE_NONE;
1413
    for (i = 0; i < gShadow_clip_plane_count; i++) {
1414
        BrClipPlaneDisable(gShadow_clip_planes[i].clip);
1415
    }
1416
}
1417
 
1418
// IDA: void __usercall RenderShadows(br_actor *pWorld@<EAX>, tTrack_spec *pTrack_spec@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world_transform@<ECX>)
1419
void RenderShadows(br_actor* pWorld, tTrack_spec* pTrack_spec, br_actor* pCamera, br_matrix34* pCamera_to_world_transform) {
1420
    int i;
1421
    int cat;
1422
    int car_count;
1423
    tCar_spec* the_car;
1424
    br_vector3 camera_to_car;
1425
    br_scalar distance_factor;
1426
    LOG_TRACE("(%p, %p, %p, %p)", pWorld, pTrack_spec, pCamera, pCamera_to_world_transform);
1427
 
1428
    if (gShadow_level == eShadow_none) {
1429
        return;
1430
    }
1431
    for (cat = eVehicle_self;; ++cat) {
1432
        if (gShadow_level == eShadow_everyone) {
1433
            if (cat > 4) {
1434
                break;
1435
            }
1436
        } else {
1437
            if (cat > (gShadow_level == eShadow_us_and_opponents ? 3 : 0)) {
1438
                break;
1439
            }
1440
        }
1441
 
1442
        if (cat == eVehicle_self) {
1443
            car_count = 1;
1444
        } else {
1445
            car_count = GetCarCount(cat);
1446
        }
1447
        for (i = 0; i < car_count; i++) {
1448
            if (cat == eVehicle_self) {
1449
                the_car = &gProgram_state.current_car;
1450
            } else {
1451
                the_car = GetCarSpec(cat, i);
1452
            }
1453
            if (!the_car->active) {
1454
                continue;
1455
            }
1456
 
1457
            BrVector3Sub(&camera_to_car, (br_vector3*)gCamera_to_world.m[3], &the_car->car_master_actor->t.t.translate.t);
1458
            distance_factor = BrVector3LengthSquared(&camera_to_car);
1459
            if (gAction_replay_mode || distance_factor <= SHADOW_MAX_RENDER_DISTANCE) {
1460
                ProcessShadow(the_car, gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, distance_factor);
1461
            }
1462
        }
1463
    }
1464
    if (gFancy_shadow) {
1465
        for (i = 0; i < gSaved_table_count; i++) {
1466
            gSaved_shade_tables[i].original->height = gSaved_shade_tables[i].copy->height;
1467
            gSaved_shade_tables[i].original->pixels = gSaved_shade_tables[i].copy->pixels;
1468
            BrTableUpdate(gSaved_shade_tables[i].original, 0x7FFF);
1469
        }
1470
    }
1471
}
1472
 
1473
// IDA: void __usercall FlashyMapCheckpoint(int pIndex@<EAX>, tU32 pTime@<EDX>)
1474
void FlashyMapCheckpoint(int pIndex, tU32 pTime) {
1475
    //tCheckpoint* cp; // Pierre-Marie Baty -- unused variable
1476
    static tU32 last_flash;
1477
    static int flash_state;
1478
    LOG_TRACE("(%d, %d)", pIndex, pTime);
1479
 
1480
    if (pIndex >= 0 && pIndex < gCurrent_race.check_point_count && gRace_file_version > 0) {
1481
        if (Flash(300, &last_flash, &flash_state)) {
1482
            switch (gGraf_data_index) {
1483
            case 0:
1484
                DimRectangle(gBack_screen,
1485
                    gCurrent_race.checkpoints[pIndex].map_left[0],
1486
                    gCurrent_race.checkpoints[pIndex].map_top[0],
1487
                    gCurrent_race.checkpoints[pIndex].map_right[0],
1488
                    gCurrent_race.checkpoints[pIndex].map_bottom[0],
1489
                    0);
1490
                break;
1491
            case 1:
1492
                DimRectangle(gBack_screen,
1493
                    2 * gCurrent_race.checkpoints[pIndex].map_left[0],
1494
                    2 * gCurrent_race.checkpoints[pIndex].map_top[0] + 40,
1495
                    2 * gCurrent_race.checkpoints[pIndex].map_right[0],
1496
                    2 * gCurrent_race.checkpoints[pIndex].map_bottom[0] + 40,
1497
                    0);
1498
                break;
1499
            default:
1500
                TELL_ME_IF_WE_PASS_THIS_WAY();
1501
            }
1502
        }
1503
    }
1504
}
1505
 
1506
// IDA: int __usercall ConditionallyFillWithSky@<EAX>(br_pixelmap *pPixelmap@<EAX>)
1507
int ConditionallyFillWithSky(br_pixelmap* pPixelmap) {
1508
    int bgnd_col;
1509
    LOG_TRACE("(%p)", pPixelmap);
1510
 
1511
    if (gProgram_state.current_depth_effect.sky_texture != NULL && (gLast_camera_special_volume == NULL || gLast_camera_special_volume->sky_col < 0)) {
1512
        return 0;
1513
    }
1514
 
1515
    if (gProgram_state.current_depth_effect.type == eDepth_effect_fog || gSwap_depth_effect_type == eDepth_effect_fog) {
1516
        bgnd_col = 255;
1517
    } else if (gProgram_state.current_depth_effect.type && gSwap_depth_effect_type) {
1518
        if (gLast_camera_special_volume && gLast_camera_special_volume->sky_col >= 0) {
1519
            bgnd_col = gLast_camera_special_volume->sky_col;
1520
        } else {
1521
            bgnd_col = 0;
1522
        }
1523
    } else {
1524
        bgnd_col = 0;
1525
    }
1526
    BrPixelmapFill(pPixelmap, bgnd_col);
1527
    return 1;
1528
}
1529
 
1530
// IDA: void __usercall RenderAFrame(int pDepth_mask_on@<EAX>)
1531
void RenderAFrame(int pDepth_mask_on) {
1532
    int cat;
1533
    int i;
1534
    int car_count;
1535
    int flags;
1536
    int x_shift;
1537
    int y_shift;
1538
    int cockpit_on;
1539
    int real_origin_x = 0;
1540
    int real_origin_y = 0;
1541
    int real_base_x = 0;
1542
    int real_base_y = 0;
1543
    int map_timer_x;
1544
    int map_timer_width;
1545
    int ped_type;
1546
    char* old_pixels;
1547
    br_matrix34 old_camera_matrix;
1548
    br_matrix34 old_mirror_cam_matrix;
1549
    tU32 the_time;
1550
    br_vector3* car_pos;
1551
    br_vector3 pos;
1552
    char the_text[256];
1553
    tCar_spec* car;
1554
    LOG_TRACE("(%d)", pDepth_mask_on);
1555
 
1556
    gRender_screen->pixels = gBack_screen->pixels;
1557
    the_time = GetTotalTime();
1558
    old_pixels = gRender_screen->pixels;
1559
    cockpit_on = gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0 && !gMap_mode;
1560
    gMirror_on__graphics = gProgram_state.mirror_on && cockpit_on && gProgram_state.which_view == eView_forward;
1561
    if (gMap_mode) {
1562
        real_origin_x = gBack_screen->origin_x;
1563
        real_origin_y = gBack_screen->origin_y;
1564
        real_base_x = gBack_screen->base_x;
1565
        real_base_y = gBack_screen->base_y;
1566
        gBack_screen->origin_x = 0;
1567
        gBack_screen->origin_y = 0;
1568
        gBack_screen->base_x = 0;
1569
        gBack_screen->base_y = 0;
1570
        if (gCurrent_race.map_image != NULL) {
1571
            if (gReal_graf_data_index) {
1572
                BrPixelmapRectangleFill(gBack_screen, 0, 0, 640, 40, 0);
1573
                BrPixelmapRectangleFill(gBack_screen, 0, 440, 640, 40, 0);
1574
                DRPixelmapDoubledCopy(
1575
                    gBack_screen,
1576
                    gCurrent_race.map_image,
1577
                    gCurrent_race.map_image->width,
1578
                    gCurrent_race.map_image->height,
1579
                    0,
1580
                    40);
1581
            } else {
1582
                DRPixelmapCopy(gBack_screen, gCurrent_race.map_image);
1583
            }
1584
        }
1585
        DimRectangle(
1586
            gBack_screen,
1587
            gMap_render_x_i - gCurrent_graf_data->map_render_x_marg,
1588
            gMap_render_y_i - gCurrent_graf_data->map_render_y_marg,
1589
            gMap_render_x_i + gMap_render_width_i + gCurrent_graf_data->map_render_x_marg,
1590
            gMap_render_y_i + gMap_render_height_i + gCurrent_graf_data->map_render_y_marg,
1591
            1);
1592
    }
1593
    if (!gAction_replay_mode) {
1594
        CalculateWobblitude(the_time);
1595
    }
1596
    if (cockpit_on) {
1597
        if (-gScreen_wobble_x > gX_offset) {
1598
            x_shift = -gX_offset;
1599
        } else if (gScreen_wobble_x + gX_offset + gRender_screen->width > gBack_screen->width) {
1600
            x_shift = gBack_screen->width - gRender_screen->width - gX_offset;
1601
        } else {
1602
            x_shift = gScreen_wobble_x;
1603
        }
1604
        if (-gScreen_wobble_y > gY_offset) {
1605
            y_shift = -gY_offset;
1606
        } else if (gScreen_wobble_y + gY_offset + gRender_screen->height > gBack_screen->height) {
1607
            y_shift = gBack_screen->height - gRender_screen->height - gY_offset;
1608
        } else {
1609
            y_shift = gScreen_wobble_y;
1610
        }
1611
    } else {
1612
        x_shift = 0;
1613
        y_shift = 0;
1614
    }
1615
    BrMatrix34Copy(&old_camera_matrix, &gCamera->t.t.mat);
1616
    if (gMirror_on__graphics) {
1617
        BrMatrix34Copy(&old_mirror_cam_matrix, &gRearview_camera->t.t.mat);
1618
    }
1619
    if (cockpit_on) {
1620
        gSheer_mat.m[2][1] = y_shift / (float)gRender_screen->height;
1621
        gSheer_mat.m[2][0] = -x_shift / (float)gRender_screen->width;
1622
        BrMatrix34Pre(&gCamera->t.t.mat, &gSheer_mat);
1623
        gCamera->t.t.translate.t.v[0] -= gScreen_wobble_x * 1.5f / gRender_screen->width / WORLD_SCALE;
1624
        gCamera->t.t.translate.t.v[1] += gScreen_wobble_y * 1.5f / gRender_screen->width / WORLD_SCALE;
1625
    }
1626
    gRender_screen->pixels = (char*)gRender_screen->pixels + x_shift + y_shift * gRender_screen->row_bytes;
1627
    CalculateConcussion(the_time);
1628
    BrPixelmapRectangleFill(gDepth_buffer, 0, 0, gRender_screen->width, gRender_screen->height, 0xFFFFFFFF);
1629
    if (gRender_indent && !gMap_mode) {
1630
        BrPixelmapRectangleFill(
1631
            gBack_screen,
1632
            0,
1633
            0,
1634
            gGraf_specs[gGraf_spec_index].total_width,
1635
            gProgram_state.current_render_top,
1636
            0);
1637
        BrPixelmapRectangleFill(
1638
            gBack_screen,
1639
            0,
1640
            gProgram_state.current_render_bottom,
1641
            gGraf_specs[gGraf_spec_index].total_width,
1642
            gGraf_specs[gGraf_spec_index].total_height - gProgram_state.current_render_bottom,
1643
            0);
1644
        BrPixelmapRectangleFill(
1645
            gBack_screen,
1646
            0,
1647
            gProgram_state.current_render_top,
1648
            gProgram_state.current_render_left,
1649
            gProgram_state.current_render_bottom - gProgram_state.current_render_top,
1650
            0);
1651
        BrPixelmapRectangleFill(
1652
            gBack_screen,
1653
            gProgram_state.current_render_right,
1654
            gProgram_state.current_render_top,
1655
            gGraf_specs[gGraf_spec_index].total_width - gProgram_state.current_render_right,
1656
            gProgram_state.current_render_bottom - gProgram_state.current_render_top,
1657
            0);
1658
    }
1659
    gRendering_mirror = 0;
1660
    DoSpecialCameraEffect(gCamera, &gCamera_to_world);
1661
    if (!ConditionallyFillWithSky(gRender_screen)
1662
        && !gProgram_state.cockpit_on
1663
        && !(gAction_replay_camera_mode && gAction_replay_mode)) {
1664
        ExternalSky(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
1665
    }
1666
#if !defined(DETHRACE_FIX_BUGS)
1667
    // in map mode, the scene is rendered 3 times. We have no idea why.
1668
    for (i = 0; i < (gMap_mode ? 3 : 1); i++)
1669
#endif
1670
    {
1671
        RenderShadows(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world);
1672
        BrZbSceneRenderBegin(gUniverse_actor, gCamera, gRender_screen, gDepth_buffer);
1673
        ProcessNonTrackActors(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, &old_camera_matrix);
1674
        ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, 0);
1675
        RenderLollipops();
1676
 
1677
        // dethrace: must flush gpu buffer before rendering depth effect into framebuffer
1678
        gHarness_platform.Renderer_FlushBuffers();
1679
        DepthEffectSky(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
1680
        DepthEffect(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
1681
        if (!gAusterity_mode) {
1682
            ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, 1);
1683
        }
1684
        RenderSplashes();
1685
        // dethrace: must flush gpu buffer before rendering smoke into framebuffer
1686
        gHarness_platform.Renderer_FlushBuffers();
1687
        RenderSmoke(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, gFrame_period);
1688
        RenderSparks(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, gFrame_period);
1689
        RenderProximityRays(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, gFrame_period);
1690
        BrZbSceneRenderEnd();
1691
    }
1692
    BrMatrix34Copy(&gCamera->t.t.mat, &old_camera_matrix);
1693
    if (gMirror_on__graphics) {
1694
        LOG_WARN_ONCE("rearview mirror not implemented");
11 pmbaty 1695
#if 0
1696
        BrPixelmapFill(gRearview_depth_buffer, 0xFFFFFFFF);
1 pmbaty 1697
        gRendering_mirror = 1;
1698
        DoSpecialCameraEffect(gRearview_camera, &gRearview_camera_to_world);
1699
        ConditionallyFillWithSky(gRearview_screen);
1700
        BrZbSceneRenderBegin(gUniverse_actor, gRearview_camera, gRearview_screen, gRearview_depth_buffer);
1701
        ProcessNonTrackActors(
1702
            gRearview_screen,
1703
            gRearview_depth_buffer,
1704
            gRearview_camera,
1705
            &gRearview_camera_to_world,
1706
            &old_mirror_cam_matrix);
1707
        ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 0);
1708
        RenderLollipops();
1709
        DepthEffectSky(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
1710
        DepthEffect(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
1711
        if (!gAusterity_mode) {
1712
            ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 1);
1713
        }
1714
        RenderSplashes();
1715
        BrZbSceneRenderEnd();
1716
        BrMatrix34Copy(&gRearview_camera->t.t.mat, &old_mirror_cam_matrix);
11 pmbaty 1717
        gRendering_mirror = 0;
1718
#endif
1 pmbaty 1719
    }
1720
    if (gMap_mode) {
1721
        if (gNet_mode == eNet_mode_none) {
1722
            GetTimerString(the_text, 0);
1723
            map_timer_width = DRTextWidth(&gFonts[2], the_text);
1724
            map_timer_x = gCurrent_graf_data->map_timer_text_x - map_timer_width;
1725
            BrPixelmapRectangleFill(
1726
                gBack_screen,
1727
                map_timer_x - gCurrent_graf_data->map_timer_border_x,
1728
                gCurrent_graf_data->map_timer_text_y - gCurrent_graf_data->map_timer_border_y,
1729
                map_timer_width + 2 * gCurrent_graf_data->map_timer_border_x,
11 pmbaty 1730
                gFonts[kFont_BLUEHEAD].height + 2 * gCurrent_graf_data->map_timer_border_y,
1 pmbaty 1731
                0);
1732
            TransDRPixelmapText(
1733
                gBack_screen,
1734
                map_timer_x,
1735
                gCurrent_graf_data->map_timer_text_y,
11 pmbaty 1736
                &gFonts[kFont_BLUEHEAD],
1 pmbaty 1737
                the_text,
1738
                gBack_screen->width);
1739
        }
1740
        the_time = PDGetTotalTime();
1741
        if (gNet_mode != eNet_mode_none) {
1742
            if (gCurrent_net_game->type == eNet_game_type_checkpoint) {
1743
                flags = gNet_players[gThis_net_player_index].score;
1744
                for (i = 0; gCurrent_race.check_point_count > i; ++i) {
1745
                    if ((flags & 1) != 0) {
1746
                        FlashyMapCheckpoint(i, the_time);
1747
                    }
1748
                    flags >>= 1;
1749
                }
1750
            } else if (gCurrent_net_game->type == eNet_game_type_sudden_death
1751
                && gNet_players[gThis_net_player_index].score >= 0) {
1752
                FlashyMapCheckpoint(
1753
                    gNet_players[gThis_net_player_index].score % gCurrent_race.check_point_count,
1754
                    the_time);
1755
            }
1756
        } else {
1757
            FlashyMapCheckpoint(gCheckpoint - 1, the_time);
1758
        }
1759
        if (gShow_peds_on_map || (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
1760
            for (i = 0; i < GetPedCount(); i++) {
1761
                ped_type = GetPedPosition(i, &pos);
1762
                if (ped_type > 0 && gShow_peds_on_map) {
1763
                    DrawMapSmallBlip(the_time, &pos, 52);
1764
                } else if (ped_type < 0 && (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
1765
                    DrawMapSmallBlip(the_time, &pos, 4);
1766
                }
1767
            }
1768
        }
1769
        if (gShow_opponents) {
1770
            cat = eVehicle_opponent;
1771
        } else {
1772
            cat = eVehicle_self;
1773
        }
1774
        while (cat >= eVehicle_self) {
1775
            if (cat) {
1776
                car_count = GetCarCount(cat);
1777
            } else {
1778
                car_count = 1;
1779
            }
1780
            for (i = 0; i < car_count; i++) {
1781
                if (cat) {
1782
                    car = GetCarSpec(cat, i);
1783
                } else {
1784
                    car = &gProgram_state.current_car;
1785
                }
1786
                if (gNet_mode == eNet_mode_none || (!car->knackered && !NetPlayerFromCar(car)->wasted)) {
1787
                    if (cat) {
1788
                        car_pos = &GetCarSpec(cat, i)->car_master_actor->t.t.euler.t;
1789
                    } else {
1790
                        car_pos = &gSelf->t.t.euler.t;
1791
                    }
1792
                    if (gNet_mode) {
1793
                        DrawMapBlip(
1794
                            car,
1795
                            the_time,
1796
                            &car->car_master_actor->t.t.mat,
1797
                            car_pos,
1798
                            car->shrapnel_material[0]->index_range + car->shrapnel_material[0]->index_base - 1);
1799
                    } else if (car->knackered) {
1800
                        DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, 0);
1801
                    } else {
1802
                        DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, gMap_colours[cat]);
1803
                    }
1804
                }
1805
            }
1806
            cat--;
1807
        }
1808
        gBack_screen->origin_x = real_origin_x;
1809
        gBack_screen->origin_y = real_origin_y;
1810
        gBack_screen->base_x = real_base_x;
1811
        gBack_screen->base_y = real_base_y;
1812
    } else {
1813
        if (cockpit_on) {
1814
            CopyStripImage(
1815
                gBack_screen,
1816
                -gCurrent_graf_data->cock_margin_x,
1817
                gScreen_wobble_x,
1818
                -gCurrent_graf_data->cock_margin_y,
1819
                gScreen_wobble_y,
1820
                gProgram_state.current_car.cockpit_images[gProgram_state.cockpit_image_index],
1821
                0,
1822
                0,
1823
                gCurrent_graf_data->total_cock_width,
1824
                gCurrent_graf_data->total_cock_height);
1825
            if (gMirror_on__graphics) {
1826
                BrPixelmapRectangleCopy(
1827
                    gBack_screen,
1828
                    gScreen_wobble_x + gProgram_state.current_car.mirror_left,
1829
                    gScreen_wobble_y + gProgram_state.current_car.mirror_top,
1830
                    gRearview_screen,
1831
                    -gRearview_screen->origin_x,
1832
                    -gRearview_screen->origin_y,
1833
                    gProgram_state.current_car.mirror_right - gProgram_state.current_car.mirror_left,
1834
                    gProgram_state.current_car.mirror_bottom - gProgram_state.current_car.mirror_top);
1835
            }
1836
        }
1837
        DimAFewBits();
1838
        DoDamageScreen(the_time);
1839
        if (!gAction_replay_mode || gAR_fudge_headups) {
1840
            DoPratcam(the_time);
1841
            DoHeadups(the_time);
1842
        }
1843
        DoInstruments(the_time);
1844
        DoSteeringWheel(the_time);
1845
        if (!gAction_replay_mode || gAR_fudge_headups) {
1846
            DrawPowerups(the_time);
1847
        }
1848
    }
1849
    if (gNet_mode != eNet_mode_none) {
1850
        DisplayUserMessage();
1851
    }
1852
    if (gAction_replay_mode && !gAR_fudge_headups) {
1853
        DoActionReplayHeadups();
1854
    }
1855
    if (gAction_replay_mode) {
1856
        SynchronizeActionReplay();
1857
    } else {
1858
        PipeFrameFinish();
1859
    }
1860
    gRender_screen->pixels = old_pixels;
1861
    if (!gPalette_fade_time || GetRaceTime() > gPalette_fade_time + 500) {
1862
        PDScreenBufferSwap(0);
1863
    }
1864
    if (gAction_replay_mode) {
1865
        DoActionReplayPostSwap();
1866
    }
1867
}
1868
 
1869
// IDA: void __cdecl InitPaletteAnimate()
1870
void InitPaletteAnimate(void) {
1871
    LOG_TRACE("()");
1872
 
1873
    gLast_palette_change = 0;
1874
    gPalette_index = 0;
1875
}
1876
 
1877
// IDA: void __cdecl RevertPalette()
1878
void RevertPalette(void) {
1879
 
1880
    memcpy(gRender_palette->pixels, gOrig_render_palette->pixels, 0x400u);
1881
    DRSetPalette3(gRender_palette, 1);
1882
}
1883
 
1884
// IDA: void __cdecl MungePalette()
1885
void MungePalette(void) {
1886
    //tU8* p; // Pierre-Marie Baty -- unused variable
1887
    //tU8* q; // Pierre-Marie Baty -- unused variable
1888
    //int i; // Pierre-Marie Baty -- unused variable
1889
    //float damage; // Pierre-Marie Baty -- unused variable
1890
    //float throb_start; // Pierre-Marie Baty -- unused variable
1891
    //float throb_end; // Pierre-Marie Baty -- unused variable
1892
    //float throb_amount; // Pierre-Marie Baty -- unused variable
1893
    //float throb_amount_dash; // Pierre-Marie Baty -- unused variable
1894
    //float omega; // Pierre-Marie Baty -- unused variable
1895
    //tU32 period; // Pierre-Marie Baty -- unused variable
1896
    //tU32 the_time; // Pierre-Marie Baty -- unused variable
1897
    //static int palette_spammed; // Pierre-Marie Baty -- unused variable
1898
    //static float last_omega; // Pierre-Marie Baty -- unused variable
1899
    //static tU32 next_repair_time; // Pierre-Marie Baty -- unused variable
1900
    //static tU32 last_sound; // Pierre-Marie Baty -- unused variable
1901
    LOG_TRACE("()");
1902
    NOT_IMPLEMENTED();
1903
}
1904
 
1905
// IDA: void __cdecl ResetPalette()
1906
void ResetPalette(void) {
1907
    LOG_TRACE("()");
1908
 
1909
    InitPaletteAnimate();
1910
    DRSetPalette(gRender_palette);
1911
}
1912
 
1913
// IDA: void __usercall Darken(tU8 *pPtr@<EAX>, unsigned int pDarken_amount@<EDX>)
1914
void Darken(tU8* pPtr, unsigned int pDarken_amount) {
1915
    //unsigned int value; // Pierre-Marie Baty -- unused variable
1916
    LOG_TRACE10("(%p, %d)", pPtr, pDarken_amount);
1917
 
1918
    *pPtr = (pDarken_amount * *pPtr) / 256;
1919
}
1920
 
1921
// IDA: void __usercall SetFadedPalette(int pDegree@<EAX>)
1922
void SetFadedPalette(int pDegree) {
1923
    int j;
1924
    //br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
1925
    //char* the_pixels; // Pierre-Marie Baty -- unused variable
1926
    LOG_TRACE10("(%d)", pDegree);
1927
 
1928
    memcpy(gScratch_pixels, gCurrent_palette->pixels, 0x400u);
1929
    for (j = 0; j < 256; j++) {
1930
        Darken((tU8*)&gScratch_pixels[4 * j], pDegree);
1931
        Darken((tU8*)&gScratch_pixels[4 * j + 1], pDegree);
1932
        Darken((tU8*)&gScratch_pixels[4 * j + 2], pDegree);
1933
        Darken((tU8*)&gScratch_pixels[4 * j + 3], pDegree);
1934
    }
1935
    DRSetPalette2(gScratch_palette, 0);
1936
}
1937
 
1938
// IDA: void __cdecl FadePaletteDown()
1939
void FadePaletteDown(void) {
1940
    int i;
1941
    int start_time;
1942
    int the_time;
1943
    LOG_TRACE("()");
1944
 
1945
    if (!gFaded_palette) {
1946
        gFaded_palette = 1;
1947
        MungeEngineNoise();
1948
        gFaded_palette = 0;
1949
        start_time = PDGetTotalTime();
1950
        while (1) {
1951
            the_time = PDGetTotalTime() - start_time;
1952
            if (the_time >= 500) {
1953
                break;
1954
            }
1955
            i = 256 - ((the_time * 256) / 500);
1956
            SetFadedPalette(i);
1957
        }
1958
        SetFadedPalette(0);
1959
        gFaded_palette = 1;
1960
    }
1961
}
1962
 
1963
// IDA: void __cdecl FadePaletteUp()
1964
void FadePaletteUp(void) {
1965
    int i;
1966
    int start_time;
1967
    int the_time;
1968
    LOG_TRACE("()");
1969
 
1970
    if (gFaded_palette) {
1971
        gFaded_palette = 0;
1972
        start_time = PDGetTotalTime();
1973
        while (1) {
1974
            the_time = PDGetTotalTime() - start_time;
1975
            if (the_time >= 500) {
1976
                break;
1977
            }
1978
            i = (the_time * 256) / 500;
1979
            SetFadedPalette(i);
1980
        }
1981
        DRSetPalette(gCurrent_palette);
1982
    }
1983
}
1984
 
1985
// IDA: void __cdecl KillSplashScreen()
1986
void KillSplashScreen(void) {
1987
 
1988
    if (gCurrent_splash != NULL) {
1989
        BrMapRemove(gCurrent_splash);
1990
        BrPixelmapFree(gCurrent_splash);
1991
        gCurrent_splash = NULL;
1992
        FadePaletteDown();
1993
        ClearEntireScreen();
1994
    }
1995
}
1996
 
1997
// IDA: void __cdecl EnsureRenderPalette()
1998
void EnsureRenderPalette(void) {
1999
    LOG_TRACE("()");
2000
 
2001
    if (gPalette_munged) {
2002
        ResetPalette();
2003
        gPalette_munged = 0;
2004
    }
2005
}
2006
 
2007
// IDA: void __usercall SplashScreenWith(char *pPixmap_name@<EAX>)
2008
void SplashScreenWith(char* pPixmap_name) {
2009
    br_pixelmap* the_map;
2010
    LOG_TRACE("(\"%s\")", pPixmap_name);
2011
 
2012
    the_map = BrMapFind(pPixmap_name);
2013
    if (gCurrent_splash == NULL || the_map != gCurrent_splash) {
2014
        FadePaletteDown();
2015
        EnsureRenderPalette();
2016
 
2017
        if (gCurrent_splash != NULL) {
2018
            KillSplashScreen();
2019
        }
2020
        gCurrent_splash = the_map;
2021
        if (the_map == NULL) {
2022
            the_map = LoadPixelmap(pPixmap_name);
2023
            gCurrent_splash = the_map;
2024
            if (the_map != NULL) {
2025
                BrMapAdd(the_map);
2026
            }
2027
        }
2028
        if (gCurrent_splash != NULL) {
2029
            BrPixelmapRectangleCopy(
2030
                gBack_screen,
2031
                0,
2032
                0,
2033
                gCurrent_splash,
2034
                0,
2035
                0,
2036
                gCurrent_splash->width,
2037
                gCurrent_splash->height);
2038
            PDScreenBufferSwap(0);
2039
            if (gFaded_palette) {
2040
                FadePaletteUp();
2041
            }
2042
        }
2043
    }
2044
}
2045
 
2046
// IDA: void __cdecl EnsurePaletteUp()
2047
void EnsurePaletteUp(void) {
2048
 
2049
    if (gFaded_palette) {
2050
        FadePaletteUp();
2051
    }
2052
}
2053
 
2054
// IDA: br_uint_32 __cdecl AmbientificateMaterial(br_material *pMat, void *pArg)
2055
br_uint_32 AmbientificateMaterial(br_material* pMat, void* pArg) {
2056
    float a;
2057
 
2058
    a = pMat->ka + *(br_scalar*)pArg;
2059
    if (a < 0.f) {
2060
        a = 0.f;
2061
    } else if (a > 0.99f) {
2062
        a = 0.99f;
2063
    }
2064
    pMat->ka = a;
2065
    return 0;
2066
}
2067
 
2068
// IDA: void __cdecl ChangeAmbience(br_scalar pDelta)
2069
void ChangeAmbience(br_scalar pDelta) {
2070
    LOG_TRACE("(%f)", pDelta);
2071
 
2072
    BrMaterialEnum("*", AmbientificateMaterial, &pDelta);
2073
}
2074
 
2075
// IDA: void __cdecl InitAmbience()
2076
void InitAmbience(void) {
2077
    LOG_TRACE("()");
2078
 
2079
    gCurrent_ambience = gAmbient_adjustment;
2080
    ChangeAmbience(gAmbient_adjustment);
2081
}
2082
 
2083
// IDA: void __usercall DRPixelmapRectangleMaskedCopy(br_pixelmap *pDest@<EAX>, br_int_16 pDest_x@<EDX>, br_int_16 pDest_y@<EBX>, br_pixelmap *pSource@<ECX>, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight)
2084
void DRPixelmapRectangleMaskedCopy(br_pixelmap* pDest, br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight) {
2085
    int y_count;
2086
    int x_count;
2087
    int dest_row_wrap;
2088
    int source_row_wrap;
2089
    //int x_delta; // Pierre-Marie Baty -- unused variable
2090
    tU8 the_byte;
2091
    tU8* source_ptr;
2092
    tU8* dest_ptr;
2093
    tU8* conv_table;
2094
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2095
 
2096
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2097
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2098
    source_row_wrap = pSource->row_bytes - pWidth;
2099
    dest_row_wrap = pDest->row_bytes - pWidth;
2100
 
2101
    if (pDest_y < 0) {
2102
        pHeight += pDest_y;
2103
        if (pHeight <= 0) {
2104
            return;
2105
        }
2106
        source_ptr -= pDest_y * pSource->row_bytes;
2107
        dest_ptr -= pDest_y * pDest->row_bytes;
2108
        pDest_y = 0;
2109
    }
2110
    if (pDest_y >= pDest->height) {
2111
        return;
2112
    }
2113
    if (pDest_y + pHeight > pDest->height) {
2114
        pHeight = pDest->height - pDest_y;
2115
    }
2116
    if (pDest_x < 0) {
2117
        pWidth += pDest_x;
2118
        if (pWidth <= 0) {
2119
            return;
2120
        }
2121
        source_ptr -= pDest_x;
2122
        dest_ptr -= pDest_x;
2123
        source_row_wrap -= pDest_x;
2124
        dest_row_wrap -= pDest_x;
2125
        pDest_x = 0;
2126
    }
2127
    if (pDest_x >= pDest->width) {
2128
        return;
2129
    }
2130
    if (pDest_x + pWidth > pDest->width) {
2131
        source_row_wrap += pDest_x + pWidth - pDest->width;
2132
        dest_row_wrap += pDest_x + pWidth - pDest->width;
2133
        pWidth = pDest->width - pDest_x;
2134
    }
2135
    // LOG_DEBUG("2 (src->width: %d, src->height: %d, pDest_x: %d, pDest_y: %d, pSource_x: %d, pSource_y: %d, pWidth: %d, pHeight: %d)", pSource->width, pSource->height, pDest_x, pDest_y, pSource_x, pSource_y, pWidth, pHeight);
2136
    if (gCurrent_conversion_table != NULL) {
2137
        conv_table = gCurrent_conversion_table->pixels;
2138
        for (y_count = 0; y_count < pHeight; y_count++) {
2139
            for (x_count = 0; x_count < pWidth; x_count++) {
2140
                the_byte = *source_ptr;
2141
                if (the_byte != 0) {
2142
                    *dest_ptr = conv_table[the_byte];
2143
                }
2144
                source_ptr++;
2145
                dest_ptr++;
2146
            }
2147
            source_ptr += source_row_wrap;
2148
            dest_ptr += dest_row_wrap;
2149
        }
2150
    } else {
2151
        for (y_count = 0; y_count < pHeight; y_count++) {
2152
            for (x_count = 0; x_count < pWidth; x_count++) {
2153
                the_byte = *source_ptr;
2154
                if (the_byte != 0) {
2155
                    *dest_ptr = the_byte;
2156
                }
2157
                source_ptr++;
2158
                dest_ptr++;
2159
            }
2160
            source_ptr += source_row_wrap;
2161
            dest_ptr += dest_row_wrap;
2162
        }
2163
    }
2164
}
2165
 
2166
// IDA: void __usercall DRMaskedStamp(br_int_16 pDest_x@<EAX>, br_int_16 pDest_y@<EDX>, br_pixelmap *pSource@<EBX>)
2167
void DRMaskedStamp(br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource) {
2168
    LOG_TRACE("(%d, %d, %p)", pDest_x, pDest_y, pSource);
2169
 
2170
    DRPixelmapRectangleMaskedCopy(gBack_screen,
2171
        pDest_x,
2172
        pDest_y,
2173
        pSource,
2174
        0,
2175
        0,
2176
        pSource->width,
2177
        pSource->height);
2178
}
2179
 
2180
// IDA: void __usercall DRPixelmapRectangleOnscreenCopy(br_pixelmap *pDest@<EAX>, br_int_16 pDest_x@<EDX>, br_int_16 pDest_y@<EBX>, br_pixelmap *pSource@<ECX>, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight)
2181
void DRPixelmapRectangleOnscreenCopy(br_pixelmap* pDest, br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight) {
2182
    int y_count;
2183
    int x_count;
2184
    int dest_row_wrap;
2185
    int source_row_wrap;
2186
    //int x_delta; // Pierre-Marie Baty -- unused variable
2187
    tU8 the_byte;
2188
    tU8* source_ptr;
2189
    tU8* dest_ptr;
2190
    //tU8* conv_table; // Pierre-Marie Baty -- unused variable
2191
    // LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2192
 
2193
    source_row_wrap = pSource->row_bytes - pWidth;
2194
    dest_row_wrap = pDest->row_bytes - pWidth;
2195
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2196
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2197
 
2198
    for (y_count = 0; y_count < pHeight; y_count++) {
2199
        for (x_count = 0; x_count < pWidth; x_count++) {
2200
            the_byte = *source_ptr;
2201
            if (the_byte) {
2202
                *dest_ptr = the_byte;
2203
            }
2204
            source_ptr++;
2205
            dest_ptr++;
2206
        }
2207
        source_ptr += source_row_wrap;
2208
        dest_ptr += dest_row_wrap;
2209
    }
2210
}
2211
 
2212
// IDA: void __usercall DRPixelmapRectangleShearedCopy(br_pixelmap *pDest@<EAX>, br_int_16 pDest_x@<EDX>, br_int_16 pDest_y@<EBX>, br_pixelmap *pSource@<ECX>, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight, tX1616 pShear)
2213
void DRPixelmapRectangleShearedCopy(br_pixelmap* pDest, br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight, tX1616 pShear) {
2214
    int y_count;
2215
    int x_count;
2216
    int dest_row_wrap;
2217
    int source_row_wrap;
2218
    //int x_delta; // Pierre-Marie Baty -- unused variable
2219
    int last_shear_x;
2220
    int current_shear_x;
2221
    int shear_x_difference;
2222
    int pWidth_orig;
2223
    tU8 the_byte;
2224
    tU8* source_ptr;
2225
    tU8* dest_ptr;
2226
    //tU8* conv_table; // Pierre-Marie Baty -- unused variable
2227
    tX1616 current_shear;
2228
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight, pShear);
2229
 
2230
    current_shear = 0;
2231
    last_shear_x = 0;
2232
    source_ptr = (tU8*)pSource->pixels + pSource_x + pSource_y * pSource->row_bytes;
2233
    dest_ptr = (tU8*)pDest->pixels + pDest_x + pDest_y * pDest->row_bytes;
2234
    source_row_wrap = pSource->row_bytes - pWidth;
2235
    dest_row_wrap = pDest->row_bytes - pWidth;
2236
    if (pDest_y < 0) {
2237
        pHeight += pDest_y;
2238
        if (pHeight <= 0) {
2239
            return;
2240
        }
2241
        source_ptr -= pDest_y * pSource->row_bytes;
2242
        dest_ptr -= pDest_y * pDest->row_bytes;
2243
        pDest_y = 0;
2244
    }
2245
    if (pDest->height > pDest_y) {
2246
        if (pDest_y + pHeight > pDest->height) {
2247
            pHeight = pDest->height - pDest_y;
2248
        }
2249
        if (pDest_x < 0) {
2250
            pWidth += pDest_x;
2251
            if (pWidth <= 0) {
2252
                return;
2253
            }
2254
            source_ptr -= pDest_x;
2255
            dest_ptr -= pDest_x;
2256
            source_row_wrap -= pDest_x;
2257
            dest_row_wrap -= pDest_x;
2258
            pDest_x = 0;
2259
        }
2260
        if (pDest->width > pDest_x) {
2261
            pWidth_orig = pWidth;
2262
            for (y_count = 0; pHeight > y_count; ++y_count) {
2263
#if !defined(DETHRACE_FIX_BUGS)
2264
                /*
2265
                 * The OG compares against pWidth instead of pWidth_orig, which
2266
                 * ends up clipped to the dest pixelmap width. This effectively
2267
                 * clips the consecutive rows of pixels along the shear, leaving
2268
                 * a visible gap on the screen. Instead, when comparing against
2269
                 * pWidth_orig, the clip takes place vertically along the dest
2270
                 * pixelmap edge, allowing all pixels to be displayed.
2271
                 *
2272
                 * Simulate OG behavior by overwriting pWidth_orig with pWidth.
2273
                 */
2274
                pWidth_orig = pWidth;
2275
#endif
2276
                if (pDest_x + pWidth_orig > pDest->width) {
2277
                    shear_x_difference = pDest_x + pWidth - pDest->width;
2278
                    pWidth = pDest->width - pDest_x;
2279
                    source_row_wrap += shear_x_difference;
2280
                    dest_row_wrap += shear_x_difference;
2281
                }
2282
                for (x_count = 0; pWidth > x_count; ++x_count) {
2283
                    the_byte = *source_ptr++;
2284
                    if (the_byte) {
2285
                        *dest_ptr = the_byte;
2286
                    }
2287
                    ++dest_ptr;
2288
                }
2289
                current_shear_x = (current_shear >> 16) - last_shear_x;
2290
                dest_ptr += dest_row_wrap + current_shear_x;
2291
                last_shear_x = current_shear >> 16;
2292
                source_ptr += source_row_wrap;
2293
                current_shear += pShear;
2294
                pDest_x += current_shear_x;
2295
                if (pDest_x < 0) {
2296
                    pWidth += pDest_x;
2297
                    source_ptr -= pDest_x;
2298
                    dest_ptr -= pDest_x;
2299
                    source_row_wrap -= pDest_x;
2300
                    dest_row_wrap -= pDest_x;
2301
                    pDest_x = 0;
2302
                }
2303
                if (pDest->width <= pDest_x) {
2304
                    break;
2305
                }
2306
            }
2307
        }
2308
    }
2309
}
2310
 
2311
// IDA: void __usercall DRPixelmapRectangleVScaledCopy(br_pixelmap *pDest@<EAX>, br_int_16 pDest_x@<EDX>, br_int_16 pDest_y@<EBX>, br_pixelmap *pSource@<ECX>, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight)
2312
void DRPixelmapRectangleVScaledCopy(br_pixelmap* pDest, br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource, br_int_16 pSource_x, br_int_16 pSource_y, br_int_16 pWidth, br_int_16 pHeight) {
2313
    int y_count;
2314
    int x_count;
2315
    int dest_row_wrap;
2316
    int source_row_wrap;
2317
    //int x_delta; // Pierre-Marie Baty -- unused variable
2318
    tU8 the_byte;
2319
    tU8* source_ptr;
2320
    tU8* dest_ptr;
2321
    tU32 source_y;
2322
    tU32 source_y_delta;
2323
    tU32 old_source_y;
2324
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2325
 
2326
    if (!pHeight) {
2327
        return;
2328
    }
2329
 
2330
    source_row_wrap = pSource->row_bytes - pWidth;
2331
    dest_row_wrap = pDest->row_bytes - pWidth;
2332
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2333
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2334
 
2335
    source_y = 0;
2336
    source_y_delta = (pSource->height << 16) / pHeight - 0x10000;
2337
 
2338
    for (y_count = 0; y_count < pHeight; y_count++) {
2339
        for (x_count = 0; x_count < pWidth; x_count++) {
2340
            the_byte = *source_ptr;
2341
            if (the_byte) {
2342
                *dest_ptr = the_byte;
2343
            }
2344
            source_ptr++;
2345
            dest_ptr++;
2346
        }
2347
        old_source_y = source_y;
2348
        source_y += source_y_delta;
2349
        source_ptr += (((source_y >> 16) - (old_source_y >> 16)) * pSource->row_bytes) + source_row_wrap;
2350
        dest_ptr += dest_row_wrap;
2351
    }
2352
}
2353
 
2354
// IDA: void __cdecl InitTransientBitmaps()
2355
void InitTransientBitmaps(void) {
2356
    int i;
2357
    LOG_TRACE("()");
2358
 
2359
    for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2360
        gTransient_bitmaps[i].pixmap = NULL;
2361
        gTransient_bitmaps[i].in_use = 0;
2362
    }
2363
}
2364
 
2365
// IDA: int __usercall AllocateTransientBitmap@<EAX>(int pWidth@<EAX>, int pHeight@<EDX>, int pUser_data@<EBX>)
2366
int AllocateTransientBitmap(int pWidth, int pHeight, int pUser_data) {
2367
    int bm_index;
2368
    LOG_TRACE("(%d, %d, %d)", pWidth, pHeight, pUser_data);
2369
 
2370
    for (bm_index = 0; bm_index < COUNT_OF(gTransient_bitmaps); bm_index++) {
2371
        if (gTransient_bitmaps[bm_index].pixmap == NULL) {
2372
            gTransient_bitmaps[bm_index].pixmap = DRPixelmapAllocate(BR_PMT_INDEX_8, pWidth + 8, pHeight, NULL, 0);
2373
            gTransient_bitmaps[bm_index].in_use = 0;
2374
            gTransient_bitmaps[bm_index].user_data = pUser_data;
2375
            return bm_index;
2376
        }
2377
    }
2378
    FatalError(kFatalError_FindSpareTransientBitmap);
2379
}
2380
 
2381
// IDA: void __usercall DeallocateTransientBitmap(int pIndex@<EAX>)
2382
void DeallocateTransientBitmap(int pIndex) {
2383
    LOG_TRACE("(%d)", pIndex);
2384
 
2385
    if (gTransient_bitmaps[pIndex].pixmap != NULL) {
2386
        BrPixelmapFree(gTransient_bitmaps[pIndex].pixmap);
2387
        gTransient_bitmaps[pIndex].pixmap = NULL;
2388
        gTransient_bitmaps[pIndex].in_use = 0;
2389
    }
2390
}
2391
 
2392
// IDA: void __cdecl DeallocateAllTransientBitmaps()
2393
void DeallocateAllTransientBitmaps(void) {
2394
    int i;
2395
    LOG_TRACE("()");
2396
 
2397
    for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2398
        DeallocateTransientBitmap(i);
2399
    }
2400
}
2401
 
2402
// IDA: void __usercall RemoveTransientBitmaps(int pGraphically_remove_them@<EAX>)
2403
void RemoveTransientBitmaps(int pGraphically_remove_them) {
2404
    int i;
2405
    int order_number;
2406
 
2407
    if (pGraphically_remove_them) {
2408
        for (order_number = gNext_transient - 1; order_number >= 0; order_number--) {
2409
            for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2410
                if (gTransient_bitmaps[i].pixmap != NULL && gTransient_bitmaps[i].order_number == order_number) {
2411
                    if (gTransient_bitmaps[i].in_use) {
2412
                        BrPixelmapRectangleCopy(gBack_screen,
2413
                            gTransient_bitmaps[i].x_coord,
2414
                            gTransient_bitmaps[i].y_coord,
2415
                            gTransient_bitmaps[i].pixmap,
2416
                            0,
2417
                            0,
2418
                            gTransient_bitmaps[i].pixmap->width,
2419
                            gTransient_bitmaps[i].pixmap->height);
2420
                    }
2421
                    break;
2422
                }
2423
            }
2424
        }
2425
    }
2426
    gNext_transient = 0;
2427
}
2428
 
2429
// IDA: void __usercall SaveTransient(int pIndex@<EAX>, int pX_coord@<EDX>, int pY_coord@<EBX>)
2430
void SaveTransient(int pIndex, int pX_coord, int pY_coord) {
2431
    LOG_TRACE("(%d, %d, %d)", pIndex, pX_coord, pY_coord);
2432
 
2433
    gTransient_bitmaps[pIndex].x_coord = pX_coord & ~3;
2434
    gTransient_bitmaps[pIndex].y_coord = pY_coord;
2435
    gTransient_bitmaps[pIndex].in_use = 1;
2436
    gTransient_bitmaps[pIndex].order_number = gNext_transient;
2437
    gNext_transient++;
2438
    BrPixelmapRectangleCopy(gTransient_bitmaps[pIndex].pixmap,
2439
        0,
2440
        0,
2441
        gBack_screen,
2442
        gTransient_bitmaps[pIndex].x_coord,
2443
        gTransient_bitmaps[pIndex].y_coord,
2444
        gTransient_bitmaps[pIndex].pixmap->width,
2445
        gTransient_bitmaps[pIndex].pixmap->height);
2446
}
2447
 
2448
// IDA: void __usercall DrawCursorGiblet(tCursor_giblet *pGib@<EAX>)
2449
void DrawCursorGiblet(tCursor_giblet* pGib) {
2450
    br_pixelmap* the_image;
2451
    LOG_TRACE("(%p)", pGib);
2452
 
2453
    SaveTransient(pGib->transient_index, pGib->x_coord, pGib->y_coord);
2454
    the_image = gCursor_giblet_images[gCursor_giblet_sequences[pGib->sequence_index][pGib->current_giblet]];
2455
    DRPixelmapRectangleMaskedCopy(gBack_screen,
2456
        pGib->x_coord,
2457
        pGib->y_coord,
2458
        the_image,
2459
        0,
2460
        0,
2461
        the_image->width,
2462
        the_image->height);
2463
}
2464
 
2465
// IDA: void __usercall ProcessCursorGiblets(int pPeriod@<EAX>)
2466
void ProcessCursorGiblets(int pPeriod) {
2467
    int i;
2468
    int kill_the_giblet;
2469
    tU32 time_now;
2470
    tCursor_giblet* gib;
2471
    LOG_TRACE("(%d)", pPeriod);
2472
 
2473
    time_now = PDGetTotalTime();
2474
    for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2475
        gib = &gCursor_giblets[i];
2476
        kill_the_giblet = 0;
2477
        if (gib->current_giblet == -1) {
2478
            continue;
2479
        }
2480
        if (!gib->landed && gib->e_t_a <= time_now) {
2481
            gib->landed = 1;
2482
            gib->the_speed = 0.f;
2483
        }
2484
        if (gib->landed) {
2485
            gib->giblet_change_period -= pPeriod / 2;
2486
            if (gib->giblet_change_period < 50) {
2487
                gib->giblet_change_period = 50;
2488
            }
2489
            if (gib->giblet_change_period <= time_now - gib->last_giblet_change) {
2490
                if (gCursor_giblet_sequences[gib->sequence_index][0] == gib->current_giblet) {
2491
                    gib->current_giblet = 1;
2492
                } else {
2493
                    gib->current_giblet++;
2494
                }
2495
                gib->last_giblet_change = time_now;
2496
            }
2497
            gib->y_coord += pPeriod * gib->the_speed / 1000.f;
2498
            if (gib->y_coord <= gGraf_data[gGraf_data_index].height) {
2499
                if (gib->the_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
2500
                    gib->the_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f;
2501
                }
2502
            } else {
2503
                kill_the_giblet = 1;
2504
            }
2505
        } else {
2506
            if (gib->y_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
2507
                gib->y_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f * 2.f;
2508
            }
2509
            gib->x_coord += pPeriod * gib->x_speed / 1000.f;
2510
            gib->y_coord += pPeriod * gib->y_speed / 1000.f;
2511
            if (gib->x_coord < 0.f || gib->x_coord >= gGraf_data[gGraf_spec_index].width || gib->y_coord < 0.f || gib->y_coord >= gGraf_data[gGraf_spec_index].height) {
2512
                kill_the_giblet = 1;
2513
            }
2514
        }
2515
        if (kill_the_giblet) {
2516
            gib->current_giblet = -1;
2517
            DeallocateTransientBitmap(gib->transient_index);
2518
        } else {
2519
            DrawCursorGiblet(gib);
2520
        }
2521
    }
2522
}
2523
 
2524
// IDA: int __usercall NewCursorGiblet@<EAX>(int pX_coord@<EAX>, int pY_coord@<EDX>, float pX_speed, float pY_speed, tU32 pDrop_time)
2525
int NewCursorGiblet(int pX_coord, int pY_coord, float pX_speed, float pY_speed, tU32 pDrop_time) {
2526
    int i;
2527
    int the_width;
2528
    int the_height;
2529
    int sequence_number;
2530
    LOG_TRACE("(%d, %d, %f, %f, %d)", pX_coord, pY_coord, pX_speed, pY_speed, pDrop_time);
2531
 
2532
    sequence_number = IRandomBetween(0, COUNT_OF(gCursor_giblet_sequences) - 1);
2533
    if (pX_coord >= 0 && pX_coord < gGraf_data[gGraf_data_index].width && pY_coord >= 0 && pY_coord < gGraf_data[gGraf_data_index].height) {
2534
        for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2535
            if (gCursor_giblets[i].current_giblet == -1) {
2536
                the_width = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->width;
2537
                the_height = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->height;
2538
                gCursor_giblets[i].transient_index = AllocateTransientBitmap(the_width, the_height, 1);
2539
                gCursor_giblets[i].current_giblet = 1;
2540
                gCursor_giblets[i].sequence_index = sequence_number;
2541
                gCursor_giblets[i].landed = 0;
2542
                gCursor_giblets[i].x_coord = sequence_number * gGraf_specs[gGraf_spec_index].total_width / 640 - the_width / 2 + pX_coord;
2543
                gCursor_giblets[i].y_coord = FRandomPosNeg(6.f) * gGraf_specs[gGraf_spec_index].total_height / 480 - the_height / 2 + pY_coord;
2544
                gCursor_giblets[i].x_speed = pX_speed;
2545
                gCursor_giblets[i].y_speed = pY_speed;
2546
                gCursor_giblets[i].last_giblet_change = 0;
2547
                gCursor_giblets[i].giblet_change_period = 1000;
2548
                gCursor_giblets[i].e_t_a = PDGetTotalTime() + pDrop_time;
2549
                return i;
2550
            }
2551
        }
2552
    }
2553
    return -1;
2554
}
2555
 
2556
// IDA: int __cdecl DoMouseCursor()
2557
int DoMouseCursor(void) {
2558
    int x_coord; // Added by DethRace
2559
    int y_coord;
2560
    int mouse_moved;
2561
    int new_required;
2562
    //int giblet_index; // Pierre-Marie Baty -- unused variable
2563
    int cursor_offset;
2564
    int button_is_down;
2565
    int giblet_chance;
2566
    int giblet_count;
2567
    tU32 this_call_time;
2568
    static tU32 last_cursor_change;
2569
    static tU32 last_call_time;
2570
    static tU32 last_required_change;
2571
    tS32 period;
2572
    static int delta_x;
2573
    static int required_cursor;
2574
    static int zero_count;
2575
    static int button_was_down;
2576
 
2577
    period = 0;
2578
    this_call_time = PDGetTotalTime();
2579
    if (last_call_time == 0) {
2580
        period = 1000;
2581
    }
2582
    while (period <= 20) {
2583
        this_call_time = PDGetTotalTime();
2584
        period = this_call_time - last_call_time;
2585
        // added by dethrace to avoid 100% CPU usage
2586
        gHarness_platform.Sleep(1);
2587
    }
2588
    GetMousePosition(&x_coord, &y_coord);
2589
    mouse_moved = x_coord != gMouse_last_x_coord || y_coord != gMouse_last_y_coord;
2590
    button_is_down = EitherMouseButtonDown();
2591
    cursor_offset = button_is_down ? 4 : 0;
2592
    if (gMouse_in_use || mouse_moved) {
2593
        gMouse_in_use = 1;
2594
        if (gMouse_last_x_coord == x_coord) {
2595
            if (zero_count >= 5) {
2596
                delta_x = 0;
2597
            }
2598
            zero_count++;
2599
        } else {
2600
            zero_count = 0;
2601
            delta_x = (x_coord - gMouse_last_x_coord) * 1000 / period;
2602
        }
2603
        if (delta_x < -10) {
2604
            new_required = 0;
2605
        } else if (delta_x < 11) {
2606
            new_required = 2;
2607
        } else {
2608
            new_required = 3;
2609
        }
2610
        if (new_required != required_cursor && this_call_time - last_required_change >= 200) {
2611
            last_required_change = this_call_time;
2612
            required_cursor = new_required;
2613
        }
2614
        if (gCurrent_cursor_index != required_cursor && PDGetTotalTime() - last_cursor_change >= 50) {
2615
            if (required_cursor < gCurrent_cursor_index) {
2616
                gCurrent_cursor_index--;
2617
            } else {
2618
                gCurrent_cursor_index++;
2619
            }
2620
            last_cursor_change = PDGetTotalTime();
2621
        }
2622
        giblet_chance = Chance(1.f + 20.f * (abs(x_coord - gMouse_last_x_coord) + abs(y_coord - gMouse_last_y_coord)) / (float)period, period);
2623
        if (gProgram_state.sausage_eater_mode) {
2624
            giblet_count = 0;
2625
        } else {
2626
            giblet_count = 6 * BooleanTo1Or0(button_is_down && !button_was_down) + BooleanTo1Or0(giblet_chance);
2627
        }
2628
        for (; giblet_count != 0; giblet_count--) {
2629
            NewCursorGiblet(
2630
                x_coord + gCursor_gib_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2631
                y_coord + gCursor_gib_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
2632
                ((float)(x_coord - gMouse_last_x_coord)) / period * 1000.f / 4.f,
2633
                ((float)(y_coord - gMouse_last_y_coord)) / period * 1000.f / 3.f,
2634
                (button_is_down && !button_was_down) ? 50 : 400);
2635
        }
2636
        ProcessCursorGiblets(period);
2637
        SaveTransient(gCursor_transient_index,
2638
            x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2639
            y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480);
2640
        DRPixelmapRectangleMaskedCopy(gBack_screen,
2641
            x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2642
            y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
2643
            gCursors[gCurrent_cursor_index + cursor_offset],
2644
            0,
2645
            0,
2646
            gCursors[gCurrent_cursor_index + cursor_offset]->width,
2647
            gCursors[gCurrent_cursor_index + cursor_offset]->height);
2648
    }
2649
    last_call_time = this_call_time;
2650
    button_was_down = button_is_down;
2651
    gMouse_last_x_coord = x_coord;
2652
    gMouse_last_y_coord = y_coord;
2653
    return mouse_moved;
2654
}
2655
 
2656
// IDA: int __cdecl AllocateCursorTransient()
2657
int AllocateCursorTransient(void) {
2658
    int i;
2659
    int largest_width;
2660
    int largest_height;
2661
    LOG_TRACE("()");
2662
 
2663
    largest_width = 0;
2664
    largest_height = 0;
2665
    for (i = 0; i < COUNT_OF(gCursors); i++) {
2666
        if (largest_width < gCursors[i]->width) {
2667
            largest_width = gCursors[i]->width;
2668
        }
2669
        if (largest_height < gCursors[i]->height) {
2670
            largest_height = gCursors[i]->height;
2671
        }
2672
    }
2673
    return AllocateTransientBitmap(largest_width, largest_height, 0);
2674
}
2675
 
2676
// IDA: void __cdecl StartMouseCursor()
2677
void StartMouseCursor(void) {
2678
    int i;
2679
    LOG_TRACE("()");
2680
 
2681
    gNext_transient = 0;
2682
    gCursor_transient_index = AllocateCursorTransient();
2683
    GetMousePosition(&gMouse_last_x_coord, &gMouse_last_y_coord);
2684
    gMouse_in_use = 0;
2685
    gCurrent_cursor_index = 2;
2686
    for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2687
        gCursor_giblets[i].current_giblet = -1;
2688
    }
2689
    gMouse_started = 1;
2690
}
2691
 
2692
// IDA: void __cdecl EndMouseCursor()
2693
void EndMouseCursor(void) {
2694
    LOG_TRACE("()");
2695
 
2696
    RemoveTransientBitmaps(1);
2697
    DeallocateAllTransientBitmaps();
2698
    gMouse_started = 0;
2699
}
2700
 
2701
// IDA: void __usercall LoadFont(int pFont_ID@<EAX>)
2702
void LoadFont(int pFont_ID) {
2703
    tPath_name the_path;
2704
    int i;
2705
    int number_of_chars;
2706
    FILE* f;
2707
    tU32 the_size;
2708
    LOG_TRACE("(%d)", pFont_ID);
2709
 
2710
    if (gFonts[pFont_ID].images != NULL) {
2711
        return;
2712
    }
2713
 
2714
    PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
2715
    PathCat(the_path, the_path, "FONTS");
2716
    PathCat(the_path, the_path, gFont_names[pFont_ID]);
2717
    number_of_chars = strlen(the_path);
2718
    strcat(the_path, ".PIX");
2719
    gFonts[pFont_ID].images = DRPixelmapLoad(the_path);
2720
 
2721
    if (gFonts[pFont_ID].images == NULL) {
2722
        FatalError(kFatalError_LoadFontImage_S, gFont_names[pFont_ID]);
2723
    }
2724
    if (!gFonts[pFont_ID].file_read_once) {
2725
        strcpy(&the_path[number_of_chars + 1], "TXT");
2726
 
2727
        f = DRfopen(the_path, "rt");
2728
        if (f == NULL) {
2729
            FatalError(kFatalError_LoadFontWidthTable_S, gFont_names[pFont_ID]);
2730
        }
2731
 
2732
        gFonts[pFont_ID].height = GetAnInt(f);
2733
        gFonts[pFont_ID].width = GetAnInt(f);
2734
        gFonts[pFont_ID].spacing = GetAnInt(f);
2735
        gFonts[pFont_ID].offset = GetAnInt(f);
2736
        gFonts[pFont_ID].num_entries = GetAnInt(f);
2737
        if (gFonts[pFont_ID].width <= 0) {
2738
            for (i = 0; i < gFonts[pFont_ID].num_entries; i++) {
2739
                the_size = GetAnInt(f);
2740
                gFonts[pFont_ID].width_table[i] = the_size;
2741
            }
2742
        }
2743
        fclose(f);
2744
        gFonts[pFont_ID].file_read_once = 1;
2745
    }
2746
}
2747
 
2748
// IDA: void __usercall DisposeFont(int pFont_ID@<EAX>)
2749
void DisposeFont(int pFont_ID) {
2750
    LOG_TRACE("(%d)", pFont_ID);
2751
    if (gFonts[pFont_ID].images && (!TranslationMode() || (gAusterity_mode && FlicsPlayedFromDisk()))) {
2752
        BrPixelmapFree(gFonts[pFont_ID].images);
2753
        gFonts[pFont_ID].images = NULL;
2754
        gFonts[pFont_ID].file_read_once = 0;
2755
    }
2756
}
2757
 
2758
// IDA: void __cdecl InitDRFonts()
2759
void InitDRFonts(void) {
2760
    int i;
2761
    LOG_TRACE("()");
2762
 
2763
    for (i = 0; i < 21; i++) {
2764
        gFonts[i].file_read_once = 0;
2765
        gFonts[i].images = NULL;
2766
    }
2767
}
2768
 
2769
// IDA: void __usercall DrawDropImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip, int pOffset)
2770
void DrawDropImage(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip, int pOffset) {
2771
    int y;
2772
    int src_y;
2773
    int src_height;
2774
    int y_diff;
2775
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip, pOffset);
2776
 
2777
    BrPixelmapRectangleFill(gBack_screen,
2778
        pLeft,
2779
        pTop_clip,
2780
        pImage->width,
2781
        pBottom_clip - pTop_clip,
2782
        0);
2783
    if (pOffset != 1000) {
2784
        src_y = 0;
2785
        src_height = pImage->height;
2786
        y = pOffset + pTop;
2787
        y_diff = pTop_clip - y;
2788
        if (y_diff > 0) {
2789
            src_height -= y_diff;
2790
            y += y_diff;
2791
            src_y = y_diff;
2792
        }
2793
        y_diff = pBottom_clip - y - pImage->height;
2794
        if (y_diff < 0) {
2795
            src_height += y_diff;
2796
        }
2797
        BrPixelmapRectangleCopy(gBack_screen,
2798
            pLeft,
2799
            y,
2800
            pImage,
2801
            0,
2802
            src_y,
2803
            pImage->width,
2804
            src_height);
2805
        PDScreenBufferSwap(0);
2806
    }
2807
}
2808
 
2809
// IDA: void __usercall DropInImageFromTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2810
void DropInImageFromTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2811
    tS32 start_time;
2812
    tS32 the_time;
2813
    int drop_distance;
2814
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2815
 
2816
    start_time = PDGetTotalTime();
2817
    drop_distance = pImage->height - pTop_clip + pTop;
2818
    while (1) {
2819
        the_time = PDGetTotalTime();
2820
        if (the_time >= start_time + 100) {
2821
            break;
2822
        }
2823
        DrawDropImage(pImage,
2824
            pLeft,
2825
            pTop,
2826
            pTop_clip,
2827
            pBottom_clip,
2828
            (the_time - start_time - 100) * drop_distance / 100);
2829
    }
2830
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
2831
}
2832
 
2833
// IDA: void __usercall DropOutImageThruBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2834
void DropOutImageThruBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2835
    tS32 start_time;
2836
    tS32 the_time;
2837
    int drop_distance;
2838
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2839
 
2840
    start_time = PDGetTotalTime();
2841
    drop_distance = pBottom_clip - pTop;
2842
    while (1) {
2843
        the_time = PDGetTotalTime();
2844
        if (the_time >= start_time + 100) {
2845
            break;
2846
        }
2847
        DrawDropImage(pImage,
2848
            pLeft,
2849
            pTop,
2850
            pTop_clip,
2851
            pBottom_clip,
2852
            (the_time - start_time) * drop_distance / 100);
2853
    }
2854
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
2855
}
2856
 
2857
// IDA: void __usercall DropInImageFromBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2858
void DropInImageFromBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2859
    tS32 start_time;
2860
    tS32 the_time;
2861
    int drop_distance;
2862
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2863
 
2864
    start_time = PDGetTotalTime();
2865
    drop_distance = pBottom_clip - pTop;
2866
    while (1) {
2867
        the_time = PDGetTotalTime();
2868
        if (the_time >= start_time + 100) {
2869
            break;
2870
        }
2871
        DrawDropImage(pImage,
2872
            pLeft,
2873
            pTop,
2874
            pTop_clip,
2875
            pBottom_clip,
2876
            (100 - the_time + start_time) * drop_distance / 100);
2877
    }
2878
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
2879
}
2880
 
2881
// IDA: void __usercall DropOutImageThruTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2882
void DropOutImageThruTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2883
    tS32 start_time;
2884
    tS32 the_time;
2885
    int drop_distance;
2886
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2887
 
2888
    start_time = PDGetTotalTime();
2889
    drop_distance = pImage->height - pTop_clip + pTop;
2890
    while (1) {
2891
        the_time = PDGetTotalTime();
2892
        if (the_time >= start_time + 100) {
2893
            break;
2894
        }
2895
        DrawDropImage(pImage,
2896
            pLeft,
2897
            pTop,
2898
            pTop_clip,
2899
            pBottom_clip,
2900
            (start_time - the_time) * drop_distance / 100);
2901
    }
2902
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
2903
}
2904
 
2905
// IDA: void __usercall DrawTellyLine(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
2906
void DrawTellyLine(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
2907
    int the_width;
2908
    int the_height;
2909
    LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
2910
 
2911
    the_width = pImage->width;
2912
    the_height = pImage->height / 2 + pTop;
2913
    BrPixelmapLine(gBack_screen, pLeft, the_height, pLeft + the_width, the_height, 0);
2914
    BrPixelmapLine(gBack_screen, the_width / 2 + pLeft - pPercentage * the_width / 200, the_height, the_width / 2 + pLeft + pPercentage * the_width / 200, the_height, 1);
2915
    PDScreenBufferSwap(0);
2916
}
2917
 
2918
// IDA: void __usercall DrawTellyImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
2919
void DrawTellyImage(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
2920
    //int the_height; // Pierre-Marie Baty -- unused variable
2921
    LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
2922
 
2923
    BrPixelmapRectangleFill(gBack_screen, pLeft, pTop, pImage->width, pImage->height, 0);
2924
    if (pPercentage != 1000) {
2925
        DRPixelmapRectangleVScaledCopy(
2926
            gBack_screen,
2927
            pLeft,
2928
            pTop + pImage->height * (100 - pPercentage) / 200,
2929
            pImage,
2930
            0,
2931
            0,
2932
            pImage->width,
2933
            pPercentage * pImage->height / 100);
2934
        PDScreenBufferSwap(0);
2935
    }
2936
}
2937
 
2938
// IDA: void __usercall TellyInImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
2939
void TellyInImage(br_pixelmap* pImage, int pLeft, int pTop) {
2940
    tS32 start_time;
2941
    tS32 the_time;
2942
    LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
2943
 
2944
    start_time = PDGetTotalTime();
2945
    while (1) {
2946
        the_time = PDGetTotalTime();
2947
        if (start_time + 100 <= the_time) {
2948
            break;
2949
        }
2950
        DrawTellyLine(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
2951
    }
2952
    start_time = PDGetTotalTime();
2953
    while (1) {
2954
        the_time = PDGetTotalTime();
2955
        if (start_time + 100 <= the_time) {
2956
            break;
2957
        }
2958
        DrawTellyImage(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
2959
    }
2960
    DrawTellyImage(pImage, pLeft, pTop, 100);
2961
}
2962
 
2963
// IDA: void __usercall TellyOutImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
2964
void TellyOutImage(br_pixelmap* pImage, int pLeft, int pTop) {
2965
    tS32 start_time;
2966
    tS32 the_time;
2967
    //int drop_distance; // Pierre-Marie Baty -- unused variable
2968
    LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
2969
 
2970
    start_time = PDGetTotalTime();
2971
    while (1) {
2972
        the_time = PDGetTotalTime();
2973
        if (start_time + 100 <= the_time) {
2974
            break;
2975
        }
2976
        DrawTellyImage(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
2977
    }
2978
    DrawTellyImage(pImage, pLeft, pTop, 1000);
2979
 
2980
    start_time = PDGetTotalTime();
2981
    while (1) {
2982
        the_time = PDGetTotalTime();
2983
        if (start_time + 100 <= the_time) {
2984
            break;
2985
        }
2986
        DrawTellyLine(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
2987
    }
2988
    DrawTellyLine(pImage, pLeft, pTop, 0);
2989
}
2990
 
2991
// IDA: void __usercall SetShadowLevel(tShadow_level pLevel@<EAX>)
2992
void SetShadowLevel(tShadow_level pLevel) {
2993
    LOG_TRACE("(%d)", pLevel);
2994
 
2995
    gShadow_level = pLevel;
2996
}
2997
 
2998
// IDA: tShadow_level __cdecl GetShadowLevel()
2999
tShadow_level GetShadowLevel(void) {
3000
    LOG_TRACE("()");
3001
 
3002
    return gShadow_level;
3003
}
3004
 
3005
// IDA: void __cdecl ToggleShadow()
3006
void ToggleShadow(void) {
3007
    LOG_TRACE("()");
3008
 
3009
    gShadow_level++;
3010
    if (gShadow_level == eShadow_everyone) {
3011
        gShadow_level = eShadow_none;
3012
    }
3013
    switch (gShadow_level) {
3014
    case eShadow_none:
3015
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoShadows));
3016
        break;
3017
    case eShadow_us_only:
3018
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderOwnCar));
3019
        break;
3020
    case eShadow_us_and_opponents:
3021
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderMainCars));
3022
        break;
3023
    case eShadow_everyone:
3024
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderAllCars));
3025
        break;
3026
    default:
3027
        return;
3028
    }
3029
}
3030
 
3031
// IDA: void __cdecl InitShadow()
3032
void InitShadow(void) {
3033
    int i;
3034
    //br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
3035
    LOG_TRACE("()");
3036
 
3037
    for (i = 0; i < 8; i++) {
3038
        gShadow_clip_planes[i].clip = BrActorAllocate(BR_ACTOR_CLIP_PLANE, NULL);
3039
        BrActorAdd(gUniverse_actor, gShadow_clip_planes[i].clip);
3040
        BrClipPlaneDisable(gShadow_clip_planes[i].clip);
3041
        BrMatrix34Identity(&gShadow_clip_planes[i].clip->t.t.mat);
3042
    }
3043
    gFancy_shadow = 1;
3044
    gShadow_material = BrMaterialFind("SHADOW.MAT");
3045
    BrVector3Set(&gShadow_light_ray, 0.f, -1.f, 0.f);
3046
    BrVector3Set(&gShadow_light_z, -0.f, -0.f, -1.f);
3047
    BrVector3Set(&gShadow_light_x, 1.f, 0.f, 0.f);
3048
 
3049
    gShadow_model = BrModelAllocate("", 0, 0);
3050
    gShadow_model->flags = BR_MODF_GENERATE_TAGS | BR_MODF_KEEP_ORIGINAL;
3051
    gShadow_actor = BrActorAllocate(BR_ACTOR_MODEL, 0);
3052
    gShadow_actor->model = gShadow_model;
3053
    BrActorAdd(gUniverse_actor, gShadow_actor);
3054
}
3055
 
3056
// IDA: br_uint_32 __cdecl SaveShadeTable(br_pixelmap *pTable, void *pArg)
3057
br_uint_32 SaveShadeTable(br_pixelmap* pTable, void* pArg) {
3058
    LOG_TRACE("(%p, %p)", pTable, pArg);
3059
 
3060
    if (gSaved_table_count == COUNT_OF(gSaved_shade_tables)) {
3061
        return 1;
3062
    }
3063
    gSaved_shade_tables[gSaved_table_count].original = pTable;
3064
    gSaved_shade_tables[gSaved_table_count].copy = (br_pixelmap*)BrMemAllocate(sizeof(br_pixelmap), kMem_shade_table_copy);
3065
    memcpy(gSaved_shade_tables[gSaved_table_count].copy, pTable, sizeof(br_pixelmap));
3066
    gSaved_table_count++;
3067
    return 0;
3068
}
3069
 
3070
// IDA: void __cdecl SaveShadeTables()
3071
void SaveShadeTables(void) {
3072
    LOG_TRACE("()");
3073
 
3074
    PossibleService();
3075
    gSaved_table_count = 0;
3076
    BrTableEnum("*", SaveShadeTable, 0);
3077
}
3078
 
3079
// IDA: void __cdecl DisposeSavedShadeTables()
3080
void DisposeSavedShadeTables(void) {
3081
    int i;
3082
    LOG_TRACE("()");
3083
 
3084
    for (i = 0; i < gSaved_table_count; i++) {
3085
        BrMemFree(gSaved_shade_tables[i].copy);
3086
    }
3087
}
3088
 
3089
// IDA: void __cdecl ShadowMode()
3090
void ShadowMode(void) {
3091
    LOG_TRACE("()");
3092
 
3093
    gFancy_shadow = !gFancy_shadow;
3094
    if (gFancy_shadow) {
3095
        NewTextHeadupSlot(4, 0, 2000, -4, "Translucent shadow");
3096
    } else {
3097
        NewTextHeadupSlot(4, 0, 2000, -4, "Solid shadow");
3098
    }
3099
}
3100
 
3101
// IDA: int __cdecl SwitchToRealResolution()
3102
int SwitchToRealResolution(void) {
3103
    LOG_TRACE("()");
3104
 
3105
    if (gGraf_data_index == gReal_graf_data_index) {
3106
        return 0;
3107
    }
3108
    gGraf_data_index = gReal_graf_data_index;
3109
    gGraf_spec_index = gReal_graf_data_index;
3110
    gCurrent_graf_data = &gGraf_data[gReal_graf_data_index];
3111
    PDSwitchToRealResolution();
3112
    return 1;
3113
}
3114
 
3115
// IDA: int __cdecl SwitchToLoresMode()
3116
int SwitchToLoresMode(void) {
3117
    LOG_TRACE("()");
3118
    if (!gGraf_data_index || gGraf_data_index != gReal_graf_data_index) {
3119
        return 0;
3120
    }
3121
    gGraf_data_index = 0;
3122
    gGraf_spec_index = 0;
3123
    gCurrent_graf_data = gGraf_data;
3124
    PDSwitchToLoresMode();
3125
    return 1;
3126
}
3127
 
3128
// IDA: void __usercall DRPixelmapDoubledCopy(br_pixelmap *pDestn@<EAX>, br_pixelmap *pSource@<EDX>, int pSource_width@<EBX>, int pSource_height@<ECX>, int pX_offset, int pY_offset)
3129
void DRPixelmapDoubledCopy(br_pixelmap* pDestn, br_pixelmap* pSource, int pSource_width, int pSource_height, int pX_offset, int pY_offset) {
3130
    tU16* sptr;
3131
    tU16 pixels;
3132
    tU8* dptr;
3133
    tU8* dptr2;
3134
    tU8 pixel_1;
3135
    tU8 pixel_2;
3136
    int i;
3137
    int j;
3138
    int dst_row_skip;
3139
    int src_row_skip;
3140
    int width_over_2;
3141
    LOG_TRACE("(%p, %p, %d, %d, %d, %d)", pDestn, pSource, pSource_width, pSource_height, pX_offset, pY_offset);
3142
 
3143
    dst_row_skip = 2 * pDestn->row_bytes - 2 * pSource_width;
3144
    src_row_skip = (pSource->row_bytes - pSource_width) / 2;
3145
    sptr = (tU16*)((tU8*)pSource->pixels - 2 * src_row_skip + 2 * (pSource->row_bytes * pSource_height / 2));
3146
    dptr = (tU8*)pDestn->pixels + 2 * pSource_width + (2 * pSource_height + pY_offset) * pDestn->row_bytes - pDestn->row_bytes;
3147
    dptr2 = dptr - pDestn->row_bytes;
3148
    width_over_2 = pSource_width / 2;
3149
    for (i = 0; i < pSource_height; i++) {
3150
        for (j = 0; j < width_over_2; j++) {
3151
            --sptr;
3152
            pixels = *sptr;
3153
            pixel_1 = pixels >> 8;
3154
            pixel_2 = pixels >> 0;
3155
            dptr[-1] = pixel_1;
3156
            dptr2[-1] = pixel_1;
3157
            dptr[-2] = pixel_1;
3158
            dptr2[-2] = pixel_1;
3159
            dptr[-3] = pixel_2;
3160
            dptr2[-3] = pixel_2;
3161
            dptr[-4] = pixel_2;
3162
            dptr2[-4] = pixel_2;
3163
            dptr -= 4;
3164
            dptr2 -= 4;
3165
        }
3166
        dptr -= dst_row_skip;
3167
        dptr2 -= dst_row_skip;
3168
        sptr -= src_row_skip;
3169
    }
3170
}