Subversion Repositories Games.Carmageddon

Rev

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

Rev Author Line No. Line
1 pmbaty 1
#include "graphics.h"
2
 
20 pmbaty 3
#include "brender/brender.h"
1 pmbaty 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) {
20 pmbaty 710
    //br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
1 pmbaty 711
    LOG_TRACE("(\"%s\")", pPal_name);
20 pmbaty 712
    NOT_IMPLEMENTED();
1 pmbaty 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
 
20 pmbaty 1677
        // dethrace: must flush gpu buffer before rendering depth effect into framebuffer
1678
        gHarness_platform.Renderer_FlushBuffers();
1 pmbaty 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();
20 pmbaty 1685
        // dethrace: must flush gpu buffer before rendering smoke into framebuffer
1686
        gHarness_platform.Renderer_FlushBuffers();
1 pmbaty 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) {
20 pmbaty 1694
        LOG_WARN_ONCE("rearview mirror not implemented");
1695
        // BrPixelmapFill(gRearview_depth_buffer, 0xFFFFFFFF);
1696
        // gRendering_mirror = 1;
1697
        // DoSpecialCameraEffect(gRearview_camera, &gRearview_camera_to_world);
1698
        // ConditionallyFillWithSky(gRearview_screen);
1699
        // BrZbSceneRenderBegin(gUniverse_actor, gRearview_camera, gRearview_screen, gRearview_depth_buffer);
1700
        // ProcessNonTrackActors(
1701
        //     gRearview_screen,
1702
        //     gRearview_depth_buffer,
1703
        //     gRearview_camera,
1704
        //     &gRearview_camera_to_world,
1705
        //     &old_mirror_cam_matrix);
1706
        // ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 0);
1707
        // RenderLollipops();
1708
        // DepthEffectSky(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
1709
        // DepthEffect(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
1710
        // if (!gAusterity_mode) {
1711
        //     ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 1);
1712
        // }
1713
        // RenderSplashes();
1714
        // BrZbSceneRenderEnd();
1715
        // BrMatrix34Copy(&gRearview_camera->t.t.mat, &old_mirror_cam_matrix);
1716
        // gRendering_mirror = 0;
1 pmbaty 1717
    }
1718
    if (gMap_mode) {
1719
        if (gNet_mode == eNet_mode_none) {
1720
            GetTimerString(the_text, 0);
1721
            map_timer_width = DRTextWidth(&gFonts[2], the_text);
1722
            map_timer_x = gCurrent_graf_data->map_timer_text_x - map_timer_width;
1723
            BrPixelmapRectangleFill(
1724
                gBack_screen,
1725
                map_timer_x - gCurrent_graf_data->map_timer_border_x,
1726
                gCurrent_graf_data->map_timer_text_y - gCurrent_graf_data->map_timer_border_y,
1727
                map_timer_width + 2 * gCurrent_graf_data->map_timer_border_x,
11 pmbaty 1728
                gFonts[kFont_BLUEHEAD].height + 2 * gCurrent_graf_data->map_timer_border_y,
1 pmbaty 1729
                0);
1730
            TransDRPixelmapText(
1731
                gBack_screen,
1732
                map_timer_x,
1733
                gCurrent_graf_data->map_timer_text_y,
11 pmbaty 1734
                &gFonts[kFont_BLUEHEAD],
1 pmbaty 1735
                the_text,
1736
                gBack_screen->width);
1737
        }
1738
        the_time = PDGetTotalTime();
1739
        if (gNet_mode != eNet_mode_none) {
1740
            if (gCurrent_net_game->type == eNet_game_type_checkpoint) {
1741
                flags = gNet_players[gThis_net_player_index].score;
1742
                for (i = 0; gCurrent_race.check_point_count > i; ++i) {
1743
                    if ((flags & 1) != 0) {
1744
                        FlashyMapCheckpoint(i, the_time);
1745
                    }
1746
                    flags >>= 1;
1747
                }
1748
            } else if (gCurrent_net_game->type == eNet_game_type_sudden_death
1749
                && gNet_players[gThis_net_player_index].score >= 0) {
1750
                FlashyMapCheckpoint(
1751
                    gNet_players[gThis_net_player_index].score % gCurrent_race.check_point_count,
1752
                    the_time);
1753
            }
1754
        } else {
1755
            FlashyMapCheckpoint(gCheckpoint - 1, the_time);
1756
        }
1757
        if (gShow_peds_on_map || (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
1758
            for (i = 0; i < GetPedCount(); i++) {
1759
                ped_type = GetPedPosition(i, &pos);
1760
                if (ped_type > 0 && gShow_peds_on_map) {
1761
                    DrawMapSmallBlip(the_time, &pos, 52);
1762
                } else if (ped_type < 0 && (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
1763
                    DrawMapSmallBlip(the_time, &pos, 4);
1764
                }
1765
            }
1766
        }
1767
        if (gShow_opponents) {
1768
            cat = eVehicle_opponent;
1769
        } else {
1770
            cat = eVehicle_self;
1771
        }
1772
        while (cat >= eVehicle_self) {
1773
            if (cat) {
1774
                car_count = GetCarCount(cat);
1775
            } else {
1776
                car_count = 1;
1777
            }
1778
            for (i = 0; i < car_count; i++) {
1779
                if (cat) {
1780
                    car = GetCarSpec(cat, i);
1781
                } else {
1782
                    car = &gProgram_state.current_car;
1783
                }
1784
                if (gNet_mode == eNet_mode_none || (!car->knackered && !NetPlayerFromCar(car)->wasted)) {
1785
                    if (cat) {
1786
                        car_pos = &GetCarSpec(cat, i)->car_master_actor->t.t.euler.t;
1787
                    } else {
1788
                        car_pos = &gSelf->t.t.euler.t;
1789
                    }
1790
                    if (gNet_mode) {
1791
                        DrawMapBlip(
1792
                            car,
1793
                            the_time,
1794
                            &car->car_master_actor->t.t.mat,
1795
                            car_pos,
1796
                            car->shrapnel_material[0]->index_range + car->shrapnel_material[0]->index_base - 1);
1797
                    } else if (car->knackered) {
1798
                        DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, 0);
1799
                    } else {
1800
                        DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, gMap_colours[cat]);
1801
                    }
1802
                }
1803
            }
1804
            cat--;
1805
        }
1806
        gBack_screen->origin_x = real_origin_x;
1807
        gBack_screen->origin_y = real_origin_y;
1808
        gBack_screen->base_x = real_base_x;
1809
        gBack_screen->base_y = real_base_y;
1810
    } else {
1811
        if (cockpit_on) {
1812
            CopyStripImage(
1813
                gBack_screen,
1814
                -gCurrent_graf_data->cock_margin_x,
1815
                gScreen_wobble_x,
1816
                -gCurrent_graf_data->cock_margin_y,
1817
                gScreen_wobble_y,
1818
                gProgram_state.current_car.cockpit_images[gProgram_state.cockpit_image_index],
1819
                0,
1820
                0,
1821
                gCurrent_graf_data->total_cock_width,
1822
                gCurrent_graf_data->total_cock_height);
1823
            if (gMirror_on__graphics) {
1824
                BrPixelmapRectangleCopy(
1825
                    gBack_screen,
1826
                    gScreen_wobble_x + gProgram_state.current_car.mirror_left,
1827
                    gScreen_wobble_y + gProgram_state.current_car.mirror_top,
1828
                    gRearview_screen,
1829
                    -gRearview_screen->origin_x,
1830
                    -gRearview_screen->origin_y,
1831
                    gProgram_state.current_car.mirror_right - gProgram_state.current_car.mirror_left,
1832
                    gProgram_state.current_car.mirror_bottom - gProgram_state.current_car.mirror_top);
1833
            }
1834
        }
1835
        DimAFewBits();
1836
        DoDamageScreen(the_time);
1837
        if (!gAction_replay_mode || gAR_fudge_headups) {
1838
            DoPratcam(the_time);
1839
            DoHeadups(the_time);
1840
        }
1841
        DoInstruments(the_time);
1842
        DoSteeringWheel(the_time);
1843
        if (!gAction_replay_mode || gAR_fudge_headups) {
1844
            DrawPowerups(the_time);
1845
        }
1846
    }
