#include "graphics.h"
#include "brender/brender.h"
#include "car.h"
#include "constants.h"
#include "controls.h"
#include "depth.h"
#include "displays.h"
#include "errors.h"
#include "finteray.h"
#include "flicplay.h"
#include "globvars.h"
#include "globvrpb.h"
#include "grafdata.h"
#include "harness/hooks.h"
#include "harness/os.h"
#include "harness/trace.h"
#include "init.h"
#include "input.h"
#include "loading.h"
#include "netgame.h"
#include "network.h"
#include "oil.h"
#include "opponent.h"
#include "pd/sys.h"
#include "pedestrn.h"
#include "piping.h"
#include "powerup.h"
#include "pratcam.h"
#include "replay.h"
#include "sound.h"
#include "spark.h"
#include "trig.h"
#include "utility.h"
#include "world.h"
#include <limits.h>
#include <stdlib.h>
#include <math.h>
int gPalette_munged;
int gColourValues[1];
int gNext_transient;
int gCursor_x_offsets[8] = {
6,
8,
16,
36,
6,
8,
16,
36,
};
int gCursor_y_offsets[8] = {
26,
19,
12,
5,
26,
19,
12,
5,
};
int gCursor_gib_x_offsets[8] = {
82,
72,
66,
36,
82,
72,
66,
36,
};
int gCursor_gib_y_offsets[8] = {
74,
86,
93,
106,
74,
86,
93,
106,
};
int gCursor_giblet_sequence0[7] = {
6,
0,
1,
2,
3,
4,
5,
};
int gCursor_giblet_sequence1[5] = {
4,
6,
7,
8,
9,
};
int gCursor_giblet_sequence2[5] = {
4,
10,
11,
12,
13,
};
int gCursor_giblet_sequence3[5] = {
4,
14,
15,
16,
17,
};
int* gCursor_giblet_sequences[4] = {
gCursor_giblet_sequence0,
gCursor_giblet_sequence1,
gCursor_giblet_sequence2,
gCursor_giblet_sequence3,
};
char* gFont_names[21] = {
"TYPEABLE",
"ORANGHED",
"BLUEHEAD",
"GREENHED",
"MEDIUMHD",
"TIMER",
"NEWHITE",
"NEWRED",
"NEWBIGGR",
"GRNDK",
"GRNLIT",
"GRYDK",
"GRYLIT",
"BUTTIN",
"BUTTOUT",
"LITPLAQ",
"DRKPLAQ",
"BUTTIN1",
"BUTTOUT1",
"LITPLAQ1",
"DRKPLAQ1"
};
br_colour gRGB_colours[9] = {
0u,
16777215u,
16711680u,
65280u,
255u,
16776960u,
65535u,
16711935u,
13649666u
};
br_matrix34 gSheer_mat = {
{ { 1.0, 0.0, 0.0 },
{ 0.0, 1.0, 0.0 },
{ 0.0, 0.0, 1.0 },
{ 0.0, 0.0, 0.0 } }
};
br_matrix34 gIdentity34 = {
{ { 1.0, 0.0, 0.0 },
{ 0.0, 1.0, 0.0 },
{ 0.0, 0.0, 1.0 },
{ 0.0, 0.0, 0.0 } }
};
tShadow_level gShadow_level = eShadow_us_only;
br_scalar gShadow_hither_z_move;
br_scalar gShadow_hither_min_move;
/* clang-format off */
// arrows pointing to 180, 202, 224, 246 degrees (step = 90 / 4 = 22(.5) degrees)
int gArrows[2][4][60] =
{
{
// inner arrow (=fill)
{ 10, 0, 0, -1, 0, 1, 0, 0, -1, 0, -2, 0, 1, -1, 1, 1, 1, -2, 2, 2, 2, },
{ 11, 0, 0, -1, 0, 1, 0, 0, -1, 1, -1, 1, -2, -2, 1, -1, 1, 0, 1, 1, 1, 1, 2, },
{ 9, 0, 0, -2, 0, -1, 0, 1, 0, 0, -1, 1, -1, 2, -2, 0, 1, 0, 2, },
{ 11, 0, 0, -1, 0, 1, 0, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, -1, 1, 0, 1, -1, 2, },
},
{
// outer arrow (=border)
{ 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,
-1, 3, -2, 3, -3, 3, -3, 2, -3, 1, -2, 1, -2, 0, -2, -1, -1, -1, -1, -2, -1, -3, 0, -3, },
{ 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,
-3, 2, -3, 1, -3, 0, -2, 0, -2, -1, -1, -1, -1, -2, 0, -2, },
{ 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,
-1, 1, -2, 1, -3, 1, -3, 0, -3, -1, -2, -1, -1, -1, -1, -2, 0, -2, 1, -2, },
{ 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,
0, 3, -1, 3, -2, 3, -2, 2, -2, 1, -2, 0, -3, 0, -3, -1, },
},
};
/* clang-format on */
float gMap_render_x = 80.f;
float gMap_render_y = 6.f;
float gMap_render_width = 64.f;
float gMap_render_height = 40.f;
int gMouse_started;
int gFaded_palette;
int gAR_fudge_headups;
br_pixelmap* gCurrent_splash;
br_pixelmap* gCurrent_conversion_table;
int gMap_colours[4] = { 4, 0, 52, 132 };
br_vector3 gShadow_points[8];
tConcussion gConcussion;
tClip_details gShadow_clip_planes[8];
br_actor* gLollipops[100];
tWobble_spec gWobble_array[5];
tSaved_table gSaved_shade_tables[100];
tCursor_giblet gCursor_giblets[45];
tTransient_bm gTransient_bitmaps[50];
float gCosine_array[64];
br_pixelmap* gCursors[8];
br_pixelmap* gCursor_giblet_images[18];
br_pixelmap* gEval_1;
br_pixelmap* gEval_2;
br_vector3 gShadow_light_z;
br_vector3 gShadow_light_x;
int gShadow_dim_amount;
int gNumber_of_lollipops;
br_vector3 gShadow_light_ray;
int gFancy_shadow;
br_model* gShadow_model;
br_actor* gShadow_actor;
int gShadow_clip_plane_count;
br_pixelmap* gPalette_conversion_table;
br_material* gShadow_material;
int gSaved_table_count;
int gCurrent_cursor_index;
int gPalette_index;
int gCursor_transient_index;
char* gScratch_pixels;
br_pixelmap* gScratch_palette;
int gLast_palette_change;
br_pixelmap* gOrig_render_palette;
br_pixelmap* gCurrent_palette;
br_pixelmap* gRender_palette;
float gCamera_to_horiz_angle;
int gColours[9];
br_pixelmap* gFlic_palette;
tDR_font gFonts[21];
char* gCurrent_palette_pixels;
int gWidth;
int gMap_render_height_i;
int gScreen_wobble_x;
int gScreen_wobble_y;
br_scalar gCurrent_ambience;
int gY_offset;
int gMap_render_width_i;
int gMouse_in_use;
int gHeight;
int gMouse_last_y_coord;
int gMouse_last_x_coord;
br_scalar gAmbient_adjustment;
int gMap_render_x_i;
int gX_offset;
int gMap_render_y_i;
int gMirror_on__graphics; // suffix added to avoid duplicate symbol
br_scalar gYon_squared;
#define SHADOW_D_IGNORE_FLAG 10000.0
// IDA: void __cdecl TurnOnPaletteConversion()
void TurnOnPaletteConversion(void) {
LOG_TRACE("()");
gCurrent_conversion_table = gPalette_conversion_table;
}
// IDA: void __cdecl TurnOffPaletteConversion()
void TurnOffPaletteConversion(void) {
LOG_TRACE("()");
gCurrent_conversion_table = NULL;
}
// IDA: void __cdecl ResetLollipopQueue()
void ResetLollipopQueue(void) {
LOG_TRACE("()");
gNumber_of_lollipops = 0;
}
// IDA: int __usercall AddToLollipopQueue@<EAX>(br_actor *pActor@<EAX>, int pIndex@<EDX>)
int AddToLollipopQueue(br_actor* pActor, int pIndex) {
LOG_TRACE("(%p, %d)", pActor, pIndex);
if (pIndex >= 0) {
gLollipops[pIndex] = pActor;
} else if (gNumber_of_lollipops >= 100) {
pIndex = -1;
} else {
gLollipops[gNumber_of_lollipops] = pActor;
pIndex = gNumber_of_lollipops;
gNumber_of_lollipops++;
}
return pIndex;
}
// IDA: void __cdecl RenderLollipops()
void RenderLollipops(void) {
int i;
int must_relink;
br_actor** the_actor;
br_actor* old_parent;
LOG_TRACE("()");
for (i = 0, the_actor = gLollipops; i < gNumber_of_lollipops; i++, the_actor++) {
if ((*the_actor)->render_style == BR_RSTYLE_NONE) {
must_relink = (*the_actor)->parent != gDont_render_actor;
if (must_relink) {
old_parent = (*the_actor)->parent;
BrActorRelink(gDont_render_actor, *the_actor);
}
(*the_actor)->render_style = BR_RSTYLE_FACES;
SetPedMaterialForRender(*the_actor);
BrZbSceneRenderAdd(*the_actor);
(*the_actor)->render_style = BR_RSTYLE_NONE;
if (must_relink) {
BrActorRelink(old_parent, *the_actor);
}
}
}
}
// IDA: void __usercall DRDrawLine(br_pixelmap *pDestn@<EAX>, int pX1@<EDX>, int pY1@<EBX>, int pX2@<ECX>, int pY2, int pColour)
void DRDrawLine(br_pixelmap* pDestn, int pX1, int pY1, int pX2, int pY2, int pColour) {
//tU8* d_ptr; // Pierre-Marie Baty -- unused variable
//tS32 y_delta; // Pierre-Marie Baty -- unused variable
//tS32 x_delta; // Pierre-Marie Baty -- unused variable
//tU32 current_y; // Pierre-Marie Baty -- unused variable
//tU32 current_x; // Pierre-Marie Baty -- unused variable
//int row_bytes; // Pierre-Marie Baty -- unused variable
//int x; // Pierre-Marie Baty -- unused variable
//int y; // Pierre-Marie Baty -- unused variable
//int the_diff; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pDestn, pX1, pY1, pX2, pY2, pColour);
BrPixelmapLine(pDestn, pX1, pY1, pX2, pY2, pColour);
}
// IDA: void __usercall DrawDigitAt(br_pixelmap *gImage@<EAX>, int pX@<EDX>, int pY@<EBX>, int pY_pitch@<ECX>, int pValue)
void DrawDigitAt(br_pixelmap* gImage, int pX, int pY, int pY_pitch, int pValue) {
LOG_TRACE("(%p, %d, %d, %d, %d)", gImage, pX, pY, pY_pitch, pValue);
DRPixelmapRectangleMaskedCopy(gBack_screen, pX, pY, gImage, 0, pY_pitch * pValue, gImage->width, pY_pitch);
}
// 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)
void DrawNumberAt(br_pixelmap* gImage, int pX, int pY, int pX_pitch, int pY_pitch, int pValue, int pDigit_count, int pLeading_zeroes) {
int i;
int the_value;
LOG_TRACE("(%p, %d, %d, %d, %d, %d, %d, %d)", gImage, pX, pY, pX_pitch, pY_pitch, pValue, pDigit_count, pLeading_zeroes);
for (i = pDigit_count - 1; i >= 0; i--) {
the_value = pValue % 10;
pValue /= 10;
if (pValue || pLeading_zeroes || pDigit_count - 1 == i) {
DrawDigitAt(gImage, pX + pX_pitch * i, pY, pY_pitch, the_value);
}
}
}
// IDA: void __usercall BuildColourTable(br_pixelmap *pPalette@<EAX>)
void BuildColourTable(br_pixelmap* pPalette) {
int i;
int j;
int nearest_index = 0;
int red;
int green;
int blue;
float nearest_distance;
float distance;
LOG_TRACE("(%p)", pPalette);
#define SQR(i) i* i
for (i = 0; i < COUNT_OF(gRGB_colours); i++) {
nearest_distance = 196608.f;
red = (gRGB_colours[i] >> 16) & 0xFF;
green = (gRGB_colours[i] >> 8) & 0xFF;
blue = gRGB_colours[i] & 0xFF;
for (j = 0; j < 256; j++) {
distance = SQR((double)(signed int)(*((br_uint_8*)pPalette->pixels + 4 * j + 2) - red));
distance += SQR((double)(signed int)(*((br_uint_8*)pPalette->pixels + 4 * j) - blue));
distance += SQR((double)(signed int)(*((br_uint_8*)pPalette->pixels + 4 * j + 1) - green));
if (distance < nearest_distance) {
nearest_index = j;
nearest_distance = distance;
}
}
gColours[i] = nearest_index;
}
}
// IDA: void __cdecl ClearConcussion()
void ClearConcussion(void) {
LOG_TRACE("()");
gConcussion.concussed = 0;
}
// IDA: tS8* __usercall SkipLines@<EAX>(tS8 *pSource@<EAX>, int pCount@<EDX>)
tS8* SkipLines(tS8* pSource, int pCount) {
int i;
int j;
int number_of_chunks;
int chunk_length;
LOG_TRACE("(%p, %d)", pSource, pCount);
for (i = 0; i < pCount; ++i) {
number_of_chunks = *pSource++;
for (j = 0; j < number_of_chunks; j++) {
chunk_length = *pSource++;
if (chunk_length < 0) {
pSource -= chunk_length;
}
}
}
return pSource;
}
// IDA: void __usercall CopyWords(char *pDst@<EAX>, char *pSrc@<EDX>, int pN@<EBX>)
void CopyWords(char* pDst, char* pSrc, int pN) {
//tU16* dst; // Pierre-Marie Baty -- unused variable
//tU16* src; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(\"%s\", \"%s\", %d)", pDst, pSrc, pN);
NOT_IMPLEMENTED();
}
// 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)
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) {
//int i; // Pierre-Marie Baty -- unused variable
//int j; // Pierre-Marie Baty -- unused variable
//int height; // Pierre-Marie Baty -- unused variable
//int number_of_chunks; // Pierre-Marie Baty -- unused variable
//int old_x_byte; // Pierre-Marie Baty -- unused variable
//int x_byte; // Pierre-Marie Baty -- unused variable
//int off_the_left; // Pierre-Marie Baty -- unused variable
//int destn_width; // Pierre-Marie Baty -- unused variable
//int chunk_length; // Pierre-Marie Baty -- unused variable
//char* destn_ptr; // Pierre-Marie Baty -- unused variable
//char* destn_ptr2; // Pierre-Marie Baty -- unused variable
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);
NOT_IMPLEMENTED();
}
// 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)
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) {
int i;
int j;
int height;
int number_of_chunks;
int old_x_byte;
int x_byte;
int off_the_left;
//int destn_width; // Pierre-Marie Baty -- unused variable
int chunk_length;
char* destn_ptr;
char* destn_ptr2;
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);
height = *(uint16_t*)pSource;
pSource = pSource + 2;
if (pDest_y + pOffset_y >= 0) {
destn_ptr = (char*)pDest->pixels + pDest->row_bytes * (pDest_y + pOffset_y);
} else {
pSource = SkipLines(pSource, -pDest_y - pOffset_y);
destn_ptr = (char*)pDest->pixels;
height += pDest_y + pOffset_y;
pOffset_y = 0;
pDest_y = 0;
}
if (height + pDest_y + pOffset_y > pDest->height) {
height = pDest->height - pDest_y - pOffset_y;
}
off_the_left = pDest_x + pOffset_x;
if (off_the_left > 0) {
destn_ptr += off_the_left;
}
for (i = 0; i < height; i++) {
destn_ptr2 = destn_ptr;
number_of_chunks = *pSource;
pSource++;
x_byte = off_the_left;
for (j = 0; j < number_of_chunks; j++) {
chunk_length = *pSource;
pSource++;
if (chunk_length >= 0) {
old_x_byte = x_byte;
x_byte += chunk_length;
if (old_x_byte >= 0) {
destn_ptr2 += chunk_length;
} else if (x_byte > 0) {
destn_ptr2 += chunk_length + old_x_byte;
}
} else {
old_x_byte = x_byte;
x_byte += -chunk_length;
if (old_x_byte >= 0) {
if (pDest->width >= x_byte) {
memcpy(destn_ptr2
, pSource
, -chunk_length
);
destn_ptr2 += -chunk_length;
} else if (old_x_byte < pDest->width) {
memcpy(destn_ptr2
, pSource
, pDest
->width
- old_x_byte
);
}
} else if (x_byte > 0) {
memcpy(destn_ptr2
, &pSource
[-old_x_byte
], -chunk_length
+ old_x_byte
);
destn_ptr2 += -chunk_length + old_x_byte;
}
pSource += -chunk_length;
}
}
destn_ptr += pDest->row_bytes;
}
}
// IDA: void __usercall SetBRenderScreenAndBuffers(int pX_offset@<EAX>, int pY_offset@<EDX>, int pWidth@<EBX>, int pHeight@<ECX>)
void SetBRenderScreenAndBuffers(int pX_offset, int pY_offset, int pWidth, int pHeight) {
LOG_TRACE("(%d, %d, %d, %d)", pX_offset, pY_offset, pWidth, pHeight);
PDAllocateScreenAndBack();
if (!pWidth) {
pWidth = gBack_screen->width;
}
if (!pHeight) {
pHeight = gBack_screen->height;
}
gRender_screen = DRPixelmapAllocateSub(gBack_screen, pX_offset, pY_offset, pWidth, pHeight);
gWidth = pWidth;
gHeight = pHeight;
gY_offset = pY_offset;
gX_offset = pX_offset;
if (gGraf_specs[gGraf_spec_index].doubled) {
gScreen->base_x = (gGraf_specs[gGraf_spec_index].phys_width - 2 * gGraf_specs[gGraf_spec_index].total_width) / 2;
gScreen->base_y = (gGraf_specs[gGraf_spec_index].phys_height - 2 * gGraf_specs[gGraf_spec_index].total_height) / 2;
} else {
gScreen->base_x = (gGraf_specs[gGraf_spec_index].phys_width - gGraf_specs[gGraf_spec_index].total_width) / 2;
gScreen->base_y = (gGraf_specs[gGraf_spec_index].phys_height - gGraf_specs[gGraf_spec_index].total_height) / 2;
}
gScreen->origin_x = 0;
gScreen->origin_y = 0;
if (gBack_screen == NULL) {
FatalError(kFatalError_AllocateOffScreenBuffer);
}
gDepth_buffer = BrPixelmapMatch(gBack_screen, BR_PMMATCH_DEPTH_16);
if (gDepth_buffer == NULL) {
FatalError(kFatalError_AllocateZBuffer);
}
BrZbBegin(gRender_screen->type, gDepth_buffer->type);
gBrZb_initialized = 1;
}
// IDA: void __cdecl SetIntegerMapRenders()
void SetIntegerMapRenders(void) {
LOG_TRACE("()");
gMap_render_x_i = ((int)gMap_render_x) & ~3;
gMap_render_y_i = ((int)gMap_render_y) & ~1;
gMap_render_width_i = ((int)gMap_render_width) & ~3;
gMap_render_height_i = ((int)gMap_render_height) & ~1;
if (gReal_graf_data_index != 0) {
gMap_render_x_i = 2 * gMap_render_x_i;
gMap_render_y_i = 2 * gMap_render_y_i + 40;
gMap_render_width_i = 2 * gMap_render_width_i;
gMap_render_height_i = 2 * gMap_render_height_i;
}
}
// IDA: void __cdecl AdjustRenderScreenSize()
void AdjustRenderScreenSize(void) {
int switched_res;
LOG_TRACE("()");
switched_res = SwitchToRealResolution();
ReinitialiseRenderStuff();
if (gMap_mode) {
gRender_screen->base_x = gMap_render_x_i;
gRender_screen->base_y = gMap_render_y_i;
gRender_screen->width = gMap_render_width_i;
gRender_screen->height = gMap_render_height_i;
} else {
gRender_screen->base_x = gProgram_state.current_render_left;
gRender_screen->base_y = gProgram_state.current_render_top;
gRender_screen->height = gProgram_state.current_render_bottom - gProgram_state.current_render_top;
gRender_screen->width = gProgram_state.current_render_right - gProgram_state.current_render_left;
}
if (gRender_screen->row_bytes == gRender_screen->width) {
gRender_screen->flags |= BR_PMF_ROW_WHOLEPIXELS;
} else {
gRender_screen->flags &= ~BR_PMF_ROW_WHOLEPIXELS;
}
gRender_screen->origin_x = gRender_screen->width / 2;
gRender_screen->origin_y = gRender_screen->height / 2;
gWidth = gRender_screen->width;
gHeight = gRender_screen->height;
ReinitialiseForwardCamera();
if (switched_res) {
SwitchToLoresMode();
}
}
// IDA: void __cdecl ScreenSmaller()
void ScreenSmaller(void) {
LOG_TRACE("()");
if (!gMap_mode) {
if (gProgram_state.cockpit_on) {
ToggleCockpit();
}
gRender_indent++;
if (gRender_indent > 8) {
gRender_indent = 8;
}
AdjustRenderScreenSize();
}
}
// IDA: void __cdecl ScreenLarger()
void ScreenLarger(void) {
LOG_TRACE("()");
if (!gMap_mode) {
if (gProgram_state.cockpit_on) {
ToggleCockpit();
}
gRender_indent--;
if (gRender_indent < 0) {
gRender_indent = 0;
}
AdjustRenderScreenSize();
}
}
// IDA: void __usercall DRSetPaletteEntries(br_pixelmap *pPalette@<EAX>, int pFirst_colour@<EDX>, int pCount@<EBX>)
void DRSetPaletteEntries(br_pixelmap* pPalette, int pFirst_colour, int pCount) {
LOG_TRACE("(%p, %d, %d)", pPalette, pFirst_colour, pCount);
if (pFirst_colour == 0) {
((br_int_32*)pPalette->pixels)[0] = 0;
}
memcpy(gCurrent_palette_pixels
+ 4 * pFirst_colour
, (char*)pPalette
->pixels
+ 4 * pFirst_colour
, 4 * pCount
);
if (!gFaded_palette) {
PDSetPaletteEntries(pPalette, pFirst_colour, pCount);
}
gPalette_munged = 1;
}
// IDA: void __usercall DRSetPalette3(br_pixelmap *pThe_palette@<EAX>, int pSet_current_palette@<EDX>)
void DRSetPalette3(br_pixelmap* pThe_palette, int pSet_current_palette) {
LOG_TRACE("(%p, %d)", pThe_palette, pSet_current_palette);
if (pSet_current_palette) {
memcpy(gCurrent_palette_pixels
, pThe_palette
->pixels
, 0x400u
);
}
if (!gFaded_palette) {
PDSetPalette(pThe_palette);
}
if (pThe_palette != gRender_palette) {
gPalette_munged |= 1u;
}
}
// IDA: void __usercall DRSetPalette2(br_pixelmap *pThe_palette@<EAX>, int pSet_current_palette@<EDX>)
void DRSetPalette2(br_pixelmap* pThe_palette, int pSet_current_palette) {
((br_int_32*)pThe_palette->pixels)[0] = 0;
if (pSet_current_palette) {
memcpy(gCurrent_palette_pixels
, pThe_palette
->pixels
, 0x400u
);
}
if (!gFaded_palette) {
PDSetPalette(pThe_palette);
}
if (pThe_palette != gRender_palette) {
gPalette_munged |= 1u;
}
}
// IDA: void __usercall DRSetPalette(br_pixelmap *pThe_palette@<EAX>)
void DRSetPalette(br_pixelmap* pThe_palette) {
DRSetPalette2(pThe_palette, 1);
}
// IDA: void __cdecl InitializePalettes()
void InitializePalettes(void) {
//int j; // Pierre-Marie Baty -- unused variable
gCurrent_palette_pixels = BrMemAllocate(0x400u, kMem_cur_pal_pixels);
gCurrent_palette = DRPixelmapAllocate(BR_PMT_RGBX_888, 1u, 256, gCurrent_palette_pixels, 0);
gRender_palette = BrTableFind("DRRENDER.PAL");
if (gRender_palette == NULL) {
FatalError(kFatalError_RequiredPalette);
}
gOrig_render_palette = BrPixelmapAllocateSub(gRender_palette, 0, 0, gRender_palette->width, gRender_palette->height);
gOrig_render_palette->pixels = BrMemAllocate(0x400u, kMem_render_pal_pixels);
memcpy(gOrig_render_palette
->pixels
, gRender_palette
->pixels
, 0x400u
);
gFlic_palette = BrTableFind("DRACEFLC.PAL");
if (gFlic_palette == NULL) {
FatalError(kFatalError_RequiredPalette);
}
DRSetPalette(gFlic_palette);
gScratch_pixels = BrMemAllocate(0x400u, kMem_scratch_pal_pixels);
gScratch_palette = DRPixelmapAllocate(BR_PMT_RGBX_888, 1u, 256, gScratch_pixels, 0);
gPalette_conversion_table = BrTableFind("FLC2REND.TAB");
gRender_shade_table = BrTableFind("DRRENDER.TAB");
gEval_1 = LoadPixelmap("Evalu01.PIX");
}
// IDA: void __usercall SwitchToPalette(char *pPal_name@<EAX>)
void SwitchToPalette(char* pPal_name) {
//br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(\"%s\")", pPal_name);
NOT_IMPLEMENTED();
}
// IDA: void __cdecl ClearEntireScreen()
void ClearEntireScreen(void) {
LOG_TRACE("()");
if (gScreen) {
BrPixelmapFill(gScreen, gGraf_specs[gGraf_spec_index].black_value);
}
BrPixelmapFill(gBack_screen, gGraf_specs[gGraf_spec_index].black_value);
PDScreenBufferSwap(0);
}
// IDA: void __cdecl ClearWobbles()
void ClearWobbles(void) {
int i;
LOG_TRACE("()");
for (i = 0; i < COUNT_OF(gWobble_array); i++) {
gWobble_array[i].time_started = 0;
}
}
// IDA: void __cdecl InitWobbleStuff()
void InitWobbleStuff(void) {
int i;
ClearWobbles();
for (i = 0; i < COUNT_OF(gCosine_array); i++) {
gCosine_array[i] = cosf(i / 64.0f * DR_PI / 2.0f);
}
}
// IDA: void __cdecl NewScreenWobble(double pAmplitude_x, double pAmplitude_y, double pPeriod)
void NewScreenWobble(double pAmplitude_x, double pAmplitude_y, double pPeriod) {
int i;
int oldest_time;
int oldest_index;
LOG_TRACE("(%d, %d, %d)", pAmplitude_x, pAmplitude_y, pPeriod);
oldest_index = -1;
oldest_time = INT_MAX;
for (i = 0; i < COUNT_OF(gWobble_array); i++) {
if (gWobble_array[i].time_started == 0) {
oldest_index = i;
break;
}
if (gWobble_array[i].time_started < oldest_time) {
oldest_time = gWobble_array[i].time_started;
oldest_index = i;
}
}
gWobble_array[oldest_index].time_started = GetTotalTime();
gWobble_array[oldest_index].amplitude_x = pAmplitude_x;
gWobble_array[oldest_index].amplitude_y = pAmplitude_y;
gWobble_array[oldest_index].period = pPeriod;
}
// IDA: void __usercall SetScreenWobble(int pWobble_x@<EAX>, int pWobble_y@<EDX>)
void SetScreenWobble(int pWobble_x, int pWobble_y) {
LOG_TRACE("(%d, %d)", pWobble_x, pWobble_y);
gScreen_wobble_y = pWobble_y;
gScreen_wobble_x = pWobble_x;
}
// IDA: void __cdecl ResetScreenWobble()
void ResetScreenWobble(void) {
LOG_TRACE("()");
SetScreenWobble(0, 0);
}
// IDA: void __usercall CalculateWobblitude(tU32 pThe_time@<EAX>)
void CalculateWobblitude(tU32 pThe_time) {
int i;
tU32 time_going;
double angle;
double mod_angle;
double cosine_over_angle;
LOG_TRACE("(%d)", pThe_time);
if (gProgram_state.new_view != eView_undefined) {
return;
}
gScreen_wobble_x = 0;
gScreen_wobble_y = 0;
for (i = 0; i < COUNT_OF(gWobble_array); i++) {
if (gWobble_array[i].time_started != 0) {
time_going = pThe_time - gWobble_array[i].time_started;
if (time_going > 1000) {
gWobble_array[i].time_started = 0;
} else {
mod_angle = fmod(time_going / gWobble_array[i].period, TAU);
if (mod_angle > DR_3PI_OVER_2) {
cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.0)];
} else if (mod_angle > DR_PI) {
cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.0)];
} else if (mod_angle > DR_PI_OVER_2) {
cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.0)];
} else {
cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.0)];
}
angle = cosine_over_angle / ((double)(pThe_time - gWobble_array[i].time_started) * 0.0035f + 1.0f);
gScreen_wobble_x = (gWobble_array[i].amplitude_x * angle + gScreen_wobble_x);
gScreen_wobble_y = (gWobble_array[i].amplitude_y * angle + gScreen_wobble_y);
}
}
}
if (gScreen_wobble_x > gCurrent_graf_data->cock_margin_x) {
gScreen_wobble_x = gCurrent_graf_data->cock_margin_x;
} else if (gScreen_wobble_x < -gCurrent_graf_data->cock_margin_x) {
gScreen_wobble_x = -gCurrent_graf_data->cock_margin_x;
}
if (gScreen_wobble_y > gCurrent_graf_data->cock_margin_y) {
gScreen_wobble_y = gCurrent_graf_data->cock_margin_y;
} else if (gScreen_wobble_y < -gCurrent_graf_data->cock_margin_y) {
gScreen_wobble_y = -gCurrent_graf_data->cock_margin_y;
}
PipeSingleScreenShake(gScreen_wobble_x, gScreen_wobble_y);
}
// IDA: void __usercall CalculateConcussion(tU32 pThe_time@<EAX>)
void CalculateConcussion(tU32 pThe_time) {
tU32 time_difference;
int i;
int j;
float the_amplitude;
float angle;
float mod_angle;
float cosine_over_angle;
LOG_TRACE("(%d)", pThe_time);
if (!gConcussion.concussed) {
return;
}
time_difference = pThe_time - gConcussion.time_started;
if (pThe_time - gConcussion.time_started > 2000) {
gConcussion.concussed = 0;
} else {
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
the_amplitude = gConcussion.amplitudes.m[i][j];
if (the_amplitude != 0.0) {
mod_angle = fmodf(time_difference / gConcussion.periods.m[i][j], (float) TAU); // Pierre-Marie Baty -- added type cast
if (mod_angle > DR_3PI_OVER_2) {
cosine_over_angle = gCosine_array[(unsigned int)((TAU - mod_angle) / DR_PI * 128.f)];
} else if (mod_angle > DR_PI) {
cosine_over_angle = -gCosine_array[(unsigned int)((mod_angle - DR_PI) / DR_PI * 128.f)];
} else if (mod_angle > DR_PI_OVER_2) {
cosine_over_angle = -gCosine_array[(unsigned int)((DR_PI - mod_angle) / DR_PI * 128.f)];
} else {
cosine_over_angle = gCosine_array[(unsigned int)(mod_angle / DR_PI * 128.f)];
}
angle = cosine_over_angle / ((double)time_difference * 0.02f + 1.0f);
gCamera->t.t.mat.m[i][j] = angle * the_amplitude + gCamera->t.t.mat.m[i][j];
gRearview_camera->t.t.mat.m[i][j] = angle * the_amplitude + gRearview_camera->t.t.mat.m[i][j];
}
}
}
}
}
// IDA: void __cdecl SufferFromConcussion(float pSeriousness)
void SufferFromConcussion(float pSeriousness) {
int i;
int j;
LOG_TRACE("(%f)", pSeriousness);
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
gConcussion.amplitudes.m[i][j] = FRandomPosNeg(pSeriousness);
gConcussion.periods.m[i][j] = FRandomBetween(20.f, 100.f);
}
}
gConcussion.concussed = 1;
gConcussion.time_started = GetTotalTime();
}
// 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)
void ProcessNonTrackActors(br_pixelmap* pRender_buffer, br_pixelmap* pDepth_buffer, br_actor* pCamera, br_matrix34* pCamera_to_world, br_matrix34* pOld_camera_matrix) {
LOG_TRACE("(%p, %p, %p, %p, %p)", pRender_buffer, pDepth_buffer, pCamera, pCamera_to_world, pOld_camera_matrix);
BrZbSceneRenderAdd(gNon_track_actor);
}
// IDA: int __usercall OppositeColour@<EAX>(int pColour@<EAX>)
int OppositeColour(int pColour) {
int brightness;
LOG_TRACE("(%d)", pColour);
if (pColour < 224) {
if ((pColour & 0x7) < 4) {
brightness = 255;
} else {
brightness = 0;
}
} else {
if ((pColour & 0xf) < 8) {
brightness = 255;
} else {
brightness = 0;
}
}
return brightness;
}
// IDA: void __usercall DrawMapBlip(tCar_spec *pCar@<EAX>, tU32 pTime@<EDX>, br_matrix34 *pTrans@<EBX>, br_vector3 *pPos@<ECX>, int pColour)
void DrawMapBlip(tCar_spec* pCar, tU32 pTime, br_matrix34* pTrans, br_vector3* pPos, int pColour) {
br_vector3 map_pos;
int offset;
int* arrow_ptr;
int point_count;
int colours[2];
int x;
int y;
int colour;
int i;
int j;
int temp;
int from_x;
int from_y;
int to_x;
int to_y;
int arrow_index;
tU32 time_diff;
tU32 period;
br_matrix34 car_in_map_space;
float bearing;
//float cos_factor; // Pierre-Marie Baty -- unused variable
//float sin_factor; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %d, %p, %p, %d)", pCar, pTime, pTrans, pPos, pColour);
time_diff = pTime - gMap_mode;
BrMatrix34ApplyP(&map_pos, pPos, &gCurrent_race.map_transformation);
switch (gReal_graf_data_index) {
case 0:
break;
case 1:
map_pos.v[0] = map_pos.v[0] * 2.f;
map_pos.v[1] = map_pos.v[1] * 2.f + 40.f;
break;
default:
TELL_ME_IF_WE_PASS_THIS_WAY();
}
period = 256; // Must be power of 2
colours[0] = pColour;
colours[1] = OppositeColour(pColour);
BrMatrix34Mul(&car_in_map_space, pTrans, &gCurrent_race.map_transformation);
bearing = FastScalarArcTan2(car_in_map_space.m[2][0], car_in_map_space.m[2][1]);
// Calculate in which of the 16 directions, the arrow is pointing to
bearing = (360.f - bearing + 12.25) / 22.5f;
arrow_index = ((int)bearing) % 16;
// The player's blip blinks, others are shown permanently
if (pCar->driver != eDriver_local_human || (period & pTime) != 0) {
for (i = 0; i < COUNT_OF(colours); i++) {
colour = colours[i];
point_count = gArrows[i][arrow_index & 0x3][0];
arrow_ptr = &gArrows[i][arrow_index & 0x3][1];
for (j = 0; j < point_count; j++, arrow_ptr += 2) {
if (arrow_index & 0x8) {
x = -arrow_ptr[0];
y = -arrow_ptr[1];
} else {
x = arrow_ptr[0];
y = arrow_ptr[1];
}
if (arrow_index & 0x4) {
temp = x;
x = -y;
y = temp;
}
BrPixelmapPixelSet(gBack_screen, map_pos.v[0] + x, map_pos.v[1] + y, colour);
}
}
}
// Draw a rectangle around the fox
colour = colours[!!(pTime & period)];
if (gNet_mode != eNet_mode_none && gCurrent_net_game->type == eNet_game_type_foxy && gNet_players[gIt_or_fox].car == pCar) {
from_x = map_pos.v[0] - 8.f;
from_y = map_pos.v[1] - 8.f;
to_x = map_pos.v[0] + 8.f;
to_y = map_pos.v[1] + 8.f;
BrPixelmapLine(gBack_screen, from_x, from_y, to_x, from_y, colour);
BrPixelmapLine(gBack_screen, from_x, to_y, to_x, to_y, colour);
BrPixelmapLine(gBack_screen, from_x, from_y, from_x, to_y, colour);
BrPixelmapLine(gBack_screen, to_x, from_y, to_x, to_y, colour);
}
// To attract the player's attention, draw a rectangle around the player's position that decreases in size,
if (time_diff <= 500 && pCar->driver == eDriver_local_human) {
offset = ((500 - time_diff) * 70) / 500;
from_x = map_pos.v[0] - offset - .5f;
from_y = map_pos.v[1] - offset - .5f;
to_x = map_pos.v[0] + offset + .5f;
to_y = map_pos.v[1] + offset + .5f;
BrPixelmapLine(gBack_screen, from_x, from_y, to_x, from_y, colour);
BrPixelmapLine(gBack_screen, from_x, to_y, to_x, to_y, colour);
BrPixelmapLine(gBack_screen, from_x, from_y, from_x, to_y, colour);
BrPixelmapLine(gBack_screen, to_x, from_y, to_x, to_y, colour);
}
}
// IDA: void __usercall DrawMapSmallBlip(tU32 pTime@<EAX>, br_vector3 *pPos@<EDX>, int pColour@<EBX>)
void DrawMapSmallBlip(tU32 pTime, br_vector3* pPos, int pColour) {
br_vector3 map_pos;
int offset;
//tU32 time_diff; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d, %p, %d)", pTime, pPos, pColour);
if ((pTime & 0x100) == 0) {
BrMatrix34ApplyP(&map_pos, pPos, &gCurrent_race.map_transformation);
if (gReal_graf_data_index != 0) {
map_pos.v[0] = 2.f * map_pos.v[0];
map_pos.v[1] = 2.f * map_pos.v[1] + 40.f;
}
offset = (int)map_pos.v[0] + gBack_screen->row_bytes * (int)map_pos.v[1];
((br_uint_8*)gBack_screen->pixels)[offset] = pColour;
}
}
// IDA: void __usercall MungeClipPlane(br_vector3 *pLight@<EAX>, tCar_spec *pCar@<EDX>, br_vector3 *p1@<EBX>, br_vector3 *p2@<ECX>, br_scalar pY_offset)
void MungeClipPlane(br_vector3* pLight, tCar_spec* pCar, br_vector3* p1, br_vector3* p2, br_scalar pY_offset) {
br_vector3 v1;
br_vector3 v2;
br_vector3 v3;
br_vector3 v4;
br_scalar length;
br_actor* new_clip;
LOG_TRACE("(%p, %p, %p, %p, %f)", pLight, pCar, p1, p2, pY_offset);
BrMatrix34ApplyP(&v1, p1, &pCar->car_master_actor->t.t.mat);
BrMatrix34ApplyP(&v2, p2, &pCar->car_master_actor->t.t.mat);
BrVector3Sub(&v3, p2, p1);
BrVector3Cross(&v4, &v3, pLight);
if (fabsf(v4.v[0]) >= 0.01f || fabsf(v4.v[1]) >= 0.01f || fabsf(v4.v[2]) >= 0.01f) {
BrVector3Copy(&v3, p1);
v3.v[1] -= pY_offset;
if (BrVector3Dot(&v3, &v4) > 0.f) {
BrVector3Negate(&v4, &v4);
}
BrVector3Normalise(&v3, &v4);
BrMatrix34ApplyV(&v4, &v3, &pCar->car_master_actor->t.t.mat);
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]);
new_clip = gShadow_clip_planes[gShadow_clip_plane_count].clip;
((br_vector4*)new_clip->type_data)->v[0] = v4.v[0];
((br_vector4*)new_clip->type_data)->v[1] = v4.v[1];
((br_vector4*)new_clip->type_data)->v[2] = v4.v[2];
((br_vector4*)new_clip->type_data)->v[3] = -BrVector3Dot(&v1, &v4);
gShadow_clip_planes[gShadow_clip_plane_count].length = length;
gShadow_clip_plane_count++;
}
}
// 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)
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) {
br_scalar dot_1;
br_scalar dot_2;
br_scalar mult;
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);
dot_1 = pSign_1 * pLight->v[pIndex_1];
dot_2 = pSign_2 * pLight->v[pIndex_2];
mult = dot_1 * dot_2;
if (mult < 0 || (mult == 0 && (dot_1 > 0 || dot_2 > 0))) {
if (gShadow_clip_plane_count < 6) {
MungeClipPlane(pLight, pCar, &gShadow_points[pPoint_index_1], &gShadow_points[pPoint_index_2], pY_offset);
}
}
}
// IDA: br_scalar __usercall DistanceFromPlane@<ST0>(br_vector3 *pPos@<EAX>, br_scalar pA, br_scalar pB, br_scalar pC, br_scalar pD)
br_scalar DistanceFromPlane(br_vector3* pPos, br_scalar pA, br_scalar pB, br_scalar pC, br_scalar pD) {
//br_vector3 normal; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %f, %f, %f, %f)", pPos, pA, pB, pC, pD);
return fabsf((pPos->v[1] * pB + pPos->v[0] * pA + pPos->v[2] * pC + pD) / (pA * pA + pC * pC + pB * pB));
}
// IDA: void __cdecl DisableLights()
void DisableLights(void) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
NOT_IMPLEMENTED();
}
// IDA: void __cdecl EnableLights()
void EnableLights(void) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
NOT_IMPLEMENTED();
}
// 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)
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) {
int i;
//int j; // Pierre-Marie Baty -- unused variable
int face_count;
//int force_shadow; // Pierre-Marie Baty -- unused variable
//int models_used; // Pierre-Marie Baty -- unused variable
//int point_to_use; // Pierre-Marie Baty -- unused variable
int oily_count;
int f_num;
//br_vector3 pos; // Pierre-Marie Baty -- unused variable
br_vector3 light_ray_car;
//br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
br_vector3 shadow_points_world[8];
br_vector3 poly_centre;
br_vector3 car_to_poly;
br_vector3 ray;
br_vector3 ray_pos;
br_vector3 normal;
//br_vector3 the_normal; // Pierre-Marie Baty -- unused variable
br_vector3 pos_cam_space;
//br_vector3* v0; // Pierre-Marie Baty -- unused variable
br_vector3* v1;
br_vector3* v2;
br_vector4* clip_normal;
br_scalar bounds_x_min;
br_scalar bounds_x_max;
br_scalar bounds_y_min;
br_scalar bounds_y_max;
br_scalar bounds_z_min;
br_scalar bounds_z_max;
//br_scalar height; // Pierre-Marie Baty -- unused variable
br_scalar oily_size;
br_scalar highest_underneath;
br_scalar shadow_scaling_factor;
br_scalar y_offset;
//br_scalar most_neg_dotty; // Pierre-Marie Baty -- unused variable
//br_scalar mr_dotty; // Pierre-Marie Baty -- unused variable
br_scalar first_poly_below;
br_scalar distance;
br_scalar camera_hither_fudge;
br_scalar camera_angle_additional_fudge;
br_scalar ray_length;
tBounds kev_bounds;
tFace_ref the_list[100];
tFace_ref* face_ref;
tFace_ref* list_ptr;
//br_renderbounds_cbfn* old_call_back; // Pierre-Marie Baty -- unused variable
br_camera* camera_ptr;
br_actor* oily_actor;
//br_model* model; // Pierre-Marie Baty -- unused variable
br_material* material;
br_vertex verts[48];
br_face faces[16];
LOG_TRACE("(%p, %p, %p, %p, %p, %f)", pCar, pWorld, pTrack_spec, pCamera, pCamera_to_world_transform, pDistance_factor);
#if defined(DETHRACE_FIX_BUGS)
ray_length = 0.f;
#endif
f_num = 0;
bounds_x_min = pCar->bounds[1].min.v[0] / WORLD_SCALE;
bounds_x_max = pCar->bounds[1].max.v[0] / WORLD_SCALE;
bounds_y_min = pCar->bounds[1].min.v[1] / WORLD_SCALE;
bounds_y_max = pCar->bounds[1].max.v[1] / WORLD_SCALE;
bounds_z_min = pCar->bounds[1].min.v[2] / WORLD_SCALE;
bounds_z_max = pCar->bounds[1].max.v[2] / WORLD_SCALE;
gShadow_points[0].v[0] = bounds_x_max;
gShadow_points[0].v[1] = bounds_y_max;
gShadow_points[0].v[2] = bounds_z_max;
gShadow_points[1].v[0] = bounds_x_max;
gShadow_points[1].v[1] = bounds_y_max;
gShadow_points[1].v[2] = bounds_z_min;
gShadow_points[2].v[0] = bounds_x_min;
gShadow_points[2].v[1] = bounds_y_max;
gShadow_points[2].v[2] = bounds_z_min;
gShadow_points[3].v[0] = bounds_x_min;
gShadow_points[3].v[1] = bounds_y_max;
gShadow_points[3].v[2] = bounds_z_max;
gShadow_points[4].v[0] = bounds_x_max;
gShadow_points[4].v[1] = bounds_y_min;
gShadow_points[4].v[2] = bounds_z_max;
gShadow_points[5].v[0] = bounds_x_max;
gShadow_points[5].v[1] = bounds_y_min;
gShadow_points[5].v[2] = bounds_z_min;
gShadow_points[6].v[0] = bounds_x_min;
gShadow_points[6].v[1] = bounds_y_min;
gShadow_points[6].v[2] = bounds_z_min;
gShadow_points[7].v[0] = bounds_x_min;
gShadow_points[7].v[1] = bounds_y_min;
gShadow_points[7].v[2] = bounds_z_max;
gShadow_clip_plane_count = 0;
BrMatrix34TApplyV(&light_ray_car, &gShadow_light_ray, &pCar->car_master_actor->t.t.mat);
y_offset = (bounds_y_max + bounds_y_min) / 2.0;
TryThisEdge(pCar, &light_ray_car, 2, 1.0, 1, 1.0, 0, 3, y_offset);
TryThisEdge(pCar, &light_ray_car, 2, -1.0, 1, 1.0, 1, 2, y_offset);
TryThisEdge(pCar, &light_ray_car, 2, -1.0, 1, -1.0, 6, 5, y_offset);
TryThisEdge(pCar, &light_ray_car, 2, 1.0, 1, -1.0, 7, 4, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, 1.0, 1, 1.0, 1, 0, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, -1.0, 1, 1.0, 2, 3, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, -1.0, 1, -1.0, 7, 6, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, 1.0, 1, -1.0, 4, 5, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, 1.0, 2, 1.0, 4, 0, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, -1.0, 2, 1.0, 3, 7, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, -1.0, 2, -1.0, 2, 6, y_offset);
TryThisEdge(pCar, &light_ray_car, 0, 1.0, 2, -1.0, 5, 1, y_offset);
for (i = 0; i < gShadow_clip_plane_count; ++i) {
BrClipPlaneEnable(gShadow_clip_planes[i].clip);
}
face_count = GetPrecalculatedFacesUnderCar(pCar, &face_ref);
if (!gAction_replay_mode && pCar->number_of_wheels_on_ground >= 3 && face_count != 0) {
highest_underneath = 0.0;
} else {
kev_bounds.original_bounds.min.v[0] = 1000.0;
kev_bounds.original_bounds.min.v[1] = 1000.0;
kev_bounds.original_bounds.min.v[2] = 1000.0;
kev_bounds.original_bounds.max.v[0] = -1000.0;
kev_bounds.original_bounds.max.v[1] = -1000.0;
kev_bounds.original_bounds.max.v[2] = -1000.0;
for (i = 0; i < COUNT_OF(shadow_points_world); i++) {
BrMatrix34ApplyP(&shadow_points_world[i], &gShadow_points[i], &pCar->car_master_actor->t.t.mat);
if (shadow_points_world[i].v[0] >= kev_bounds.original_bounds.min.v[0]) {
if (shadow_points_world[i].v[0] > kev_bounds.original_bounds.max.v[0]) {
kev_bounds.original_bounds.max.v[0] = shadow_points_world[i].v[0];
}
} else {
kev_bounds.original_bounds.min.v[0] = shadow_points_world[i].v[0];
}
if (shadow_points_world[i].v[1] >= kev_bounds.original_bounds.min.v[1]) {
if (shadow_points_world[i].v[1] > kev_bounds.original_bounds.max.v[1]) {
kev_bounds.original_bounds.max.v[1] = shadow_points_world[i].v[1];
}
} else {
kev_bounds.original_bounds.min.v[1] = shadow_points_world[i].v[1];
}
if (shadow_points_world[i].v[2] >= kev_bounds.original_bounds.min.v[2]) {
if (shadow_points_world[i].v[2] > kev_bounds.original_bounds.max.v[2]) {
kev_bounds.original_bounds.max.v[2] = shadow_points_world[i].v[2];
}
} else {
kev_bounds.original_bounds.min.v[2] = shadow_points_world[i].v[2];
}
}
kev_bounds.original_bounds.min.v[1] = kev_bounds.original_bounds.min.v[1] - 4.4000001;
kev_bounds.mat = &gIdentity34;
face_count = FindFacesInBox(&kev_bounds, the_list, 100);
face_ref = the_list;
highest_underneath = 1000.0;
ray_length = kev_bounds.original_bounds.max.v[1] - kev_bounds.original_bounds.min.v[1];
ray.v[0] = 0.0;
ray.v[1] = -ray_length;
ray.v[2] = 0.0;
ray_pos = pCar->car_master_actor->t.t.translate.t;
ray_pos.v[1] = kev_bounds.original_bounds.max.v[1];
}
if (face_count) {
first_poly_below = -1000.0;
i = 0;
list_ptr = face_ref;
for (i = 0; i < face_count; i++) {
v1 = &list_ptr->v[1];
v2 = &list_ptr->v[2];
if (list_ptr->normal.v[1] >= -0.1 || (list_ptr->material && (list_ptr->material->flags & 0x1000) != 0)) {
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))) {
list_ptr->d = SHADOW_D_IGNORE_FLAG;
} 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) {
list_ptr->d = SHADOW_D_IGNORE_FLAG;
}
} else {
poly_centre.v[0] = v1->v[0] + list_ptr->v[0].v[0];
poly_centre.v[1] = v1->v[1] + list_ptr->v[0].v[1];
poly_centre.v[2] = v1->v[2] + list_ptr->v[0].v[2];
poly_centre.v[0] = v2->v[0] + poly_centre.v[0];
poly_centre.v[1] = v2->v[1] + poly_centre.v[1];
poly_centre.v[2] = v2->v[2] + poly_centre.v[2];
poly_centre.v[0] = poly_centre.v[0] / 3.0;
poly_centre.v[1] = poly_centre.v[1] / 3.0;
poly_centre.v[2] = poly_centre.v[2] / 3.0;
poly_centre.v[1] = (v2->v[1] + v1->v[1] + list_ptr->v[0].v[1]) / 3.0;
if (poly_centre.v[1] > first_poly_below) {
car_to_poly.v[0] = poly_centre.v[0] - pCar->car_master_actor->t.t.mat.m[3][0];
car_to_poly.v[1] = poly_centre.v[1] - pCar->car_master_actor->t.t.mat.m[3][1];
car_to_poly.v[2] = poly_centre.v[2] - pCar->car_master_actor->t.t.mat.m[3][2];
if (BrVector3Dot(&list_ptr->normal, &car_to_poly) > 0.0) {
first_poly_below = poly_centre.v[1];
}
}
list_ptr->d = SHADOW_D_IGNORE_FLAG;
}
list_ptr++;
}
list_ptr = face_ref;
for (i = 0; i < face_count; i++) {
if (list_ptr->d != 10000.0) {
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) {
if (gFancy_shadow) {
faces[f_num].material = list_ptr->material;
if (list_ptr->material && list_ptr->material->colour_map && (list_ptr->material->flags & BR_MATF_LIGHT) == 0) {
list_ptr->material->flags |= BR_MATF_SMOOTH | BR_MATF_LIGHT;
BrMaterialUpdate(list_ptr->material, BR_MATU_RENDERING);
}
} else {
faces[f_num].material = gShadow_material;
}
verts[3 * f_num].p = list_ptr->v[0];
verts[3 * f_num].map = *list_ptr->map[0];
verts[3 * f_num + 1].p = list_ptr->v[1];
verts[3 * f_num + 1].map = *list_ptr->map[1];
verts[3 * f_num + 2].p = list_ptr->v[2];
verts[3 * f_num + 2].map = *list_ptr->map[2];
faces[f_num].vertices[0] = 3 * f_num;
faces[f_num].vertices[1] = 3 * f_num + 1;
faces[f_num].vertices[2] = 3 * f_num + 2;
f_num++;
if (highest_underneath > 0.0) {
CheckSingleFace(list_ptr, &ray_pos, &ray, &normal, &distance);
if (distance < 1.0 && ray_length * distance < highest_underneath) {
highest_underneath = ray_length * distance;
}
}
if (f_num >= LEN(faces)) {
break;
}
}
}
list_ptr++;
}
highest_underneath = highest_underneath - (bounds_y_max - bounds_y_min);
if (highest_underneath < 2.2) {
if (highest_underneath < 0.0) {
highest_underneath = 0.0;
}
} else {
highest_underneath = (br_scalar) 2.2; // Pierre-Marie Baty -- added type cast
}
if (gFancy_shadow) {
gShadow_dim_amount = ((2.2 - highest_underneath) * 5.0 / 2.2 + 2.5);
for (i = 0; i < gSaved_table_count; i++) {
gSaved_shade_tables[i].original->height = 1;
gSaved_shade_tables[i].original->pixels = (tU8*)gDepth_shade_table->pixels + gShadow_dim_amount * gDepth_shade_table->row_bytes;
BrTableUpdate(gSaved_shade_tables[i].original, BR_TABU_ALL);
}
}
shadow_scaling_factor = (2.2 - highest_underneath) * 0.52 / 2.2 + 0.4;
for (i = 0; i < gShadow_clip_plane_count; i++) {
clip_normal = (br_vector4*)gShadow_clip_planes[i].clip->type_data;
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]);
gShadow_clip_planes[i].clip->t.t.mat.m[3][0] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[0];
gShadow_clip_planes[i].clip->t.t.mat.m[3][1] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[1];
gShadow_clip_planes[i].clip->t.t.mat.m[3][2] = (1.0 - shadow_scaling_factor) * distance * clip_normal->v[2];
}
camera_ptr = (br_camera*)gCamera->type_data;
DRMatrix34TApplyP(&pos_cam_space, &pCar->car_master_actor->t.t.euler.t, &gCamera_to_world);
if (pos_cam_space.v[2] >= 36.0 || pos_cam_space.v[2] >= camera_ptr->yon_z) {
camera_hither_fudge = 0.0;
} else {
camera_angle_additional_fudge = sqr(camera_ptr->yon_z - camera_ptr->hither_z);
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);
if (camera_hither_fudge < 0.0002) {
camera_hither_fudge = (br_scalar) 0.0002; // Pierre-Marie Baty -- added type cast
}
camera_ptr->hither_z += camera_hither_fudge;
}
if (f_num) {
BrZbSceneRenderBegin(gUniverse_actor, gCamera, gRender_screen, gDepth_buffer);
gShadow_model->vertices = verts;
gShadow_model->faces = faces;
gShadow_model->nfaces = f_num;
gShadow_model->nvertices = 3 * f_num;
gShadow_actor->render_style = BR_RSTYLE_FACES;
BrModelAdd(gShadow_model);
BrZbSceneRenderAdd(gShadow_actor);
BrModelRemove(gShadow_model);
if (pCar->shadow_intersection_flags) {
oily_count = GetOilSpillCount();
for (i = 0; i < oily_count; ++i) {
if (((1 << i) & pCar->shadow_intersection_flags) != 0) {
GetOilSpillDetails(i, &oily_actor, &oily_size);
if (oily_actor) {
MungeIndexedOilsHeightAboveGround(i);
BrZbSceneRenderAdd(oily_actor);
}
}
}
}
BrZbSceneRenderEnd();
}
camera_ptr->hither_z -= camera_hither_fudge;
for (i = 0; i < f_num; i++) {
if (gFancy_shadow) {
material = gShadow_model->faces[i].material;
if (material) {
if (material->colour_map && (material->flags & BR_MATF_LIGHT) != 0) {
material->flags &= ~(BR_MATF_LIGHT | BR_MATF_PRELIT | BR_MATF_SMOOTH);
BrMaterialUpdate(material, BR_MATU_RENDERING);
}
}
}
}
}
gShadow_actor->render_style = BR_RSTYLE_NONE;
for (i = 0; i < gShadow_clip_plane_count; i++) {
BrClipPlaneDisable(gShadow_clip_planes[i].clip);
}
}
// IDA: void __usercall RenderShadows(br_actor *pWorld@<EAX>, tTrack_spec *pTrack_spec@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world_transform@<ECX>)
void RenderShadows(br_actor* pWorld, tTrack_spec* pTrack_spec, br_actor* pCamera, br_matrix34* pCamera_to_world_transform) {
int i;
int cat;
int car_count;
tCar_spec* the_car;
br_vector3 camera_to_car;
br_scalar distance_factor;
LOG_TRACE("(%p, %p, %p, %p)", pWorld, pTrack_spec, pCamera, pCamera_to_world_transform);
if (gShadow_level == eShadow_none) {
return;
}
for (cat = eVehicle_self;; ++cat) {
if (gShadow_level == eShadow_everyone) {
if (cat > 4) {
break;
}
} else {
if (cat > (gShadow_level == eShadow_us_and_opponents ? 3 : 0)) {
break;
}
}
if (cat == eVehicle_self) {
car_count = 1;
} else {
car_count = GetCarCount(cat);
}
for (i = 0; i < car_count; i++) {
if (cat == eVehicle_self) {
the_car = &gProgram_state.current_car;
} else {
the_car = GetCarSpec(cat, i);
}
if (!the_car->active) {
continue;
}
BrVector3Sub(&camera_to_car, (br_vector3*)gCamera_to_world.m[3], &the_car->car_master_actor->t.t.translate.t);
distance_factor = BrVector3LengthSquared(&camera_to_car);
if (gAction_replay_mode || distance_factor <= SHADOW_MAX_RENDER_DISTANCE) {
ProcessShadow(the_car, gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, distance_factor);
}
}
}
if (gFancy_shadow) {
for (i = 0; i < gSaved_table_count; i++) {
gSaved_shade_tables[i].original->height = gSaved_shade_tables[i].copy->height;
gSaved_shade_tables[i].original->pixels = gSaved_shade_tables[i].copy->pixels;
BrTableUpdate(gSaved_shade_tables[i].original, 0x7FFF);
}
}
}
// IDA: void __usercall FlashyMapCheckpoint(int pIndex@<EAX>, tU32 pTime@<EDX>)
void FlashyMapCheckpoint(int pIndex, tU32 pTime) {
//tCheckpoint* cp; // Pierre-Marie Baty -- unused variable
static tU32 last_flash;
static int flash_state;
LOG_TRACE("(%d, %d)", pIndex, pTime);
if (pIndex >= 0 && pIndex < gCurrent_race.check_point_count && gRace_file_version > 0) {
if (Flash(300, &last_flash, &flash_state)) {
switch (gGraf_data_index) {
case 0:
DimRectangle(gBack_screen,
gCurrent_race.checkpoints[pIndex].map_left[0],
gCurrent_race.checkpoints[pIndex].map_top[0],
gCurrent_race.checkpoints[pIndex].map_right[0],
gCurrent_race.checkpoints[pIndex].map_bottom[0],
0);
break;
case 1:
DimRectangle(gBack_screen,
2 * gCurrent_race.checkpoints[pIndex].map_left[0],
2 * gCurrent_race.checkpoints[pIndex].map_top[0] + 40,
2 * gCurrent_race.checkpoints[pIndex].map_right[0],
2 * gCurrent_race.checkpoints[pIndex].map_bottom[0] + 40,
0);
break;
default:
TELL_ME_IF_WE_PASS_THIS_WAY();
}
}
}
}
// IDA: int __usercall ConditionallyFillWithSky@<EAX>(br_pixelmap *pPixelmap@<EAX>)
int ConditionallyFillWithSky(br_pixelmap* pPixelmap) {
int bgnd_col;
LOG_TRACE("(%p)", pPixelmap);
if (gProgram_state.current_depth_effect.sky_texture != NULL && (gLast_camera_special_volume == NULL || gLast_camera_special_volume->sky_col < 0)) {
return 0;
}
if (gProgram_state.current_depth_effect.type == eDepth_effect_fog || gSwap_depth_effect_type == eDepth_effect_fog) {
bgnd_col = 255;
} else if (gProgram_state.current_depth_effect.type && gSwap_depth_effect_type) {
if (gLast_camera_special_volume && gLast_camera_special_volume->sky_col >= 0) {
bgnd_col = gLast_camera_special_volume->sky_col;
} else {
bgnd_col = 0;
}
} else {
bgnd_col = 0;
}
BrPixelmapFill(pPixelmap, bgnd_col);
return 1;
}
// IDA: void __usercall RenderAFrame(int pDepth_mask_on@<EAX>)
void RenderAFrame(int pDepth_mask_on) {
int cat;
int i;
int car_count;
int flags;
int x_shift;
int y_shift;
int cockpit_on;
int real_origin_x = 0;
int real_origin_y = 0;
int real_base_x = 0;
int real_base_y = 0;
int map_timer_x;
int map_timer_width;
int ped_type;
char* old_pixels;
br_matrix34 old_camera_matrix;
br_matrix34 old_mirror_cam_matrix;
tU32 the_time;
br_vector3* car_pos;
br_vector3 pos;
char the_text[256];
tCar_spec* car;
LOG_TRACE("(%d)", pDepth_mask_on);
gRender_screen->pixels = gBack_screen->pixels;
the_time = GetTotalTime();
old_pixels = gRender_screen->pixels;
cockpit_on = gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0 && !gMap_mode;
gMirror_on__graphics = gProgram_state.mirror_on && cockpit_on && gProgram_state.which_view == eView_forward;
if (gMap_mode) {
real_origin_x = gBack_screen->origin_x;
real_origin_y = gBack_screen->origin_y;
real_base_x = gBack_screen->base_x;
real_base_y = gBack_screen->base_y;
gBack_screen->origin_x = 0;
gBack_screen->origin_y = 0;
gBack_screen->base_x = 0;
gBack_screen->base_y = 0;
if (gCurrent_race.map_image != NULL) {
if (gReal_graf_data_index) {
BrPixelmapRectangleFill(gBack_screen, 0, 0, 640, 40, 0);
BrPixelmapRectangleFill(gBack_screen, 0, 440, 640, 40, 0);
DRPixelmapDoubledCopy(
gBack_screen,
gCurrent_race.map_image,
gCurrent_race.map_image->width,
gCurrent_race.map_image->height,
0,
40);
} else {
DRPixelmapCopy(gBack_screen, gCurrent_race.map_image);
}
}
DimRectangle(
gBack_screen,
gMap_render_x_i - gCurrent_graf_data->map_render_x_marg,
gMap_render_y_i - gCurrent_graf_data->map_render_y_marg,
gMap_render_x_i + gMap_render_width_i + gCurrent_graf_data->map_render_x_marg,
gMap_render_y_i + gMap_render_height_i + gCurrent_graf_data->map_render_y_marg,
1);
}
if (!gAction_replay_mode) {
CalculateWobblitude(the_time);
}
if (cockpit_on) {
if (-gScreen_wobble_x > gX_offset) {
x_shift = -gX_offset;
} else if (gScreen_wobble_x + gX_offset + gRender_screen->width > gBack_screen->width) {
x_shift = gBack_screen->width - gRender_screen->width - gX_offset;
} else {
x_shift = gScreen_wobble_x;
}
if (-gScreen_wobble_y > gY_offset) {
y_shift = -gY_offset;
} else if (gScreen_wobble_y + gY_offset + gRender_screen->height > gBack_screen->height) {
y_shift = gBack_screen->height - gRender_screen->height - gY_offset;
} else {
y_shift = gScreen_wobble_y;
}
} else {
x_shift = 0;
y_shift = 0;
}
BrMatrix34Copy(&old_camera_matrix, &gCamera->t.t.mat);
if (gMirror_on__graphics) {
BrMatrix34Copy(&old_mirror_cam_matrix, &gRearview_camera->t.t.mat);
}
if (cockpit_on) {
gSheer_mat.m[2][1] = y_shift / (float)gRender_screen->height;
gSheer_mat.m[2][0] = -x_shift / (float)gRender_screen->width;
BrMatrix34Pre(&gCamera->t.t.mat, &gSheer_mat);
gCamera->t.t.translate.t.v[0] -= gScreen_wobble_x * 1.5f / gRender_screen->width / WORLD_SCALE;
gCamera->t.t.translate.t.v[1] += gScreen_wobble_y * 1.5f / gRender_screen->width / WORLD_SCALE;
}
gRender_screen->pixels = (char*)gRender_screen->pixels + x_shift + y_shift * gRender_screen->row_bytes;
CalculateConcussion(the_time);
BrPixelmapRectangleFill(gDepth_buffer, 0, 0, gRender_screen->width, gRender_screen->height, 0xFFFFFFFF);
if (gRender_indent && !gMap_mode) {
BrPixelmapRectangleFill(
gBack_screen,
0,
0,
gGraf_specs[gGraf_spec_index].total_width,
gProgram_state.current_render_top,
0);
BrPixelmapRectangleFill(
gBack_screen,
0,
gProgram_state.current_render_bottom,
gGraf_specs[gGraf_spec_index].total_width,
gGraf_specs[gGraf_spec_index].total_height - gProgram_state.current_render_bottom,
0);
BrPixelmapRectangleFill(
gBack_screen,
0,
gProgram_state.current_render_top,
gProgram_state.current_render_left,
gProgram_state.current_render_bottom - gProgram_state.current_render_top,
0);
BrPixelmapRectangleFill(
gBack_screen,
gProgram_state.current_render_right,
gProgram_state.current_render_top,
gGraf_specs[gGraf_spec_index].total_width - gProgram_state.current_render_right,
gProgram_state.current_render_bottom - gProgram_state.current_render_top,
0);
}
gRendering_mirror = 0;
DoSpecialCameraEffect(gCamera, &gCamera_to_world);
if (!ConditionallyFillWithSky(gRender_screen)
&& !gProgram_state.cockpit_on
&& !(gAction_replay_camera_mode && gAction_replay_mode)) {
ExternalSky(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
}
#if !defined(DETHRACE_FIX_BUGS)
// in map mode, the scene is rendered 3 times. We have no idea why.
for (i = 0; i < (gMap_mode ? 3 : 1); i++)
#endif
{
RenderShadows(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world);
BrZbSceneRenderBegin(gUniverse_actor, gCamera, gRender_screen, gDepth_buffer);
ProcessNonTrackActors(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, &old_camera_matrix);
ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, 0);
RenderLollipops();
// dethrace: must flush gpu buffer before rendering depth effect into framebuffer
gHarness_platform.Renderer_FlushBuffers();
DepthEffectSky(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
DepthEffect(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world);
if (!gAusterity_mode) {
ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gCamera, &gCamera_to_world, 1);
}
RenderSplashes();
// dethrace: must flush gpu buffer before rendering smoke into framebuffer
gHarness_platform.Renderer_FlushBuffers();
RenderSmoke(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, gFrame_period);
RenderSparks(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, gFrame_period);
RenderProximityRays(gRender_screen, gDepth_buffer, gCamera, &gCamera_to_world, gFrame_period);
BrZbSceneRenderEnd();
}
BrMatrix34Copy(&gCamera->t.t.mat, &old_camera_matrix);
if (gMirror_on__graphics) {
LOG_WARN_ONCE("rearview mirror not implemented");
// BrPixelmapFill(gRearview_depth_buffer, 0xFFFFFFFF);
// gRendering_mirror = 1;
// DoSpecialCameraEffect(gRearview_camera, &gRearview_camera_to_world);
// ConditionallyFillWithSky(gRearview_screen);
// BrZbSceneRenderBegin(gUniverse_actor, gRearview_camera, gRearview_screen, gRearview_depth_buffer);
// ProcessNonTrackActors(
// gRearview_screen,
// gRearview_depth_buffer,
// gRearview_camera,
// &gRearview_camera_to_world,
// &old_mirror_cam_matrix);
// ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 0);
// RenderLollipops();
// DepthEffectSky(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
// DepthEffect(gRearview_screen, gRearview_depth_buffer, gRearview_camera, &gRearview_camera_to_world);
// if (!gAusterity_mode) {
// ProcessTrack(gUniverse_actor, &gProgram_state.track_spec, gRearview_camera, &gRearview_camera_to_world, 1);
// }
// RenderSplashes();
// BrZbSceneRenderEnd();
// BrMatrix34Copy(&gRearview_camera->t.t.mat, &old_mirror_cam_matrix);
// gRendering_mirror = 0;
}
if (gMap_mode) {
if (gNet_mode == eNet_mode_none) {
GetTimerString(the_text, 0);
map_timer_width = DRTextWidth(&gFonts[2], the_text);
map_timer_x = gCurrent_graf_data->map_timer_text_x - map_timer_width;
BrPixelmapRectangleFill(
gBack_screen,
map_timer_x - gCurrent_graf_data->map_timer_border_x,
gCurrent_graf_data->map_timer_text_y - gCurrent_graf_data->map_timer_border_y,
map_timer_width + 2 * gCurrent_graf_data->map_timer_border_x,
gFonts[kFont_BLUEHEAD].height + 2 * gCurrent_graf_data->map_timer_border_y,
0);
TransDRPixelmapText(
gBack_screen,
map_timer_x,
gCurrent_graf_data->map_timer_text_y,
&gFonts[kFont_BLUEHEAD],
the_text,
gBack_screen->width);
}
the_time = PDGetTotalTime();
if (gNet_mode != eNet_mode_none) {
if (gCurrent_net_game->type == eNet_game_type_checkpoint) {
flags = gNet_players[gThis_net_player_index].score;
for (i = 0; gCurrent_race.check_point_count > i; ++i) {
if ((flags & 1) != 0) {
FlashyMapCheckpoint(i, the_time);
}
flags >>= 1;
}
} else if (gCurrent_net_game->type == eNet_game_type_sudden_death
&& gNet_players[gThis_net_player_index].score >= 0) {
FlashyMapCheckpoint(
gNet_players[gThis_net_player_index].score % gCurrent_race.check_point_count,
the_time);
}
} else {
FlashyMapCheckpoint(gCheckpoint - 1, the_time);
}
if (gShow_peds_on_map || (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
for (i = 0; i < GetPedCount(); i++) {
ped_type = GetPedPosition(i, &pos);
if (ped_type > 0 && gShow_peds_on_map) {
DrawMapSmallBlip(the_time, &pos, 52);
} else if (ped_type < 0 && (gNet_mode != eNet_mode_none && gCurrent_net_game->options.show_powerups_on_map)) {
DrawMapSmallBlip(the_time, &pos, 4);
}
}
}
if (gShow_opponents) {
cat = eVehicle_opponent;
} else {
cat = eVehicle_self;
}
while (cat >= eVehicle_self) {
if (cat) {
car_count = GetCarCount(cat);
} else {
car_count = 1;
}
for (i = 0; i < car_count; i++) {
if (cat) {
car = GetCarSpec(cat, i);
} else {
car = &gProgram_state.current_car;
}
if (gNet_mode == eNet_mode_none || (!car->knackered && !NetPlayerFromCar(car)->wasted)) {
if (cat) {
car_pos = &GetCarSpec(cat, i)->car_master_actor->t.t.euler.t;
} else {
car_pos = &gSelf->t.t.euler.t;
}
if (gNet_mode) {
DrawMapBlip(
car,
the_time,
&car->car_master_actor->t.t.mat,
car_pos,
car->shrapnel_material[0]->index_range + car->shrapnel_material[0]->index_base - 1);
} else if (car->knackered) {
DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, 0);
} else {
DrawMapBlip(car, the_time, &car->car_master_actor->t.t.mat, car_pos, gMap_colours[cat]);
}
}
}
cat--;
}
gBack_screen->origin_x = real_origin_x;
gBack_screen->origin_y = real_origin_y;
gBack_screen->base_x = real_base_x;
gBack_screen->base_y = real_base_y;
} else {
if (cockpit_on) {
CopyStripImage(
gBack_screen,
-gCurrent_graf_data->cock_margin_x,
gScreen_wobble_x,
-gCurrent_graf_data->cock_margin_y,
gScreen_wobble_y,
gProgram_state.current_car.cockpit_images[gProgram_state.cockpit_image_index],
0,
0,
gCurrent_graf_data->total_cock_width,
gCurrent_graf_data->total_cock_height);
if (gMirror_on__graphics) {
BrPixelmapRectangleCopy(
gBack_screen,
gScreen_wobble_x + gProgram_state.current_car.mirror_left,
gScreen_wobble_y + gProgram_state.current_car.mirror_top,
gRearview_screen,
-gRearview_screen->origin_x,
-gRearview_screen->origin_y,
gProgram_state.current_car.mirror_right - gProgram_state.current_car.mirror_left,
gProgram_state.current_car.mirror_bottom - gProgram_state.current_car.mirror_top);
}
}
DimAFewBits();
DoDamageScreen(the_time);
if (!gAction_replay_mode || gAR_fudge_headups) {
DoPratcam(the_time);
DoHeadups(the_time);
}
DoInstruments(the_time);
DoSteeringWheel(the_time);
if (!gAction_replay_mode || gAR_fudge_headups) {
DrawPowerups(the_time);
}
}
if (gNet_mode != eNet_mode_none) {
DisplayUserMessage();
}
if (gAction_replay_mode && !gAR_fudge_headups) {
DoActionReplayHeadups();
}
if (gAction_replay_mode) {
SynchronizeActionReplay();
} else {
PipeFrameFinish();
}
gRender_screen->pixels = old_pixels;
if (!gPalette_fade_time || GetRaceTime() > gPalette_fade_time + 500) {
PDScreenBufferSwap(0);
}
if (gAction_replay_mode) {
DoActionReplayPostSwap();
}
}
// IDA: void __cdecl InitPaletteAnimate()
void InitPaletteAnimate(void) {
LOG_TRACE("()");
gLast_palette_change = 0;
gPalette_index = 0;
}
// IDA: void __cdecl RevertPalette()
void RevertPalette(void) {
memcpy(gRender_palette
->pixels
, gOrig_render_palette
->pixels
, 0x400u
);
DRSetPalette3(gRender_palette, 1);
}
// IDA: void __cdecl MungePalette()
void MungePalette(void) {
//tU8* p; // Pierre-Marie Baty -- unused variable
//tU8* q; // Pierre-Marie Baty -- unused variable
//int i; // Pierre-Marie Baty -- unused variable
//float damage; // Pierre-Marie Baty -- unused variable
//float throb_start; // Pierre-Marie Baty -- unused variable
//float throb_end; // Pierre-Marie Baty -- unused variable
//float throb_amount; // Pierre-Marie Baty -- unused variable
//float throb_amount_dash; // Pierre-Marie Baty -- unused variable
//float omega; // Pierre-Marie Baty -- unused variable
//tU32 period; // Pierre-Marie Baty -- unused variable
//tU32 the_time; // Pierre-Marie Baty -- unused variable
//static int palette_spammed; // Pierre-Marie Baty -- unused variable
//static float last_omega; // Pierre-Marie Baty -- unused variable
//static tU32 next_repair_time; // Pierre-Marie Baty -- unused variable
//static tU32 last_sound; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
NOT_IMPLEMENTED();
}
// IDA: void __cdecl ResetPalette()
void ResetPalette(void) {
LOG_TRACE("()");
InitPaletteAnimate();
DRSetPalette(gRender_palette);
}
// IDA: void __usercall Darken(tU8 *pPtr@<EAX>, unsigned int pDarken_amount@<EDX>)
void Darken(tU8* pPtr, unsigned int pDarken_amount) {
//unsigned int value; // Pierre-Marie Baty -- unused variable
LOG_TRACE10("(%p, %d)", pPtr, pDarken_amount);
*pPtr = (pDarken_amount * *pPtr) / 256;
}
// IDA: void __usercall SetFadedPalette(int pDegree@<EAX>)
void SetFadedPalette(int pDegree) {
int j;
//br_pixelmap* the_palette; // Pierre-Marie Baty -- unused variable
//char* the_pixels; // Pierre-Marie Baty -- unused variable
LOG_TRACE10("(%d)", pDegree);
memcpy(gScratch_pixels
, gCurrent_palette
->pixels
, 0x400u
);
for (j = 0; j < 256; j++) {
Darken((tU8*)&gScratch_pixels[4 * j], pDegree);
Darken((tU8*)&gScratch_pixels[4 * j + 1], pDegree);
Darken((tU8*)&gScratch_pixels[4 * j + 2], pDegree);
Darken((tU8*)&gScratch_pixels[4 * j + 3], pDegree);
}
DRSetPalette2(gScratch_palette, 0);
}
// IDA: void __cdecl FadePaletteDown()
void FadePaletteDown(void) {
int i;
int start_time;
int the_time;
LOG_TRACE("()");
if (!gFaded_palette) {
gFaded_palette = 1;
MungeEngineNoise();
gFaded_palette = 0;
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime() - start_time;
if (the_time >= 500) {
break;
}
i = 256 - ((the_time * 256) / 500);
SetFadedPalette(i);
}
SetFadedPalette(0);
gFaded_palette = 1;
}
}
// IDA: void __cdecl FadePaletteUp()
void FadePaletteUp(void) {
int i;
int start_time;
int the_time;
LOG_TRACE("()");
if (gFaded_palette) {
gFaded_palette = 0;
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime() - start_time;
if (the_time >= 500) {
break;
}
i = (the_time * 256) / 500;
SetFadedPalette(i);
}
DRSetPalette(gCurrent_palette);
}
}
// IDA: void __cdecl KillSplashScreen()
void KillSplashScreen(void) {
if (gCurrent_splash != NULL) {
BrMapRemove(gCurrent_splash);
BrPixelmapFree(gCurrent_splash);
gCurrent_splash = NULL;
FadePaletteDown();
ClearEntireScreen();
}
}
// IDA: void __cdecl EnsureRenderPalette()
void EnsureRenderPalette(void) {
LOG_TRACE("()");
if (gPalette_munged) {
ResetPalette();
gPalette_munged = 0;
}
}
// IDA: void __usercall SplashScreenWith(char *pPixmap_name@<EAX>)
void SplashScreenWith(char* pPixmap_name) {
br_pixelmap* the_map;
LOG_TRACE("(\"%s\")", pPixmap_name);
the_map = BrMapFind(pPixmap_name);
if (gCurrent_splash == NULL || the_map != gCurrent_splash) {
FadePaletteDown();
EnsureRenderPalette();
if (gCurrent_splash != NULL) {
KillSplashScreen();
}
gCurrent_splash = the_map;
if (the_map == NULL) {
the_map = LoadPixelmap(pPixmap_name);
gCurrent_splash = the_map;
if (the_map != NULL) {
BrMapAdd(the_map);
}
}
if (gCurrent_splash != NULL) {
BrPixelmapRectangleCopy(
gBack_screen,
0,
0,
gCurrent_splash,
0,
0,
gCurrent_splash->width,
gCurrent_splash->height);
PDScreenBufferSwap(0);
if (gFaded_palette) {
FadePaletteUp();
}
}
}
}
// IDA: void __cdecl EnsurePaletteUp()
void EnsurePaletteUp(void) {
if (gFaded_palette) {
FadePaletteUp();
}
}
// IDA: br_uint_32 __cdecl AmbientificateMaterial(br_material *pMat, void *pArg)
br_uint_32 AmbientificateMaterial(br_material* pMat, void* pArg) {
float a;
a = pMat->ka + *(br_scalar*)pArg;
if (a < 0.f) {
a = 0.f;
} else if (a > 0.99f) {
a = 0.99f;
}
pMat->ka = a;
return 0;
}
// IDA: void __cdecl ChangeAmbience(br_scalar pDelta)
void ChangeAmbience(br_scalar pDelta) {
LOG_TRACE("(%f)", pDelta);
BrMaterialEnum("*", AmbientificateMaterial, &pDelta);
}
// IDA: void __cdecl InitAmbience()
void InitAmbience(void) {
LOG_TRACE("()");
gCurrent_ambience = gAmbient_adjustment;
ChangeAmbience(gAmbient_adjustment);
}
// 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)
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) {
int y_count;
int x_count;
int dest_row_wrap;
int source_row_wrap;
//int x_delta; // Pierre-Marie Baty -- unused variable
tU8 the_byte;
tU8* source_ptr;
tU8* dest_ptr;
tU8* conv_table;
LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
source_row_wrap = pSource->row_bytes - pWidth;
dest_row_wrap = pDest->row_bytes - pWidth;
if (pDest_y < 0) {
pHeight += pDest_y;
if (pHeight <= 0) {
return;
}
source_ptr -= pDest_y * pSource->row_bytes;
dest_ptr -= pDest_y * pDest->row_bytes;
pDest_y = 0;
}
if (pDest_y >= pDest->height) {
return;
}
if (pDest_y + pHeight > pDest->height) {
pHeight = pDest->height - pDest_y;
}
if (pDest_x < 0) {
pWidth += pDest_x;
if (pWidth <= 0) {
return;
}
source_ptr -= pDest_x;
dest_ptr -= pDest_x;
source_row_wrap -= pDest_x;
dest_row_wrap -= pDest_x;
pDest_x = 0;
}
if (pDest_x >= pDest->width) {
return;
}
if (pDest_x + pWidth > pDest->width) {
source_row_wrap += pDest_x + pWidth - pDest->width;
dest_row_wrap += pDest_x + pWidth - pDest->width;
pWidth = pDest->width - pDest_x;
}
// 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);
if (gCurrent_conversion_table != NULL) {
conv_table = gCurrent_conversion_table->pixels;
for (y_count = 0; y_count < pHeight; y_count++) {
for (x_count = 0; x_count < pWidth; x_count++) {
the_byte = *source_ptr;
if (the_byte != 0) {
*dest_ptr = conv_table[the_byte];
}
source_ptr++;
dest_ptr++;
}
source_ptr += source_row_wrap;
dest_ptr += dest_row_wrap;
}
} else {
for (y_count = 0; y_count < pHeight; y_count++) {
for (x_count = 0; x_count < pWidth; x_count++) {
the_byte = *source_ptr;
if (the_byte != 0) {
*dest_ptr = the_byte;
}
source_ptr++;
dest_ptr++;
}
source_ptr += source_row_wrap;
dest_ptr += dest_row_wrap;
}
}
}
// IDA: void __usercall DRMaskedStamp(br_int_16 pDest_x@<EAX>, br_int_16 pDest_y@<EDX>, br_pixelmap *pSource@<EBX>)
void DRMaskedStamp(br_int_16 pDest_x, br_int_16 pDest_y, br_pixelmap* pSource) {
LOG_TRACE("(%d, %d, %p)", pDest_x, pDest_y, pSource);
DRPixelmapRectangleMaskedCopy(gBack_screen,
pDest_x,
pDest_y,
pSource,
0,
0,
pSource->width,
pSource->height);
}
// 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)
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) {
int y_count;
int x_count;
int dest_row_wrap;
int source_row_wrap;
//int x_delta; // Pierre-Marie Baty -- unused variable
tU8 the_byte;
tU8* source_ptr;
tU8* dest_ptr;
//tU8* conv_table; // Pierre-Marie Baty -- unused variable
// LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
source_row_wrap = pSource->row_bytes - pWidth;
dest_row_wrap = pDest->row_bytes - pWidth;
dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
for (y_count = 0; y_count < pHeight; y_count++) {
for (x_count = 0; x_count < pWidth; x_count++) {
the_byte = *source_ptr;
if (the_byte) {
*dest_ptr = the_byte;
}
source_ptr++;
dest_ptr++;
}
source_ptr += source_row_wrap;
dest_ptr += dest_row_wrap;
}
}
// 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)
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) {
int y_count;
int x_count;
int dest_row_wrap;
int source_row_wrap;
//int x_delta; // Pierre-Marie Baty -- unused variable
int last_shear_x;
int current_shear_x;
int shear_x_difference;
int pWidth_orig;
tU8 the_byte;
tU8* source_ptr;
tU8* dest_ptr;
//tU8* conv_table; // Pierre-Marie Baty -- unused variable
tX1616 current_shear;
LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight, pShear);
current_shear = 0;
last_shear_x = 0;
source_ptr = (tU8*)pSource->pixels + pSource_x + pSource_y * pSource->row_bytes;
dest_ptr = (tU8*)pDest->pixels + pDest_x + pDest_y * pDest->row_bytes;
source_row_wrap = pSource->row_bytes - pWidth;
dest_row_wrap = pDest->row_bytes - pWidth;
if (pDest_y < 0) {
pHeight += pDest_y;
if (pHeight <= 0) {
return;
}
source_ptr -= pDest_y * pSource->row_bytes;
dest_ptr -= pDest_y * pDest->row_bytes;
pDest_y = 0;
}
if (pDest->height > pDest_y) {
if (pDest_y + pHeight > pDest->height) {
pHeight = pDest->height - pDest_y;
}
if (pDest_x < 0) {
pWidth += pDest_x;
if (pWidth <= 0) {
return;
}
source_ptr -= pDest_x;
dest_ptr -= pDest_x;
source_row_wrap -= pDest_x;
dest_row_wrap -= pDest_x;
pDest_x = 0;
}
if (pDest->width > pDest_x) {
pWidth_orig = pWidth;
for (y_count = 0; pHeight > y_count; ++y_count) {
#if !defined(DETHRACE_FIX_BUGS)
/*
* The OG compares against pWidth instead of pWidth_orig, which
* ends up clipped to the dest pixelmap width. This effectively
* clips the consecutive rows of pixels along the shear, leaving
* a visible gap on the screen. Instead, when comparing against
* pWidth_orig, the clip takes place vertically along the dest
* pixelmap edge, allowing all pixels to be displayed.
*
* Simulate OG behavior by overwriting pWidth_orig with pWidth.
*/
pWidth_orig = pWidth;
#endif
if (pDest_x + pWidth_orig > pDest->width) {
shear_x_difference = pDest_x + pWidth - pDest->width;
pWidth = pDest->width - pDest_x;
source_row_wrap += shear_x_difference;
dest_row_wrap += shear_x_difference;
}
for (x_count = 0; pWidth > x_count; ++x_count) {
the_byte = *source_ptr++;
if (the_byte) {
*dest_ptr = the_byte;
}
++dest_ptr;
}
current_shear_x = (current_shear >> 16) - last_shear_x;
dest_ptr += dest_row_wrap + current_shear_x;
last_shear_x = current_shear >> 16;
source_ptr += source_row_wrap;
current_shear += pShear;
pDest_x += current_shear_x;
if (pDest_x < 0) {
pWidth += pDest_x;
source_ptr -= pDest_x;
dest_ptr -= pDest_x;
source_row_wrap -= pDest_x;
dest_row_wrap -= pDest_x;
pDest_x = 0;
}
if (pDest->width <= pDest_x) {
break;
}
}
}
}
}
// 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)
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) {
int y_count;
int x_count;
int dest_row_wrap;
int source_row_wrap;
//int x_delta; // Pierre-Marie Baty -- unused variable
tU8 the_byte;
tU8* source_ptr;
tU8* dest_ptr;
tU32 source_y;
tU32 source_y_delta;
tU32 old_source_y;
LOG_TRACE("(%p, %d, %d, %p, %d, %d, %d, %d)", pDest, pDest_x, pDest_y, pSource, pSource_x, pSource_y, pWidth, pHeight);
if (!pHeight) {
return;
}
source_row_wrap = pSource->row_bytes - pWidth;
dest_row_wrap = pDest->row_bytes - pWidth;
dest_ptr = (tU8*)pDest->pixels + (pDest->row_bytes * pDest_y + pDest_x);
source_ptr = (tU8*)pSource->pixels + (pSource->row_bytes * pSource_y + pSource_x);
source_y = 0;
source_y_delta = (pSource->height << 16) / pHeight - 0x10000;
for (y_count = 0; y_count < pHeight; y_count++) {
for (x_count = 0; x_count < pWidth; x_count++) {
the_byte = *source_ptr;
if (the_byte) {
*dest_ptr = the_byte;
}
source_ptr++;
dest_ptr++;
}
old_source_y = source_y;
source_y += source_y_delta;
source_ptr += (((source_y >> 16) - (old_source_y >> 16)) * pSource->row_bytes) + source_row_wrap;
dest_ptr += dest_row_wrap;
}
}
// IDA: void __cdecl InitTransientBitmaps()
void InitTransientBitmaps(void) {
int i;
LOG_TRACE("()");
for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
gTransient_bitmaps[i].pixmap = NULL;
gTransient_bitmaps[i].in_use = 0;
}
}
// IDA: int __usercall AllocateTransientBitmap@<EAX>(int pWidth@<EAX>, int pHeight@<EDX>, int pUser_data@<EBX>)
int AllocateTransientBitmap(int pWidth, int pHeight, int pUser_data) {
int bm_index;
LOG_TRACE("(%d, %d, %d)", pWidth, pHeight, pUser_data);
for (bm_index = 0; bm_index < COUNT_OF(gTransient_bitmaps); bm_index++) {
if (gTransient_bitmaps[bm_index].pixmap == NULL) {
gTransient_bitmaps[bm_index].pixmap = DRPixelmapAllocate(BR_PMT_INDEX_8, pWidth + 8, pHeight, NULL, 0);
gTransient_bitmaps[bm_index].in_use = 0;
gTransient_bitmaps[bm_index].user_data = pUser_data;
return bm_index;
}
}
FatalError(kFatalError_FindSpareTransientBitmap);
}
// IDA: void __usercall DeallocateTransientBitmap(int pIndex@<EAX>)
void DeallocateTransientBitmap(int pIndex) {
LOG_TRACE("(%d)", pIndex);
if (gTransient_bitmaps[pIndex].pixmap != NULL) {
BrPixelmapFree(gTransient_bitmaps[pIndex].pixmap);
gTransient_bitmaps[pIndex].pixmap = NULL;
gTransient_bitmaps[pIndex].in_use = 0;
}
}
// IDA: void __cdecl DeallocateAllTransientBitmaps()
void DeallocateAllTransientBitmaps(void) {
int i;
LOG_TRACE("()");
for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
DeallocateTransientBitmap(i);
}
}
// IDA: void __usercall RemoveTransientBitmaps(int pGraphically_remove_them@<EAX>)
void RemoveTransientBitmaps(int pGraphically_remove_them) {
int i;
int order_number;
if (pGraphically_remove_them) {
for (order_number = gNext_transient - 1; order_number >= 0; order_number--) {
for (i = 0; i < COUNT_OF(gTransient_bitmaps); i++) {
if (gTransient_bitmaps[i].pixmap != NULL && gTransient_bitmaps[i].order_number == order_number) {
if (gTransient_bitmaps[i].in_use) {
BrPixelmapRectangleCopy(gBack_screen,
gTransient_bitmaps[i].x_coord,
gTransient_bitmaps[i].y_coord,
gTransient_bitmaps[i].pixmap,
0,
0,
gTransient_bitmaps[i].pixmap->width,
gTransient_bitmaps[i].pixmap->height);
}
break;
}
}
}
}
gNext_transient = 0;
}
// IDA: void __usercall SaveTransient(int pIndex@<EAX>, int pX_coord@<EDX>, int pY_coord@<EBX>)
void SaveTransient(int pIndex, int pX_coord, int pY_coord) {
LOG_TRACE("(%d, %d, %d)", pIndex, pX_coord, pY_coord);
gTransient_bitmaps[pIndex].x_coord = pX_coord & ~3;
gTransient_bitmaps[pIndex].y_coord = pY_coord;
gTransient_bitmaps[pIndex].in_use = 1;
gTransient_bitmaps[pIndex].order_number = gNext_transient;
gNext_transient++;
BrPixelmapRectangleCopy(gTransient_bitmaps[pIndex].pixmap,
0,
0,
gBack_screen,
gTransient_bitmaps[pIndex].x_coord,
gTransient_bitmaps[pIndex].y_coord,
gTransient_bitmaps[pIndex].pixmap->width,
gTransient_bitmaps[pIndex].pixmap->height);
}
// IDA: void __usercall DrawCursorGiblet(tCursor_giblet *pGib@<EAX>)
void DrawCursorGiblet(tCursor_giblet* pGib) {
br_pixelmap* the_image;
LOG_TRACE("(%p)", pGib);
SaveTransient(pGib->transient_index, pGib->x_coord, pGib->y_coord);
the_image = gCursor_giblet_images[gCursor_giblet_sequences[pGib->sequence_index][pGib->current_giblet]];
DRPixelmapRectangleMaskedCopy(gBack_screen,
pGib->x_coord,
pGib->y_coord,
the_image,
0,
0,
the_image->width,
the_image->height);
}
// IDA: void __usercall ProcessCursorGiblets(int pPeriod@<EAX>)
void ProcessCursorGiblets(int pPeriod) {
int i;
int kill_the_giblet;
tU32 time_now;
tCursor_giblet* gib;
LOG_TRACE("(%d)", pPeriod);
time_now = PDGetTotalTime();
for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
gib = &gCursor_giblets[i];
kill_the_giblet = 0;
if (gib->current_giblet == -1) {
continue;
}
if (!gib->landed && gib->e_t_a <= time_now) {
gib->landed = 1;
gib->the_speed = 0.f;
}
if (gib->landed) {
gib->giblet_change_period -= pPeriod / 2;
if (gib->giblet_change_period < 50) {
gib->giblet_change_period = 50;
}
if (gib->giblet_change_period <= time_now - gib->last_giblet_change) {
if (gCursor_giblet_sequences[gib->sequence_index][0] == gib->current_giblet) {
gib->current_giblet = 1;
} else {
gib->current_giblet++;
}
gib->last_giblet_change = time_now;
}
gib->y_coord += pPeriod * gib->the_speed / 1000.f;
if (gib->y_coord <= gGraf_data[gGraf_data_index].height) {
if (gib->the_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
gib->the_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f;
}
} else {
kill_the_giblet = 1;
}
} else {
if (gib->y_speed < gGraf_specs[gGraf_spec_index].total_height * 160 / 480) {
gib->y_speed += pPeriod * gGraf_specs[gGraf_spec_index].total_height * 60 / 480 / 1000.f * 2.f;
}
gib->x_coord += pPeriod * gib->x_speed / 1000.f;
gib->y_coord += pPeriod * gib->y_speed / 1000.f;
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) {
kill_the_giblet = 1;
}
}
if (kill_the_giblet) {
gib->current_giblet = -1;
DeallocateTransientBitmap(gib->transient_index);
} else {
DrawCursorGiblet(gib);
}
}
}
// IDA: int __usercall NewCursorGiblet@<EAX>(int pX_coord@<EAX>, int pY_coord@<EDX>, float pX_speed, float pY_speed, tU32 pDrop_time)
int NewCursorGiblet(int pX_coord, int pY_coord, float pX_speed, float pY_speed, tU32 pDrop_time) {
int i;
int the_width;
int the_height;
int sequence_number;
LOG_TRACE("(%d, %d, %f, %f, %d)", pX_coord, pY_coord, pX_speed, pY_speed, pDrop_time);
sequence_number = IRandomBetween(0, COUNT_OF(gCursor_giblet_sequences) - 1);
if (pX_coord >= 0 && pX_coord < gGraf_data[gGraf_data_index].width && pY_coord >= 0 && pY_coord < gGraf_data[gGraf_data_index].height) {
for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
if (gCursor_giblets[i].current_giblet == -1) {
the_width = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->width;
the_height = gCursor_giblet_images[gCursor_giblet_sequences[sequence_number][1]]->height;
gCursor_giblets[i].transient_index = AllocateTransientBitmap(the_width, the_height, 1);
gCursor_giblets[i].current_giblet = 1;
gCursor_giblets[i].sequence_index = sequence_number;
gCursor_giblets[i].landed = 0;
gCursor_giblets[i].x_coord = sequence_number * gGraf_specs[gGraf_spec_index].total_width / 640 - the_width / 2 + pX_coord;
gCursor_giblets[i].y_coord = FRandomPosNeg(6.f) * gGraf_specs[gGraf_spec_index].total_height / 480 - the_height / 2 + pY_coord;
gCursor_giblets[i].x_speed = pX_speed;
gCursor_giblets[i].y_speed = pY_speed;
gCursor_giblets[i].last_giblet_change = 0;
gCursor_giblets[i].giblet_change_period = 1000;
gCursor_giblets[i].e_t_a = PDGetTotalTime() + pDrop_time;
return i;
}
}
}
return -1;
}
// IDA: int __cdecl DoMouseCursor()
int DoMouseCursor(void) {
int x_coord; // Added by DethRace
int y_coord;
int mouse_moved;
int new_required;
//int giblet_index; // Pierre-Marie Baty -- unused variable
int cursor_offset;
int button_is_down;
int giblet_chance;
int giblet_count;
tU32 this_call_time;
static tU32 last_cursor_change;
static tU32 last_call_time;
static tU32 last_required_change;
tS32 period;
static int delta_x;
static int required_cursor;
static int zero_count;
static int button_was_down;
period = 0;
this_call_time = PDGetTotalTime();
if (last_call_time == 0) {
period = 1000;
}
while (period <= 20) {
this_call_time = PDGetTotalTime();
period = this_call_time - last_call_time;
// added by dethrace to avoid 100% CPU usage
gHarness_platform.Sleep(1);
}
GetMousePosition(&x_coord, &y_coord);
mouse_moved = x_coord != gMouse_last_x_coord || y_coord != gMouse_last_y_coord;
button_is_down = EitherMouseButtonDown();
cursor_offset = button_is_down ? 4 : 0;
if (gMouse_in_use || mouse_moved) {
gMouse_in_use = 1;
if (gMouse_last_x_coord == x_coord) {
if (zero_count >= 5) {
delta_x = 0;
}
zero_count++;
} else {
zero_count = 0;
delta_x = (x_coord - gMouse_last_x_coord) * 1000 / period;
}
if (delta_x < -10) {
new_required = 0;
} else if (delta_x < 11) {
new_required = 2;
} else {
new_required = 3;
}
if (new_required != required_cursor && this_call_time - last_required_change >= 200) {
last_required_change = this_call_time;
required_cursor = new_required;
}
if (gCurrent_cursor_index != required_cursor && PDGetTotalTime() - last_cursor_change >= 50) {
if (required_cursor < gCurrent_cursor_index) {
gCurrent_cursor_index--;
} else {
gCurrent_cursor_index++;
}
last_cursor_change = PDGetTotalTime();
}
giblet_chance
= Chance
(1.
f + 20.
f * (abs(x_coord
- gMouse_last_x_coord
) + abs(y_coord
- gMouse_last_y_coord
)) / (float)period
, period
);
if (gProgram_state.sausage_eater_mode) {
giblet_count = 0;
} else {
giblet_count = 6 * BooleanTo1Or0(button_is_down && !button_was_down) + BooleanTo1Or0(giblet_chance);
}
for (; giblet_count != 0; giblet_count--) {
NewCursorGiblet(
x_coord + gCursor_gib_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
y_coord + gCursor_gib_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
((float)(x_coord - gMouse_last_x_coord)) / period * 1000.f / 4.f,
((float)(y_coord - gMouse_last_y_coord)) / period * 1000.f / 3.f,
(button_is_down && !button_was_down) ? 50 : 400);
}
ProcessCursorGiblets(period);
SaveTransient(gCursor_transient_index,
x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480);
DRPixelmapRectangleMaskedCopy(gBack_screen,
x_coord - gCursor_x_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_width / 640,
y_coord - gCursor_y_offsets[gCurrent_cursor_index + cursor_offset] * gGraf_specs[gGraf_spec_index].total_height / 480,
gCursors[gCurrent_cursor_index + cursor_offset],
0,
0,
gCursors[gCurrent_cursor_index + cursor_offset]->width,
gCursors[gCurrent_cursor_index + cursor_offset]->height);
}
last_call_time = this_call_time;
button_was_down = button_is_down;
gMouse_last_x_coord = x_coord;
gMouse_last_y_coord = y_coord;
return mouse_moved;
}
// IDA: int __cdecl AllocateCursorTransient()
int AllocateCursorTransient(void) {
int i;
int largest_width;
int largest_height;
LOG_TRACE("()");
largest_width = 0;
largest_height = 0;
for (i = 0; i < COUNT_OF(gCursors); i++) {
if (largest_width < gCursors[i]->width) {
largest_width = gCursors[i]->width;
}
if (largest_height < gCursors[i]->height) {
largest_height = gCursors[i]->height;
}
}
return AllocateTransientBitmap(largest_width, largest_height, 0);
}
// IDA: void __cdecl StartMouseCursor()
void StartMouseCursor(void) {
int i;
LOG_TRACE("()");
gNext_transient = 0;
gCursor_transient_index = AllocateCursorTransient();
GetMousePosition(&gMouse_last_x_coord, &gMouse_last_y_coord);
gMouse_in_use = 0;
gCurrent_cursor_index = 2;
for (i = 0; i < COUNT_OF(gCursor_giblets); i++) {
gCursor_giblets[i].current_giblet = -1;
}
gMouse_started = 1;
}
// IDA: void __cdecl EndMouseCursor()
void EndMouseCursor(void) {
LOG_TRACE("()");
RemoveTransientBitmaps(1);
DeallocateAllTransientBitmaps();
gMouse_started = 0;
}
// IDA: void __usercall LoadFont(int pFont_ID@<EAX>)
void LoadFont(int pFont_ID) {
tPath_name the_path;
int i;
int number_of_chars;
FILE* f;
tU32 the_size;
LOG_TRACE("(%d)", pFont_ID);
if (gFonts[pFont_ID].images != NULL) {
return;
}
PathCat(the_path, gApplication_path, gGraf_specs[gGraf_spec_index].data_dir_name);
PathCat(the_path, the_path, "FONTS");
PathCat(the_path, the_path, gFont_names[pFont_ID]);
number_of_chars
= strlen(the_path
);
gFonts[pFont_ID].images = DRPixelmapLoad(the_path);
if (gFonts[pFont_ID].images == NULL) {
FatalError(kFatalError_LoadFontImage_S, gFont_names[pFont_ID]);
}
if (!gFonts[pFont_ID].file_read_once) {
strcpy(&the_path
[number_of_chars
+ 1], "TXT");
f = DRfopen(the_path, "rt");
if (f == NULL) {
FatalError(kFatalError_LoadFontWidthTable_S, gFont_names[pFont_ID]);
}
gFonts[pFont_ID].height = GetAnInt(f);
gFonts[pFont_ID].width = GetAnInt(f);
gFonts[pFont_ID].spacing = GetAnInt(f);
gFonts[pFont_ID].offset = GetAnInt(f);
gFonts[pFont_ID].num_entries = GetAnInt(f);
if (gFonts[pFont_ID].width <= 0) {
for (i = 0; i < gFonts[pFont_ID].num_entries; i++) {
the_size = GetAnInt(f);
gFonts[pFont_ID].width_table[i] = the_size;
}
}
gFonts[pFont_ID].file_read_once = 1;
}
}
// IDA: void __usercall DisposeFont(int pFont_ID@<EAX>)
void DisposeFont(int pFont_ID) {
LOG_TRACE("(%d)", pFont_ID);
if (gFonts[pFont_ID].images && (!TranslationMode() || (gAusterity_mode && FlicsPlayedFromDisk()))) {
BrPixelmapFree(gFonts[pFont_ID].images);
gFonts[pFont_ID].images = NULL;
gFonts[pFont_ID].file_read_once = 0;
}
}
// IDA: void __cdecl InitDRFonts()
void InitDRFonts(void) {
int i;
LOG_TRACE("()");
for (i = 0; i < 21; i++) {
gFonts[i].file_read_once = 0;
gFonts[i].images = NULL;
}
}
// IDA: void __usercall DrawDropImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip, int pOffset)
void DrawDropImage(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip, int pOffset) {
int y;
int src_y;
int src_height;
int y_diff;
LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip, pOffset);
BrPixelmapRectangleFill(gBack_screen,
pLeft,
pTop_clip,
pImage->width,
pBottom_clip - pTop_clip,
0);
if (pOffset != 1000) {
src_y = 0;
src_height = pImage->height;
y = pOffset + pTop;
y_diff = pTop_clip - y;
if (y_diff > 0) {
src_height -= y_diff;
y += y_diff;
src_y = y_diff;
}
y_diff = pBottom_clip - y - pImage->height;
if (y_diff < 0) {
src_height += y_diff;
}
BrPixelmapRectangleCopy(gBack_screen,
pLeft,
y,
pImage,
0,
src_y,
pImage->width,
src_height);
PDScreenBufferSwap(0);
}
}
// IDA: void __usercall DropInImageFromTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
void DropInImageFromTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
tS32 start_time;
tS32 the_time;
int drop_distance;
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
start_time = PDGetTotalTime();
drop_distance = pImage->height - pTop_clip + pTop;
while (1) {
the_time = PDGetTotalTime();
if (the_time >= start_time + 100) {
break;
}
DrawDropImage(pImage,
pLeft,
pTop,
pTop_clip,
pBottom_clip,
(the_time - start_time - 100) * drop_distance / 100);
}
DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
}
// IDA: void __usercall DropOutImageThruBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
void DropOutImageThruBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
tS32 start_time;
tS32 the_time;
int drop_distance;
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
start_time = PDGetTotalTime();
drop_distance = pBottom_clip - pTop;
while (1) {
the_time = PDGetTotalTime();
if (the_time >= start_time + 100) {
break;
}
DrawDropImage(pImage,
pLeft,
pTop,
pTop_clip,
pBottom_clip,
(the_time - start_time) * drop_distance / 100);
}
DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
}
// IDA: void __usercall DropInImageFromBottom(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
void DropInImageFromBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
tS32 start_time;
tS32 the_time;
int drop_distance;
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
start_time = PDGetTotalTime();
drop_distance = pBottom_clip - pTop;
while (1) {
the_time = PDGetTotalTime();
if (the_time >= start_time + 100) {
break;
}
DrawDropImage(pImage,
pLeft,
pTop,
pTop_clip,
pBottom_clip,
(100 - the_time + start_time) * drop_distance / 100);
}
DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 0);
}
// IDA: void __usercall DropOutImageThruTop(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pTop_clip@<ECX>, int pBottom_clip)
void DropOutImageThruTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip, int pBottom_clip) {
tS32 start_time;
tS32 the_time;
int drop_distance;
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
start_time = PDGetTotalTime();
drop_distance = pImage->height - pTop_clip + pTop;
while (1) {
the_time = PDGetTotalTime();
if (the_time >= start_time + 100) {
break;
}
DrawDropImage(pImage,
pLeft,
pTop,
pTop_clip,
pBottom_clip,
(start_time - the_time) * drop_distance / 100);
}
DrawDropImage(pImage, pLeft, pTop, pTop_clip, pBottom_clip, 1000);
}
// IDA: void __usercall DrawTellyLine(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
void DrawTellyLine(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
int the_width;
int the_height;
LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
the_width = pImage->width;
the_height = pImage->height / 2 + pTop;
BrPixelmapLine(gBack_screen, pLeft, the_height, pLeft + the_width, the_height, 0);
BrPixelmapLine(gBack_screen, the_width / 2 + pLeft - pPercentage * the_width / 200, the_height, the_width / 2 + pLeft + pPercentage * the_width / 200, the_height, 1);
PDScreenBufferSwap(0);
}
// IDA: void __usercall DrawTellyImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pPercentage@<ECX>)
void DrawTellyImage(br_pixelmap* pImage, int pLeft, int pTop, int pPercentage) {
//int the_height; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %d, %d, %d)", pImage, pLeft, pTop, pPercentage);
BrPixelmapRectangleFill(gBack_screen, pLeft, pTop, pImage->width, pImage->height, 0);
if (pPercentage != 1000) {
DRPixelmapRectangleVScaledCopy(
gBack_screen,
pLeft,
pTop + pImage->height * (100 - pPercentage) / 200,
pImage,
0,
0,
pImage->width,
pPercentage * pImage->height / 100);
PDScreenBufferSwap(0);
}
}
// IDA: void __usercall TellyInImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
void TellyInImage(br_pixelmap* pImage, int pLeft, int pTop) {
tS32 start_time;
tS32 the_time;
LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime();
if (start_time + 100 <= the_time) {
break;
}
DrawTellyLine(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
}
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime();
if (start_time + 100 <= the_time) {
break;
}
DrawTellyImage(pImage, pLeft, pTop, 100 * (the_time - start_time) / 100);
}
DrawTellyImage(pImage, pLeft, pTop, 100);
}
// IDA: void __usercall TellyOutImage(br_pixelmap *pImage@<EAX>, int pLeft@<EDX>, int pTop@<EBX>)
void TellyOutImage(br_pixelmap* pImage, int pLeft, int pTop) {
tS32 start_time;
tS32 the_time;
//int drop_distance; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %d, %d)", pImage, pLeft, pTop);
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime();
if (start_time + 100 <= the_time) {
break;
}
DrawTellyImage(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
}
DrawTellyImage(pImage, pLeft, pTop, 1000);
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime();
if (start_time + 100 <= the_time) {
break;
}
DrawTellyLine(pImage, pLeft, pTop, 100 * (start_time + 100 - the_time) / 100);
}
DrawTellyLine(pImage, pLeft, pTop, 0);
}
// IDA: void __usercall SetShadowLevel(tShadow_level pLevel@<EAX>)
void SetShadowLevel(tShadow_level pLevel) {
LOG_TRACE("(%d)", pLevel);
gShadow_level = pLevel;
}
// IDA: tShadow_level __cdecl GetShadowLevel()
tShadow_level GetShadowLevel(void) {
LOG_TRACE("()");
return gShadow_level;
}
// IDA: void __cdecl ToggleShadow()
void ToggleShadow(void) {
LOG_TRACE("()");
gShadow_level++;
if (gShadow_level == eShadow_everyone) {
gShadow_level = eShadow_none;
}
switch (gShadow_level) {
case eShadow_none:
NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_NoShadows));
break;
case eShadow_us_only:
NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderOwnCar));
break;
case eShadow_us_and_opponents:
NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderMainCars));
break;
case eShadow_everyone:
NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ShadowUnderAllCars));
break;
default:
return;
}
}
// IDA: void __cdecl InitShadow()
void InitShadow(void) {
int i;
//br_vector3 temp_v; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
for (i = 0; i < 8; i++) {
gShadow_clip_planes[i].clip = BrActorAllocate(BR_ACTOR_CLIP_PLANE, NULL);
BrActorAdd(gUniverse_actor, gShadow_clip_planes[i].clip);
BrClipPlaneDisable(gShadow_clip_planes[i].clip);
BrMatrix34Identity(&gShadow_clip_planes[i].clip->t.t.mat);
}
gFancy_shadow = 1;
gShadow_material = BrMaterialFind("SHADOW.MAT");
BrVector3Set(&gShadow_light_ray, 0.f, -1.f, 0.f);
BrVector3Set(&gShadow_light_z, -0.f, -0.f, -1.f);
BrVector3Set(&gShadow_light_x, 1.f, 0.f, 0.f);
gShadow_model = BrModelAllocate("", 0, 0);
gShadow_model->flags = BR_MODF_GENERATE_TAGS | BR_MODF_KEEP_ORIGINAL;
gShadow_actor = BrActorAllocate(BR_ACTOR_MODEL, 0);
gShadow_actor->model = gShadow_model;
BrActorAdd(gUniverse_actor, gShadow_actor);
}
// IDA: br_uint_32 __cdecl SaveShadeTable(br_pixelmap *pTable, void *pArg)
br_uint_32 SaveShadeTable(br_pixelmap* pTable, void* pArg) {
LOG_TRACE("(%p, %p)", pTable, pArg);
if (gSaved_table_count == COUNT_OF(gSaved_shade_tables)) {
return 1;
}
gSaved_shade_tables[gSaved_table_count].original = pTable;
gSaved_shade_tables[gSaved_table_count].copy = (br_pixelmap*)BrMemAllocate(sizeof(br_pixelmap), kMem_shade_table_copy);
memcpy(gSaved_shade_tables
[gSaved_table_count
].
copy, pTable
, sizeof(br_pixelmap
));
gSaved_table_count++;
return 0;
}
// IDA: void __cdecl SaveShadeTables()
void SaveShadeTables(void) {
LOG_TRACE("()");
PossibleService();
gSaved_table_count = 0;
BrTableEnum("*", SaveShadeTable, 0);
}
// IDA: void __cdecl DisposeSavedShadeTables()
void DisposeSavedShadeTables(void) {
int i;
LOG_TRACE("()");
for (i = 0; i < gSaved_table_count; i++) {
BrMemFree(gSaved_shade_tables[i].copy);
}
}
// IDA: void __cdecl ShadowMode()
void ShadowMode(void) {
LOG_TRACE("()");
gFancy_shadow = !gFancy_shadow;
if (gFancy_shadow) {
NewTextHeadupSlot(4, 0, 2000, -4, "Translucent shadow");
} else {
NewTextHeadupSlot(4, 0, 2000, -4, "Solid shadow");
}
}
// IDA: int __cdecl SwitchToRealResolution()
int SwitchToRealResolution(void) {
LOG_TRACE("()");
if (gGraf_data_index == gReal_graf_data_index) {
return 0;
}
gGraf_data_index = gReal_graf_data_index;
gGraf_spec_index = gReal_graf_data_index;
gCurrent_graf_data = &gGraf_data[gReal_graf_data_index];
PDSwitchToRealResolution();
return 1;
}
// IDA: int __cdecl SwitchToLoresMode()
int SwitchToLoresMode(void) {
LOG_TRACE("()");
if (!gGraf_data_index || gGraf_data_index != gReal_graf_data_index) {
return 0;
}
gGraf_data_index = 0;
gGraf_spec_index = 0;
gCurrent_graf_data = gGraf_data;
PDSwitchToLoresMode();
return 1;
}
// 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)
void DRPixelmapDoubledCopy(br_pixelmap* pDestn, br_pixelmap* pSource, int pSource_width, int pSource_height, int pX_offset, int pY_offset) {
tU16* sptr;
tU16 pixels;
tU8* dptr;
tU8* dptr2;
tU8 pixel_1;
tU8 pixel_2;
int i;
int j;
int dst_row_skip;
int src_row_skip;
int width_over_2;
LOG_TRACE("(%p, %p, %d, %d, %d, %d)", pDestn, pSource, pSource_width, pSource_height, pX_offset, pY_offset);
dst_row_skip = 2 * pDestn->row_bytes - 2 * pSource_width;
src_row_skip = (pSource->row_bytes - pSource_width) / 2;
sptr = (tU16*)((tU8*)pSource->pixels - 2 * src_row_skip + 2 * (pSource->row_bytes * pSource_height / 2));
dptr = (tU8*)pDestn->pixels + 2 * pSource_width + (2 * pSource_height + pY_offset) * pDestn->row_bytes - pDestn->row_bytes;
dptr2 = dptr - pDestn->row_bytes;
width_over_2 = pSource_width / 2;
for (i = 0; i < pSource_height; i++) {
for (j = 0; j < width_over_2; j++) {
--sptr;
pixels = *sptr;
pixel_1 = pixels >> 8;
pixel_2 = pixels >> 0;
dptr[-1] = pixel_1;
dptr2[-1] = pixel_1;
dptr[-2] = pixel_1;
dptr2[-2] = pixel_1;
dptr[-3] = pixel_2;
dptr2[-3] = pixel_2;
dptr[-4] = pixel_2;
dptr2[-4] = pixel_2;
dptr -= 4;
dptr2 -= 4;
}
dptr -= dst_row_skip;
dptr2 -= dst_row_skip;
sptr -= src_row_skip;
}
}