Subversion Repositories Games.Carmageddon

Rev

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

Rev Author Line No. Line
1 pmbaty 1
#include "graphics.h"
2
 
18 pmbaty 3
#include "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) {
18 pmbaty 710
    br_pixelmap* the_palette;
1 pmbaty 711
    LOG_TRACE("(\"%s\")", pPal_name);
18 pmbaty 712
 
713
    the_palette = BrTableFind(pPal_name);
714
    if (the_palette != NULL) {
715
        DRSetPalette(the_palette);
716
    }
1 pmbaty 717
}
718
 
719
// IDA: void __cdecl ClearEntireScreen()
720
void ClearEntireScreen(void) {
721
    LOG_TRACE("()");
722
 
723
    if (gScreen) {
724
        BrPixelmapFill(gScreen, gGraf_specs[gGraf_spec_index].black_value);
725
    }
726
    BrPixelmapFill(gBack_screen, gGraf_specs[gGraf_spec_index].black_value);
727
    PDScreenBufferSwap(0);
728
}
729
 
730
// IDA: void __cdecl ClearWobbles()
731
void ClearWobbles(void) {
732
    int i;
733
    LOG_TRACE("()");
734
 
735
    for (i = 0; i < COUNT_OF(gWobble_array); i++) {
736
        gWobble_array[i].time_started = 0;
737
    }
738
}
739
 
740
// IDA: void __cdecl InitWobbleStuff()
741
void InitWobbleStuff(void) {
742
    int i;
743
 
744
    ClearWobbles();
745
    for (i = 0; i < COUNT_OF(gCosine_array); i++) {
746
        gCosine_array[i] = cosf(i / 64.0f * DR_PI / 2.0f);
747
    }
748
}
749
 
750
// IDA: void __cdecl NewScreenWobble(double pAmplitude_x, double pAmplitude_y, double pPeriod)
751
void NewScreenWobble(double pAmplitude_x, double pAmplitude_y, double pPeriod) {
752
    int i;
753
    int oldest_time;
754
    int oldest_index;
755
    LOG_TRACE("(%d, %d, %d)", pAmplitude_x, pAmplitude_y, pPeriod);
756
 
757
    oldest_index = -1;
758
    oldest_time = INT_MAX;
759
    for (i = 0; i < COUNT_OF(gWobble_array); i++) {
760
        if (gWobble_array[i].time_started == 0) {
761
            oldest_index = i;
762
            break;
763
        }
764
        if (gWobble_array[i].time_started < oldest_time) {
765
            oldest_time = gWobble_array[i].time_started;
766
            oldest_index = i;
767
        }
768
    }
769
    gWobble_array[oldest_index].time_started = GetTotalTime();
770
    gWobble_array[oldest_index].amplitude_x = pAmplitude_x;
771
    gWobble_array[oldest_index].amplitude_y = pAmplitude_y;
772
    gWobble_array[oldest_index].period = pPeriod;
773
}
774
 
775
// IDA: void __usercall SetScreenWobble(int pWobble_x@<EAX>, int pWobble_y@<EDX>)
776
void SetScreenWobble(int pWobble_x, int pWobble_y) {
777
    LOG_TRACE("(%d, %d)", pWobble_x, pWobble_y);
778
 
779
    gScreen_wobble_y = pWobble_y;
780
    gScreen_wobble_x = pWobble_x;
781
}
782
 
783
// IDA: void __cdecl ResetScreenWobble()
784
void ResetScreenWobble(void) {
785
    LOG_TRACE("()");
786
 
787
    SetScreenWobble(0, 0);
788
}
789
 
790
// IDA: void __usercall CalculateWobblitude(tU32 pThe_time@<EAX>)
791
void CalculateWobblitude(tU32 pThe_time) {
792
    int i;
793
    tU32 time_going;
794
    double angle;
795
    double mod_angle;
796
    double cosine_over_angle;
797
    LOG_TRACE("(%d)", pThe_time);
798
 
799
    if (gProgram_state.new_view != eView_undefined) {
800
        return;
801
    }
802
    gScreen_wobble_x = 0;
803
    gScreen_wobble_y = 0;
804
    for (i = 0; i < COUNT_OF(gWobble_array); i++) {
805
        if (gWobble_array[i].time_started != 0) {
806
            time_going = pThe_time - gWobble_array[i].time_started;
807
            if (time_going > 1000) {
808
                gWobble_array[i].time_started = 0;
809
            } else {
810
                mod_angle = fmod(time_going / gWobble_array[i].period, TAU);
811
                if (mod_angle > DR_3PI_OVER_2) {
812
                    cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.0)];
813
                } else if (mod_angle > DR_PI) {
814
                    cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.0)];
815
                } else if (mod_angle > DR_PI_OVER_2) {
816
                    cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.0)];
817
                } else {
818
                    cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.0)];
819
                }
820
                angle = cosine_over_angle / ((double)(pThe_time - gWobble_array[i].time_started) * 0.0035f + 1.0f);
821
                gScreen_wobble_x = (gWobble_array[i].amplitude_x * angle + gScreen_wobble_x);
822
                gScreen_wobble_y = (gWobble_array[i].amplitude_y * angle + gScreen_wobble_y);
823
            }
824
        }
825
    }
826
    if (gScreen_wobble_x > gCurrent_graf_data->cock_margin_x) {
827
        gScreen_wobble_x = gCurrent_graf_data->cock_margin_x;
828
    } else if (gScreen_wobble_x < -gCurrent_graf_data->cock_margin_x) {
829
        gScreen_wobble_x = -gCurrent_graf_data->cock_margin_x;
830
    }
831
    if (gScreen_wobble_y > gCurrent_graf_data->cock_margin_y) {
832
        gScreen_wobble_y = gCurrent_graf_data->cock_margin_y;
833
    } else if (gScreen_wobble_y < -gCurrent_graf_data->cock_margin_y) {
834
        gScreen_wobble_y = -gCurrent_graf_data->cock_margin_y;
835
    }
836
    PipeSingleScreenShake(gScreen_wobble_x, gScreen_wobble_y);
837
}
838
 
839
// IDA: void __usercall CalculateConcussion(tU32 pThe_time@<EAX>)
840
void CalculateConcussion(tU32 pThe_time) {
841
    tU32 time_difference;
842
    int i;
843
    int j;
844
    float the_amplitude;
845
    float angle;
846
    float mod_angle;
847
    float cosine_over_angle;
848
    LOG_TRACE("(%d)", pThe_time);
849
 
850
    if (!gConcussion.concussed) {
851
        return;
852
    }
853
    time_difference = pThe_time - gConcussion.time_started;
854
    if (pThe_time - gConcussion.time_started > 2000) {
855
        gConcussion.concussed = 0;
856
    } else {
857
        for (i = 0; i < 3; ++i) {
858
            for (j = 0; j < 3; ++j) {
859
                the_amplitude = gConcussion.amplitudes.m[i][j];
860
                if (the_amplitude != 0.0) {
861
                    mod_angle = fmodf(time_difference / gConcussion.periods.m[i][j], (float) TAU); // Pierre-Marie Baty -- added type cast
862
                    if (mod_angle > DR_3PI_OVER_2) {
863
                        cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.f)];
864
                    } else if (mod_angle > DR_PI) {
865
                        cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.f)];
866
                    } else if (mod_angle > DR_PI_OVER_2) {
867
                        cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.f)];
868
                    } else {
869
                        cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.f)];
870
                    }
871
                    angle = cosine_over_angle / ((double)time_difference * 0.02f + 1.0f);
872
                    gCamera->t.t.mat.m[i][j] = angle * the_amplitude + gCamera->t.t.mat.m[i][j];
873
                    gRearview_camera->t.t.mat.m[i][j] = angle * the_amplitude + gRearview_camera->t.t.mat.m[i][j];
874
                }
875
            }
876
        }
877
    }
878
}
879
 
880
// IDA: void __cdecl SufferFromConcussion(float pSeriousness)
881
void SufferFromConcussion(float pSeriousness) {
882
    int i;
883
    int j;
884
    LOG_TRACE("(%f)", pSeriousness);
885
 
886
    for (i = 0; i < 3; i++) {
887
        for (j = 0; j < 3; j++) {
888
            gConcussion.amplitudes.m[i][j] = FRandomPosNeg(pSeriousness);
889
            gConcussion.periods.m[i][j] = FRandomBetween(20.f, 100.f);
890
        }
891
    }
892
    gConcussion.concussed = 1;
893
    gConcussion.time_started = GetTotalTime();
894
}
895
 
896
// 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)
897
void ProcessNonTrackActors(br_pixelmap* pRender_buffer, br_pixelmap* pDepth_buffer, br_actor* pCamera, br_matrix34* pCamera_to_world, br_matrix34* pOld_camera_matrix) {
898
    LOG_TRACE("(%p, %p, %p, %p, %p)", pRender_buffer, pDepth_buffer, pCamera, pCamera_to_world, pOld_camera_matrix);
899
 
900
    BrZbSceneRenderAdd(gNon_track_actor);
901
}
902
 
903
// IDA: int __usercall OppositeColour@<EAX>(int pColour@<EAX>)
904
int OppositeColour(int pColour) {
905
    int brightness;
906
    LOG_TRACE("(%d)", pColour);
907
 
908
    if (pColour < 224) {
909
        if ((pColour & 0x7) < 4) {
910
            brightness = 255;
911
        } else {
912
            brightness = 0;
913
        }
914
    } else {
915
        if ((pColour & 0xf) < 8) {
916
            brightness = 255;
917
        } else {
918
            brightness = 0;
919
        }
920
    }
921
    return brightness;
922
}
923
 
924
// IDA: void __usercall DrawMapBlip(tCar_spec *pCar@<EAX>, tU32 pTime@<EDX>, br_matrix34 *pTrans@<EBX>, br_vector3 *pPos@<ECX>, int pColour)
925
void DrawMapBlip(tCar_spec* pCar, tU32 pTime, br_matrix34* pTrans, br_vector3* pPos, int pColour) {
926
    br_vector3 map_pos;
927
    int offset;
928
    int* arrow_ptr;
929
    int point_count;
930
    int colours[2];
931
    int x;
932
    int y;
933
    int colour;
934
    int i;
935
    int j;
936
    int temp;
937
    int from_x;
938
    int from_y;
939
    int to_x;
940
    int to_y;
941
    int arrow_index;
942
    tU32 time_diff;
943
    tU32 period;
944
    br_matrix34 car_in_map_space;
945
    float bearing;
946
    //float cos_factor; // Pierre-Marie Baty -- unused variable
947
    //float sin_factor; // Pierre-Marie Baty -- unused variable
948
    LOG_TRACE("(%p, %d, %p, %p, %d)", pCar, pTime, pTrans, pPos, pColour);
949
 
950
    time_diff = pTime - gMap_mode;
951
    BrMatrix34ApplyP(&map_pos, pPos, &gCurrent_race.map_transformation);
952
    switch (gReal_graf_data_index) {
953
    case 0:
954
        break;
955
    case 1:
956
        map_pos.v[0] = map_pos.v[0] * 2.f;
957
        map_pos.v[1] = map_pos.v[1] * 2.f + 40.f;
958
        break;
959
    default:
960
        TELL_ME_IF_WE_PASS_THIS_WAY();
961
    }
962
    period = 256; // Must be power of 2
963
    colours[0] = pColour;
964
    colours[1] = OppositeColour(pColour);
965
    BrMatrix34Mul(&car_in_map_space, pTrans, &gCurrent_race.map_transformation);
966
    bearing = FastScalarArcTan2(car_in_map_space.m[2][0], car_in_map_space.m[2][1]);
967
 
968
    // Calculate in which of the 16 directions, the arrow is pointing to
969
    bearing = (360.f - bearing + 12.25) / 22.5f;
970
    arrow_index = ((int)bearing) % 16;
971
 
972
    // The player's blip blinks, others are shown permanently
973
    if (pCar->driver != eDriver_local_human || (period & pTime) != 0) {
974
        for (i = 0; i < COUNT_OF(colours); i++) {
975
            colour = colours[i];
976
            point_count = gArrows[i][arrow_index & 0x3][0];
977
            arrow_ptr = &gArrows[i][arrow_index & 0x3][1];
978
            for (j = 0; j < point_count; j++, arrow_ptr += 2) {
979
                if (arrow_index & 0x8) {
980
                    x = -arrow_ptr[0];
981
                    y = -arrow_ptr[1];
982
                } else {
983
                    x = arrow_ptr[0];
984
                    y = arrow_ptr[1];
985
                }
986
                if (arrow_index & 0x4) {
987
                    temp = x;
988
                    x = -y;
989
                    y = temp;
990
                }
991
                BrPixelmapPixelSet(gBack_screen, map_pos.v[0] + x, map_pos.v[1] + y, colour);
992
            }
993
        }
994
    }
995
    // Draw a rectangle around the fox
996
    colour = colours[!!(pTime & period)];
997
    if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_foxy && gNet_players[gIt_or_fox].car == pCar) {
998
        from_x = map_pos.v[0] - 8.f;
999
        from_y = map_pos.v[1] - 8.f;
1000
        to_x = map_pos.v[0] + 8.f;
1001
        to_y = map_pos.v[1] + 8.f;
1002
        BrPixelmapLine(gBack_screen, from_x, from_y, to_x, from_y, colour);
1003
        BrPixelmapLine(gBack_screen, from_x, to_y, to_x, to_y, colour);
1004
        BrPixelmapLine(gBack_screen, from_x, from_y, from_x, to_y, colour);
1005
        BrPixelmapLine(gBack_screen, to_x, from_y, to_x, to_y, colour);
1006
    }
1007
    // To attract the player's attention, draw a rectangle around the player's position that decreases in size,
1008
    if (time_diff <= 500 && pCar->driver == eDriver_local_human) {
1009
        offset = ((500 - time_diff) * 70) / 500;
1010
        from_x = map_pos.v[0] - offset - .5f;
1011
        from_y = map_pos.v[1] - offset - .5f;
1012
        to_x = map_pos.v[0] + offset + .5f;
1013
        to_y = map_pos.v[1] + offset + .5f;
1014
        BrPixelmapLine(gBack_screen, from_x, from_y, to_x, from_y, colour);
1015
        BrPixelmapLine(gBack_screen, from_x, to_y, to_x, to_y, colour);
1016
        BrPixelmapLine(gBack_screen, from_x, from_y, from_x, to_y, colour);
1017
        BrPixelmapLine(gBack_screen, to_x, from_y, to_x, to_y, colour);
1018
    }