1847
    if (gNet_mode != eNet_mode_none) {
1848
        DisplayUserMessage();
1849
    }
1850
    if (gAction_replay_mode && !gAR_fudge_headups) {
1851
        DoActionReplayHeadups();
1852
    }
1853
    if (gAction_replay_mode) {
1854
        SynchronizeActionReplay();
1855
    } else {
1856
        PipeFrameFinish();
1857
    }
1858
    gRender_screen->pixels = old_pixels;
1859
    if (!gPalette_fade_time || GetRaceTime() > gPalette_fade_time + 500) {
1860
        PDScreenBufferSwap(0);
1861
    }
1862
    if (gAction_replay_mode) {
1863
        DoActionReplayPostSwap();
1864
    }
1865
}
1866
 
1867
// IDA: void __cdecl InitPaletteAnimate()
1868
void InitPaletteAnimate(void) {
1869
    LOG_TRACE("()");
1870
 
1871
    gLast_palette_change = 0;
1872
    gPalette_index = 0;
1873
}
1874
 
1875
// IDA: void __cdecl RevertPalette()
1876
void RevertPalette(void) {
1877
 
1878
    memcpy(gRender_palette->pixels, gOrig_render_palette->pixels, 0x400u);
1879
    DRSetPalette3(gRender_palette, 1);
1880
}
1881
 
1882
// IDA: void __cdecl MungePalette()
1883
void MungePalette(void) {
1884
    //tU8* p; // Pierre-Marie Baty -- unused variable
1885
    //tU8* q; // Pierre-Marie Baty -- unused variable
1886
    //int i; // Pierre-Marie Baty -- unused variable
1887
    //float damage; // Pierre-Marie Baty -- unused variable
1888
    //float throb_start; // Pierre-Marie Baty -- unused variable
1889
    //float throb_end; // Pierre-Marie Baty -- unused variable
1890
    //float throb_amount; // Pierre-Marie Baty -- unused variable
1891
    //float throb_amount_dash; // Pierre-Marie Baty -- unused variable
1892
    //float omega; // Pierre-Marie Baty -- unused variable
1893
    //tU32 period; // Pierre-Marie Baty -- unused variable
1894
    //tU32 the_time; // Pierre-Marie Baty -- unused variable
1895
    //static int palette_spammed; // Pierre-Marie Baty -- unused variable
1896
    //static float last_omega; // Pierre-Marie Baty -- unused variable
1897
    //static tU32 next_repair_time; // Pierre-Marie Baty -- unused variable
1898
    //static tU32 last_sound; // Pierre-Marie Baty -- unused variable
1899
    LOG_TRACE("()");
1900
    NOT_IMPLEMENTED();
1901
}
1902
 
1903
// IDA: void __cdecl ResetPalette()
1904
void ResetPalette(void) {
1905
    LOG_TRACE("()");
1906
 
1907
    InitPaletteAnimate();
1908
    DRSetPalette(gRender_palette);
1909
}
1910
 
1911
// IDA: void __usercall Darken(tU8 *pPtr@<EAX>, unsigned int pDarken_amount@<EDX>)
1912
void Darken(tU8* pPtr, unsigned int pDarken_amount) {
1913
    //unsigned int value; // Pierre-Marie Baty -- unused variable
1914
    LOG_TRACE10("(%p, %d)", pPtr, pDarken_amount);
1915
 
1916
    *pPtr = (pDarken_amount * *pPtr) / 256;
1917
}
1918
 
1919
// IDA: void __usercall SetFadedPalette(int pDegree@<EAX>)
1920
void SetFadedPalette(int pDegree) {
1921
    int j;
1922
    //br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
1923
    //char* the_pixels; // Pierre-Marie Baty -- unused variable
1924
    LOG_TRACE10("(%d)", pDegree);
1925
 
1926
    memcpy(gScratch_pixels, gCurrent_palette->pixels, 0x400u);
1927
    for (j = 0; j < 256; j++) {
1928
        Darken((tU8*)&gScratch_pixels[4 * j], pDegree);
1929
        Darken((tU8*)&gScratch_pixels[4 * j + 1], pDegree);
1930
        Darken((tU8*)&gScratch_pixels[4 * j + 2], pDegree);
1931
        Darken((tU8*)&gScratch_pixels[4 * j + 3], pDegree);
1932
    }
1933
    DRSetPalette2(gScratch_palette, 0);
1934
}
1935
 
1936
// IDA: void __cdecl FadePaletteDown()
1937
void FadePaletteDown(void) {
1938
    int i;
1939
    int start_time;
1940
    int the_time;
1941
    LOG_TRACE("()");
1942
 
1943
    if (!gFaded_palette) {
1944
        gFaded_palette = 1;
1945
        MungeEngineNoise();
1946
        gFaded_palette = 0;
1947
        start_time = PDGetTotalTime();
1948
        while (1) {
1949
            the_time = PDGetTotalTime() - start_time;
1950
            if (the_time >= 500) {
1951
                break;
1952
            }
1953
            i = 256 - ((the_time * 256) / 500);
1954
            SetFadedPalette(i);
1955
        }
1956
        SetFadedPalette(0);
1957
        gFaded_palette = 1;
1958
    }
1959
}
1960
 
1961
// IDA: void __cdecl FadePaletteUp()
1962
void FadePaletteUp(void) {
1963
    int i;
1964
    int start_time;
1965
    int the_time;
1966
    LOG_TRACE("()");
1967
 
1968
    if (gFaded_palette) {
1969
        gFaded_palette = 0;
1970
        start_time = PDGetTotalTime();
1971
        while (1) {
1972
            the_time = PDGetTotalTime() - start_time;
1973
            if (the_time >= 500) {
1974
                break;
1975
            }
1976
            i = (the_time * 256) / 500;
1977
            SetFadedPalette(i);
1978
        }
1979
        DRSetPalette(gCurrent_palette);
1980
    }
1981
}
1982
 
1983
// IDA: void __cdecl KillSplashScreen()
1984
void KillSplashScreen(void) {
1985
 
1986
    if (gCurrent_splash != NULL) {
1987
        BrMapRemove(gCurrent_splash);
1988
        BrPixelmapFree(gCurrent_splash);
1989
        gCurrent_splash = NULL;
1990
        FadePaletteDown();
1991
        ClearEntireScreen();
1992
    }
1993
}
1994
 
1995
// IDA: void __cdecl EnsureRenderPalette()
1996
void EnsureRenderPalette(void) {
1997
    LOG_TRACE("()");
1998
 
1999
    if (gPalette_munged) {
2000
        ResetPalette();
2001
        gPalette_munged = 0;
2002
    }
2003
}
2004
 
2005
// IDA: void __usercall SplashScreenWith(char *pPixmap_name@<EAX>)
2006
void SplashScreenWith(char* pPixmap_name) {
2007
    br_pixelmap* the_map;
2008
    LOG_TRACE("(\"%s\")", pPixmap_name);
2009
 
2010
    the_map = BrMapFind(pPixmap_name);
2011
    if (gCurrent_splash == NULL || the_map != gCurrent_splash) {
2012
        FadePaletteDown();
2013
        EnsureRenderPalette();
2014
 
2015
        if (gCurrent_splash != NULL) {
2016
            KillSplashScreen();
2017
        }
2018
        gCurrent_splash = the_map;
2019
        if (the_map == NULL) {
2020
            the_map = LoadPixelmap(pPixmap_name);
2021
            gCurrent_splash = the_map;
2022
            if (the_map != NULL) {
2023
                BrMapAdd(the_map);
2024
            }
2025
        }
2026
        if (gCurrent_splash != NULL) {
2027
            BrPixelmapRectangleCopy(
2028
                gBack_screen,
2029
                0,
2030
                0,
2031
                gCurrent_splash,
2032
                0,
2033
                0,
2034
                gCurrent_splash->width,
2035
                gCurrent_splash->height);
2036
            PDScreenBufferSwap(0);
2037
            if (gFaded_palette) {
2038
                FadePaletteUp();
2039
            }
2040
        }
2041
    }
2042
}
2043
 
