Subversion Repositories Games.Carmageddon

Rev

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

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