1019
}
1020
 
1021
// IDA: void __usercall DrawMapSmallBlip(tU32 pTime@<EAX>, br_vector3 *pPos@<EDX>, int pColour@<EBX>)
1022
void DrawMapSmallBlip(tU32 pTime, br_vector3* pPos, int pColour) {
1023
    br_vector3 map_pos;
1024
    int offset;
1025
    //tU32 time_diff; // Pierre-Marie Baty -- unused variable
1026
    LOG_TRACE("(%d, %p, %d)", pTime, pPos, pColour);
1027
 
1028
    if ((pTime & 0x100) == 0) {
1029
        BrMatrix34ApplyP(&map_pos, pPos, &gCurrent_race.map_transformation);
1030
        if (gReal_graf_data_index != 0) {
1031
            map_pos.v[0] = 2.f * map_pos.v[0];
1032
            map_pos.v[1] = 2.f * map_pos.v[1] + 40.f;
1033
        }
1034
        offset = (int)map_pos.v[0] + gBack_screen->row_bytes * (int)map_pos.v[1];
1035
        ((br_uint_8*)gBack_screen->pixels)[offset] = pColour;
1036
    }
1037
}
1038
 
1039
// IDA: void __usercall MungeClipPlane(br_vector3 *pLight@<EAX>, tCar_spec *pCar@<EDX>, br_vector3 *p1@<EBX>, br_vector3 *p2@<ECX>, br_scalar pY_offset)
1040
void MungeClipPlane(br_vector3* pLight, tCar_spec* pCar, br_vector3* p1, br_vector3* p2, br_scalar pY_offset) {
1041
    br_vector3 v1;
1042
    br_vector3 v2;
1043
    br_vector3 v3;
1044
    br_vector3 v4;
1045
    br_scalar length;
1046
    br_actor* new_clip;
1047
    LOG_TRACE("(%p, %p, %p, %p, %f)", pLight, pCar, p1, p2, pY_offset);
1048
 
1049
    BrMatrix34ApplyP(&v1, p1, &pCar->car_master_actor->t.t.mat);
1050
    BrMatrix34ApplyP(&v2, p2, &pCar->car_master_actor->t.t.mat);
1051
    BrVector3Sub(&v3, p2, p1);
1052
    BrVector3Cross(&v4, &v3, pLight);
1053
    if (fabsf(v4.v[0]) >= 0.01f || fabsf(v4.v[1]) >= 0.01f || fabsf(v4.v[2]) >= 0.01f) {
1054
        BrVector3Copy(&v3, p1);
1055
        v3.v[1] -= pY_offset;
1056
        if (BrVector3Dot(&v3, &v4) > 0.f) {
1057
            BrVector3Negate(&v4, &v4);
1058
        }
1059
        BrVector3Normalise(&v3, &v4);
1060
        BrMatrix34ApplyV(&v4, &v3, &pCar->car_master_actor->t.t.mat);
1061
        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]);
1062
 
1063
        new_clip = gShadow_clip_planes[gShadow_clip_plane_count].clip;
1064
        ((br_vector4*)new_clip->type_data)->v[0] = v4.v[0];
1065
        ((br_vector4*)new_clip->type_data)->v[1] = v4.v[1];
1066
        ((br_vector4*)new_clip->type_data)->v[2] = v4.v[2];
1067
        ((br_vector4*)new_clip->type_data)->v[3] = -BrVector3Dot(&v1, &v4);
1068
        gShadow_clip_planes[gShadow_clip_plane_count].length = length;
1069
        gShadow_clip_plane_count++;
1070
    }
1071
}
1072
 
1073
// 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)
1074
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) {
1075
    br_scalar dot_1;
1076
    br_scalar dot_2;
1077
    br_scalar mult;
1078
    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);
1079
 
1080
    dot_1 = pSign_1 * pLight->v[pIndex_1];
1081
    dot_2 = pSign_2 * pLight->v[pIndex_2];
1082
    mult = dot_1 * dot_2;
1083
    if (mult < 0 || (mult == 0 && (dot_1 > 0 || dot_2 > 0))) {
1084
        if (gShadow_clip_plane_count < 6) {
1085
            MungeClipPlane(pLight, pCar, &gShadow_points[pPoint_index_1], &gShadow_points[pPoint_index_2], pY_offset);
1086
        }
1087
    }
1088
}
1089
 
1090
// IDA: br_scalar __usercall DistanceFromPlane@<ST0>(br_vector3 *pPos@<EAX>, br_scalar pA, br_scalar pB, br_scalar pC, br_scalar pD)
1091
br_scalar DistanceFromPlane(br_vector3* pPos, br_scalar pA, br_scalar pB, br_scalar pC, br_scalar pD) {
1092
    //br_vector3 normal; // Pierre-Marie Baty -- unused variable
1093
    LOG_TRACE("(%p, %f, %f, %f, %f)", pPos, pA, pB, pC, pD);
1094
 
1095
    return fabsf((pPos->v[1] * pB + pPos->v[0] * pA + pPos->v[2] * pC + pD) / (pA * pA + pC * pC + pB * pB));
1096
}
1097
 
1098
// IDA: void __cdecl DisableLights()
1099
void DisableLights(void) {
1100
    //int i; // Pierre-Marie Baty -- unused variable
1101
    LOG_TRACE("()");
1102
    NOT_IMPLEMENTED();
1103
}
1104
 
1105
// IDA: void __cdecl EnableLights()
1106
void EnableLights(void) {
1107
    //int i; // Pierre-Marie Baty -- unused variable
1108
    LOG_TRACE("()");
1109
    NOT_IMPLEMENTED();
1110
}
1111
 
1112
// 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)
1113
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) {
1114
    int i;
1115
    //int j; // Pierre-Marie Baty -- unused variable
1116
    int face_count;
1117
    //int force_shadow; // Pierre-Marie Baty -- unused variable
1118
    //int models_used; // Pierre-Marie Baty -- unused variable
1119
    //int point_to_use; // Pierre-Marie Baty -- unused variable
1120
    int oily_count;
1121
    int f_num;
1122
    //br_vector3 pos; // Pierre-Marie Baty -- unused variable
1123
    br_vector3 light_ray_car;
1124
    //br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
1125
    br_vector3 shadow_points_world[8];
1126
    br_vector3 poly_centre;
1127
    br_vector3 car_to_poly;
1128
    br_vector3 ray;
1129
    br_vector3 ray_pos;
1130
    br_vector3 normal;
1131
    //br_vector3 the_normal; // Pierre-Marie Baty -- unused variable
1132
    br_vector3 pos_cam_space;
1133
    //br_vector3* v0; // Pierre-Marie Baty -- unused variable
1134
    br_vector3* v1;
1135
    br_vector3* v2;
1136
    br_vector4* clip_normal;
1137
    br_scalar bounds_x_min;
1138
    br_scalar bounds_x_max;
1139
    br_scalar bounds_y_min;
1140
    br_scalar bounds_y_max;
1141
    br_scalar bounds_z_min;
1142
    br_scalar bounds_z_max;
1143
    //br_scalar height; // Pierre-Marie Baty -- unused variable
1144
    br_scalar oily_size;
1145
    br_scalar highest_underneath;
1146
    br_scalar shadow_scaling_factor;
1147
    br_scalar y_offset;
1148
    //br_scalar most_neg_dotty; // Pierre-Marie Baty -- unused variable
1149
    //br_scalar mr_dotty; // Pierre-Marie Baty -- unused variable
1150
    br_scalar first_poly_below;
1151
    br_scalar distance;
1152
    br_scalar camera_hither_fudge;
1153
    br_scalar camera_angle_additional_fudge;
1154
    br_scalar ray_length;
1155
    tBounds kev_bounds;
1156
    tFace_ref the_list[100];
1157
    tFace_ref* face_ref;
1158
    tFace_ref* list_ptr;
1159
    //br_renderbounds_cbfn* old_call_back; // Pierre-Marie Baty -- unused variable
1160
    br_camera* camera_ptr;
1161
    br_actor* oily_actor;
1162
    //br_model* model; // Pierre-Marie Baty -- unused variable
1163
    br_material* material;
1164
    br_vertex verts[48];
1165
    br_face faces[16];
1166
    LOG_TRACE("(%p, %p, %p, %p, %p, %f)", pCar, pWorld, pTrack_spec, pCamera, pCamera_to_world_transform, pDistance_factor);
1167
 
1168
#if defined(DETHRACE_FIX_BUGS)
1169
    ray_length = 0.f;
1170
#endif
1171
    f_num = 0;
1172
    bounds_x_min = pCar->bounds[1].min.v[0] / WORLD_SCALE;
1173
    bounds_x_max = pCar->bounds[1].max.v[0] / WORLD_SCALE;
1174
    bounds_y_min = pCar->bounds[1].min.v[1] / WORLD_SCALE;
1175
    bounds_y_max = pCar->bounds[1].max.v[1] / WORLD_SCALE;
1176
    bounds_z_min = pCar->bounds[1].min.v[2] / WORLD_SCALE;
1177
    bounds_z_max = pCar->bounds[1].max.v[2] / WORLD_SCALE;
1178
    gShadow_points[0].v[0] = bounds_x_max;
1179
    gShadow_points[0].v[1] = bounds_y_max;
1180
    gShadow_points[0].v[2] = bounds_z_max;
1181
    gShadow_points[1].v[0] = bounds_x_max;
1182
    gShadow_points[1].v[1] = bounds_y_max;
1183
    gShadow_points[1].v[2] = bounds_z_min;
1184
    gShadow_points[2].v[0] = bounds_x_min;
1185
    gShadow_points[2].v[1] = bounds_y_max;
1186
    gShadow_points[2].v[2] = bounds_z_min;
1187
    gShadow_points[3].v[0] = bounds_x_min;
1188
    gShadow_points[3].v[1] = bounds_y_max;
1189
    gShadow_points[3].v[2] = bounds_z_max;
1190
    gShadow_points[4].v[0] = bounds_x_max;
1191
    gShadow_points[4].v[1] = bounds_y_min;
1192
    gShadow_points[4].v[2] = bounds_z_max;
1193
    gShadow_points[5].v[0] = bounds_x_max;
1194
    gShadow_points[5].v[1] = bounds_y_min;
1195
    gShadow_points[5].v[2] = bounds_z_min;
1196
    gShadow_points[6].v[0] = bounds_x_min;
1197
    gShadow_points[6].v[1] = bounds_y_min;
1198
    gShadow_points[6].v[2] = bounds_z_min;
1199
    gShadow_points[7].v[0] = bounds_x_min;
1200
    gShadow_points[7].v[1] = bounds_y_min;
1201
    gShadow_points[7].v[2] = bounds_z_max;
1202
    gShadow_clip_plane_count = 0;
1203
    BrMatrix34TApplyV(&light_ray_car, &gShadow_light_ray, &pCar->car_master_actor->t.t.mat);
1204
    y_offset = (bounds_y_max + bounds_y_min) / 2.0;
1205
    TryThisEdge(pCar, &light_ray_car, 2, 1.0, 1, 1.0, 0, 3, y_offset);
1206
    TryThisEdge(pCar, &light_ray_car, 2, -1.0, 1, 1.0, 1, 2, y_offset);
1207
    TryThisEdge(pCar, &light_ray_car, 2, -1.0, 1, -1.0, 6, 5, y_offset);
1208
    TryThisEdge(pCar, &light_ray_car, 2, 1.0, 1, -1.0, 7, 4, y_offset);
1209
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 1, 1.0, 1, 0, y_offset);
1210
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 1, 1.0, 2, 3, y_offset);
1211
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 1, -1.0, 7, 6, y_offset);
1212
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 1, -1.0, 4, 5, y_offset);
1213
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 2, 1.0, 4, 0, y_offset);
1214
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 2, 1.0, 3, 7, y_offset);
1215
    TryThisEdge(pCar, &light_ray_car, 0, -1.0, 2, -1.0, 2, 6, y_offset);
1216
    TryThisEdge(pCar, &light_ray_car, 0, 1.0, 2, -1.0, 5, 1, y_offset);
1217
    for (i = 0; i < gShadow_clip_plane_count; ++i) {
1218
        BrClipPlaneEnable(gShadow_clip_planes[i].clip);
1219
    }
1220
    face_count = GetPrecalculatedFacesUnderCar(pCar, &face_ref);
1221
 
1222
    if (!gAction_replay_mode && pCar->number_of_wheels_on_ground >= 3 && face_count != 0) {
1223
        highest_underneath = 0.0;
1224
    } else {
1225
        kev_bounds.original_bounds.min.v[0] = 1000.0;
1226
        kev_bounds.original_bounds.min.v[1] = 1000.0;
1227
        kev_bounds.original_bounds.min.v[2] = 1000.0;
1228
        kev_bounds.original_bounds.max.v[0] = -1000.0;
1229
        kev_bounds.original_bounds.max.v[1] = -1000.0;
1230
        kev_bounds.original_bounds.max.v[2] = -1000.0;
1231
        for (i = 0; i < COUNT_OF(shadow_points_world); i++) {
1232
            BrMatrix34ApplyP(&shadow_points_world[i], &gShadow_points[i], &pCar->car_master_actor->t.t.mat);
1233
            if (shadow_points_world[i].v[0] >= kev_bounds.original_bounds.min.v[0]) {
1234
                if (shadow_points_world[i].v[0] > kev_bounds.original_bounds.max.v[0]) {
1235
                    kev_bounds.original_bounds.max.v[0] = shadow_points_world[i].v[0];
1236
                }
1237
            } else {
1238
                kev_bounds.original_bounds.min.v[0] = shadow_points_world[i].v[0];
1239
            }
1240
            if (shadow_points_world[i].v[1] >= kev_bounds.original_bounds.min.v[1]) {
1241
                if (shadow_points_world[i].v[1] > kev_bounds.original_bounds.max.v[1]) {
1242
                    kev_bounds.original_bounds.max.v[1] = shadow_points_world[i].v[1];
1243
                }
1244
            } else {
1245
                kev_bounds.original_bounds.min.v[1] = shadow_points_world[i].v[1];
1246
            }
1247
            if (shadow_points_world[i].v[2] >= kev_bounds.original_bounds.min.v[2]) {
1248
                if (shadow_points_world[i].v[2] > kev_bounds.original_bounds.max.v[2]) {
1249
                    kev_bounds.original_bounds.max.v[2] = shadow_points_world[i].v[2];
1250
                }
1251
            } else {
1252
                kev_bounds.original_bounds.min.v[2] = shadow_points_world[i].v[2];
1253
            }
1254
        }
1255
        kev_bounds.original_bounds.min.v[1] = kev_bounds.original_bounds.min.v[1] - 4.4000001;
1256
        kev_bounds.mat = &gIdentity34;
1257
        face_count = FindFacesInBox(&kev_bounds, the_list, 100);
1258
        face_ref = the_list;
1259
        highest_underneath = 1000.0;
1260
        ray_length = kev_bounds.original_bounds.max.v[1] - kev_bounds.original_bounds.min.v[1];
1261
        ray.v[0] = 0.0;
1262
        ray.v[1] = -ray_length;
1263
        ray.v[2] = 0.0;
1264
        ray_pos = pCar->car_master_actor->t.t.translate.t;
1265
        ray_pos.v[1] = kev_bounds.original_bounds.max.v[1];
1266
    }