2044
// IDA: void __cdecl EnsurePaletteUp()
2045
void EnsurePaletteUp(void) {
2046
 
2047
    if (gFaded_palette) {
2048
        FadePaletteUp();
2049
    }
2050
}
2051
 
2052
// IDA: br_uint_32 __cdecl AmbientificateMaterial(br_material *pMat, void *pArg)
2053
br_uint_32 AmbientificateMaterial(br_material* pMat, void* pArg) {
2054
    float a;
2055
 
2056
    a = pMat->ka + *(br_scalar*)pArg;
2057
    if (a < 0.f) {
2058
        a = 0.f;
2059
    } else if (a > 0.99f) {
2060
        a = 0.99f;
2061
    }
2062
    pMat->ka = a;
2063
    return 0;
2064
}
2065
 
2066
// IDA: void __cdecl ChangeAmbience(br_scalar pDelta)
2067
void ChangeAmbience(br_scalar pDelta) {
2068
    LOG_TRACE("(%f)", pDelta);
2069
 
2070
    BrMaterialEnum("*", AmbientificateMaterial, &pDelta);
2071
}
2072
 
2073
// IDA: void __cdecl InitAmbience()
2074
void InitAmbience(void) {
2075
    LOG_TRACE("()");
2076
 
2077
    gCurrent_ambience = gAmbient_adjustment;
2078
    ChangeAmbience(gAmbient_adjustment);
2079
}
2080
 
2081
// 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)
2082
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) {
2083
    int y_count;
2084
    int x_count;
2085
    int dest_row_wrap;
2086
    int source_row_wrap;
2087
    //int x_delta; // Pierre-Marie Baty -- unused variable
2088
    tU8 the_byte;
2089
    tU8* source_ptr;
2090
    tU8* dest_ptr;
2091
    tU8* conv_table;
2092
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2093
 
2094
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2095
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2096
    source_row_wrap = pSource->row_bytes - pWidth;
2097
    dest_row_wrap = pDest->row_bytes - pWidth;
2098
 
2099
    if (pDest_y < 0) {
2100
        pHeight += pDest_y;
2101
        if (pHeight <= 0) {
2102
            return;
2103
        }
2104
        source_ptr -= pDest_y * pSource->row_bytes;
2105
        dest_ptr -= pDest_y * pDest->row_bytes;
2106
        pDest_y = 0;
2107
    }
2108
    if (pDest_y >= pDest->height) {
2109
        return;
2110
    }
2111
    if (pDest_y + pHeight > pDest->height) {
2112
        pHeight = pDest->height - pDest_y;
2113
    }
2114
    if (pDest_x < 0) {
2115
        pWidth += pDest_x;
2116
        if (pWidth <= 0) {
2117
            return;
2118
        }
2119
        source_ptr -= pDest_x;
2120
        dest_ptr -= pDest_x;
2121
        source_row_wrap -= pDest_x;
2122
        dest_row_wrap -= pDest_x;
2123
        pDest_x = 0;
2124
    }
2125
    if (pDest_x >= pDest->width) {
2126
        return;
2127
    }
2128
    if (pDest_x + pWidth > pDest->width) {
2129
        source_row_wrap += pDest_x + pWidth - pDest->width;
2130
        dest_row_wrap += pDest_x + pWidth - pDest->width;
2131
        pWidth = pDest->width - pDest_x;
2132
    }
2133
    // 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);
2134
    if (gCurrent_conversion_table != NULL) {
2135
        conv_table = gCurrent_conversion_table->pixels;
2136
        for (y_count = 0; y_count < pHeight; y_count++) {
2137
            for (x_count = 0; x_count < pWidth; x_count++) {
2138
                the_byte = *source_ptr;
2139
                if (the_byte != 0) {
2140
                    *dest_ptr = conv_table[the_byte];
2141
                }
2142
                source_ptr++;
2143
                dest_ptr++;
2144
            }
2145
            source_ptr += source_row_wrap;
2146
            dest_ptr += dest_row_wrap;
2147
        }
2148
    } else {
2149
        for (y_count = 0; y_count < pHeight; y_count++) {
2150
            for (x_count = 0; x_count < pWidth; x_count++) {
2151
                the_byte = *source_ptr;
2152
                if (the_byte != 0) {
2153
                    *dest_ptr = the_byte;
2154
                }
2155
                source_ptr++;
2156
                dest_ptr++;
2157
            }
2158
            source_ptr += source_row_wrap;
2159
            dest_ptr += dest_row_wrap;
2160
        }
2161
    }
2162
}
2163
 
2164
// IDA: void __usercall DRMaskedStamp(br_int_16 pDest_x@<EAX>, br_int_16 pDest_y@<EDX>, br_pixelmap *pSource@<EBX>)
2165
void DRMaskedStamp(br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource) {
2166
    LOG_TRACE("(%d, %d, %p)", pDest_x, pDest_y, pSource);
2167
 
2168
    DRPixelmapRectangleMaskedCopy(gBack_screen,
2169
        pDest_x,
2170
        pDest_y,
2171
        pSource,
2172
        0,
2173
        0,
2174
        pSource->width,
2175
        pSource->height);
2176
}
2177
 
2178
// 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)
2179
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) {
2180
    int y_count;
2181
    int x_count;
2182
    int dest_row_wrap;
2183
    int source_row_wrap;
2184
    //int x_delta; // Pierre-Marie Baty -- unused variable
2185
    tU8 the_byte;
2186
    tU8* source_ptr;
2187
    tU8* dest_ptr;
2188
    //tU8* conv_table; // Pierre-Marie Baty -- unused variable
2189
    // LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2190
 
2191
    source_row_wrap = pSource->row_bytes - pWidth;
2192
    dest_row_wrap = pDest->row_bytes - pWidth;
2193
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2194
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2195
 
2196
    for (y_count = 0; y_count < pHeight; y_count++) {
2197
        for (x_count = 0; x_count < pWidth; x_count++) {
2198
            the_byte = *source_ptr;
2199
            if (the_byte) {
2200
                *dest_ptr = the_byte;
2201
            }
2202
            source_ptr++;
2203
            dest_ptr++;
2204
        }
2205
        source_ptr += source_row_wrap;
2206
        dest_ptr += dest_row_wrap;
2207
    }
2208
}
2209
 
2210
// 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)
2211
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) {
2212
    int y_count;
2213
    int x_count;
2214
    int dest_row_wrap;
2215
    int source_row_wrap;
2216
    //int x_delta; // Pierre-Marie Baty -- unused variable
2217
    int last_shear_x;
2218
    int current_shear_x;
2219
    int shear_x_difference;
2220
    int pWidth_orig;
2221
    tU8 the_byte;
2222
    tU8* source_ptr;
2223
    tU8* dest_ptr;
2224
    //tU8* conv_table; // Pierre-Marie Baty -- unused variable
2225
    tX1616 current_shear;
2226
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight, pShear);
2227
 
2228
    current_shear = 0;
2229
    last_shear_x = 0;
2230
    source_ptr = (tU8*)pSource->pixels + pSource_x + pSource_y * pSource->row_bytes;
2231
    dest_ptr = (tU8*)pDest->pixels + pDest_x + pDest_y * pDest->row_bytes;
2232
    source_row_wrap = pSource->row_bytes - pWidth;
2233
    dest_row_wrap = pDest->row_bytes - pWidth;
2234
    if (pDest_y < 0) {
2235
        pHeight += pDest_y;
2236
        if (pHeight <= 0) {
2237
            return;
2238
        }
2239
        source_ptr -= pDest_y * pSource->row_bytes;
2240
        dest_ptr -= pDest_y * pDest->row_bytes;
2241
        pDest_y = 0;
2242
    }
