Subversion Repositories Games.Carmageddon

Rev

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

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