1267
    if (face_count) {
1268
        first_poly_below = -1000.0;
1269
        i = 0;
1270
        list_ptr = face_ref;
1271
        for (i = 0; i < face_count; i++) {
1272
            v1 = &list_ptr->v[1];
1273
            v2 = &list_ptr->v[2];
1274
            if (list_ptr->normal.v[1] >= -0.1 || (list_ptr->material && (list_ptr->material->flags & 0x1000) != 0)) {
1275
                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))) {
1276
                    list_ptr->d = SHADOW_D_IGNORE_FLAG;
1277
                } 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) {
1278
                    list_ptr->d = SHADOW_D_IGNORE_FLAG;
1279
                }
1280
            } else {
1281
                poly_centre.v[0] = v1->v[0] + list_ptr->v[0].v[0];
1282
                poly_centre.v[1] = v1->v[1] + list_ptr->v[0].v[1];
1283
                poly_centre.v[2] = v1->v[2] + list_ptr->v[0].v[2];
1284
                poly_centre.v[0] = v2->v[0] + poly_centre.v[0];
1285
                poly_centre.v[1] = v2->v[1] + poly_centre.v[1];
1286
                poly_centre.v[2] = v2->v[2] + poly_centre.v[2];
1287
                poly_centre.v[0] = poly_centre.v[0] / 3.0;
1288
                poly_centre.v[1] = poly_centre.v[1] / 3.0;
1289
                poly_centre.v[2] = poly_centre.v[2] / 3.0;
1290
                poly_centre.v[1] = (v2->v[1] + v1->v[1] + list_ptr->v[0].v[1]) / 3.0;
1291
                if (poly_centre.v[1] > first_poly_below) {
1292
                    car_to_poly.v[0] = poly_centre.v[0] - pCar->car_master_actor->t.t.mat.m[3][0];
1293
                    car_to_poly.v[1] = poly_centre.v[1] - pCar->car_master_actor->t.t.mat.m[3][1];
1294
                    car_to_poly.v[2] = poly_centre.v[2] - pCar->car_master_actor->t.t.mat.m[3][2];
1295
 
1296
                    if (BrVector3Dot(&list_ptr->normal, &car_to_poly) > 0.0) {
1297
                        first_poly_below = poly_centre.v[1];
1298
                    }
1299
                }
1300
                list_ptr->d = SHADOW_D_IGNORE_FLAG;
1301
            }
1302
            list_ptr++;
1303
        }
1304
        list_ptr = face_ref;
1305
        for (i = 0; i < face_count; i++) {
1306
            if (list_ptr->d != 10000.0) {
1307
                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) {
1308
                    if (gFancy_shadow) {
1309
                        faces[f_num].material = list_ptr->material;
1310
                        if (list_ptr->material && list_ptr->material->colour_map && (list_ptr->material->flags & BR_MATF_LIGHT) == 0) {
1311
                            list_ptr->material->flags |= BR_MATF_SMOOTH | BR_MATF_LIGHT;
1312
                            BrMaterialUpdate(list_ptr->material, BR_MATU_RENDERING);
1313
                        }
1314
                    } else {
1315
                        faces[f_num].material = gShadow_material;
1316
                    }
1317
 
1318
                    verts[3 * f_num].p = list_ptr->v[0];
1319
                    verts[3 * f_num].map = *list_ptr->map[0];
1320
                    verts[3 * f_num + 1].p = list_ptr->v[1];
1321
                    verts[3 * f_num + 1].map = *list_ptr->map[1];
1322
                    verts[3 * f_num + 2].p = list_ptr->v[2];
1323
                    verts[3 * f_num + 2].map = *list_ptr->map[2];
1324
                    faces[f_num].vertices[0] = 3 * f_num;
1325
                    faces[f_num].vertices[1] = 3 * f_num + 1;
1326
                    faces[f_num].vertices[2] = 3 * f_num + 2;
1327
                    f_num++;
1328
                    if (highest_underneath > 0.0) {
1329
                        CheckSingleFace(list_ptr, &ray_pos, &ray, &normal, &distance);
1330
                        if (distance < 1.0 && ray_length * distance < highest_underneath) {
1331
                            highest_underneath = ray_length * distance;
1332
                        }
1333
                    }
1334
                    if (f_num >= LEN(faces)) {
1335
                        break;
1336
                    }
1337
                }
1338
            }
1339
            list_ptr++;
1340
        }
1341
        highest_underneath = highest_underneath - (bounds_y_max - bounds_y_min);
1342
        if (highest_underneath < 2.2) {
1343
            if (highest_underneath < 0.0) {
1344
                highest_underneath = 0.0;
1345
            }
1346
        } else {
1347
            highest_underneath = (br_scalar) 2.2; // Pierre-Marie Baty -- added type cast
1348
        }
1349
        if (gFancy_shadow) {
1350
            gShadow_dim_amount = ((2.2 - highest_underneath) * 5.0 / 2.2 + 2.5);
1351
            for (i = 0; i < gSaved_table_count; i++) {
1352
                gSaved_shade_tables[i].original->height = 1;
1353
                gSaved_shade_tables[i].original->pixels = (tU8*)gDepth_shade_table->pixels + gShadow_dim_amount * gDepth_shade_table->row_bytes;
1354
 
1355
                BrTableUpdate(gSaved_shade_tables[i].original, BR_TABU_ALL);
1356
            }
1357
        }
1358
        shadow_scaling_factor = (2.2 - highest_underneath) * 0.52 / 2.2 + 0.4;
1359
        for (i = 0; i < gShadow_clip_plane_count; i++) {
1360
            clip_normal = (br_vector4*)gShadow_clip_planes[i].clip->type_data;
1361
            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]);
1362
            gShadow_clip_planes[i].clip->t.t.mat.m[3][0] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[0];
1363
            gShadow_clip_planes[i].clip->t.t.mat.m[3][1] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[1];
1364
            gShadow_clip_planes[i].clip->t.t.mat.m[3][2] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[2];
1365
        }
1366
 
1367
        camera_ptr = (br_camera*)gCamera->type_data;
1368
        DRMatrix34TApplyP(&pos_cam_space, &pCar->car_master_actor->t.t.euler.t, &gCamera_to_world);
1369
        if (pos_cam_space.v[2] >= 36.0 || pos_cam_space.v[2] >= camera_ptr->yon_z) {
1370
            camera_hither_fudge = 0.0;
1371
        } else {
1372
            camera_angle_additional_fudge = sqr(camera_ptr->yon_z - camera_ptr->hither_z);
1373
            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);
1374
            if (camera_hither_fudge < 0.0002) {
1375
                camera_hither_fudge = (br_scalar) 0.0002; // Pierre-Marie Baty -- added type cast
1376
            }
1377
            camera_ptr->hither_z += camera_hither_fudge;
1378
        }
1379
        if (f_num) {
1380
            BrZbSceneRenderBegin(gUniverse_actor, gCamera, gRender_screen, gDepth_buffer);
1381
            gShadow_model->vertices = verts;
1382
            gShadow_model->faces = faces;
1383
            gShadow_model->nfaces = f_num;
1384
            gShadow_model->nvertices = 3 * f_num;
1385
            gShadow_actor->render_style = BR_RSTYLE_FACES;
1386
            BrModelAdd(gShadow_model);
1387
            BrZbSceneRenderAdd(gShadow_actor);
1388
            BrModelRemove(gShadow_model);
1389
            if (pCar->shadow_intersection_flags) {
1390
                oily_count = GetOilSpillCount();
1391
                for (i = 0; i < oily_count; ++i) {
1392
                    if (((1 << i) & pCar->shadow_intersection_flags) != 0) {
1393
                        GetOilSpillDetails(i, &oily_actor, &oily_size);
1394
                        if (oily_actor) {
1395
                            MungeIndexedOilsHeightAboveGround(i);
1396
                            BrZbSceneRenderAdd(oily_actor);
1397
                        }
1398
                    }
1399
                }
1400
            }
1401
            BrZbSceneRenderEnd();
1402
        }
1403
        camera_ptr->hither_z -= camera_hither_fudge;
1404
        for (i = 0; i < f_num; i++) {
1405
            if (gFancy_shadow) {
1406
                material = gShadow_model->faces[i].material;
1407
                if (material) {
1408
                    if (material->colour_map && (material->flags & BR_MATF_LIGHT) != 0) {
1409
                        material->flags &= ~(BR_MATF_LIGHT | BR_MATF_PRELIT | BR_MATF_SMOOTH);
1410
                        BrMaterialUpdate(material, BR_MATU_RENDERING);
1411
                    }
1412
                }
1413
            }
1414
        }
1415
    }
1416
    gShadow_actor->render_style = BR_RSTYLE_NONE;
1417
    for (i = 0; i < gShadow_clip_plane_count; i++) {
1418
        BrClipPlaneDisable(gShadow_clip_planes[i].clip);
1419
    }
1420
}
1421
 
1422
// IDA: void __usercall RenderShadows(br_actor *pWorld@<EAX>, tTrack_spec *pTrack_spec@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world_transform@<ECX>)
1423
void RenderShadows(br_actor* pWorld, tTrack_spec* pTrack_spec, br_actor* pCamera, br_matrix34* pCamera_to_world_transform) {
1424
    int i;
1425
    int cat;
1426
    int car_count;
1427
    tCar_spec* the_car;
1428
    br_vector3 camera_to_car;
1429
    br_scalar distance_factor;
1430
    LOG_TRACE("(%p, %p, %p, %p)", pWorld, pTrack_spec, pCamera, pCamera_to_world_transform);
1431
 
1432
    if (gShadow_level == eShadow_none) {
1433
        return;
1434
    }
1435
    for (cat = eVehicle_self;; ++cat) {
1436
        if (gShadow_level == eShadow_everyone) {
1437
            if (cat > 4) {
1438
                break;
1439
            }
1440
        } else {
1441
            if (cat > (gShadow_level == eShadow_us_and_opponents ? 3 : 0)) {
1442
                break;
1443
            }
1444
        }
1445
 
1446
        if (cat == eVehicle_self) {
1447
            car_count = 1;
1448
        } else {
1449
            car_count = GetCarCount(cat);
1450
        }
1451
        for (i = 0; i < car_count; i++) {
1452
            if (cat == eVehicle_self) {
1453
                the_car = &gProgram_state.current_car;
1454
            } else {
1455
                the_car = GetCarSpec(cat, i);
1456
            }
1457
            if (!the_car->active) {
1458
                continue;
1459
            }
1460
 
1461
            BrVector3Sub(&camera_to_car, (br_vector3*)gCamera_to_world.m[3], &the_car->car_master_actor->t.t.translate.t);
1462
            distance_factor = BrVector3LengthSquared(&camera_to_car);
1463
            if (gAction_replay_mode || distance_factor <= SHADOW_MAX_RENDER_DISTANCE) {
1464
                ProcessShadow(the_car, gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, distance_factor);
1465
            }
1466
        }
1467
    }
1468
    if (gFancy_shadow) {
1469
        for (i = 0; i < gSaved_table_count; i++) {
1470
            gSaved_shade_tables[i].original->height = gSaved_shade_tables[i].copy->height;
1471
            gSaved_shade_tables[i].original->pixels = gSaved_shade_tables[i].copy->pixels;
1472
            BrTableUpdate(gSaved_shade_tables[i].original, 0x7FFF);
1473
        }
1474
    }
1475
}
1476
 
1477
// IDA: void __usercall FlashyMapCheckpoint(int pIndex@<EAX>, tU32 pTime@<EDX>)
1478
void FlashyMapCheckpoint(int pIndex, tU32 pTime) {
1479
    //tCheckpoint* cp; // Pierre-Marie Baty -- unused variable
1480
    static tU32 last_flash;
1481
    static int flash_state;
1482
    LOG_TRACE("(%d, %d)", pIndex, pTime);
1483
 
1484
    if (pIndex >= 0 && pIndex < gCurrent_race.check_point_count && gRace_file_version > 0) {
1485
        if (Flash(300, &last_flash, &flash_state)) {
1486
            switch (gGraf_data_index) {
1487
            case 0:
1488
                DimRectangle(gBack_screen,
1489
                    gCurrent_race.checkpoints[pIndex].map_left[0],
1490
                    gCurrent_race.checkpoints[pIndex].map_top[0],
1491
                    gCurrent_race.checkpoints[pIndex].map_right[0],
1492
                    gCurrent_race.checkpoints[pIndex].map_bottom[0],
1493
                    0);
1494
                break;
1495
            case 1:
1496
                DimRectangle(gBack_screen,
1497
                    2 * gCurrent_race.checkpoints[pIndex].map_left[0],
1498
                    2 * gCurrent_race.checkpoints[pIndex].map_top[0] + 40,
1499
                    2 * gCurrent_race.checkpoints[pIndex].map_right[0],
1500
                    2 * gCurrent_race.checkpoints[pIndex].map_bottom[0] + 40,
1501
                    0);
1502
                break;
1503
            default:
1504
                TELL_ME_IF_WE_PASS_THIS_WAY();
1505
            }
1506
        }
1507
    }
1508
}
1509
 