2243
    if (pDest->height > pDest_y) {
2244
        if (pDest_y + pHeight > pDest->height) {
2245
            pHeight = pDest->height - pDest_y;
2246
        }
2247
        if (pDest_x < 0) {
2248
            pWidth += pDest_x;
2249
            if (pWidth <= 0) {
2250
                return;
2251
            }
2252
            source_ptr -= pDest_x;
2253
            dest_ptr -= pDest_x;
2254
            source_row_wrap -= pDest_x;
2255
            dest_row_wrap -= pDest_x;
2256
            pDest_x = 0;
2257
        }
2258
        if (pDest->width > pDest_x) {
2259
            pWidth_orig = pWidth;
2260
            for (y_count = 0; pHeight > y_count; ++y_count) {
2261
#if !defined(DETHRACE_FIX_BUGS)
2262
                /*
2263
                 * The OG compares against pWidth instead of pWidth_orig, which
2264
                 * ends up clipped to the dest pixelmap width. This effectively
2265
                 * clips the consecutive rows of pixels along the shear, leaving
2266
                 * a visible gap on the screen. Instead, when comparing against
2267
                 * pWidth_orig, the clip takes place vertically along the dest
2268
                 * pixelmap edge, allowing all pixels to be displayed.
2269
                 *
2270
                 * Simulate OG behavior by overwriting pWidth_orig with pWidth.
2271
                 */
2272
                pWidth_orig = pWidth;
2273
#endif
2274
                if (pDest_x + pWidth_orig > pDest->width) {
2275
                    shear_x_difference = pDest_x + pWidth - pDest->width;
2276
                    pWidth = pDest->width - pDest_x;
2277
                    source_row_wrap += shear_x_difference;
2278
                    dest_row_wrap += shear_x_difference;
2279
                }
2280
                for (x_count = 0; pWidth > x_count; ++x_count) {
2281
                    the_byte = *source_ptr++;
2282
                    if (the_byte) {
2283
                        *dest_ptr = the_byte;
2284
                    }
2285
                    ++dest_ptr;
2286
                }
2287
                current_shear_x = (current_shear >> 16) - last_shear_x;
2288
                dest_ptr += dest_row_wrap + current_shear_x;
2289
                last_shear_x = current_shear >> 16;
2290
                source_ptr += source_row_wrap;
2291
                current_shear += pShear;
2292
                pDest_x += current_shear_x;
2293
                if (pDest_x < 0) {
2294
                    pWidth += pDest_x;
2295
                    source_ptr -= pDest_x;
2296
                    dest_ptr -= pDest_x;
2297
                    source_row_wrap -= pDest_x;
2298
                    dest_row_wrap -= pDest_x;
2299
                    pDest_x = 0;
2300
                }
2301
                if (pDest->width <= pDest_x) {
2302
                    break;
2303
                }
2304
            }
2305
        }
2306
    }
2307
}
2308
 
2309
// 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)
2310
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) {
2311
    int y_count;
2312
    int x_count;
2313
    int dest_row_wrap;
2314
    int source_row_wrap;
2315
    //int x_delta; // Pierre-Marie Baty -- unused variable
2316
    tU8 the_byte;
2317
    tU8* source_ptr;
2318
    tU8* dest_ptr;
2319
    tU32 source_y;
2320
    tU32 source_y_delta;
2321
    tU32 old_source_y;
2322
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2323
 
2324
    if (!pHeight) {
2325
        return;
2326
    }
2327
 
2328
    source_row_wrap = pSource->row_bytes - pWidth;
2329
    dest_row_wrap = pDest->row_bytes - pWidth;
2330
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2331
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2332
 
2333
    source_y = 0;
2334
    source_y_delta = (pSource->height << 16) / pHeight - 0x10000;
2335
 
2336
    for (y_count = 0; y_count < pHeight; y_count++) {
2337
        for (x_count = 0; x_count < pWidth; x_count++) {
2338
            the_byte = *source_ptr;
2339
            if (the_byte) {
2340
                *dest_ptr = the_byte;
2341
            }
2342
            source_ptr++;
2343
            dest_ptr++;
2344
        }
2345
        old_source_y = source_y;
2346
        source_y += source_y_delta;
2347
        source_ptr += (((source_y >> 16) - (old_source_y >> 16)) * pSource->row_bytes) + source_row_wrap;
2348
        dest_ptr += dest_row_wrap;
2349
    }
2350
}
2351
 
2352
// IDA: void __cdecl InitTransientBitmaps()
2353
void InitTransientBitmaps(void) {
2354
    int i;
2355
    LOG_TRACE("()");
2356
 
2357
    for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2358
        gTransient_bitmaps[i].pixmap = NULL;
2359
        gTransient_bitmaps[i].in_use = 0;
2360
    }
2361
}
2362
 
2363
// IDA: int __usercall AllocateTransientBitmap@<EAX>(int pWidth@<EAX>, int pHeight@<EDX>, int pUser_data@<EBX>)
2364
int AllocateTransientBitmap(int pWidth, int pHeight, int pUser_data) {
2365
    int bm_index;
2366
    LOG_TRACE("(%d, %d, %d)", pWidth, pHeight, pUser_data);
2367
 
2368
    for (bm_index = 0; bm_index < COUNT_OF(gTransient_bitmaps); bm_index++) {
2369
        if (gTransient_bitmaps[bm_index].pixmap == NULL) {
2370
            gTransient_bitmaps[bm_index].pixmap = DRPixelmapAllocate(BR_PMT_INDEX_8, pWidth + 8, pHeight, NULL, 0);
2371
            gTransient_bitmaps[bm_index].in_use = 0;
2372
            gTransient_bitmaps[bm_index].user_data = pUser_data;
2373
            return bm_index;
2374
        }
2375
    }
2376
    FatalError(kFatalError_FindSpareTransientBitmap);
2377
}
2378
 
2379
// IDA: void __usercall DeallocateTransientBitmap(int pIndex@<EAX>)
2380
void DeallocateTransientBitmap(int pIndex) {
2381
    LOG_TRACE("(%d)", pIndex);
2382
 
2383
    if (gTransient_bitmaps[pIndex].pixmap != NULL) {
2384
        BrPixelmapFree(gTransient_bitmaps[pIndex].pixmap);
2385
        gTransient_bitmaps[pIndex].pixmap = NULL;
2386
        gTransient_bitmaps[pIndex].in_use = 0;
2387
    }
2388
}
2389
 
2390
// IDA: void __cdecl DeallocateAllTransientBitmaps()
2391
void DeallocateAllTransientBitmaps(void) {
2392
    int i;
2393
    LOG_TRACE("()");
2394
 
2395
    for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2396
        DeallocateTransientBitmap(i);
2397
    }
2398
}
2399
 
2400
// IDA: void __usercall RemoveTransientBitmaps(int pGraphically_remove_them@<EAX>)
2401
void RemoveTransientBitmaps(int pGraphically_remove_them) {
2402
    int i;
2403
    int order_number;
2404
 
2405
    if (pGraphically_remove_them) {
2406
        for (order_number = gNext_transient - 1; order_number >= 0; order_number--) {
2407
            for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2408
                if (gTransient_bitmaps[i].pixmap != NULL && gTransient_bitmaps[i].order_number == order_number) {
2409
                    if (gTransient_bitmaps[i].in_use) {
2410
                        BrPixelmapRectangleCopy(gBack_screen,
2411
                            gTransient_bitmaps[i].x_coord,
2412
                            gTransient_bitmaps[i].y_coord,
2413
                            gTransient_bitmaps[i].pixmap,
2414
                            0,
2415
                            0,
2416
                            gTransient_bitmaps[i].pixmap->width,
2417
                            gTransient_bitmaps[i].pixmap->height);
2418
                    }
2419
                    break;
2420
                }
2421
            }
2422
        }
2423
    }
2424
    gNext_transient = 0;
2425
}
2426
 
2427
// IDA: void __usercall SaveTransient(int pIndex@<EAX>, int pX_coord@<EDX>, int pY_coord@<EBX>)
2428
void SaveTransient(int pIndex, int pX_coord, int pY_coord) {
2429
    LOG_TRACE("(%d, %d, %d)", pIndex, pX_coord, pY_coord);
2430
 
2431
    gTransient_bitmaps[pIndex].x_coord = pX_coord & ~3;
2432
    gTransient_bitmaps[pIndex].y_coord = pY_coord;
2433
    gTransient_bitmaps[pIndex].in_use = 1;
2434
    gTransient_bitmaps[pIndex].order_number = gNext_transient;
2435
    gNext_transient++;
2436
    BrPixelmapRectangleCopy(gTransient_bitmaps[pIndex].pixmap,
2437
        0,
2438
        0,
2439
        gBack_screen,
2440
        gTransient_bitmaps[pIndex].x_coord,
2441
        gTransient_bitmaps[pIndex].y_coord,
2442
        gTransient_bitmaps[pIndex].pixmap->width,
2443
        gTransient_bitmaps[pIndex].pixmap->height);
2444
}
2445
 
2446
// IDA: void __usercall DrawCursorGiblet(tCursor_giblet *pGib@<EAX>)
2447
void DrawCursorGiblet(tCursor_giblet* pGib) {
2448
    br_pixelmap* the_image;
2449
    LOG_TRACE("(%p)", pGib);
2450
 
2451
    SaveTransient(pGib->transient_index, pGib->x_coord, pGib->y_coord);
2452
    the_image = gCursor_giblet_images[gCursor_giblet_sequences[pGib->sequence_index][pGib->current_giblet]];
2453
    DRPixelmapRectangleMaskedCopy(gBack_screen,
2454
        pGib->x_coord,
2455
        pGib->y_coord,
2456
        the_image,
2457
        0,
2458
        0,
2459
        the_image->width,
2460
        the_image->height);
2461
}
2462
 
2463
// IDA: void __usercall ProcessCursorGiblets(int pPeriod@<EAX>)
2464
void ProcessCursorGiblets(int pPeriod) {
2465
    int i;
2466
    int kill_the_giblet;
2467
    tU32 time_now;
2468
    tCursor_giblet* gib;
2469
    LOG_TRACE("(%d)", pPeriod);
2470
 
2471
    time_now = PDGetTotalTime();
2472
    for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2473
        gib = &gCursor_giblets[i];
2474
        kill_the_giblet = 0;
2475
        if (gib->current_giblet == -1) {
2476
            continue;
2477
        }
2478
        if (!gib->landed && gib->e_t_a <= time_now) {
2479
            gib->landed = 1;
2480
            gib->the_speed = 0.f;
2481
        }
2482
        if (gib->landed) {
2483
            gib->giblet_change_period -= pPeriod / 2;
2484
            if (gib->giblet_change_period < 50) {
2485
                gib->giblet_change_period = 50;
2486
            }
2487
            if (gib->giblet_change_period <= time_now - gib->last_giblet_change) {
2488
                if (gCursor_giblet_sequences[gib->sequence_index][0] == gib->current_giblet) {
2489
                    gib->current_giblet = 1;
2490
                } else {
2491
                    gib->current_giblet++;
2492
                }
2493
                gib->last_giblet_change = time_now;
2494
            }
2495
            gib->y_coord += pPeriod * gib->the_speed / 1000.f;
2496
            if (gib->y_coord <= gGraf_data[gGraf_data_index].height) {
2497
                if (gib->the_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
2498
                    gib->the_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f;
2499
                }
2500
            } else {
2501
                kill_the_giblet = 1;
2502
            }
2503
        } else {
2504
            if (gib->y_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
2505
                gib->y_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f * 2.f;
2506
            }
2507
            gib->x_coord += pPeriod * gib->x_speed / 1000.f;
2508
            gib->y_coord += pPeriod * gib->y_speed / 1000.f;
2509
            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) {
2510
                kill_the_giblet = 1;
2511
            }
2512
        }
2513
        if (kill_the_giblet) {
2514
            gib->current_giblet = -1;
2515
            DeallocateTransientBitmap(gib->transient_index);
2516
        } else {
2517
            DrawCursorGiblet(gib);
2518
        }
2519
    }
2520
}
2521
 
2522
// IDA: int __usercall NewCursorGiblet@<EAX>(int pX_coord@<EAX>, int pY_coord@<EDX>, float pX_speed, float pY_speed, tU32 pDrop_time)
2523
int NewCursorGiblet(int pX_coord, int pY_coord, float pX_speed, float pY_speed, tU32 pDrop_time) {
2524
    int i;
2525
    int the_width;
2526
    int the_height;
2527
    int sequence_number;
2528
    LOG_TRACE("(%d, %d, %f, %f, %d)", pX_coord, pY_coord, pX_speed, pY_speed, pDrop_time);
2529
 
2530
    sequence_number = IRandomBetween(0, COUNT_OF(gCursor_giblet_sequences) - 1);
2531
    if (pX_coord >= 0 && pX_coord < gGraf_data[gGraf_data_index].width && pY_coord >= 0 && pY_coord < gGraf_data[gGraf_data_index].height) {
2532
        for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2533
            if (gCursor_giblets[i].current_giblet == -1) {
2534
                the_width = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->width;
2535
                the_height = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->height;
2536
                gCursor_giblets[i].transient_index = AllocateTransientBitmap(the_width, the_height, 1);
2537
                gCursor_giblets[i].current_giblet = 1;
2538
                gCursor_giblets[i].sequence_index = sequence_number;
2539
                gCursor_giblets[i].landed = 0;
2540
                gCursor_giblets[i].x_coord = sequence_number * gGraf_specs[gGraf_spec_index].total_width / 640 - the_width / 2 + pX_coord;
2541
                gCursor_giblets[i].y_coord = FRandomPosNeg(6.f) * gGraf_specs[gGraf_spec_index].total_height / 480 - the_height / 2 + pY_coord;
2542
                gCursor_giblets[i].x_speed = pX_speed;
2543
                gCursor_giblets[i].y_speed = pY_speed;
2544
                gCursor_giblets[i].last_giblet_change = 0;
2545
                gCursor_giblets[i].giblet_change_period = 1000;
2546
                gCursor_giblets[i].e_t_a = PDGetTotalTime() + pDrop_time;
2547
                return i;
2548
            }
2549
        }
2550
    }
2551
    return -1;
2552
}
2553
 