1510
// IDA: int __usercall ConditionallyFillWithSky@<EAX>(br_pixelmap *pPixelmap@<EAX>)
1511
int ConditionallyFillWithSky(br_pixelmap* pPixelmap) {
1512
    int bgnd_col;
1513
    LOG_TRACE("(%p)", pPixelmap);
1514
 
1515
    if (gProgram_state.current_depth_effect.sky_texture != NULL && (gLast_camera_special_volume == NULL || gLast_camera_special_volume->sky_col < 0)) {
1516
        return 0;
1517
    }
1518
 
1519
    if (gProgram_state.current_depth_effect.type == eDepth_effect_fog || gSwap_depth_effect_type == eDepth_effect_fog) {
1520
        bgnd_col = 255;
1521
    } else if (gProgram_state.current_depth_effect.type && gSwap_depth_effect_type) {
1522
        if (gLast_camera_special_volume && gLast_camera_special_volume->sky_col >= 0) {
1523
            bgnd_col = gLast_camera_special_volume->sky_col;
1524
        } else {
1525
            bgnd_col = 0;
1526
        }
1527
    } else {
1528
        bgnd_col = 0;
1529
    }
1530
    BrPixelmapFill(pPixelmap, bgnd_col);
1531
    return 1;
1532
}
1533
 
1534
// IDA: void __usercall RenderAFrame(int pDepth_mask_on@<EAX>)
1535
void RenderAFrame(int pDepth_mask_on) {
1536
    int cat;
1537
    int i;
1538
    int car_count;
1539
    int flags;
1540
    int x_shift;
1541
    int y_shift;
1542
    int cockpit_on;
1543
    int real_origin_x = 0;
1544
    int real_origin_y = 0;
1545
    int real_base_x = 0;
1546
    int real_base_y = 0;
1547
    int map_timer_x;
1548
    int map_timer_width;
1549
    int ped_type;
1550
    char* old_pixels;
1551
    br_matrix34 old_camera_matrix;
1552
    br_matrix34 old_mirror_cam_matrix;
1553
    tU32 the_time;
1554
    br_vector3* car_pos;
1555
    br_vector3 pos;
1556
    char the_text[256];
1557
    tCar_spec* car;
1558
    LOG_TRACE("(%d)", pDepth_mask_on);
1559
 
1560
    gRender_screen->pixels = gBack_screen->pixels;
1561
    the_time = GetTotalTime();
1562
    old_pixels = gRender_screen->pixels;
1563
    cockpit_on = gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0 && !gMap_mode;
1564
    gMirror_on__graphics = gProgram_state.mirror_on && cockpit_on && gProgram_state.which_view == eView_forward;
1565
    if (gMap_mode) {
1566
        real_origin_x = gBack_screen->origin_x;
1567
        real_origin_y = gBack_screen->origin_y;
1568
        real_base_x = gBack_screen->base_x;
1569
        real_base_y = gBack_screen->base_y;
1570
        gBack_screen->origin_x = 0;
1571
        gBack_screen->origin_y = 0;
1572
        gBack_screen->base_x = 0;
1573
        gBack_screen->base_y = 0;
1574
        if (gCurrent_race.map_image != NULL) {
1575
            if (gReal_graf_data_index) {
1576
                BrPixelmapRectangleFill(gBack_screen, 0, 0, 640, 40, 0);
1577
                BrPixelmapRectangleFill(gBack_screen, 0, 440, 640, 40, 0);
1578
                DRPixelmapDoubledCopy(
1579
                    gBack_screen,
1580
                    gCurrent_race.map_image,
1581
                    gCurrent_race.map_image->width,
1582
                    gCurrent_race.map_image->height,
1583
                    0,
1584
                    40);
1585
            } else {
1586
                DRPixelmapCopy(gBack_screen, gCurrent_race.map_image);
1587
            }
1588
        }
1589
        DimRectangle(
1590
            gBack_screen,
1591
            gMap_render_x_i - gCurrent_graf_data->map_render_x_marg,
1592
            gMap_render_y_i - gCurrent_graf_data->map_render_y_marg,
1593
            gMap_render_x_i + gMap_render_width_i + gCurrent_graf_data->map_render_x_marg,
1594
            gMap_render_y_i + gMap_render_height_i + gCurrent_graf_data->map_render_y_marg,
1595
            1);
1596
    }
1597
    if (!gAction_replay_mode) {
1598
        CalculateWobblitude(the_time);
1599
    }
1600
    if (cockpit_on) {
1601
        if (-gScreen_wobble_x > gX_offset) {
1602
            x_shift = -gX_offset;
1603
        } else if (gScreen_wobble_x + gX_offset + gRender_screen->width > gBack_screen->width) {
1604
            x_shift = gBack_screen->width - gRender_screen->width - gX_offset;
1605
        } else {
1606
            x_shift = gScreen_wobble_x;
1607
        }
1608
        if (-gScreen_wobble_y > gY_offset) {
1609
            y_shift = -gY_offset;
1610
        } else if (gScreen_wobble_y + gY_offset + gRender_screen->height > gBack_screen->height) {
1611
            y_shift = gBack_screen->height - gRender_screen->height - gY_offset;
1612
        } else {
1613
            y_shift = gScreen_wobble_y;
1614
        }
1615
    } else {
1616
        x_shift = 0;
1617
        y_shift = 0;
1618
    }
1619
    BrMatrix34Copy(&old_camera_matrix, &gCamera->t.t.mat);
1620
    if (gMirror_on__graphics) {
1621
        BrMatrix34Copy(&old_mirror_cam_matrix, &gRearview_camera->t.t.mat);
1622
    }
1623
    if (cockpit_on) {
1624
        gSheer_mat.m[2][1] = y_shift / (float)gRender_screen->height;
1625
        gSheer_mat.m[2][0] = -x_shift / (float)gRender_screen->width;
1626
        BrMatrix34Pre(&gCamera->t.t.mat, &gSheer_mat);
1627
        gCamera->t.t.translate.t.v[0] -= gScreen_wobble_x * 1.5f / gRender_screen->width / WORLD_SCALE;
1628
        gCamera->t.t.translate.t.v[1] += gScreen_wobble_y * 1.5f / gRender_screen->width / WORLD_SCALE;
1629
    }
1630
    gRender_screen->pixels = (char*)gRender_screen->pixels + x_shift + y_shift * gRender_screen->row_bytes;
1631
    CalculateConcussion(the_time);
1632
    BrPixelmapRectangleFill(gDepth_buffer, 0, 0, gRender_screen->width, gRender_screen->height, 0xFFFFFFFF);
1633
    if (gRender_indent && !gMap_mode) {
1634
        BrPixelmapRectangleFill(
1635
            gBack_screen,
1636
            0,
1637
            0,
1638
            gGraf_specs[gGraf_spec_index].total_width,
1639
            gProgram_state.current_render_top,
1640
            0);
1641
        BrPixelmapRectangleFill(
1642
            gBack_screen,
1643
            0,
1644
            gProgram_state.current_render_bottom,
1645
            gGraf_specs[gGraf_spec_index].total_width,
1646
            gGraf_specs[gGraf_spec_index].total_height - gProgram_state.current_render_bottom,
1647
            0);
1648
        BrPixelmapRectangleFill(
1649
            gBack_screen,
1650
            0,
1651
            gProgram_state.current_render_top,
1652
            gProgram_state.current_render_left,
1653
            gProgram_state.current_render_bottom - gProgram_state.current_render_top,
1654
            0);
1655
        BrPixelmapRectangleFill(
1656
            gBack_screen,
1657
            gProgram_state.current_render_right,
1658
            gProgram_state.current_render_top,
1659
            gGraf_specs[gGraf_spec_index].total_width - gProgram_state.current_render_right,
1660
            gProgram_state.current_render_bottom - gProgram_state.current_render_top,
1661
            0);
1662
    }
1663
    gRendering_mirror = 0;
1664
    DoSpecialCameraEffect(gCamera, &gCamera_to_world);
1665
    if (!ConditionallyFillWithSky(gRender_screen)
1666
        && !gProgram_state.cockpit_on
1667
        && !(gAction_replay_camera_mode && gAction_replay_mode)) {
1668
        ExternalSky(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
1669
    }
1670
#if !defined(DETHRACE_FIX_BUGS)
1671
    // in map mode, the scene is rendered 3 times. We have no idea why.
1672
    for (i = 0; i < (gMap_mode ? 3 : 1); i++)
1673
#endif
1674
    {
1675
        RenderShadows(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world);
1676
        BrZbSceneRenderBegin(gUniverse_actor, gCamera, gRender_screen, gDepth_buffer);
1677
        ProcessNonTrackActors(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, &old_camera_matrix);
1678
        ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, 0);
1679
        RenderLollipops();
1680
 
1681
        DepthEffectSky(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
1682
        DepthEffect(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
1683
        if (!gAusterity_mode) {
1684
            ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, 1);
1685
        }
1686
        RenderSplashes();
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) {
18 pmbaty 1694
        BrPixelmapFill(gRearview_depth_buffer, 0xFFFFFFFF);
1695
        gRendering_mirror = 1;
1696
        DoSpecialCameraEffect(gRearview_camera, &gRearview_camera_to_world);
1697
        ConditionallyFillWithSky(gRearview_screen);
1698
        BrZbSceneRenderBegin(gUniverse_actor, gRearview_camera, gRearview_screen, gRearview_depth_buffer);
1699
        ProcessNonTrackActors(
1700
            gRearview_screen,
1701
            gRearview_depth_buffer,
1702
            gRearview_camera,
1703
            &gRearview_camera_to_world,
1704
            &old_mirror_cam_matrix);
1705
        ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 0);
1706
        RenderLollipops();
1707
        DepthEffectSky(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
1708
        DepthEffect(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
1709
        if (!gAusterity_mode) {
1710
            ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 1);
1711
        }
1712
        RenderSplashes();
1713
        BrZbSceneRenderEnd();
1714
        BrMatrix34Copy(&gRearview_camera->t.t.mat, &old_mirror_cam_matrix);
1715
        gRendering_mirror = 0;
1 pmbaty 1716
    }
1717
    if (gMap_mode) {
1718
        if (gNet_mode == eNet_mode_none) {
1719
            GetTimerString(the_text, 0);
1720
            map_timer_width = DRTextWidth(&gFonts[2], the_text);
1721
            map_timer_x = gCurrent_graf_data->map_timer_text_x - map_timer_width;
1722
            BrPixelmapRectangleFill(
1723
                gBack_screen,
1724
                map_timer_x - gCurrent_graf_data->map_timer_border_x,
1725
                gCurrent_graf_data->map_timer_text_y - gCurrent_graf_data->map_timer_border_y,
1726
                map_timer_width + 2 * gCurrent_graf_data->map_timer_border_x,
11 pmbaty 1727
                gFonts[kFont_BLUEHEAD].height + 2 * gCurrent_graf_data->map_timer_border_y,
1 pmbaty 1728
                0);
1729
            TransDRPixelmapText(
1730
                gBack_screen,
1731
                map_timer_x,
1732
                gCurrent_graf_data->map_timer_text_y,
11 pmbaty 1733
                &gFonts[kFont_BLUEHEAD],
1 pmbaty 1734
                the_text,
1735
                gBack_screen->width);
1736
        }
1737
        the_time = PDGetTotalTime();
1738
        if (gNet_mode != eNet_mode_none) {
1739
            if (gCurrent_net_game->type == eNet_game_type_checkpoint) {
1740
                flags = gNet_players[gThis_net_player_index].score;
1741
                for (i = 0; gCurrent_race.check_point_count > i; ++i) {
1742
                    if ((flags & 1) != 0) {
1743
                        FlashyMapCheckpoint(i, the_time);
1744
                    }
1745
                    flags >>= 1;
1746
                }
1747
            } else if (gCurrent_net_game->type == eNet_game_type_sudden_death
1748
                && gNet_players[gThis_net_player_index].score >= 0) {
1749
                FlashyMapCheckpoint(
1750
                    gNet_players[gThis_net_player_index].score % gCurrent_race.check_point_count,
1751
                    the_time);
1752
            }
1753
        } else {
1754
            FlashyMapCheckpoint(gCheckpoint - 1, the_time);
1755
        }
1756
        if (gShow_peds_on_map || (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
1757
            for (i = 0; i < GetPedCount(); i++) {
1758
                ped_type = GetPedPosition(i, &pos);
1759
                if (ped_type > 0 && gShow_peds_on_map) {
1760
                    DrawMapSmallBlip(the_time, &pos, 52);
1761
                } else if (ped_type < 0 && (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
1762
                    DrawMapSmallBlip(the_time, &pos, 4);
1763
                }
1764
            }
1765
        }
1766
        if (gShow_opponents) {
1767
            cat = eVehicle_opponent;
1768
        } else {
1769
            cat = eVehicle_self;
1770
        }
1771
        while (cat >= eVehicle_self) {
1772
            if (cat) {
1773
                car_count = GetCarCount(cat);
1774
            } else {
1775
                car_count = 1;
1776
            }
1777
            for (i = 0; i < car_count; i++) {
1778
                if (cat) {
1779
                    car = GetCarSpec(cat, i);
1780
                } else {
1781
                    car = &gProgram_state.current_car;
1782
                }
1783
                if (gNet_mode == eNet_mode_none || (!car->knackered && !NetPlayerFromCar(car)->wasted)) {
1784
                    if (cat) {
1785
                        car_pos = &GetCarSpec(cat, i)->car_master_actor->t.t.euler.t;
1786
                    } else {
1787
                        car_pos = &gSelf->t.t.euler.t;
1788
                    }
1789
                    if (gNet_mode) {
1790
                        DrawMapBlip(
1791
                            car,
1792
                            the_time,
1793
                            &car->car_master_actor->t.t.mat,
1794
                            car_pos,
1795
                            car->shrapnel_material[0]->index_range + car->shrapnel_material[0]->index_base - 1);
1796
                    } else if (car->knackered) {
1797
                        DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, 0);
1798
                    } else {
1799
                        DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, gMap_colours[cat]);
1800
                    }
1801
                }
1802
            }
1803
            cat--;
1804
        }
1805
        gBack_screen->origin_x = real_origin_x;
1806
        gBack_screen->origin_y = real_origin_y;
1807
        gBack_screen->base_x = real_base_x;
1808
        gBack_screen->base_y = real_base_y;
1809
    } else {
1810
        if (cockpit_on) {
1811
            CopyStripImage(
1812
                gBack_screen,
1813
                -gCurrent_graf_data->cock_margin_x,
1814
                gScreen_wobble_x,
1815
                -gCurrent_graf_data->cock_margin_y,
1816
                gScreen_wobble_y,
1817
                gProgram_state.current_car.cockpit_images[gProgram_state.cockpit_image_index],
1818
                0,
1819
                0,
1820
                gCurrent_graf_data->total_cock_width,
1821
                gCurrent_graf_data->total_cock_height);
1822
            if (gMirror_on__graphics) {
1823
                BrPixelmapRectangleCopy(
1824
                    gBack_screen,
1825
                    gScreen_wobble_x + gProgram_state.current_car.mirror_left,
1826
                    gScreen_wobble_y + gProgram_state.current_car.mirror_top,
1827
                    gRearview_screen,
1828
                    -gRearview_screen->origin_x,
1829
                    -gRearview_screen->origin_y,
1830
                    gProgram_state.current_car.mirror_right - gProgram_state.current_car.mirror_left,
1831
                    gProgram_state.current_car.mirror_bottom - gProgram_state.current_car.mirror_top);
1832
            }
1833
        }
1834
        DimAFewBits();
1835
        DoDamageScreen(the_time);
1836
        if (!gAction_replay_mode || gAR_fudge_headups) {
1837
            DoPratcam(the_time);
1838
            DoHeadups(the_time);
1839
        }
1840
        DoInstruments(the_time);
1841
        DoSteeringWheel(the_time);
1842
        if (!gAction_replay_mode || gAR_fudge_headups) {
1843
            DrawPowerups(the_time);
1844
        }
1845
    }
1846
    if (gNet_mode != eNet_mode_none) {
1847
        DisplayUserMessage();
1848
    }
1849
    if (gAction_replay_mode && !gAR_fudge_headups) {
1850
        DoActionReplayHeadups();
1851
    }
1852
    if (gAction_replay_mode) {
1853
        SynchronizeActionReplay();
1854
    } else {
1855
        PipeFrameFinish();
1856
    }
1857
    gRender_screen->pixels = old_pixels;
1858
    if (!gPalette_fade_time || GetRaceTime() > gPalette_fade_time + 500) {
1859
        PDScreenBufferSwap(0);
1860
    }
1861
    if (gAction_replay_mode) {
1862
        DoActionReplayPostSwap();
1863
    }
1864
}
1865
 
1866
// IDA: void __cdecl InitPaletteAnimate()
1867
void InitPaletteAnimate(void) {
1868
    LOG_TRACE("()");
1869
 
1870
    gLast_palette_change = 0;
1871
    gPalette_index = 0;
1872
}
1873
 
1874
// IDA: void __cdecl RevertPalette()
1875
void RevertPalette(void) {
1876
 
1877
    memcpy(gRender_palette->pixels, gOrig_render_palette->pixels, 0x400u);
1878
    DRSetPalette3(gRender_palette, 1);
1879
}
1880
 
1881
// IDA: void __cdecl MungePalette()
1882
void MungePalette(void) {
1883
    //tU8* p; // Pierre-Marie Baty -- unused variable
1884
    //tU8* q; // Pierre-Marie Baty -- unused variable
1885
    //int i; // Pierre-Marie Baty -- unused variable
1886
    //float damage; // Pierre-Marie Baty -- unused variable
1887
    //float throb_start; // Pierre-Marie Baty -- unused variable
1888
    //float throb_end; // Pierre-Marie Baty -- unused variable
1889
    //float throb_amount; // Pierre-Marie Baty -- unused variable
1890
    //float throb_amount_dash; // Pierre-Marie Baty -- unused variable
1891
    //float omega; // Pierre-Marie Baty -- unused variable
1892
    //tU32 period; // Pierre-Marie Baty -- unused variable
1893
    //tU32 the_time; // Pierre-Marie Baty -- unused variable
1894
    //static int palette_spammed; // Pierre-Marie Baty -- unused variable
1895
    //static float last_omega; // Pierre-Marie Baty -- unused variable
1896
    //static tU32 next_repair_time; // Pierre-Marie Baty -- unused variable
1897
    //static tU32 last_sound; // Pierre-Marie Baty -- unused variable
1898
    LOG_TRACE("()");
1899
    NOT_IMPLEMENTED();
1900
}
1901
 
1902
// IDA: void __cdecl ResetPalette()
1903
void ResetPalette(void) {
1904
    LOG_TRACE("()");
1905
 
1906
    InitPaletteAnimate();
1907
    DRSetPalette(gRender_palette);
1908
}
1909
 
1910
// IDA: void __usercall Darken(tU8 *pPtr@<EAX>, unsigned int pDarken_amount@<EDX>)
1911
void Darken(tU8* pPtr, unsigned int pDarken_amount) {
1912
    //unsigned int value; // Pierre-Marie Baty -- unused variable
1913
    LOG_TRACE10("(%p, %d)", pPtr, pDarken_amount);
1914
 
1915
    *pPtr = (pDarken_amount * *pPtr) / 256;
1916
}
1917
 
1918
// IDA: void __usercall SetFadedPalette(int pDegree@<EAX>)
1919
void SetFadedPalette(int pDegree) {
1920
    int j;
1921
    //br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
1922
    //char* the_pixels; // Pierre-Marie Baty -- unused variable
1923
    LOG_TRACE10("(%d)", pDegree);
1924
 
1925
    memcpy(gScratch_pixels, gCurrent_palette->pixels, 0x400u);
1926
    for (j = 0; j < 256; j++) {
1927
        Darken((tU8*)&gScratch_pixels[4 * j], pDegree);
1928
        Darken((tU8*)&gScratch_pixels[4 * j + 1], pDegree);
1929
        Darken((tU8*)&gScratch_pixels[4 * j + 2], pDegree);
1930
        Darken((tU8*)&gScratch_pixels[4 * j + 3], pDegree);
1931
    }
1932
    DRSetPalette2(gScratch_palette, 0);
1933
}
1934
 
1935
// IDA: void __cdecl FadePaletteDown()
1936
void FadePaletteDown(void) {
1937
    int i;
1938
    int start_time;
1939
    int the_time;
1940
    LOG_TRACE("()");
1941
 
1942
    if (!gFaded_palette) {
1943
        gFaded_palette = 1;
1944
        MungeEngineNoise();
1945
        gFaded_palette = 0;
1946
        start_time = PDGetTotalTime();
1947
        while (1) {
1948
            the_time = PDGetTotalTime() - start_time;
1949
            if (the_time >= 500) {
1950
                break;
1951
            }
1952
            i = 256 - ((the_time * 256) / 500);
1953
            SetFadedPalette(i);
1954
        }
1955
        SetFadedPalette(0);
1956
        gFaded_palette = 1;
1957
    }
1958
}
1959
 
1960
// IDA: void __cdecl FadePaletteUp()
1961
void FadePaletteUp(void) {
1962
    int i;
1963
    int start_time;
1964
    int the_time;
1965
    LOG_TRACE("()");
1966
 
1967
    if (gFaded_palette) {
1968
        gFaded_palette = 0;
1969
        start_time = PDGetTotalTime();
1970
        while (1) {
1971
            the_time = PDGetTotalTime() - start_time;
1972
            if (the_time >= 500) {
1973
                break;
1974
            }
1975
            i = (the_time * 256) / 500;
1976
            SetFadedPalette(i);
1977
        }
1978
        DRSetPalette(gCurrent_palette);
1979
    }
1980
}
1981
 
1982
// IDA: void __cdecl KillSplashScreen()
1983
void KillSplashScreen(void) {
1984
 
1985
    if (gCurrent_splash != NULL) {
1986
        BrMapRemove(gCurrent_splash);
1987
        BrPixelmapFree(gCurrent_splash);
1988
        gCurrent_splash = NULL;
1989
        FadePaletteDown();
1990
        ClearEntireScreen();
1991
    }
1992
}
1993
 
1994
// IDA: void __cdecl EnsureRenderPalette()
1995
void EnsureRenderPalette(void) {
1996
    LOG_TRACE("()");
1997
 
1998
    if (gPalette_munged) {
1999
        ResetPalette();
2000
        gPalette_munged = 0;
2001
    }
2002
}
2003
 
2004
// IDA: void __usercall SplashScreenWith(char *pPixmap_name@<EAX>)
2005
void SplashScreenWith(char* pPixmap_name) {
2006
    br_pixelmap* the_map;
2007
    LOG_TRACE("(\"%s\")", pPixmap_name);
2008
 
2009
    the_map = BrMapFind(pPixmap_name);
2010
    if (gCurrent_splash == NULL || the_map != gCurrent_splash) {
2011
        FadePaletteDown();
2012
        EnsureRenderPalette();
2013
 
2014
        if (gCurrent_splash != NULL) {
2015
            KillSplashScreen();
2016
        }
2017
        gCurrent_splash = the_map;
2018
        if (the_map == NULL) {
2019
            the_map = LoadPixelmap(pPixmap_name);
2020
            gCurrent_splash = the_map;
2021
            if (the_map != NULL) {
2022
                BrMapAdd(the_map);
2023
            }
2024
        }
2025
        if (gCurrent_splash != NULL) {
2026
            BrPixelmapRectangleCopy(
2027
                gBack_screen,
2028
                0,
2029
                0,
2030
                gCurrent_splash,
2031
                0,
2032
                0,
2033
                gCurrent_splash->width,
2034
                gCurrent_splash->height);
2035
            PDScreenBufferSwap(0);
2036
            if (gFaded_palette) {
2037
                FadePaletteUp();
2038
            }
2039
        }
2040
    }
2041
}
2042
 
2043
// IDA: void __cdecl EnsurePaletteUp()
2044
void EnsurePaletteUp(void) {
2045
 
2046
    if (gFaded_palette) {
2047
        FadePaletteUp();
2048
    }
2049
}
2050
 
2051
// IDA: br_uint_32 __cdecl AmbientificateMaterial(br_material *pMat, void *pArg)
2052
br_uint_32 AmbientificateMaterial(br_material* pMat, void* pArg) {
2053
    float a;
2054
 
2055
    a = pMat->ka + *(br_scalar*)pArg;
2056
    if (a < 0.f) {
2057
        a = 0.f;
2058
    } else if (a > 0.99f) {
2059
        a = 0.99f;
2060
    }
2061
    pMat->ka = a;
2062
    return 0;
2063
}
2064
 
2065
// IDA: void __cdecl ChangeAmbience(br_scalar pDelta)
2066
void ChangeAmbience(br_scalar pDelta) {
2067
    LOG_TRACE("(%f)", pDelta);
2068
 
2069
    BrMaterialEnum("*", AmbientificateMaterial, &pDelta);
2070
}
2071
 
2072
// IDA: void __cdecl InitAmbience()
2073
void InitAmbience(void) {
2074
    LOG_TRACE("()");
2075
 
2076
    gCurrent_ambience = gAmbient_adjustment;
2077
    ChangeAmbience(gAmbient_adjustment);
2078
}
2079
 
2080
// 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)
2081
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) {
2082
    int y_count;
2083
    int x_count;
2084
    int dest_row_wrap;
2085
    int source_row_wrap;
2086
    //int x_delta; // Pierre-Marie Baty -- unused variable
2087
    tU8 the_byte;
2088
    tU8* source_ptr;
2089
    tU8* dest_ptr;
2090
    tU8* conv_table;
2091
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2092
 
2093
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2094
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2095
    source_row_wrap = pSource->row_bytes - pWidth;
2096
    dest_row_wrap = pDest->row_bytes - pWidth;
2097
 
2098
    if (pDest_y < 0) {
2099
        pHeight += pDest_y;
2100
        if (pHeight <= 0) {
2101
            return;
2102
        }
2103
        source_ptr -= pDest_y * pSource->row_bytes;
2104
        dest_ptr -= pDest_y * pDest->row_bytes;
2105
        pDest_y = 0;
2106
    }
2107
    if (pDest_y >= pDest->height) {
2108
        return;
2109
    }
2110
    if (pDest_y + pHeight > pDest->height) {
2111
        pHeight = pDest->height - pDest_y;
2112
    }
2113
    if (pDest_x < 0) {
2114
        pWidth += pDest_x;
2115
        if (pWidth <= 0) {
2116
            return;
2117
        }
2118
        source_ptr -= pDest_x;
2119
        dest_ptr -= pDest_x;
2120
        source_row_wrap -= pDest_x;
2121
        dest_row_wrap -= pDest_x;
2122
        pDest_x = 0;
2123
    }
2124
    if (pDest_x >= pDest->width) {
2125
        return;
2126
    }
2127
    if (pDest_x + pWidth > pDest->width) {
2128
        source_row_wrap += pDest_x + pWidth - pDest->width;
2129
        dest_row_wrap += pDest_x + pWidth - pDest->width;
2130
        pWidth = pDest->width - pDest_x;
2131
    }
2132
    // 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);
2133
    if (gCurrent_conversion_table != NULL) {
2134
        conv_table = gCurrent_conversion_table->pixels;
2135
        for (y_count = 0; y_count < pHeight; y_count++) {
2136
            for (x_count = 0; x_count < pWidth; x_count++) {
2137
                the_byte = *source_ptr;
2138
                if (the_byte != 0) {
2139
                    *dest_ptr = conv_table[the_byte];
2140
                }
2141
                source_ptr++;
2142
                dest_ptr++;
2143
            }
2144
            source_ptr += source_row_wrap;
2145
            dest_ptr += dest_row_wrap;
2146
        }
2147
    } else {
2148
        for (y_count = 0; y_count < pHeight; y_count++) {
2149
            for (x_count = 0; x_count < pWidth; x_count++) {
2150
                the_byte = *source_ptr;
2151
                if (the_byte != 0) {
2152
                    *dest_ptr = the_byte;
2153
                }
2154
                source_ptr++;
2155
                dest_ptr++;
2156
            }
2157
            source_ptr += source_row_wrap;
2158
            dest_ptr += dest_row_wrap;
2159
        }
2160
    }
2161
}
2162
 