2554
// IDA: int __cdecl DoMouseCursor()
2555
int DoMouseCursor(void) {
2556
    int x_coord; // Added by DethRace
2557
    int y_coord;
2558
    int mouse_moved;
2559
    int new_required;
2560
    //int giblet_index; // Pierre-Marie Baty -- unused variable
2561
    int cursor_offset;
2562
    int button_is_down;
2563
    int giblet_chance;
2564
    int giblet_count;
2565
    tU32 this_call_time;
2566
    static tU32 last_cursor_change;
2567
    static tU32 last_call_time;
2568
    static tU32 last_required_change;
2569
    tS32 period;
2570
    static int delta_x;
2571
    static int required_cursor;
2572
    static int zero_count;
2573
    static int button_was_down;
2574
 
2575
    period = 0;
2576
    this_call_time = PDGetTotalTime();
2577
    if (last_call_time == 0) {
2578
        period = 1000;
2579
    }
2580
    while (period <= 20) {
2581
        this_call_time = PDGetTotalTime();
2582
        period = this_call_time - last_call_time;
2583
        // added by dethrace to avoid 100% CPU usage
2584
        gHarness_platform.Sleep(1);
2585
    }
2586
    GetMousePosition(&x_coord, &y_coord);
2587
    mouse_moved = x_coord != gMouse_last_x_coord || y_coord != gMouse_last_y_coord;
2588
    button_is_down = EitherMouseButtonDown();
2589
    cursor_offset = button_is_down ? 4 : 0;
2590
    if (gMouse_in_use || mouse_moved) {
2591
        gMouse_in_use = 1;
2592
        if (gMouse_last_x_coord == x_coord) {
2593
            if (zero_count >= 5) {
2594
                delta_x = 0;
2595
            }
2596
            zero_count++;
2597
        } else {
2598
            zero_count = 0;
2599
            delta_x = (x_coord - gMouse_last_x_coord) * 1000 / period;
2600
        }
2601
        if (delta_x < -10) {
2602
            new_required = 0;
2603
        } else if (delta_x < 11) {
2604
            new_required = 2;
2605
        } else {
2606
            new_required = 3;
2607
        }
2608
        if (new_required != required_cursor && this_call_time - last_required_change >= 200) {
2609
            last_required_change = this_call_time;
2610
            required_cursor = new_required;
2611
        }
2612
        if (gCurrent_cursor_index != required_cursor && PDGetTotalTime() - last_cursor_change >= 50) {
2613
            if (required_cursor < gCurrent_cursor_index) {
2614
                gCurrent_cursor_index--;
2615
            } else {
2616
                gCurrent_cursor_index++;
2617
            }
2618
            last_cursor_change = PDGetTotalTime();
2619
        }
2620
        giblet_chance = Chance(1.f + 20.f * (abs(x_coord - gMouse_last_x_coord) + abs(y_coord - gMouse_last_y_coord)) / (float)period, period);
2621
        if (gProgram_state.sausage_eater_mode) {
2622
            giblet_count = 0;
2623
        } else {
2624
            giblet_count = 6 * BooleanTo1Or0(button_is_down && !button_was_down) + BooleanTo1Or0(giblet_chance);
2625
        }
2626
        for (; giblet_count != 0; giblet_count--) {
2627
            NewCursorGiblet(
2628
                x_coord + gCursor_gib_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2629
                y_coord + gCursor_gib_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
2630
                ((float)(x_coord - gMouse_last_x_coord)) / period * 1000.f / 4.f,
2631
                ((float)(y_coord - gMouse_last_y_coord)) / period * 1000.f / 3.f,
2632
                (button_is_down && !button_was_down) ? 50 : 400);
2633
        }
2634
        ProcessCursorGiblets(period);
2635
        SaveTransient(gCursor_transient_index,
2636
            x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2637
            y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480);
2638
        DRPixelmapRectangleMaskedCopy(gBack_screen,
2639
            x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2640
            y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
2641
            gCursors[gCurrent_cursor_index + cursor_offset],
2642
            0,
2643
            0,
2644
            gCursors[gCurrent_cursor_index + cursor_offset]->width,
2645
            gCursors[gCurrent_cursor_index + cursor_offset]->height);
2646
    }
2647
    last_call_time = this_call_time;
2648
    button_was_down = button_is_down;
2649
    gMouse_last_x_coord = x_coord;
2650
    gMouse_last_y_coord = y_coord;
2651
    return mouse_moved;
2652
}
2653
 
2654
// IDA: int __cdecl AllocateCursorTransient()
2655
int AllocateCursorTransient(void) {
2656
    int i;
2657
    int largest_width;
2658
    int largest_height;
2659
    LOG_TRACE("()");
2660
 
2661
    largest_width = 0;
2662
    largest_height = 0;
2663
    for (i = 0; i < COUNT_OF(gCursors); i++) {
2664
        if (largest_width < gCursors[i]->width) {
2665
            largest_width = gCursors[i]->width;
2666
        }
2667
        if (largest_height < gCursors[i]->height) {
2668
            largest_height = gCursors[i]->height;
2669
        }
2670
    }
2671
    return AllocateTransientBitmap(largest_width, largest_height, 0);
2672
}
2673
 
2674
// IDA: void __cdecl StartMouseCursor()
2675
void StartMouseCursor(void) {
2676
    int i;
2677
    LOG_TRACE("()");
2678
 
2679
    gNext_transient = 0;
2680
    gCursor_transient_index = AllocateCursorTransient();
2681
    GetMousePosition(&gMouse_last_x_coord, &gMouse_last_y_coord);
2682
    gMouse_in_use = 0;
2683
    gCurrent_cursor_index = 2;
2684
    for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2685
        gCursor_giblets[i].current_giblet = -1;
2686
    }
2687
    gMouse_started = 1;
2688
}
2689
 
2690
// IDA: void __cdecl EndMouseCursor()
2691
void EndMouseCursor(void) {
2692
    LOG_TRACE("()");
2693
 
2694
    RemoveTransientBitmaps(1);
2695
    DeallocateAllTransientBitmaps();
2696
    gMouse_started = 0;
2697
}
2698
 
2699
// IDA: void __usercall LoadFont(int pFont_ID@<EAX>)
2700
void LoadFont(int pFont_ID) {
2701
    tPath_name the_path;
2702
    int i;
2703
    int number_of_chars;
2704
    FILE* f;
2705
    tU32 the_size;
2706
    LOG_TRACE("(%d)", pFont_ID);
2707
 
2708
    if (gFonts[pFont_ID].images != NULL) {
2709
        return;
2710
    }
2711
 
2712
    PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
2713
    PathCat(the_path, the_path, "FONTS");
2714
    PathCat(the_path, the_path, gFont_names[pFont_ID]);
2715
    number_of_chars = strlen(the_path);
2716
    strcat(the_path, ".PIX");
2717
    gFonts[pFont_ID].images = DRPixelmapLoad(the_path);
2718
 
2719
    if (gFonts[pFont_ID].images == NULL) {
2720
        FatalError(kFatalError_LoadFontImage_S, gFont_names[pFont_ID]);
2721
    }
2722
    if (!gFonts[pFont_ID].file_read_once) {
2723
        strcpy(&the_path[number_of_chars + 1], "TXT");
2724
 
2725
        f = DRfopen(the_path, "rt");
2726
        if (f == NULL) {
2727
            FatalError(kFatalError_LoadFontWidthTable_S, gFont_names[pFont_ID]);
2728
        }
2729
 
2730
        gFonts[pFont_ID].height = GetAnInt(f);
2731
        gFonts[pFont_ID].width = GetAnInt(f);
2732
        gFonts[pFont_ID].spacing = GetAnInt(f);
2733
        gFonts[pFont_ID].offset = GetAnInt(f);
2734
        gFonts[pFont_ID].num_entries = GetAnInt(f);
2735
        if (gFonts[pFont_ID].width <= 0) {
2736
            for (i = 0; i < gFonts[pFont_ID].num_entries; i++) {
2737
                the_size = GetAnInt(f);
2738
                gFonts[pFont_ID].width_table[i] = the_size;
2739
            }
2740
        }
2741
        fclose(f);
2742
        gFonts[pFont_ID].file_read_once = 1;
2743
    }
2744
}
2745
 
2746
// IDA: void __usercall DisposeFont(int pFont_ID@<EAX>)
2747
void DisposeFont(int pFont_ID) {
2748
    LOG_TRACE("(%d)", pFont_ID);
2749
    if (gFonts[pFont_ID].images && (!TranslationMode() || (gAusterity_mode && FlicsPlayedFromDisk()))) {
2750
        BrPixelmapFree(gFonts[pFont_ID].images);
2751
        gFonts[pFont_ID].images = NULL;
2752
        gFonts[pFont_ID].file_read_once = 0;
2753
    }
2754
}
2755
 
2756
// IDA: void __cdecl InitDRFonts()
2757
void InitDRFonts(void) {
2758
    int i;
2759
    LOG_TRACE("()");
2760
 
2761
    for (i = 0; i < 21; i++) {
2762
        gFonts[i].file_read_once = 0;
2763
        gFonts[i].images = NULL;
2764
    }
2765
}
2766
 