2163
// IDA: void __usercall DRMaskedStamp(br_int_16 pDest_x@<EAX>, br_int_16 pDest_y@<EDX>, br_pixelmap *pSource@<EBX>)
2164
void DRMaskedStamp(br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource) {
2165
    LOG_TRACE("(%d, %d, %p)", pDest_x, pDest_y, pSource);
2166
 
2167
    DRPixelmapRectangleMaskedCopy(gBack_screen,
2168
        pDest_x,
2169
        pDest_y,
2170
        pSource,
2171
        0,
2172
        0,
2173
        pSource->width,
2174
        pSource->height);
2175
}
2176
 
2177
// 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)
2178
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) {
2179
    int y_count;
2180
    int x_count;
2181
    int dest_row_wrap;
2182
    int source_row_wrap;
2183
    //int x_delta; // Pierre-Marie Baty -- unused variable
2184
    tU8 the_byte;
2185
    tU8* source_ptr;
2186
    tU8* dest_ptr;
2187
    //tU8* conv_table; // Pierre-Marie Baty -- unused variable
2188
    // LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2189
 
2190
    source_row_wrap = pSource->row_bytes - pWidth;
2191
    dest_row_wrap = pDest->row_bytes - pWidth;
2192
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2193
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2194
 
2195
    for (y_count = 0; y_count < pHeight; y_count++) {
2196
        for (x_count = 0; x_count < pWidth; x_count++) {
2197
            the_byte = *source_ptr;
2198
            if (the_byte) {
2199
                *dest_ptr = the_byte;
2200
            }
2201
            source_ptr++;
2202
            dest_ptr++;
2203
        }
2204
        source_ptr += source_row_wrap;
2205
        dest_ptr += dest_row_wrap;
2206
    }
2207
}
2208
 
2209
// 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)
2210
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) {
2211
    int y_count;
2212
    int x_count;
2213
    int dest_row_wrap;
2214
    int source_row_wrap;
2215
    //int x_delta; // Pierre-Marie Baty -- unused variable
2216
    int last_shear_x;
2217
    int current_shear_x;
2218
    int shear_x_difference;
2219
    int pWidth_orig;
2220
    tU8 the_byte;
2221
    tU8* source_ptr;
2222
    tU8* dest_ptr;
2223
    //tU8* conv_table; // Pierre-Marie Baty -- unused variable
2224
    tX1616 current_shear;
2225
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight, pShear);
2226
 
2227
    current_shear = 0;
2228
    last_shear_x = 0;
2229
    source_ptr = (tU8*)pSource->pixels + pSource_x + pSource_y * pSource->row_bytes;
2230
    dest_ptr = (tU8*)pDest->pixels + pDest_x + pDest_y * pDest->row_bytes;
2231
    source_row_wrap = pSource->row_bytes - pWidth;
2232
    dest_row_wrap = pDest->row_bytes - pWidth;
2233
    if (pDest_y < 0) {
2234
        pHeight += pDest_y;
2235
        if (pHeight <= 0) {
2236
            return;
2237
        }
2238
        source_ptr -= pDest_y * pSource->row_bytes;
2239
        dest_ptr -= pDest_y * pDest->row_bytes;
2240
        pDest_y = 0;
2241
    }
2242
    if (pDest->height > pDest_y) {
2243
        if (pDest_y + pHeight > pDest->height) {
2244
            pHeight = pDest->height - pDest_y;
2245
        }
2246
        if (pDest_x < 0) {
2247
            pWidth += pDest_x;
2248
            if (pWidth <= 0) {
2249
                return;
2250
            }
2251
            source_ptr -= pDest_x;
2252
            dest_ptr -= pDest_x;
2253
            source_row_wrap -= pDest_x;
2254
            dest_row_wrap -= pDest_x;
2255
            pDest_x = 0;
2256
        }
2257
        if (pDest->width > pDest_x) {
2258
            pWidth_orig = pWidth;
2259
            for (y_count = 0; pHeight > y_count; ++y_count) {
2260
#if !defined(DETHRACE_FIX_BUGS)
2261
                /*
2262
                 * The OG compares against pWidth instead of pWidth_orig, which
2263
                 * ends up clipped to the dest pixelmap width. This effectively
2264
                 * clips the consecutive rows of pixels along the shear, leaving
2265
                 * a visible gap on the screen. Instead, when comparing against
2266
                 * pWidth_orig, the clip takes place vertically along the dest
2267
                 * pixelmap edge, allowing all pixels to be displayed.
2268
                 *
2269
                 * Simulate OG behavior by overwriting pWidth_orig with pWidth.
2270
                 */
2271
                pWidth_orig = pWidth;
2272
#endif
2273
                if (pDest_x + pWidth_orig > pDest->width) {
2274
                    shear_x_difference = pDest_x + pWidth - pDest->width;
2275
                    pWidth = pDest->width - pDest_x;
2276
                    source_row_wrap += shear_x_difference;
2277
                    dest_row_wrap += shear_x_difference;
2278
                }
2279
                for (x_count = 0; pWidth > x_count; ++x_count) {
2280
                    the_byte = *source_ptr++;
2281
                    if (the_byte) {
2282
                        *dest_ptr = the_byte;
2283
                    }
2284
                    ++dest_ptr;
2285
                }
2286
                current_shear_x = (current_shear >> 16) - last_shear_x;
2287
                dest_ptr += dest_row_wrap + current_shear_x;
2288
                last_shear_x = current_shear >> 16;
2289
                source_ptr += source_row_wrap;
2290
                current_shear += pShear;
2291
                pDest_x += current_shear_x;
2292
                if (pDest_x < 0) {
2293
                    pWidth += pDest_x;
2294
                    source_ptr -= pDest_x;
2295
                    dest_ptr -= pDest_x;
2296
                    source_row_wrap -= pDest_x;
2297
                    dest_row_wrap -= pDest_x;
2298
                    pDest_x = 0;
2299
                }
2300
                if (pDest->width <= pDest_x) {
2301
                    break;
2302
                }
2303
            }
2304
        }
2305
    }
2306
}
2307
 
2308
// 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)
2309
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) {
2310
    int y_count;
2311
    int x_count;
2312
    int dest_row_wrap;
2313
    int source_row_wrap;
2314
    //int x_delta; // Pierre-Marie Baty -- unused variable
2315
    tU8 the_byte;
2316
    tU8* source_ptr;
2317
    tU8* dest_ptr;
2318
    tU32 source_y;
2319
    tU32 source_y_delta;
2320
    tU32 old_source_y;
2321
    LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
2322
 
2323
    if (!pHeight) {
2324
        return;
2325
    }
2326
 
2327
    source_row_wrap = pSource->row_bytes - pWidth;
2328
    dest_row_wrap = pDest->row_bytes - pWidth;
2329
    dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
2330
    source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
2331
 
2332
    source_y = 0;
2333
    source_y_delta = (pSource->height << 16) / pHeight - 0x10000;
2334
 
2335
    for (y_count = 0; y_count < pHeight; y_count++) {
2336
        for (x_count = 0; x_count < pWidth; x_count++) {
2337
            the_byte = *source_ptr;
2338
            if (the_byte) {
2339
                *dest_ptr = the_byte;
2340
            }
2341
            source_ptr++;
2342
            dest_ptr++;
2343
        }
2344
        old_source_y = source_y;
2345
        source_y += source_y_delta;
2346
        source_ptr += (((source_y >> 16) - (old_source_y >> 16)) * pSource->row_bytes) + source_row_wrap;
2347
        dest_ptr += dest_row_wrap;
2348
    }
2349
}
2350
 
2351
// IDA: void __cdecl InitTransientBitmaps()
2352
void InitTransientBitmaps(void) {
2353
    int i;
2354
    LOG_TRACE("()");
2355
 
2356
    for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2357
        gTransient_bitmaps[i].pixmap = NULL;
2358
        gTransient_bitmaps[i].in_use = 0;
2359
    }
2360
}
2361
 
2362
// IDA: int __usercall AllocateTransientBitmap@<EAX>(int pWidth@<EAX>, int pHeight@<EDX>, int pUser_data@<EBX>)
2363
int AllocateTransientBitmap(int pWidth, int pHeight, int pUser_data) {
2364
    int bm_index;
2365
    LOG_TRACE("(%d, %d, %d)", pWidth, pHeight, pUser_data);
2366
 
2367
    for (bm_index = 0; bm_index < COUNT_OF(gTransient_bitmaps); bm_index++) {
2368
        if (gTransient_bitmaps[bm_index].pixmap == NULL) {
2369
            gTransient_bitmaps[bm_index].pixmap = DRPixelmapAllocate(BR_PMT_INDEX_8, pWidth + 8, pHeight, NULL, 0);
2370
            gTransient_bitmaps[bm_index].in_use = 0;
2371
            gTransient_bitmaps[bm_index].user_data = pUser_data;
2372
            return bm_index;
2373
        }
2374
    }
2375
    FatalError(kFatalError_FindSpareTransientBitmap);
2376
}
2377
 
2378
// IDA: void __usercall DeallocateTransientBitmap(int pIndex@<EAX>)
2379
void DeallocateTransientBitmap(int pIndex) {
2380
    LOG_TRACE("(%d)", pIndex);
2381
 
2382
    if (gTransient_bitmaps[pIndex].pixmap != NULL) {
2383
        BrPixelmapFree(gTransient_bitmaps[pIndex].pixmap);
2384
        gTransient_bitmaps[pIndex].pixmap = NULL;
2385
        gTransient_bitmaps[pIndex].in_use = 0;
2386
    }
2387
}
2388
 
2389
// IDA: void __cdecl DeallocateAllTransientBitmaps()
2390
void DeallocateAllTransientBitmaps(void) {
2391
    int i;
2392
    LOG_TRACE("()");
2393
 
2394
    for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2395
        DeallocateTransientBitmap(i);
2396
    }
2397
}
2398
 
2399
// IDA: void __usercall RemoveTransientBitmaps(int pGraphically_remove_them@<EAX>)
2400
void RemoveTransientBitmaps(int pGraphically_remove_them) {
2401
    int i;
2402
    int order_number;
2403
 
2404
    if (pGraphically_remove_them) {
2405
        for (order_number = gNext_transient - 1; order_number >= 0; order_number--) {
2406
            for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
2407
                if (gTransient_bitmaps[i].pixmap != NULL && gTransient_bitmaps[i].order_number == order_number) {
2408
                    if (gTransient_bitmaps[i].in_use) {
2409
                        BrPixelmapRectangleCopy(gBack_screen,
2410
                            gTransient_bitmaps[i].x_coord,
2411
                            gTransient_bitmaps[i].y_coord,
2412
                            gTransient_bitmaps[i].pixmap,
2413
                            0,
2414
                            0,
2415
                            gTransient_bitmaps[i].pixmap->width,
2416
                            gTransient_bitmaps[i].pixmap->height);
2417
                    }
2418
                    break;
2419
                }
2420
            }
2421
        }
2422
    }
2423
    gNext_transient = 0;
2424
}
2425
 
2426
// IDA: void __usercall SaveTransient(int pIndex@<EAX>, int pX_coord@<EDX>, int pY_coord@<EBX>)
2427
void SaveTransient(int pIndex, int pX_coord, int pY_coord) {
2428
    LOG_TRACE("(%d, %d, %d)", pIndex, pX_coord, pY_coord);
2429
 
2430
    gTransient_bitmaps[pIndex].x_coord = pX_coord & ~3;
2431
    gTransient_bitmaps[pIndex].y_coord = pY_coord;
2432
    gTransient_bitmaps[pIndex].in_use = 1;
2433
    gTransient_bitmaps[pIndex].order_number = gNext_transient;
2434
    gNext_transient++;
2435
    BrPixelmapRectangleCopy(gTransient_bitmaps[pIndex].pixmap,
2436
        0,
2437
        0,
2438
        gBack_screen,
2439
        gTransient_bitmaps[pIndex].x_coord,
2440
        gTransient_bitmaps[pIndex].y_coord,
2441
        gTransient_bitmaps[pIndex].pixmap->width,
2442
        gTransient_bitmaps[pIndex].pixmap->height);
2443
}
2444
 
2445
// IDA: void __usercall DrawCursorGiblet(tCursor_giblet *pGib@<EAX>)
2446
void DrawCursorGiblet(tCursor_giblet* pGib) {
2447
    br_pixelmap* the_image;
2448
    LOG_TRACE("(%p)", pGib);
2449
 
2450
    SaveTransient(pGib->transient_index, pGib->x_coord, pGib->y_coord);
2451
    the_image = gCursor_giblet_images[gCursor_giblet_sequences[pGib->sequence_index][pGib->current_giblet]];
2452
    DRPixelmapRectangleMaskedCopy(gBack_screen,
2453
        pGib->x_coord,
2454
        pGib->y_coord,
2455
        the_image,
2456
        0,
2457
        0,
2458
        the_image->width,
2459
        the_image->height);
2460
}
2461
 
2462
// IDA: void __usercall ProcessCursorGiblets(int pPeriod@<EAX>)
2463
void ProcessCursorGiblets(int pPeriod) {
2464
    int i;
2465
    int kill_the_giblet;
2466
    tU32 time_now;
2467
    tCursor_giblet* gib;
2468
    LOG_TRACE("(%d)", pPeriod);
2469
 
2470
    time_now = PDGetTotalTime();
2471
    for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2472
        gib = &gCursor_giblets[i];
2473
        kill_the_giblet = 0;
2474
        if (gib->current_giblet == -1) {
2475
            continue;
2476
        }
2477
        if (!gib->landed && gib->e_t_a <= time_now) {
2478
            gib->landed = 1;
2479
            gib->the_speed = 0.f;
2480
        }
2481
        if (gib->landed) {
2482
            gib->giblet_change_period -= pPeriod / 2;
2483
            if (gib->giblet_change_period < 50) {
2484
                gib->giblet_change_period = 50;
2485
            }
2486
            if (gib->giblet_change_period <= time_now - gib->last_giblet_change) {
2487
                if (gCursor_giblet_sequences[gib->sequence_index][0] == gib->current_giblet) {
2488
                    gib->current_giblet = 1;
2489
                } else {
2490
                    gib->current_giblet++;
2491
                }
2492
                gib->last_giblet_change = time_now;
2493
            }
2494
            gib->y_coord += pPeriod * gib->the_speed / 1000.f;
2495
            if (gib->y_coord <= gGraf_data[gGraf_data_index].height) {
2496
                if (gib->the_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
2497
                    gib->the_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f;
2498
                }
2499
            } else {
2500
                kill_the_giblet = 1;
2501
            }
2502
        } else {
2503
            if (gib->y_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
2504
                gib->y_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f * 2.f;
2505
            }
2506
            gib->x_coord += pPeriod * gib->x_speed / 1000.f;
2507
            gib->y_coord += pPeriod * gib->y_speed / 1000.f;
2508
            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) {
2509
                kill_the_giblet = 1;
2510
            }
2511
        }
2512
        if (kill_the_giblet) {
2513
            gib->current_giblet = -1;
2514
            DeallocateTransientBitmap(gib->transient_index);
2515
        } else {
2516
            DrawCursorGiblet(gib);
2517
        }
2518
    }
2519
}
2520
 
2521
// IDA: int __usercall NewCursorGiblet@<EAX>(int pX_coord@<EAX>, int pY_coord@<EDX>, float pX_speed, float pY_speed, tU32 pDrop_time)
2522
int NewCursorGiblet(int pX_coord, int pY_coord, float pX_speed, float pY_speed, tU32 pDrop_time) {
2523
    int i;
2524
    int the_width;
2525
    int the_height;
2526
    int sequence_number;
2527
    LOG_TRACE("(%d, %d, %f, %f, %d)", pX_coord, pY_coord, pX_speed, pY_speed, pDrop_time);
2528
 
2529
    sequence_number = IRandomBetween(0, COUNT_OF(gCursor_giblet_sequences) - 1);
2530
    if (pX_coord >= 0 && pX_coord < gGraf_data[gGraf_data_index].width && pY_coord >= 0 && pY_coord < gGraf_data[gGraf_data_index].height) {
2531
        for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2532
            if (gCursor_giblets[i].current_giblet == -1) {
2533
                the_width = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->width;
2534
                the_height = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->height;
2535
                gCursor_giblets[i].transient_index = AllocateTransientBitmap(the_width, the_height, 1);
2536
                gCursor_giblets[i].current_giblet = 1;
2537
                gCursor_giblets[i].sequence_index = sequence_number;
2538
                gCursor_giblets[i].landed = 0;
2539
                gCursor_giblets[i].x_coord = sequence_number * gGraf_specs[gGraf_spec_index].total_width / 640 - the_width / 2 + pX_coord;
2540
                gCursor_giblets[i].y_coord = FRandomPosNeg(6.f) * gGraf_specs[gGraf_spec_index].total_height / 480 - the_height / 2 + pY_coord;
2541
                gCursor_giblets[i].x_speed = pX_speed;
2542
                gCursor_giblets[i].y_speed = pY_speed;
2543
                gCursor_giblets[i].last_giblet_change = 0;
2544
                gCursor_giblets[i].giblet_change_period = 1000;
2545
                gCursor_giblets[i].e_t_a = PDGetTotalTime() + pDrop_time;
2546
                return i;
2547
            }
2548
        }
2549
    }
2550
    return -1;
2551
}
2552
 
2553
// IDA: int __cdecl DoMouseCursor()
2554
int DoMouseCursor(void) {
2555
    int x_coord; // Added by DethRace
2556
    int y_coord;
2557
    int mouse_moved;
2558
    int new_required;
2559
    //int giblet_index; // Pierre-Marie Baty -- unused variable
2560
    int cursor_offset;
2561
    int button_is_down;
2562
    int giblet_chance;
2563
    int giblet_count;
2564
    tU32 this_call_time;
2565
    static tU32 last_cursor_change;
2566
    static tU32 last_call_time;
2567
    static tU32 last_required_change;
2568
    tS32 period;
2569
    static int delta_x;
2570
    static int required_cursor;
2571
    static int zero_count;
2572
    static int button_was_down;
2573
 
2574
    period = 0;
2575
    this_call_time = PDGetTotalTime();
2576
    if (last_call_time == 0) {
2577
        period = 1000;
2578
    }
2579
    while (period <= 20) {
2580
        this_call_time = PDGetTotalTime();
2581
        period = this_call_time - last_call_time;
2582
        // added by dethrace to avoid 100% CPU usage
2583
        gHarness_platform.Sleep(1);
2584
    }
2585
    GetMousePosition(&x_coord, &y_coord);
2586
    mouse_moved = x_coord != gMouse_last_x_coord || y_coord != gMouse_last_y_coord;
2587
    button_is_down = EitherMouseButtonDown();
2588
    cursor_offset = button_is_down ? 4 : 0;
2589
    if (gMouse_in_use || mouse_moved) {
2590
        gMouse_in_use = 1;
2591
        if (gMouse_last_x_coord == x_coord) {
2592
            if (zero_count >= 5) {
2593
                delta_x = 0;
2594
            }
2595
            zero_count++;
2596
        } else {
2597
            zero_count = 0;
2598
            delta_x = (x_coord - gMouse_last_x_coord) * 1000 / period;
2599
        }
2600
        if (delta_x < -10) {
2601
            new_required = 0;
2602
        } else if (delta_x < 11) {
2603
            new_required = 2;
2604
        } else {
2605
            new_required = 3;
2606
        }
2607
        if (new_required != required_cursor && this_call_time - last_required_change >= 200) {
2608
            last_required_change = this_call_time;
2609
            required_cursor = new_required;
2610
        }
2611
        if (gCurrent_cursor_index != required_cursor && PDGetTotalTime() - last_cursor_change >= 50) {
2612
            if (required_cursor < gCurrent_cursor_index) {
2613
                gCurrent_cursor_index--;
2614
            } else {
2615
                gCurrent_cursor_index++;
2616
            }
2617
            last_cursor_change = PDGetTotalTime();
2618
        }
2619
        giblet_chance = Chance(1.f + 20.f * (abs(x_coord - gMouse_last_x_coord) + abs(y_coord - gMouse_last_y_coord)) / (float)period, period);
2620
        if (gProgram_state.sausage_eater_mode) {
2621
            giblet_count = 0;
2622
        } else {
2623
            giblet_count = 6 * BooleanTo1Or0(button_is_down && !button_was_down) + BooleanTo1Or0(giblet_chance);
2624
        }
2625
        for (; giblet_count != 0; giblet_count--) {
2626
            NewCursorGiblet(
2627
                x_coord + gCursor_gib_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2628
                y_coord + gCursor_gib_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
2629
                ((float)(x_coord - gMouse_last_x_coord)) / period * 1000.f / 4.f,
2630
                ((float)(y_coord - gMouse_last_y_coord)) / period * 1000.f / 3.f,
2631
                (button_is_down && !button_was_down) ? 50 : 400);
2632
        }
2633
        ProcessCursorGiblets(period);
2634
        SaveTransient(gCursor_transient_index,
2635
            x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2636
            y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480);
2637
        DRPixelmapRectangleMaskedCopy(gBack_screen,
2638
            x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
2639
            y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
2640
            gCursors[gCurrent_cursor_index + cursor_offset],
2641
            0,
2642
            0,
2643
            gCursors[gCurrent_cursor_index + cursor_offset]->width,
2644
            gCursors[gCurrent_cursor_index + cursor_offset]->height);
2645
    }
2646
    last_call_time = this_call_time;
2647
    button_was_down = button_is_down;
2648
    gMouse_last_x_coord = x_coord;
2649
    gMouse_last_y_coord = y_coord;
2650
    return mouse_moved;
2651
}
2652
 
2653
// IDA: int __cdecl AllocateCursorTransient()
2654
int AllocateCursorTransient(void) {
2655
    int i;
2656
    int largest_width;
2657
    int largest_height;
2658
    LOG_TRACE("()");
2659
 
2660
    largest_width = 0;
2661
    largest_height = 0;
2662
    for (i = 0; i < COUNT_OF(gCursors); i++) {
2663
        if (largest_width < gCursors[i]->width) {
2664
            largest_width = gCursors[i]->width;
2665
        }
2666
        if (largest_height < gCursors[i]->height) {
2667
            largest_height = gCursors[i]->height;
2668
        }
2669
    }
2670
    return AllocateTransientBitmap(largest_width, largest_height, 0);
2671
}
2672
 
2673
// IDA: void __cdecl StartMouseCursor()
2674
void StartMouseCursor(void) {
2675
    int i;
2676
    LOG_TRACE("()");
2677
 
2678
    gNext_transient = 0;
2679
    gCursor_transient_index = AllocateCursorTransient();
2680
    GetMousePosition(&gMouse_last_x_coord, &gMouse_last_y_coord);
2681
    gMouse_in_use = 0;
2682
    gCurrent_cursor_index = 2;
2683
    for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
2684
        gCursor_giblets[i].current_giblet = -1;
2685
    }
2686
    gMouse_started = 1;
2687
}
2688
 
2689
// IDA: void __cdecl EndMouseCursor()
2690
void EndMouseCursor(void) {
2691
    LOG_TRACE("()");
2692
 
2693
    RemoveTransientBitmaps(1);
2694
    DeallocateAllTransientBitmaps();
2695
    gMouse_started = 0;
2696
}
2697
 
2698
// IDA: void __usercall LoadFont(int pFont_ID@<EAX>)
2699
void LoadFont(int pFont_ID) {
2700
    tPath_name the_path;
2701
    int i;
2702
    int number_of_chars;
2703
    FILE* f;
2704
    tU32 the_size;
2705
    LOG_TRACE("(%d)", pFont_ID);
2706
 
2707
    if (gFonts[pFont_ID].images != NULL) {
2708
        return;
2709
    }
2710
 
2711
    PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
2712
    PathCat(the_path, the_path, "FONTS");
2713
    PathCat(the_path, the_path, gFont_names[pFont_ID]);
2714
    number_of_chars = strlen(the_path);
2715
    strcat(the_path, ".PIX");
2716
    gFonts[pFont_ID].images = DRPixelmapLoad(the_path);
2717
 
2718
    if (gFonts[pFont_ID].images == NULL) {
2719
        FatalError(kFatalError_LoadFontImage_S, gFont_names[pFont_ID]);
2720
    }
2721
    if (!gFonts[pFont_ID].file_read_once) {
2722
        strcpy(&the_path[number_of_chars + 1], "TXT");
2723
 
2724
        f = DRfopen(the_path, "rt");
2725
        if (f == NULL) {
2726
            FatalError(kFatalError_LoadFontWidthTable_S, gFont_names[pFont_ID]);
2727
        }
2728
 
2729
        gFonts[pFont_ID].height = GetAnInt(f);
2730
        gFonts[pFont_ID].width = GetAnInt(f);
2731
        gFonts[pFont_ID].spacing = GetAnInt(f);
2732
        gFonts[pFont_ID].offset = GetAnInt(f);
2733
        gFonts[pFont_ID].num_entries = GetAnInt(f);
2734
        if (gFonts[pFont_ID].width <= 0) {
2735
            for (i = 0; i < gFonts[pFont_ID].num_entries; i++) {
2736
                the_size = GetAnInt(f);
2737
                gFonts[pFont_ID].width_table[i] = the_size;
2738
            }
2739
        }
2740
        fclose(f);
2741
        gFonts[pFont_ID].file_read_once = 1;
2742
    }
2743
}
2744
 
2745
// IDA: void __usercall DisposeFont(int pFont_ID@<EAX>)
2746
void DisposeFont(int pFont_ID) {
2747
    LOG_TRACE("(%d)", pFont_ID);
2748
    if (gFonts[pFont_ID].images && (!TranslationMode() || (gAusterity_mode && FlicsPlayedFromDisk()))) {
2749
        BrPixelmapFree(gFonts[pFont_ID].images);
2750
        gFonts[pFont_ID].images = NULL;
2751
        gFonts[pFont_ID].file_read_once = 0;
2752
    }
2753
}
2754
 
2755
// IDA: void __cdecl InitDRFonts()
2756
void InitDRFonts(void) {
2757
    int i;
2758
    LOG_TRACE("()");
2759
 
2760
    for (i = 0; i < 21; i++) {
2761
        gFonts[i].file_read_once = 0;
2762
        gFonts[i].images = NULL;
2763
    }
2764
}
2765
 
2766
// IDA: void __usercall DrawDropImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip, int pOffset)
2767
void DrawDropImage(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip, int pOffset) {
2768
    int y;
2769
    int src_y;
2770
    int src_height;
2771
    int y_diff;
2772
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip, pOffset);
2773
 
2774
    BrPixelmapRectangleFill(gBack_screen,
2775
        pLeft,
2776
        pTop_clip,
2777
        pImage->width,
2778
        pBottom_clip - pTop_clip,
2779
        0);
2780
    if (pOffset != 1000) {
2781
        src_y = 0;
2782
        src_height = pImage->height;
2783
        y = pOffset + pTop;
2784
        y_diff = pTop_clip - y;
2785
        if (y_diff > 0) {
2786
            src_height -= y_diff;
2787
            y += y_diff;
2788
            src_y = y_diff;
2789
        }
2790
        y_diff = pBottom_clip - y - pImage->height;
2791
        if (y_diff < 0) {
2792
            src_height += y_diff;
2793
        }
2794
        BrPixelmapRectangleCopy(gBack_screen,
2795
            pLeft,
2796
            y,
2797
            pImage,
2798
            0,
2799
            src_y,
2800
            pImage->width,
2801
            src_height);
2802
        PDScreenBufferSwap(0);
2803
    }
2804
}
2805
 
2806
// IDA: void __usercall DropInImageFromTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2807
void DropInImageFromTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2808
    tS32 start_time;
2809
    tS32 the_time;
2810
    int drop_distance;