2767
// IDA: void __usercall DrawDropImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip, int pOffset)
2768
void DrawDropImage(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip, int pOffset) {
2769
    int y;
2770
    int src_y;
2771
    int src_height;
2772
    int y_diff;
2773
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip, pOffset);
2774
 
2775
    BrPixelmapRectangleFill(gBack_screen,
2776
        pLeft,
2777
        pTop_clip,
2778
        pImage->width,
2779
        pBottom_clip - pTop_clip,
2780
        0);
2781
    if (pOffset != 1000) {
2782
        src_y = 0;
2783
        src_height = pImage->height;
2784
        y = pOffset + pTop;
2785
        y_diff = pTop_clip - y;
2786
        if (y_diff > 0) {
2787
            src_height -= y_diff;
2788
            y += y_diff;
2789
            src_y = y_diff;
2790
        }
2791
        y_diff = pBottom_clip - y - pImage->height;
2792
        if (y_diff < 0) {
2793
            src_height += y_diff;
2794
        }
2795
        BrPixelmapRectangleCopy(gBack_screen,
2796
            pLeft,
2797
            y,
2798
            pImage,
2799
            0,
2800
            src_y,
2801
            pImage->width,
2802
            src_height);
2803
        PDScreenBufferSwap(0);
2804
    }
2805
}
2806
 
2807
// IDA: void __usercall DropInImageFromTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2808
void DropInImageFromTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2809
    tS32 start_time;
2810
    tS32 the_time;
2811
    int drop_distance;
2812
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2813
 
2814
    start_time = PDGetTotalTime();
2815
    drop_distance = pImage->height - pTop_clip + pTop;
2816
    while (1) {
2817
        the_time = PDGetTotalTime();
2818
        if (the_time >= start_time + 100) {
2819
            break;
2820
        }
2821
        DrawDropImage(pImage,
2822
            pLeft,
2823
            pTop,
2824
            pTop_clip,
2825
            pBottom_clip,
2826
            (the_time - start_time - 100) * drop_distance / 100);
2827
    }
2828
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
2829
}
2830
 
2831
// IDA: void __usercall DropOutImageThruBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2832
void DropOutImageThruBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2833
    tS32 start_time;
2834
    tS32 the_time;
2835
    int drop_distance;
2836
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2837
 
2838
    start_time = PDGetTotalTime();
2839
    drop_distance = pBottom_clip - pTop;
2840
    while (1) {
2841
        the_time = PDGetTotalTime();
2842
        if (the_time >= start_time + 100) {
2843
            break;
2844
        }
2845
        DrawDropImage(pImage,
2846
            pLeft,
2847
            pTop,
2848
            pTop_clip,
2849
            pBottom_clip,
2850
            (the_time - start_time) * drop_distance / 100);
2851
    }
2852
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
2853
}
2854
 
2855
// IDA: void __usercall DropInImageFromBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2856
void DropInImageFromBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2857
    tS32 start_time;
2858
    tS32 the_time;
2859
    int drop_distance;
2860
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2861
 
2862
    start_time = PDGetTotalTime();
2863
    drop_distance = pBottom_clip - pTop;
2864
    while (1) {
2865
        the_time = PDGetTotalTime();
2866
        if (the_time >= start_time + 100) {
2867
            break;
2868
        }
2869
        DrawDropImage(pImage,
2870
            pLeft,
2871
            pTop,
2872
            pTop_clip,
2873
            pBottom_clip,
2874
            (100 - the_time + start_time) * drop_distance / 100);
2875
    }
2876
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
2877
}
2878
 
2879
// IDA: void __usercall DropOutImageThruTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2880
void DropOutImageThruTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2881
    tS32 start_time;
2882
    tS32 the_time;
2883
    int drop_distance;
2884
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2885
 
2886
    start_time = PDGetTotalTime();
2887
    drop_distance = pImage->height - pTop_clip + pTop;
2888
    while (1) {
2889
        the_time = PDGetTotalTime();
2890
        if (the_time >= start_time + 100) {
2891
            break;
2892
        }
2893
        DrawDropImage(pImage,
2894
            pLeft,
2895
            pTop,
2896
            pTop_clip,
2897
            pBottom_clip,
2898
            (start_time - the_time) * drop_distance / 100);
2899
    }
2900
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
2901
}
2902
 
2903
// IDA: void __usercall DrawTellyLine(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
2904
void DrawTellyLine(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
2905
    int the_width;
2906
    int the_height;
2907
    LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
2908
 
2909
    the_width = pImage->width;
2910
    the_height = pImage->height / 2 + pTop;
2911
    BrPixelmapLine(gBack_screen, pLeft, the_height, pLeft + the_width, the_height, 0);
2912
    BrPixelmapLine(gBack_screen, the_width / 2 + pLeft - pPercentage * the_width / 200, the_height, the_width / 2 + pLeft + pPercentage * the_width / 200, the_height, 1);
2913
    PDScreenBufferSwap(0);
2914
}
2915
 
2916
// IDA: void __usercall DrawTellyImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
2917
void DrawTellyImage(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
2918
    //int the_height; // Pierre-Marie Baty -- unused variable
2919
    LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
2920
 
2921
    BrPixelmapRectangleFill(gBack_screen, pLeft, pTop, pImage->width, pImage->height, 0);
2922
    if (pPercentage != 1000) {
2923
        DRPixelmapRectangleVScaledCopy(
2924
            gBack_screen,
2925
            pLeft,
2926
            pTop + pImage->height * (100 - pPercentage) / 200,
2927
            pImage,
2928
            0,
2929
            0,
2930
            pImage->width,
2931
            pPercentage * pImage->height / 100);
2932
        PDScreenBufferSwap(0);
2933
    }
2934
}
2935
 
2936
// IDA: void __usercall TellyInImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
2937
void TellyInImage(br_pixelmap* pImage, int pLeft, int pTop) {
2938
    tS32 start_time;
2939
    tS32 the_time;
2940
    LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
2941
 
2942
    start_time = PDGetTotalTime();
2943
    while (1) {
2944
        the_time = PDGetTotalTime();
2945
        if (start_time + 100 <= the_time) {
2946
            break;
2947
        }
2948
        DrawTellyLine(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
2949
    }
2950
    start_time = PDGetTotalTime();
2951
    while (1) {
2952
        the_time = PDGetTotalTime();
2953
        if (start_time + 100 <= the_time) {
2954
            break;
2955
        }
2956
        DrawTellyImage(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
2957
    }
2958
    DrawTellyImage(pImage, pLeft, pTop, 100);
2959
}
2960
 
2961
// IDA: void __usercall TellyOutImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
2962
void TellyOutImage(br_pixelmap* pImage, int pLeft, int pTop) {
2963
    tS32 start_time;
2964
    tS32 the_time;
2965
    //int drop_distance; // Pierre-Marie Baty -- unused variable
2966
    LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
2967
 
2968
    start_time = PDGetTotalTime();
2969
    while (1) {
2970
        the_time = PDGetTotalTime();
2971
        if (start_time + 100 <= the_time) {
2972
            break;
2973
        }
2974
        DrawTellyImage(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
2975
    }
2976
    DrawTellyImage(pImage, pLeft, pTop, 1000);
2977
 
2978
    start_time = PDGetTotalTime();
2979
    while (1) {
2980
        the_time = PDGetTotalTime();
2981
        if (start_time + 100 <= the_time) {
2982
            break;
2983
        }
2984
        DrawTellyLine(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
2985
    }
2986
    DrawTellyLine(pImage, pLeft, pTop, 0);
2987
}
2988
 
2989
// IDA: void __usercall SetShadowLevel(tShadow_level pLevel@<EAX>)
2990
void SetShadowLevel(tShadow_level pLevel) {
2991
    LOG_TRACE("(%d)", pLevel);
2992
 
2993
    gShadow_level = pLevel;
2994
}
2995
 
2996
// IDA: tShadow_level __cdecl GetShadowLevel()
2997
tShadow_level GetShadowLevel(void) {
2998
    LOG_TRACE("()");
2999
 
3000
    return gShadow_level;
3001
}
3002
 
3003
// IDA: void __cdecl ToggleShadow()
3004
void ToggleShadow(void) {
3005
    LOG_TRACE("()");
3006
 
3007
    gShadow_level++;
3008
    if (gShadow_level == eShadow_everyone) {
3009
        gShadow_level = eShadow_none;
3010
    }
3011
    switch (gShadow_level) {
3012
    case eShadow_none:
21 pmbaty 3013
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, GetMiscString(kMiscString_NoShadows));
1 pmbaty 3014
        break;
3015
    case eShadow_us_only:
21 pmbaty 3016
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderOwnCar));
1 pmbaty 3017
        break;
3018
    case eShadow_us_and_opponents:
21 pmbaty 3019
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderMainCars));
1 pmbaty 3020
        break;
3021
    case eShadow_everyone:
21 pmbaty 3022
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderAllCars));
1 pmbaty 3023
        break;
3024
    default:
3025
        return;
3026
    }
3027
}
3028
 
3029
// IDA: void __cdecl InitShadow()
3030
void InitShadow(void) {
3031
    int i;
3032
    //br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
3033
    LOG_TRACE("()");
3034
 
3035
    for (i = 0; i < 8; i++) {
3036
        gShadow_clip_planes[i].clip = BrActorAllocate(BR_ACTOR_CLIP_PLANE, NULL);
3037
        BrActorAdd(gUniverse_actor, gShadow_clip_planes[i].clip);
3038
        BrClipPlaneDisable(gShadow_clip_planes[i].clip);
3039
        BrMatrix34Identity(&gShadow_clip_planes[i].clip->t.t.mat);
3040
    }
3041
    gFancy_shadow = 1;
3042
    gShadow_material = BrMaterialFind("SHADOW.MAT");
3043
    BrVector3Set(&gShadow_light_ray, 0.f, -1.f, 0.f);
3044
    BrVector3Set(&gShadow_light_z, -0.f, -0.f, -1.f);
3045
    BrVector3Set(&gShadow_light_x, 1.f, 0.f, 0.f);
3046
 
3047
    gShadow_model = BrModelAllocate("", 0, 0);
3048
    gShadow_model->flags = BR_MODF_GENERATE_TAGS | BR_MODF_KEEP_ORIGINAL;
3049
    gShadow_actor = BrActorAllocate(BR_ACTOR_MODEL, 0);
3050
    gShadow_actor->model = gShadow_model;
3051
    BrActorAdd(gUniverse_actor, gShadow_actor);
3052
}
3053
 
3054
// IDA: br_uint_32 __cdecl SaveShadeTable(br_pixelmap *pTable, void *pArg)
3055
br_uint_32 SaveShadeTable(br_pixelmap* pTable, void* pArg) {
3056
    LOG_TRACE("(%p, %p)", pTable, pArg);
3057
 
3058
    if (gSaved_table_count == COUNT_OF(gSaved_shade_tables)) {
3059
        return 1;
3060
    }
3061
    gSaved_shade_tables[gSaved_table_count].original = pTable;
3062
    gSaved_shade_tables[gSaved_table_count].copy = (br_pixelmap*)BrMemAllocate(sizeof(br_pixelmap), kMem_shade_table_copy);
3063
    memcpy(gSaved_shade_tables[gSaved_table_count].copy, pTable, sizeof(br_pixelmap));
3064
    gSaved_table_count++;
3065
    return 0;
3066
}
3067
 
3068
// IDA: void __cdecl SaveShadeTables()
3069
void SaveShadeTables(void) {
3070
    LOG_TRACE("()");
3071
 
3072
    PossibleService();
3073
    gSaved_table_count = 0;
3074
    BrTableEnum("*", SaveShadeTable, 0);
3075
}
3076
 
3077
// IDA: void __cdecl DisposeSavedShadeTables()
3078
void DisposeSavedShadeTables(void) {
3079
    int i;
3080
    LOG_TRACE("()");
3081
 
3082
    for (i = 0; i < gSaved_table_count; i++) {
3083
        BrMemFree(gSaved_shade_tables[i].copy);
3084
    }
3085
}
3086
 
3087
// IDA: void __cdecl ShadowMode()
3088
void ShadowMode(void) {
3089
    LOG_TRACE("()");
3090
 
3091
    gFancy_shadow = !gFancy_shadow;
3092
    if (gFancy_shadow) {
21 pmbaty 3093
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, "Translucent shadow");
1 pmbaty 3094
    } else {
21 pmbaty 3095
        NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, "Solid shadow");
1 pmbaty 3096
    }
3097
}
3098
 
3099
// IDA: int __cdecl SwitchToRealResolution()
3100
int SwitchToRealResolution(void) {
3101
    LOG_TRACE("()");
3102
 
3103
    if (gGraf_data_index == gReal_graf_data_index) {
3104
        return 0;
3105
    }
3106
    gGraf_data_index = gReal_graf_data_index;
3107
    gGraf_spec_index = gReal_graf_data_index;
3108
    gCurrent_graf_data = &gGraf_data[gReal_graf_data_index];
3109
    PDSwitchToRealResolution();
3110
    return 1;
3111
}
3112
 
3113
// IDA: int __cdecl SwitchToLoresMode()
3114
int SwitchToLoresMode(void) {
3115
    LOG_TRACE("()");
3116
    if (!gGraf_data_index || gGraf_data_index != gReal_graf_data_index) {
3117
        return 0;
3118
    }
3119
    gGraf_data_index = 0;
3120
    gGraf_spec_index = 0;
3121
    gCurrent_graf_data = gGraf_data;
3122
    PDSwitchToLoresMode();
3123
    return 1;
3124
}
3125
 
3126
// 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)
3127
void DRPixelmapDoubledCopy(br_pixelmap* pDestn, br_pixelmap* pSource, int pSource_width, int pSource_height, int pX_offset, int pY_offset) {
3128
    tU16* sptr;
3129
    tU16 pixels;
3130
    tU8* dptr;
3131
    tU8* dptr2;
3132
    tU8 pixel_1;
3133
    tU8 pixel_2;
3134
    int i;
3135
    int j;
3136
    int dst_row_skip;
3137
    int src_row_skip;
3138
    int width_over_2;
3139
    LOG_TRACE("(%p, %p, %d, %d, %d, %d)", pDestn, pSource, pSource_width, pSource_height, pX_offset, pY_offset);
3140
 
3141
    dst_row_skip = 2 * pDestn->row_bytes - 2 * pSource_width;
3142
    src_row_skip = (pSource->row_bytes - pSource_width) / 2;
3143
    sptr = (tU16*)((tU8*)pSource->pixels - 2 * src_row_skip + 2 * (pSource->row_bytes * pSource_height / 2));
3144
    dptr = (tU8*)pDestn->pixels + 2 * pSource_width + (2 * pSource_height + pY_offset) * pDestn->row_bytes - pDestn->row_bytes;
3145
    dptr2 = dptr - pDestn->row_bytes;
3146
    width_over_2 = pSource_width / 2;
3147
    for (i = 0; i < pSource_height; i++) {
3148
        for (j = 0; j < width_over_2; j++) {
3149
            --sptr;
3150
            pixels = *sptr;
3151
            pixel_1 = pixels >> 8;
3152
            pixel_2 = pixels >> 0;
3153
            dptr[-1] = pixel_1;
3154
            dptr2[-1] = pixel_1;
3155
            dptr[-2] = pixel_1;
3156
            dptr2[-2] = pixel_1;
3157
            dptr[-3] = pixel_2;
3158
            dptr2[-3] = pixel_2;
3159
            dptr[-4] = pixel_2;
3160
            dptr2[-4] = pixel_2;
3161
            dptr -= 4;
3162
            dptr2 -= 4;
3163
        }
3164
        dptr -= dst_row_skip;
3165
        dptr2 -= dst_row_skip;
3166
        sptr -= src_row_skip;
3167
    }
3168
}