2811
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2812
 
2813
    start_time = PDGetTotalTime();
2814
    drop_distance = pImage->height - pTop_clip + pTop;
2815
    while (1) {
2816
        the_time = PDGetTotalTime();
2817
        if (the_time >= start_time + 100) {
2818
            break;
2819
        }
2820
        DrawDropImage(pImage,
2821
            pLeft,
2822
            pTop,
2823
            pTop_clip,
2824
            pBottom_clip,
2825
            (the_time - start_time - 100) * drop_distance / 100);
2826
    }
2827
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
2828
}
2829
 
2830
// IDA: void __usercall DropOutImageThruBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2831
void DropOutImageThruBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2832
    tS32 start_time;
2833
    tS32 the_time;
2834
    int drop_distance;
2835
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2836
 
2837
    start_time = PDGetTotalTime();
2838
    drop_distance = pBottom_clip - pTop;
2839
    while (1) {
2840
        the_time = PDGetTotalTime();
2841
        if (the_time >= start_time + 100) {
2842
            break;
2843
        }
2844
        DrawDropImage(pImage,
2845
            pLeft,
2846
            pTop,
2847
            pTop_clip,
2848
            pBottom_clip,
2849
            (the_time - start_time) * drop_distance / 100);
2850
    }
2851
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
2852
}
2853
 
2854
// IDA: void __usercall DropInImageFromBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2855
void DropInImageFromBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2856
    tS32 start_time;
2857
    tS32 the_time;
2858
    int drop_distance;
2859
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2860
 
2861
    start_time = PDGetTotalTime();
2862
    drop_distance = pBottom_clip - pTop;
2863
    while (1) {
2864
        the_time = PDGetTotalTime();
2865
        if (the_time >= start_time + 100) {
2866
            break;
2867
        }
2868
        DrawDropImage(pImage,
2869
            pLeft,
2870
            pTop,
2871
            pTop_clip,
2872
            pBottom_clip,
2873
            (100 - the_time + start_time) * drop_distance / 100);
2874
    }
2875
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
2876
}
2877
 
2878
// IDA: void __usercall DropOutImageThruTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
2879
void DropOutImageThruTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
2880
    tS32 start_time;
2881
    tS32 the_time;
2882
    int drop_distance;
2883
    LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
2884
 
2885
    start_time = PDGetTotalTime();
2886
    drop_distance = pImage->height - pTop_clip + pTop;
2887
    while (1) {
2888
        the_time = PDGetTotalTime();
2889
        if (the_time >= start_time + 100) {
2890
            break;
2891
        }
2892
        DrawDropImage(pImage,
2893
            pLeft,
2894
            pTop,
2895
            pTop_clip,
2896
            pBottom_clip,
2897
            (start_time - the_time) * drop_distance / 100);
2898
    }
2899
    DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
2900
}
2901
 
2902
// IDA: void __usercall DrawTellyLine(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
2903
void DrawTellyLine(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
2904
    int the_width;
2905
    int the_height;
2906
    LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
2907
 
2908
    the_width = pImage->width;
2909
    the_height = pImage->height / 2 + pTop;
2910
    BrPixelmapLine(gBack_screen, pLeft, the_height, pLeft + the_width, the_height, 0);
2911
    BrPixelmapLine(gBack_screen, the_width / 2 + pLeft - pPercentage * the_width / 200, the_height, the_width / 2 + pLeft + pPercentage * the_width / 200, the_height, 1);
2912
    PDScreenBufferSwap(0);
2913
}
2914
 
2915
// IDA: void __usercall DrawTellyImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
2916
void DrawTellyImage(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
2917
    //int the_height; // Pierre-Marie Baty -- unused variable
2918
    LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
2919
 
2920
    BrPixelmapRectangleFill(gBack_screen, pLeft, pTop, pImage->width, pImage->height, 0);
2921
    if (pPercentage != 1000) {
2922
        DRPixelmapRectangleVScaledCopy(
2923
            gBack_screen,
2924
            pLeft,
2925
            pTop + pImage->height * (100 - pPercentage) / 200,
2926
            pImage,
2927
            0,
2928
            0,
2929
            pImage->width,
2930
            pPercentage * pImage->height / 100);
2931
        PDScreenBufferSwap(0);
2932
    }
2933
}
2934
 
2935
// IDA: void __usercall TellyInImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
2936
void TellyInImage(br_pixelmap* pImage, int pLeft, int pTop) {
2937
    tS32 start_time;
2938
    tS32 the_time;
2939
    LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
2940
 
2941
    start_time = PDGetTotalTime();
2942
    while (1) {
2943
        the_time = PDGetTotalTime();
2944
        if (start_time + 100 <= the_time) {
2945
            break;
2946
        }
2947
        DrawTellyLine(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
2948
    }
2949
    start_time = PDGetTotalTime();
2950
    while (1) {
2951
        the_time = PDGetTotalTime();
2952
        if (start_time + 100 <= the_time) {
2953
            break;
2954
        }
2955
        DrawTellyImage(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
2956
    }
2957
    DrawTellyImage(pImage, pLeft, pTop, 100);
2958
}
2959
 
2960
// IDA: void __usercall TellyOutImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
2961
void TellyOutImage(br_pixelmap* pImage, int pLeft, int pTop) {
2962
    tS32 start_time;
2963
    tS32 the_time;
2964
    //int drop_distance; // Pierre-Marie Baty -- unused variable
2965
    LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
2966
 
2967
    start_time = PDGetTotalTime();
2968
    while (1) {
2969
        the_time = PDGetTotalTime();
2970
        if (start_time + 100 <= the_time) {
2971
            break;
2972
        }
2973
        DrawTellyImage(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
2974
    }
2975
    DrawTellyImage(pImage, pLeft, pTop, 1000);
2976
 
2977
    start_time = PDGetTotalTime();
2978
    while (1) {
2979
        the_time = PDGetTotalTime();
2980
        if (start_time + 100 <= the_time) {
2981
            break;
2982
        }
2983
        DrawTellyLine(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
2984
    }
2985
    DrawTellyLine(pImage, pLeft, pTop, 0);
2986
}
2987
 
2988
// IDA: void __usercall SetShadowLevel(tShadow_level pLevel@<EAX>)
2989
void SetShadowLevel(tShadow_level pLevel) {
2990
    LOG_TRACE("(%d)", pLevel);
2991
 
2992
    gShadow_level = pLevel;
2993
}
2994
 
2995
// IDA: tShadow_level __cdecl GetShadowLevel()
2996
tShadow_level GetShadowLevel(void) {
2997
    LOG_TRACE("()");
2998
 
2999
    return gShadow_level;
3000
}
3001
 
3002
// IDA: void __cdecl ToggleShadow()
3003
void ToggleShadow(void) {
3004
    LOG_TRACE("()");
3005
 
3006
    gShadow_level++;
3007
    if (gShadow_level == eShadow_everyone) {
3008
        gShadow_level = eShadow_none;
3009
    }
3010
    switch (gShadow_level) {
3011
    case eShadow_none:
3012
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoShadows));
3013
        break;
3014
    case eShadow_us_only:
3015
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderOwnCar));
3016
        break;
3017
    case eShadow_us_and_opponents:
3018
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderMainCars));
3019
        break;
3020
    case eShadow_everyone:
3021
        NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderAllCars));
3022
        break;
3023
    default:
3024
        return;
3025
    }
3026
}
3027
 
3028
// IDA: void __cdecl InitShadow()
3029
void InitShadow(void) {
3030
    int i;
3031
    //br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
3032
    LOG_TRACE("()");
3033
 
3034
    for (i = 0; i < 8; i++) {
3035
        gShadow_clip_planes[i].clip = BrActorAllocate(BR_ACTOR_CLIP_PLANE, NULL);
3036
        BrActorAdd(gUniverse_actor, gShadow_clip_planes[i].clip);
3037
        BrClipPlaneDisable(gShadow_clip_planes[i].clip);
3038
        BrMatrix34Identity(&gShadow_clip_planes[i].clip->t.t.mat);
3039
    }
3040
    gFancy_shadow = 1;
3041
    gShadow_material = BrMaterialFind("SHADOW.MAT");
3042
    BrVector3Set(&gShadow_light_ray, 0.f, -1.f, 0.f);
3043
    BrVector3Set(&gShadow_light_z, -0.f, -0.f, -1.f);
3044
    BrVector3Set(&gShadow_light_x, 1.f, 0.f, 0.f);
3045
 
3046
    gShadow_model = BrModelAllocate("", 0, 0);
3047
    gShadow_model->flags = BR_MODF_GENERATE_TAGS | BR_MODF_KEEP_ORIGINAL;
3048
    gShadow_actor = BrActorAllocate(BR_ACTOR_MODEL, 0);
3049
    gShadow_actor->model = gShadow_model;
3050
    BrActorAdd(gUniverse_actor, gShadow_actor);
3051
}
3052
 
3053
// IDA: br_uint_32 __cdecl SaveShadeTable(br_pixelmap *pTable, void *pArg)
3054
br_uint_32 SaveShadeTable(br_pixelmap* pTable, void* pArg) {
3055
    LOG_TRACE("(%p, %p)", pTable, pArg);
3056
 
3057
    if (gSaved_table_count == COUNT_OF(gSaved_shade_tables)) {
3058
        return 1;
3059
    }
3060
    gSaved_shade_tables[gSaved_table_count].original = pTable;
3061
    gSaved_shade_tables[gSaved_table_count].copy = (br_pixelmap*)BrMemAllocate(sizeof(br_pixelmap), kMem_shade_table_copy);
3062
    memcpy(gSaved_shade_tables[gSaved_table_count].copy, pTable, sizeof(br_pixelmap));
3063
    gSaved_table_count++;
3064
    return 0;
3065
}
3066
 
3067
// IDA: void __cdecl SaveShadeTables()
3068
void SaveShadeTables(void) {
3069
    LOG_TRACE("()");
3070
 
3071
    PossibleService();
3072
    gSaved_table_count = 0;
3073
    BrTableEnum("*", SaveShadeTable, 0);
3074
}
3075
 
3076
// IDA: void __cdecl DisposeSavedShadeTables()
3077
void DisposeSavedShadeTables(void) {
3078
    int i;
3079
    LOG_TRACE("()");
3080
 
3081
    for (i = 0; i < gSaved_table_count; i++) {
3082
        BrMemFree(gSaved_shade_tables[i].copy);
3083
    }
3084
}
3085
 
3086
// IDA: void __cdecl ShadowMode()
3087
void ShadowMode(void) {
3088
    LOG_TRACE("()");
3089
 
3090
    gFancy_shadow = !gFancy_shadow;
3091
    if (gFancy_shadow) {
3092
        NewTextHeadupSlot(4, 0, 2000, -4, "Translucent shadow");
3093
    } else {
3094
        NewTextHeadupSlot(4, 0, 2000, -4, "Solid shadow");
3095
    }
3096
}
3097
 
3098
// IDA: int __cdecl SwitchToRealResolution()
3099
int SwitchToRealResolution(void) {
3100
    LOG_TRACE("()");
3101
 
3102
    if (gGraf_data_index == gReal_graf_data_index) {
3103
        return 0;
3104
    }
3105
    gGraf_data_index = gReal_graf_data_index;
3106
    gGraf_spec_index = gReal_graf_data_index;
3107
    gCurrent_graf_data = &gGraf_data[gReal_graf_data_index];
3108
    PDSwitchToRealResolution();
3109
    return 1;
3110
}
3111
 
3112
// IDA: int __cdecl SwitchToLoresMode()
3113
int SwitchToLoresMode(void) {
3114
    LOG_TRACE("()");
3115
    if (!gGraf_data_index || gGraf_data_index != gReal_graf_data_index) {
3116
        return 0;
3117
    }
3118
    gGraf_data_index = 0;
3119
    gGraf_spec_index = 0;
3120
    gCurrent_graf_data = gGraf_data;
3121
    PDSwitchToLoresMode();
3122
    return 1;
3123
}
3124
 
3125
// 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)
3126
void DRPixelmapDoubledCopy(br_pixelmap* pDestn, br_pixelmap* pSource, int pSource_width, int pSource_height, int pX_offset, int pY_offset) {
3127
    tU16* sptr;
3128
    tU16 pixels;
3129
    tU8* dptr;
3130
    tU8* dptr2;
3131
    tU8 pixel_1;
3132
    tU8 pixel_2;
3133
    int i;
3134
    int j;
3135
    int dst_row_skip;
3136
    int src_row_skip;
3137
    int width_over_2;
3138
    LOG_TRACE("(%p, %p, %d, %d, %d, %d)", pDestn, pSource, pSource_width, pSource_height, pX_offset, pY_offset);
3139
 
3140
    dst_row_skip = 2 * pDestn->row_bytes - 2 * pSource_width;
3141
    src_row_skip = (pSource->row_bytes - pSource_width) / 2;
3142
    sptr = (tU16*)((tU8*)pSource->pixels - 2 * src_row_skip + 2 * (pSource->row_bytes * pSource_height / 2));
3143
    dptr = (tU8*)pDestn->pixels + 2 * pSource_width + (2 * pSource_height + pY_offset) * pDestn->row_bytes - pDestn->row_bytes;
3144
    dptr2 = dptr - pDestn->row_bytes;
3145
    width_over_2 = pSource_width / 2;
3146
    for (i = 0; i < pSource_height; i++) {
3147
        for (j = 0; j < width_over_2; j++) {
3148
            --sptr;
3149
            pixels = *sptr;
3150
            pixel_1 = pixels >> 8;
3151
            pixel_2 = pixels >> 0;
3152
            dptr[-1] = pixel_1;
3153
            dptr2[-1] = pixel_1;
3154
            dptr[-2] = pixel_1;
3155
            dptr2[-2] = pixel_1;
3156
            dptr[-3] = pixel_2;
3157
            dptr2[-3] = pixel_2;
3158
            dptr[-4] = pixel_2;
3159
            dptr2[-4] = pixel_2;
3160
            dptr -= 4;
3161
            dptr2 -= 4;
3162
        }
3163
        dptr -= dst_row_skip;
3164
        dptr2 -= dst_row_skip;
3165
        sptr -= src_row_skip;
3166
    }
3167
}