Recovery and Race Completed logic (#74)

* implements race completed, recovery logic

* fps limiter, better framebuffer handling
This commit is contained in:
Dethrace Engineering Department 2022-01-25 22:32:11 +13:00 committed by GitHub
parent ee032df264
commit 94167e09c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1137 additions and 233 deletions

28
docs/CODE_LAYOUT.md Normal file
View File

@ -0,0 +1,28 @@
# Code layout
### DETHRACE
Game logic. According to the symbol dump, these files were originally stored in `C:\DETHRACE\src`.
`DETHRACE/common` - all common logic
`DETHRACE/pc-dos` - all platform-specific functions (DOS, in this case)
`DETHRACE/pd` - platform-dependent generic headers.
_All code here is kept as similar to how we think the original code might have been. Any changes required are implemented as hooks in the `harness`._
### BRSRC13
[BRender](https://en.wikipedia.org/wiki/Argonaut_Games#BRender), originally stored in `C:\BRSRC13`. A graphics rendering library.
Apparently Stainless Software used their own build of BRender with unknown modifications.
_All code here is kept as similar to how we think the original code might have been. Any changes required are implemented as hooks in the `harness`._
### S3
Audio library. No other information.
_All code here is kept as similar to how we think the original code might have been. Any changes required are implemented as hooks in the `harness`._
### harness
- Provides hooks into the game logic to implement modern cross-platform support.

View File

@ -0,0 +1,59 @@
# Rendering pipeline
The original game renders both 2d and 3d elements to the same memory buffer, called `gBack_screen`.
Another variable, `gRender_screen`, points into that memory buffer and is where the 3d scene is drawn on top of any existing 2d pixels.
Rendering is done in a (standard for the time) 8 bit paletted mode.
```
+-----------------------------------------+
|gBack_screen |
| +------------------------+ |
| | gRender_screen | |
| | | |
| | | |
| | | |
| | | |
| +------------------------+ |
| |
+-----------------------------------------+
```
The `RenderAFrame` function does the following:
1. Render 2d background content (horizon, map, etc) to `gBack_screen`
2. Start 3d scene rendering
3. Render 3d environment to `gRender_screen`
4. End 3d scene rendering
5. Render 2d foreground content into `gBack_screen` (HUD, messages, etc)
6. Swap buffers
If the rearview mirror is rendered, steps 3-4 are repeated, this time rendering into `gRearview_screen`
## Palette manipulation
The game palette is updated frequently:
1. Fade screen to black
2. Fade screen back up to normal brightness
3. Different palettes for the menu interface and for game play
4. The "On drugs" powerup
Palette animations run in a tight loop, assuming they are writing to the system color palette, so do not re-render the 3d scene etc. We handle this by hooking the palette functions and reusing the last-rendered scene from our framebuffer.
## OpenGL implementation
### Start 3d rendering hook
- Capture the current `gBack_screen` and convert it to a 32 bit OpenGL texture, and render it as a full-screen quad.
- Configure OpenGL framebuffer to do render-to-texture
- Clear `gBack_screen`
### Render model hook
- Render the model as an OpenGL VBO, convert referenced materials to OpenGL textures.
### End 3d rendering hook
Render the framebuffer from above as a full-screen quad.
### Swap buffers hook
- Again capture `gBack_screen` to pick up HUD elements rendered after the 3d scene, convert it to 32 bit, and render it as a full-screen quad.
- Generate a palette-manipulation image which is blended over the top of everything as a full-screen quad to handle palette animations.

View File

@ -8,5 +8,5 @@ br_pixelmap* DOSGfxBegin(char* setup_string) {
LOG_TRACE("(\"%s\")", setup_string);
Harness_Hook_DOSGfxBegin();
return BrPixelmapAllocate(BR_PMT_INDEX_8, 320, 240, NULL, BR_PMAF_NORMAL);
return BrPixelmapAllocate(BR_PMT_INDEX_8, 320, 200, NULL, BR_PMAF_NORMAL);
}

View File

@ -135,6 +135,8 @@ br_device_pixelmap* DevicePixelmapMemAllocate(br_uint_8 type, br_uint_16 w, br_u
//pm->pm_row_bytes = (v11 - (__CFSHL__(v11 >> 31, 3) + 8 * (v11 >> 31))) >> 3;
// TODO: calculate this differently
pm->pm_row_bytes = w;
pm->pm_row_bytes = tip->bits * tip->align * ((w + tip->align - 1) / tip->align) / 8;
if ((8 * pm->pm_row_bytes % tip->bits) == 0) {
pm->pm_flags |= BR_PMF_ROW_WHOLEPIXELS;
}

View File

@ -12,6 +12,7 @@
#include "globvrkm.h"
#include "globvrpb.h"
#include "graphics.h"
#include "harness/config.h"
#include "harness/trace.h"
#include "netgame.h"
#include "oil.h"
@ -280,13 +281,13 @@ void InitialiseCar2(tCar_spec* pCar, int pClear_disabled_flag) {
}
BrMatrix34Copy(&pCar->old_frame_mat, &safe_position);
BrMatrix34Copy(&pCar->oldmat, &safe_position);
pCar->oldmat.m[3][0] *= 6.9000001;
pCar->oldmat.m[3][1] *= 6.9000001;
pCar->oldmat.m[3][2] *= 6.9000001;
pCar->oldmat.m[3][0] *= WORLD_SCALE;
pCar->oldmat.m[3][1] *= WORLD_SCALE;
pCar->oldmat.m[3][2] *= WORLD_SCALE;
BrMatrix34ApplyP(&pCar->pos, &pCar->cmpos, &pCar->oldmat);
pCar->pos.v[0] /= 6.9000001;
pCar->pos.v[1] /= 6.9000001;
pCar->pos.v[2] /= 6.9000001;
pCar->pos.v[0] /= WORLD_SCALE;
pCar->pos.v[1] /= WORLD_SCALE;
pCar->pos.v[2] /= WORLD_SCALE;
for (j = 0; j < COUNT_OF(pCar->oldd); j++) {
pCar->oldd[j] = pCar->ride_height;
}
@ -662,7 +663,41 @@ void RememberSafePosition(tCar_spec* car, tU32 pTime) {
br_scalar ts;
LOG_TRACE("(%p, %d)", car, pTime);
STUB_ONCE();
if (car->disabled) {
return;
}
time_count += pTime;
if (time_count < 5000) {
return;
}
time_count = 4000;
for (j = 0; j < 4; j++) {
if (car->susp_height[j >> 1] <= car->oldd[j]) {
return;
}
}
if ((!car->last_special_volume || car->last_special_volume->gravity_multiplier == 1.0)
&& gCurrent_race.material_modifiers[car->material_index[0]].tyre_road_friction >= 0.1
&& gCurrent_race.material_modifiers[car->material_index[1]].tyre_road_friction >= 0.1
&& gCurrent_race.material_modifiers[car->material_index[2]].tyre_road_friction >= 0.1
&& gCurrent_race.material_modifiers[car->material_index[3]].tyre_road_friction >= 0.1
&& car->car_master_actor->t.t.mat.m[1][1] >= 0.80000001) {
for (j = 0; j < 5; j++) {
r.v[0] = car->car_master_actor->t.t.mat.m[3][0] - car->last_safe_positions[j].m[3][0];
r.v[1] = car->car_master_actor->t.t.mat.m[3][1] - car->last_safe_positions[j].m[3][1];
r.v[2] = car->car_master_actor->t.t.mat.m[3][2] - car->last_safe_positions[j].m[3][2];
if (BrVector3LengthSquared(&r) < 8.4015961) {
return;
}
}
for (j = 3; j > 0; j--) {
BrMatrix34Copy(&car->last_safe_positions[j], &car->last_safe_positions[j - 1]);
}
BrMatrix34Copy(&car->last_safe_positions[0], &car->car_master_actor->t.t.mat);
time_count = 0;
}
}
// IDA: void __usercall ControlOurCar(tU32 pTime_difference@<EAX>)
@ -680,14 +715,14 @@ void ControlOurCar(tU32 pTime_difference) {
if (gNet_mode) {
gCar_flying = 0;
} else {
car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * 6.9000001;
car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * 6.9000001;
car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * 6.9000001;
car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
ts = (double)pTime_difference / 1000.0;
FlyCar(car, ts);
car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] / 6.9000001;
car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] / 6.9000001;
car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] / 6.9000001;
car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] / WORLD_SCALE;
car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] / WORLD_SCALE;
car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] / WORLD_SCALE;
}
return;
}
@ -905,7 +940,7 @@ void FinishCars(tU32 pLast_frame_time, tU32 pTime) {
BrMatrix34ApplyV(&car->direction, &minus_k, &car->car_master_actor->t.t.mat);
} else if (gLast_mechanics_time > pLast_frame_time && gCar_to_view == car) {
BrVector3Sub(&car->old_v, &car->old_v, &car->v);
BrVector3Scale(&car->old_v, &car->old_v, (gLast_mechanics_time - pLast_frame_time) / (float)PHYSICS_STEP_TIME);
BrVector3Scale(&car->old_v, &car->old_v, (gLast_mechanics_time - pLast_frame_time) / harness_game_config.physics_step_time);
BrVector3Accumulate(&car->old_v, &car->v);
BrVector3Normalise(&car->direction, &car->old_v);
} else {
@ -1021,7 +1056,7 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
ForceRebuildActiveCarList();
}
if (gLast_mechanics_time < last_frame_time) {
gLast_mechanics_time = PHYSICS_STEP_TIME * (last_frame_time / PHYSICS_STEP_TIME);
gLast_mechanics_time = harness_game_config.physics_step_time * (last_frame_time / harness_game_config.physics_step_time);
}
GetNonCars();
if (frame_end_time <= gLast_mechanics_time) {
@ -1033,7 +1068,7 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
gDoing_physics = 1;
PrepareCars(last_frame_time);
gDt = PHYSICS_STEP_TIME / 1000.0; // 0.039999999;
gDt = harness_game_config.physics_step_time / 1000.0; // 0.039999999;
gMechanics_time_sync = pTime_difference - (gLast_mechanics_time - last_frame_time);
while (gLast_mechanics_time < frame_end_time && step_number < 5) {
step_number++;
@ -1047,8 +1082,8 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
for (i = 0; gNum_active_cars > i; ++i) {
car = gActive_car_list[i];
car->dt = -1.0;
if (car->message.type == 15 && car->message.time >= gLast_mechanics_time && gLast_mechanics_time + PHYSICS_STEP_TIME >= car->message.time) {
car->dt = (double)(gLast_mechanics_time + PHYSICS_STEP_TIME - car->message.time) / 1000.0;
if (car->message.type == 15 && car->message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= car->message.time) {
car->dt = (double)(gLast_mechanics_time + harness_game_config.physics_step_time - car->message.time) / 1000.0;
if (gDt - 0.0001 <= car->dt) {
GetNetPos(car);
} else if (gNet_mode == eNet_mode_host) {
@ -1066,7 +1101,7 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
}
}
if (!car->disabled
&& (!car->doing_nothing_flag || (car->driver >= eDriver_net_human && (!gRecover_timer || car->driver != eDriver_local_human)))) {
&& (!car->doing_nothing_flag || (car->driver >= eDriver_net_human && (!gPalette_fade_time || car->driver != eDriver_local_human)))) {
if (car->box_face_ref != gFace_num__car
&& (car->box_face_ref != gFace_num__car - 1 || car->box_face_start <= gFace_count)) {
car_info = (tCollision_info*)car;
@ -1081,8 +1116,8 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
non_car = gActive_non_car_list[i];
if (!non_car->collision_info.doing_nothing_flag) {
non_car->collision_info.dt = -1.0;
if (non_car->collision_info.message.type == 16 && non_car->collision_info.message.time >= gLast_mechanics_time && gLast_mechanics_time + PHYSICS_STEP_TIME >= non_car->collision_info.message.time) {
non_car->collision_info.dt = (double)(gLast_mechanics_time + PHYSICS_STEP_TIME - non_car->collision_info.message.time) / 1000.0;
if (non_car->collision_info.message.type == 16 && non_car->collision_info.message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= non_car->collision_info.message.time) {
non_car->collision_info.dt = (double)(gLast_mechanics_time + harness_game_config.physics_step_time - non_car->collision_info.message.time) / 1000.0;
GetNetPos((tCar_spec*)non_car);
}
if (non_car->collision_info.box_face_ref != gFace_num__car
@ -1099,8 +1134,8 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
old_num_cars = gNum_cars_and_non_cars;
CrashCarsTogether(gDt);
} while (old_num_cars < gNum_cars_and_non_cars);
gMechanics_time_sync -= PHYSICS_STEP_TIME;
gLast_mechanics_time += PHYSICS_STEP_TIME;
gMechanics_time_sync -= harness_game_config.physics_step_time;
gLast_mechanics_time += harness_game_config.physics_step_time;
}
gMechanics_time_sync = 1;
SendCarData(gLast_mechanics_time);
@ -1180,9 +1215,9 @@ void MoveAndCollideCar(tCar_spec* car, br_scalar dt) {
TranslateCar(car_info, dt);
CollideCarWithWall(car_info, dt);
BrMatrix34ApplyP(&car->pos, &car->cmpos, &car->car_master_actor->t.t.mat);
car->pos.v[0] = car->pos.v[0] / 6.9000001;
car->pos.v[1] = car->pos.v[1] / 6.9000001;
car->pos.v[2] = car->pos.v[2] / 6.9000001;
car->pos.v[0] = car->pos.v[0] / WORLD_SCALE;
car->pos.v[1] = car->pos.v[1] / WORLD_SCALE;
car->pos.v[2] = car->pos.v[2] / WORLD_SCALE;
for (wheel = 0; wheel < 4; wheel++) {
SkidMark(car, wheel);
}
@ -2318,7 +2353,6 @@ int CollCheck(tCollision_info* c, br_scalar dt) {
// v35 = 0;
// v36 = 0x3F800000;
// v48 = 0x3F800347;
car_spec = (tCar_spec*)c;
mat = &c->car_master_actor->t.t.mat;
oldmat = &c->oldmat;
@ -2349,7 +2383,6 @@ int CollCheck(tCollision_info* c, br_scalar dt) {
a1.v[0] = mat->m[3][0] / WORLD_SCALE;
a1.v[1] = mat->m[3][1] / WORLD_SCALE;
a1.v[2] = mat->m[3][2] / WORLD_SCALE;
BrMatrix34ApplyV(&aa, &bnds.min, mat);
BrVector3Accumulate(&aa, &a1);
for (j = 0; j < 3; ++j) {
@ -2357,9 +2390,7 @@ int CollCheck(tCollision_info* c, br_scalar dt) {
edges[j].v[1] = (bnds.max.v[j] - bnds.min.v[j]) * mat->m[j][1];
edges[j].v[2] = (bnds.max.v[j] - bnds.min.v[j]) * mat->m[j][2];
}
i = 0;
f_ref = &gFace_list__car[c->box_face_start];
while (c->box_face_end - c->box_face_start > i && i < 50) {
BrVector3Sub(&bb, &aa, &f_ref->v[0]);
@ -2489,7 +2520,6 @@ int CollCheck(tCollision_info* c, br_scalar dt) {
M.m[i][j] = BrVector3Dot(&n[i], &normal_force);
}
}
switch (k) {
case 1:
ts = SinglePointColl(f, &M, d);
@ -3015,14 +3045,14 @@ void MultiFindFloorInBoxM(int pNum_rays, br_vector3* a, br_vector3* b, br_vector
LOG_TRACE("(%d, %p, %p, %p, %p, %p, %p)", pNum_rays, a, b, nor, d, c, mat_ref);
for (i = 0; i < pNum_rays; i++) {
aa[i].v[0] = a[i].v[0] / 6.9000001;
aa[i].v[1] = a[i].v[1] / 6.9000001;
aa[i].v[2] = a[i].v[2] / 6.9000001;
aa[i].v[0] = a[i].v[0] / WORLD_SCALE;
aa[i].v[1] = a[i].v[1] / WORLD_SCALE;
aa[i].v[2] = a[i].v[2] / WORLD_SCALE;
d[i] = 2.0;
}
bb.v[0] = b->v[0] / 6.9000001;
bb.v[1] = b->v[1] / 6.9000001;
bb.v[2] = b->v[2] / 6.9000001;
bb.v[0] = b->v[0] / WORLD_SCALE;
bb.v[1] = b->v[1] / WORLD_SCALE;
bb.v[2] = b->v[2] / WORLD_SCALE;
MultiFindFloorInBoxBU(pNum_rays, aa, &bb, nor, d, c, mat_ref);
}
@ -3061,12 +3091,12 @@ void findfloor(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d) {
br_vector3 bb;
LOG_TRACE("(%p, %p, %p, %p)", a, b, nor, d);
aa.v[0] = a->v[0] / 6.9000001;
aa.v[1] = a->v[1] / 6.9000001;
aa.v[2] = a->v[2] / 6.9000001;
bb.v[0] = b->v[0] / 6.9000001;
bb.v[1] = b->v[1] / 6.9000001;
bb.v[2] = b->v[2] / 6.9000001;
aa.v[0] = a->v[0] / WORLD_SCALE;
aa.v[1] = a->v[1] / WORLD_SCALE;
aa.v[2] = a->v[2] / WORLD_SCALE;
bb.v[0] = b->v[0] / WORLD_SCALE;
bb.v[1] = b->v[1] / WORLD_SCALE;
bb.v[2] = b->v[2] / WORLD_SCALE;
FindFace(&aa, &bb, nor, d, &material);
}
@ -3076,12 +3106,12 @@ int FindFloorInBoxM(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d,
br_vector3 bb;
LOG_TRACE("(%p, %p, %p, %p, %p)", a, b, nor, d, c);
aa.v[0] = a->v[0] / 6.9000001;
aa.v[1] = a->v[1] / 6.9000001;
aa.v[2] = a->v[2] / 6.9000001;
bb.v[0] = b->v[0] / 6.9000001;
bb.v[1] = b->v[1] / 6.9000001;
bb.v[2] = b->v[2] / 6.9000001;
aa.v[0] = a->v[0] / WORLD_SCALE;
aa.v[1] = a->v[1] / WORLD_SCALE;
aa.v[2] = a->v[2] / WORLD_SCALE;
bb.v[0] = b->v[0] / WORLD_SCALE;
bb.v[1] = b->v[1] / WORLD_SCALE;
bb.v[2] = b->v[2] / WORLD_SCALE;
return FindFloorInBoxBU(&aa, &bb, nor, d, c);
}
@ -3170,12 +3200,12 @@ int FindFloorInBoxM2(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d
br_vector3 bb;
LOG_TRACE("(%p, %p, %p, %p, %p)", a, b, nor, d, c);
aa.v[0] = a->v[0] / 6.9000001;
aa.v[1] = a->v[1] / 6.9000001;
aa.v[2] = a->v[2] / 6.9000001;
bb.v[0] = b->v[0] / 6.9000001;
bb.v[1] = b->v[1] / 6.9000001;
bb.v[2] = b->v[2] / 6.9000001;
aa.v[0] = a->v[0] / WORLD_SCALE;
aa.v[1] = a->v[1] / WORLD_SCALE;
aa.v[2] = a->v[2] / WORLD_SCALE;
bb.v[0] = b->v[0] / WORLD_SCALE;
bb.v[1] = b->v[1] / WORLD_SCALE;
bb.v[2] = b->v[2] / WORLD_SCALE;
return FindFloorInBoxBU2(&aa, &bb, nor, d, c);
}
@ -3241,9 +3271,9 @@ int BoxFaceIntersect(br_bounds* pB, br_matrix34* pM, br_matrix34* pMold, br_vect
}
}
while (n > j) {
pPoint_list[j].v[0] = pPoint_list[j].v[0] * 6.9000001;
pPoint_list[j].v[1] = pPoint_list[j].v[1] * 6.9000001;
pPoint_list[j].v[2] = pPoint_list[j].v[2] * 6.9000001;
pPoint_list[j].v[0] = pPoint_list[j].v[0] * WORLD_SCALE;
pPoint_list[j].v[1] = pPoint_list[j].v[1] * WORLD_SCALE;
pPoint_list[j].v[2] = pPoint_list[j].v[2] * WORLD_SCALE;
pPoint_list[j].v[0] = pPoint_list[j].v[0] - c->cmpos.v[0];
pPoint_list[j].v[1] = pPoint_list[j].v[1] - c->cmpos.v[1];
pPoint_list[j].v[2] = pPoint_list[j].v[2] - c->cmpos.v[2];
@ -3276,9 +3306,9 @@ int BoxFaceIntersect(br_bounds* pB, br_matrix34* pM, br_matrix34* pMold, br_vect
pPoint_list[m].v[2] = pPoint_list[n - 1].v[2];
n = m + 1;
}
pMold->m[3][0] = pMold->m[3][0] * 6.9000001;
pMold->m[3][1] = pMold->m[3][1] * 6.9000001;
pMold->m[3][2] = pMold->m[3][2] * 6.9000001;
pMold->m[3][0] = pMold->m[3][0] * WORLD_SCALE;
pMold->m[3][1] = pMold->m[3][1] * WORLD_SCALE;
pMold->m[3][2] = pMold->m[3][2] * WORLD_SCALE;
return n;
}
@ -3605,7 +3635,12 @@ void ToggleCollisionDetection() {
// IDA: void __cdecl CancelPendingCunningStunt()
void CancelPendingCunningStunt() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
gQuite_wild_end = 0;
gQuite_wild_start = 0;
gOn_me_wheels_start = 0;
gWoz_upside_down_at_all = 0;
gWild_start = 0;
}
// IDA: float __cdecl frac(float pN)
@ -3703,7 +3738,7 @@ void MungeCarGraphics(tU32 pFrame_period) {
for (i = 0; i < oily_count; i++) {
GetOilSpillDetails(i, &oily_actor, &oily_size);
if (oily_actor) {
car_radius = the_car->bounds[1].max.v[2] / 6.9000001 * 1.5;
car_radius = the_car->bounds[1].max.v[2] / WORLD_SCALE * 1.5;
if (oily_actor->t.t.mat.m[3][0] - oily_size < car_x + car_radius
&& oily_actor->t.t.mat.m[3][0] + oily_size > car_x - car_radius
&& oily_actor->t.t.mat.m[3][2] - oily_size < car_z + car_radius
@ -4164,7 +4199,12 @@ void SetUpPanningCamera(tCar_spec* c) {
// IDA: void __usercall SaveCameraPosition(int i@<EAX>)
void SaveCameraPosition(int i) {
LOG_TRACE("(%d)", i);
NOT_IMPLEMENTED();
if (gSave_camera[i].saved != 1) {
gSave_camera[i].zoom = gCamera_zoom;
gSave_camera[i].yaw = gCamera_yaw;
gSave_camera[i].saved = 1;
}
}
// IDA: void __usercall RestoreCameraPosition(int i@<EAX>)
@ -5171,8 +5211,8 @@ void SetCarSuspGiveAndHeight(tCar_spec* pCar, br_scalar pFront_give_factor, br_s
int i;
LOG_TRACE("(%p, %f, %f, %f, %f, %f)", pCar, pFront_give_factor, pRear_give_factor, pDamping_factor, pExtra_front_height, pExtra_rear_height);
front_give = pCar->susp_give[1] * pFront_give_factor * 6.9000001;
rear_give = pCar->susp_give[0] * pRear_give_factor * 6.9000001;
front_give = pCar->susp_give[1] * pFront_give_factor * WORLD_SCALE;
rear_give = pCar->susp_give[0] * pRear_give_factor * WORLD_SCALE;
damping = pCar->damping * pDamping_factor;
ratio = fabs((pCar->wpos[0].v[2] - pCar->cmpos.v[2]) / (pCar->wpos[2].v[2] - pCar->cmpos.v[2]));
pCar->sk[0] = pCar->M / (ratio + 1.0) * 5.0 / rear_give;
@ -5196,7 +5236,7 @@ void SetCarSuspGiveAndHeight(tCar_spec* pCar, br_scalar pFront_give_factor, br_s
i -= pExtra_front_height;
}
pCar->bounds[0].min.v[1] = i;
pCar->bounds[0].min.v[1] = pCar->bounds[0].min.v[1] / 6.9000001;
pCar->bounds[0].min.v[1] = pCar->bounds[0].min.v[1] / WORLD_SCALE;
}
// IDA: int __usercall TestForCarInSensiblePlace@<EAX>(tCar_spec *car@<EAX>)
@ -5214,7 +5254,70 @@ int TestForCarInSensiblePlace(tCar_spec* car) {
br_vector3 tv;
br_vector3 tv2;
LOG_TRACE("(%p)", car);
NOT_IMPLEMENTED();
car_info = (tCollision_info*)car;
if (!gProgram_state.racing) {
return 1;
}
mat1 = &car_info->car_master_actor->t.t.mat;
if (!gDoing_physics) {
mat1->m[3][0] = mat1->m[3][0] * WORLD_SCALE;
mat1->m[3][1] = mat1->m[3][1] * WORLD_SCALE;
mat1->m[3][2] = mat1->m[3][2] * WORLD_SCALE;
}
GetFacesInBox(car_info);
BrMatrix34ApplyP(&car_info->pos, &car_info->cmpos, &car_info->car_master_actor->t.t.mat);
car_info->pos.v[0] = car_info->pos.v[0] / WORLD_SCALE;
car_info->pos.v[1] = car_info->pos.v[1] / WORLD_SCALE;
car_info->pos.v[2] = car_info->pos.v[2] / WORLD_SCALE;
k = CollCheck(car_info, -2.0);
if (!k) {
if (gNum_active_non_cars + gNum_active_cars != gNum_cars_and_non_cars) {
GetNonCars();
}
for (i = 0; i < gNum_cars_and_non_cars; i++) {
c2 = (tCollision_info*)gActive_car_list[i];
if (car_info != c2) {
mat2 = &c2->car_master_actor->t.t.mat;
mat2->m[3][0] = mat2->m[3][0] * WORLD_SCALE;
mat2->m[3][1] = mat2->m[3][1] * WORLD_SCALE;
mat2->m[3][2] = mat2->m[3][2] * WORLD_SCALE;
sep.v[0] = mat1->m[3][0] - mat2->m[3][0];
sep.v[1] = mat1->m[3][1] - mat2->m[3][1];
sep.v[2] = mat1->m[3][2] - mat2->m[3][2];
if (BrVector3LengthSquared(&sep) <= 100.0) {
k += TestOldMats(car_info, c2, 0);
k += TestOldMats(c2, car_info, 0);
}
if (k) {
BrMatrix34ApplyP(&tv, &car_info->cmpos, mat1);
BrMatrix34ApplyP(&tv2, &c2->cmpos, mat2);
tv.v[0] = tv2.v[0] - tv.v[0];
tv.v[1] = tv2.v[1] - tv.v[1];
tv.v[2] = tv2.v[2] - tv.v[2];
BrMatrix34TApplyV(&car_info->old_point, &tv, &car_info->car_master_actor->t.t.mat);
BrVector3Normalise(&car_info->old_norm, &car_info->old_point);
BrVector3Negate(&car_info->old_norm, &car_info->old_norm);
}
mat2->m[3][0] = mat2->m[3][0] / WORLD_SCALE;
mat2->m[3][1] = mat2->m[3][1] / WORLD_SCALE;
mat2->m[3][2] = mat2->m[3][2] / WORLD_SCALE;
if (k) {
break;
}
}
}
}
if (!gDoing_physics) {
mat1->m[3][0] = mat1->m[3][0] / WORLD_SCALE;
mat1->m[3][1] = mat1->m[3][1] / WORLD_SCALE;
mat1->m[3][2] = mat1->m[3][2] / WORLD_SCALE;
}
if (k) {
return 0;
} else {
return -1;
}
}
// IDA: int __usercall TestOldMats@<EAX>(tCollision_info *c1@<EAX>, tCollision_info *c2@<EDX>, int newmats@<EBX>)

View File

@ -3,7 +3,9 @@
#include "brender/brender.h"
#include "car.h"
#include "constants.h"
#include "crush.h"
#include "displays.h"
#include "finteray.h"
#include "flicplay.h"
#include "globvars.h"
#include "globvrkm.h"
@ -15,11 +17,15 @@
#include "mainloop.h"
#include "netgame.h"
#include "network.h"
#include "opponent.h"
#include "pd/sys.h"
#include "pedestrn.h"
#include "piping.h"
#include "pratcam.h"
#include "replay.h"
#include "s3/s3sound.h"
#include "sound.h"
#include "spark.h"
#include "structur.h"
#include "utility.h"
#include "world.h"
@ -73,7 +79,7 @@ tToggle_element gToggle_array[] = {
int gRepair_last_time;
int gHad_auto_recover;
tU32 gLast_repair_time;
tEdit_mode gWhich_edit_mode;
tEdit_mode gWhich_edit_mode = eEdit_mode_options;
char* gEdit_mode_names[10];
tEdit_func* gEdit_funcs[10][18][8];
tCheat gKev_keys[44] = {
@ -123,7 +129,7 @@ tCheat gKev_keys[44] = {
};
int gAllow_car_flying;
int gEntering_message;
tU32 gPalette_fade_time;
tU32 gPalette_fade_time; // was gRecover_timer
char* gAbuse_text[10];
char gString[84];
int gToo_late;
@ -618,13 +624,16 @@ int CarWorldOffFallenCheckThingy(tCar_spec* pCar, int pCheck_around) {
br_vector3 offset_w;
int result;
LOG_TRACE("(%p, %d)", pCar, pCheck_around);
NOT_IMPLEMENTED();
STUB_ONCE();
return 0;
}
// IDA: int __usercall HasCarFallenOffWorld@<EAX>(tCar_spec *pCar@<EAX>)
int HasCarFallenOffWorld(tCar_spec* pCar) {
LOG_TRACE("(%p)", pCar);
NOT_IMPLEMENTED();
return CarWorldOffFallenCheckThingy(pCar, 1);
}
// IDA: void __cdecl CheckForBeingOutOfThisWorld()
@ -633,38 +642,124 @@ void CheckForBeingOutOfThisWorld() {
static tU32 sLast_check;
int time_step;
LOG_TRACE("()");
NOT_IMPLEMENTED();
the_time = PDGetTotalTime();
if (!gRecover_timer || ((gProgram_state.current_car.frame_collision_flag || gProgram_state.current_car.number_of_wheels_on_ground) && !IsCarInTheSea())) {
gRecover_timer = 0;
if ((the_time - sLast_check) > 200) {
sLast_check = the_time;
if (HasCarFallenOffWorld(&gProgram_state.current_car)) {
gRecover_timer = 3000;
}
}
if (IsCarInTheSea()) {
if (!gRecover_timer) {
gRecover_timer = 3000;
}
}
return;
}
gRecover_timer -= gFrame_period;
if (gRecover_timer <= 0 || IsCarInTheSea() == 2) {
gRecover_timer = 0;
RecoverCar();
gHad_auto_recover = 1;
}
}
// IDA: void __usercall CheckHornLocal(tCar_spec *pCar@<EAX>)
void CheckHornLocal(tCar_spec* pCar) {
LOG_TRACE("(%p)", pCar);
NOT_IMPLEMENTED();
STUB_ONCE();
}
// IDA: void __usercall CheckHorn3D(tCar_spec *pCar@<EAX>)
void CheckHorn3D(tCar_spec* pCar) {
LOG_TRACE("(%p)", pCar);
NOT_IMPLEMENTED();
STUB_ONCE();
}
// IDA: void __cdecl CheckHorns()
void CheckHorns() {
int i;
LOG_TRACE("()");
NOT_IMPLEMENTED();
if (gNet_mode) {
for (i = 0; i < gNumber_of_net_players; ++i) {
CheckHorn3D(gNet_players[i].car);
}
} else {
CheckHornLocal(&gProgram_state.current_car);
}
}
// IDA: void __cdecl SetRecovery()
void SetRecovery() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
if (gRace_finished
|| gProgram_state.current_car.knackered
|| gWait_for_it
|| gHad_auto_recover
|| gPalette_fade_time) {
return;
}
if (gNet_mode == eNet_mode_none) {
gRecover_car = 1;
gRecover_timer = 0;
return;
}
if (gProgram_state.current_car.time_to_recover) {
if (GetRaceTime() + 600 >= gProgram_state.current_car.time_to_recover) {
NewTextHeadupSlot2(4, 0, 2000, -4, GetMiscString(242), 1);
gToo_late = 1;
} else {
gProgram_state.current_car.time_to_recover = 0;
NewTextHeadupSlot2(4, 0, 2000, -4, GetMiscString(125), 0);
}
return;
}
if (!CheckRecoverCost()) {
return;
}
if (gCurrent_net_game->type == eNet_game_type_foxy) {
if (gThis_net_player_index == gIt_or_fox) {
gProgram_state.current_car.time_to_recover = GetRaceTime() + 5000;
gRecover_timer = 0;
gToo_late = 0;
return;
}
} else {
if (gCurrent_net_game->type != eNet_game_type_tag) {
gProgram_state.current_car.time_to_recover = GetRaceTime() + 3000;
gRecover_timer = 0;
gToo_late = 0;
return;
}
if (gThis_net_player_index != gIt_or_fox) {
gProgram_state.current_car.time_to_recover = GetRaceTime() + 5000;
gRecover_timer = 0;
gToo_late = 0;
return;
}
}
gProgram_state.current_car.time_to_recover = GetRaceTime() + 1000;
gRecover_timer = 0;
gToo_late = 0;
}
// IDA: void __cdecl RecoverCar()
void RecoverCar() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
if (gNet_mode == eNet_mode_none || !gPalette_fade_time) {
gRecover_car = 1;
}
gProgram_state.current_car.time_to_recover = 0;
}
// IDA: void __cdecl CheckMapRenderMove()
@ -674,7 +769,8 @@ void CheckMapRenderMove() {
float old_x;
float old_y;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB_ONCE();
}
// IDA: void __usercall ExplodeCar(tCar_spec *pCar@<EAX>)
@ -691,14 +787,47 @@ void CheckRecoveryOfCars(tU32 pEndFrameTime) {
int time;
char s[256];
LOG_TRACE("(%d)", pEndFrameTime);
STUB_ONCE();
if (gProgram_state.current_car.time_to_recover) {
if (gProgram_state.current_car.knackered) {
gProgram_state.current_car.time_to_recover = 0;
} else {
time = (gProgram_state.current_car.time_to_recover - pEndFrameTime + 1000) / 1000;
sprintf(s, "%s %d %s", GetMiscString(97), time, time > 1 ? GetMiscString(99) : GetMiscString(98));
if (!gToo_late) {
NewTextHeadupSlot2(4, 0, 2000, -4, s, 0);
}
if (gProgram_state.current_car.time_to_recover <= pEndFrameTime) {
RecoverCar();
}
}
}
if (gNet_mode) {
for (i = 0; i < gNumber_of_net_players; i++) {
if (gThis_net_player_index != i && gNet_players[i].car->time_to_recover && gNet_players[i].car->time_to_recover <= pEndFrameTime) {
gNet_players[i].player_status = ePlayer_status_recovering;
gNet_players[i].car->message.type = 32;
gNet_players[i].car->message.time = pEndFrameTime;
ExplodeCar(gNet_players[i].car);
gNet_players[i].car->time_to_recover = 0;
}
}
}
}
// IDA: void __usercall LoseSomePSPowerups(int pNumber@<EAX>)
void LoseSomePSPowerups(int pNumber) {
int index;
LOG_TRACE("(%d)", pNumber);
NOT_IMPLEMENTED();
if (gNet_mode && pNumber > 0) {
while (pNumber--) {
index = IRandomBetween(0, 2);
if (gProgram_state.current_car.power_up_levels[index]) {
gProgram_state.current_car.power_up_levels[index]--;
}
}
}
}
// IDA: void __cdecl CheckOtherRacingKeys()
@ -722,13 +851,158 @@ void CheckOtherRacingKeys() {
static int stopped_repairing;
LOG_TRACE("()");
STUB_ONCE();
car = GetCarSpec(eVehicle_self, 0);
CheckMapRenderMove();
CheckHorns();
CheckForBeingOutOfThisWorld();
if (gPalette_fade_time) {
SortOutRecover(car);
} else if (gNet_mode && NetGetPlayerStatus() == ePlayer_status_recovering) {
NetPlayerStatusChanged(ePlayer_status_racing);
}
if ((!gAuto_repair && !KeyIsDown(44))
|| gRace_finished
|| gProgram_state.current_car.knackered
|| gWait_for_it
|| gEntering_message) {
gRepair_last_time = 0;
stopped_repairing = 0;
total_repair_cost = 0;
total_difference = 0;
if (sound_tag) {
for (i = 0; i < 10 && S3SoundStillPlaying(sound_tag); ++i) {
DRS3StopSound(sound_tag);
}
sound_tag = 0;
}
} else {
if (!gAuto_repair && !gRepair_last_time && GetTotalTime() - gLast_repair_time < 1200) {
gAuto_repair = 1;
}
gLast_repair_time = GetTotalTime();
gRepair_last_time = 1;
if (!NeedToExpandBoundingBox) {
if (gFree_repairs
|| gNet_mode == eNet_mode_none
|| gProgram_state.credits_earned - gProgram_state.credits_lost >= 1) {
bodywork_repair_amount = RepairCar(gProgram_state.current_car.car_ID, gFrame_period, &amount);
NeedToExpandBoundingBox = bodywork_repair_amount > 0;
cost = 0;
for (j = 0; j < COUNT_OF(gProgram_state.current_car.damage_units); j++) {
old_level = gProgram_state.current_car.damage_units[j].damage_level;
if (amount == 0.0) {
new_level = 0;
} else {
new_level = ((double)gProgram_state.current_car.damage_units[j].damage_level
- floor(bodywork_repair_amount / amount * (double)gProgram_state.current_car.damage_units[j].damage_level));
}
if (new_level >= 0) {
if (new_level < 100) {
gProgram_state.current_car.damage_units[j].damage_level = new_level;
} else {
gProgram_state.current_car.damage_units[j].damage_level = 99;
}
} else {
gProgram_state.current_car.damage_units[j].damage_level = 0;
}
gProgram_state.current_car.damage_units[j].smoke_last_level = gProgram_state.current_car.damage_units[j].damage_level;
if (gNet_mode) {
ts = gNet_repair_cost[gCurrent_net_game->type];
} else {
ts = gRepair_cost[gProgram_state.skill_level];
}
cost = (old_level - gProgram_state.current_car.damage_units[j].damage_level) * ts + cost;
total_difference += old_level - new_level;
}
if (!gFree_repairs) {
LoseSomePSPowerups(total_difference / 100);
}
total_difference %= 100;
cost = 10 * (cost / 10);
if (((!total_repair_cost && cost) || bodywork_repair_amount != 0.0) && !sound_tag) {
sound_tag = DRS3StartSound(gIndexed_outlets[1], 5200);
}
if (gProgram_state.current_car.num_smoke_columns) {
StopCarSmoking(&gProgram_state.current_car);
}
if (!cost && bodywork_repair_amount == 0.0) {
gAuto_repair = 0;
}
if (!gFree_repairs) {
cost += SpendCredits(cost);
}
total_repair_cost += cost;
if (total_repair_cost) {
if (gFree_repairs) {
NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(4));
} else {
sprintf(s, "%s %d", GetMiscString(5), total_repair_cost);
NewTextHeadupSlot(4, 0, 1000, -4, s);
}
}
} else {
if (!stopped_repairing) {
NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(95));
}
gAuto_repair = 0;
stopped_repairing = 1;
}
}
}
if (NeedToExpandBoundingBox) {
NeedToExpandBoundingBox = ExpandBoundingBox(&gProgram_state.current_car) == 0;
}
if (!gRecover_car || gProgram_state.current_car.knackered) {
gHad_auto_recover = 0;
} else if (CheckRecoverCost()) {
gRecover_timer = 0;
SetFlipUpCar(car);
if (gNet_mode) {
NewTextHeadupSlot(4, 0, 1500, -4, " ");
}
if (gRecovery_voucher_count) {
gRecovery_voucher_count--;
sprintf(s, "%s", GetMiscString(48));
NewTextHeadupSlot(4, 0, 1500, -4, s);
} else {
if (gNet_mode) {
cost = gNet_recovery_cost[gCurrent_net_game->type];
} else {
cost = gRecovery_cost[gProgram_state.skill_level];
}
SpendCredits(cost);
if (gNet_mode) {
cost = gNet_recovery_cost[gCurrent_net_game->type];
} else {
cost = gRecovery_cost[gProgram_state.skill_level];
}
sprintf(s, "%s %d", GetMiscString(7), cost);
NewTextHeadupSlot(4, 0, 1500, -4, s);
LoseSomePSPowerups(2);
}
CancelPendingCunningStunt();
PipeSingleSpecial(ePipe_special_fade);
}
gRecover_car = 0;
}
// IDA: int __cdecl CheckRecoverCost()
int CheckRecoverCost() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
if (gProgram_state.current_car.knackered
|| gNet_mode == eNet_mode_none
|| (gProgram_state.credits_earned - gProgram_state.credits_lost) >= gNet_recovery_cost[gCurrent_net_game->type]
|| gRecovery_voucher_count) {
return 1;
}
gProgram_state.credits_earned = 0;
gProgram_state.credits_lost = 0;
NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(96));
DoFancyHeadup(18);
KnackerThisCar(&gProgram_state.current_car);
SendGameplayToHost(eNet_gameplay_suicide, 0, 0, 0, 0);
return 0;
}
// IDA: void __usercall SortOutRecover(tCar_spec *pCar@<EAX>)
@ -743,7 +1017,14 @@ void SortOutRecover(tCar_spec* pCar) {
// IDA: void __usercall SetFlipUpCar(tCar_spec *pCar@<EAX>)
void SetFlipUpCar(tCar_spec* pCar) {
LOG_TRACE("(%p)", pCar);
NOT_IMPLEMENTED();
if (gNet_mode && pCar->driver == eDriver_local_human) {
DisableCar(pCar);
gPalette_fade_time = GetRaceTime();
NetPlayerStatusChanged(ePlayer_status_recovering);
} else {
FlipUpCar(pCar);
}
}
// IDA: void __usercall FlipUpCar(tCar_spec *car@<EAX>)
@ -759,7 +1040,97 @@ void FlipUpCar(tCar_spec* car) {
br_material* material;
br_scalar t;
LOG_TRACE("(%p)", car);
NOT_IMPLEMENTED();
count = 0;
if (car->driver == eDriver_local_human && gNet_mode == eNet_mode_none) {
FadePaletteDown();
while (KeyIsDown(44)) {
;
}
}
car->doing_nothing_flag = 0;
EnableCar(car);
new_pos = 1;
for (i = 0; i < 4; ++i) {
if (car->susp_height[i >> 1] <= car->oldd[i]) {
new_pos = 0;
}
}
do {
tv.v[0] = car->car_master_actor->t.t.mat.m[3][0] - car->last_safe_positions[0].m[3][0];
tv.v[1] = car->car_master_actor->t.t.mat.m[3][1] - car->last_safe_positions[0].m[3][1];
tv.v[2] = car->car_master_actor->t.t.mat.m[3][2] - car->last_safe_positions[0].m[3][2];
if (BrVector3LengthSquared(&tv) > 8.3015966) {
new_pos = 0;
}
BrMatrix34Copy(&car->car_master_actor->t.t.mat, &car->last_safe_positions[new_pos]);
BrMatrix34Copy(&car->oldmat, &car->last_safe_positions[new_pos]);
BrMatrix34Copy(&car->old_frame_mat, &car->oldmat);
car->oldmat.m[3][0] = car->oldmat.m[3][0] * WORLD_SCALE;
car->oldmat.m[3][1] = car->oldmat.m[3][1] * WORLD_SCALE;
car->oldmat.m[3][2] = car->oldmat.m[3][2] * WORLD_SCALE;
dir.v[0] = 0.0;
dir.v[1] = 0.28985506;
dir.v[2] = 0.0;
FindFace(&car->car_master_actor->t.t.euler.t, &dir, &tv, &t, &material);
if (t > 1.0) {
car->car_master_actor->t.t.mat.m[3][0] += dir.v[0];
car->car_master_actor->t.t.mat.m[3][1] += dir.v[1];
car->car_master_actor->t.t.mat.m[3][2] += dir.v[2];
car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
car->old_frame_mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0];
car->old_frame_mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1];
car->old_frame_mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2];
}
tv.v[0] = 0.0;
tv.v[1] = 0.0;
tv.v[2] = -0.001;
BrMatrix34ApplyV(&car->v, &tv, &car->car_master_actor->t.t.mat);
car->omega.v[0] = 0.0;
car->omega.v[1] = 0.0;
car->omega.v[2] = 0.0;
car->direction.v[0] = -car->oldmat.m[2][0];
car->direction.v[1] = -car->oldmat.m[2][1];
car->direction.v[2] = -car->oldmat.m[2][2];
for (i = 0; i <= new_pos; i++) {
for (j = 0; j < 4; j++) {
BrMatrix34Copy(&car->last_safe_positions[j], &car->last_safe_positions[j + 1]);
}
}
for (l = 0; l < 10; l++) {
BrVector3Scale(&car->old_norm, &car->old_norm, 0.072463766);
BrMatrix34ApplyV(&tv, &car->old_norm, &car->car_master_actor->t.t.mat);
car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] + tv.v[0];
car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] + tv.v[1];
car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] + tv.v[2];
car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
car->old_frame_mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0];
car->old_frame_mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1];
car->old_frame_mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2];
if (TestForCarInSensiblePlace(car)) {
break;
}
}
count++;
} while (l == 10 && count < 3);
car->oldmat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * WORLD_SCALE;
car->oldmat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * WORLD_SCALE;
car->oldmat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * WORLD_SCALE;
car->curvature = 0.0;
for (j = 0; j < 4; ++j) {
car->oldd[j] = car->ride_height;
}
car->revs = 0.0;
car->gear = 0;
car->auto_special_volume = 0;
if (car->driver == eDriver_local_human) {
InitialiseExternalCamera();
PositionExternalCamera(car, 100u);
}
}
// IDA: void __usercall GetPowerup(int pNum@<EAX>)
@ -1068,6 +1439,8 @@ void ToggleArrow() {
static br_actor* old_actor;
LOG_TRACE("()");
return;
if (gArrow_mode) {
gProgram_state.current_car.car_model_actors[gProgram_state.current_car.principal_car_actor].actor = old_actor;
BrActorRemove(gArrow_actor);

View File

@ -1,5 +1,6 @@
#include "crush.h"
#include "brender/brender.h"
#include "globvars.h"
#include "harness/trace.h"
#include "loading.h"
#include "utility.h"
@ -215,7 +216,10 @@ void TotallyRepairACar(tCar_spec* pCar) {
// IDA: void __cdecl TotallyRepairCar()
void TotallyRepairCar() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
if (!gArrow_mode) {
TotallyRepairACar(&gProgram_state.current_car);
}
}
// IDA: void __cdecl CheckLastCar()

View File

@ -165,7 +165,24 @@ void DoEndRaceAnimation() {
int made_a_profit;
int went_up_a_rank;
LOG_TRACE("()");
NOT_IMPLEMENTED();
made_a_profit = gProgram_state.credits_earned > gProgram_state.credits_lost;
went_up_a_rank = gProgram_state.credits_earned > gProgram_state.credits_per_rank;
FadePaletteDown();
if (gAusterity_mode || gNet_mode) {
return;
}
if (gProgram_state.credits + gProgram_state.credits_earned - gProgram_state.credits_lost >= 0) {
if (!made_a_profit && !went_up_a_rank) {
PlaySmackerFile("UNSUCSES.SMK");
} else if (!made_a_profit || !went_up_a_rank) {
PlaySmackerFile("MUNDANE.SMK");
} else {
PlaySmackerFile("SUCCESS.SMK");
}
}
}
// IDA: void __cdecl DoGameOverAnimation()

View File

@ -1176,7 +1176,19 @@ void EarnCredits(int pAmount) {
int SpendCredits(int pAmount) {
int amount;
LOG_TRACE("(%d)", pAmount);
NOT_IMPLEMENTED();
LOG_DEBUG("spending");
gProgram_state.credits_lost += pAmount;
if (gNet_mode == eNet_mode_none) {
return 0;
}
amount = gProgram_state.credits_earned - gProgram_state.credits_lost;
if (gProgram_state.credits_earned - gProgram_state.credits_lost >= 0) {
return 0;
}
gProgram_state.credits_lost = gProgram_state.credits_earned;
return amount;
}
// IDA: void __usercall AwardTime(tU32 pTime@<EAX>)

View File

@ -584,6 +584,7 @@ void PlayFlicsInDarkness() {
void ReilluminateFlics() {
LOG_TRACE("()");
gDark_mode = 0;
FadePaletteUp();
}
// IDA: void __cdecl TurnFlicTransparencyOn()

View File

@ -9,6 +9,7 @@
#include "globvars.h"
#include "globvrpb.h"
#include "grafdata.h"
#include "harness/hooks.h"
#include "harness/trace.h"
#include "init.h"
#include "loading.h"
@ -882,7 +883,6 @@ void RenderAFrame(int pDepth_mask_on) {
static int frame_counter;
frame_counter++;
//LOG_DEBUG("%d", frame_counter);
gRender_screen->pixels = gBack_screen->pixels;
the_time = GetTotalTime();
@ -1184,7 +1184,7 @@ void RenderAFrame(int pDepth_mask_on) {
PipeFrameFinish();
}
gRender_screen->pixels = old_pixels;
if (!gRecover_timer || GetRaceTime() > gRecover_timer + 500) {
if (!gPalette_fade_time || GetRaceTime() > gPalette_fade_time + 500) {
PDScreenBufferSwap(0);
}
if (gAction_replay_mode) {
@ -1238,7 +1238,7 @@ void ResetPalette() {
// IDA: void __usercall Darken(tU8 *pPtr@<EAX>, unsigned int pDarken_amount@<EDX>)
void Darken(tU8* pPtr, unsigned int pDarken_amount) {
unsigned int value;
//LOG_TRACE("(%p, %d)", pPtr, pDarken_amount);
LOG_TRACE10("(%p, %d)", pPtr, pDarken_amount);
*pPtr = (pDarken_amount * *pPtr) / 256;
}
@ -1247,9 +1247,11 @@ void Darken(tU8* pPtr, unsigned int pDarken_amount) {
void SetFadedPalette(int pDegree) {
int j;
br_pixelmap* the_palette;
unsigned char* the_pixels; //Jeff added unsigned
char* the_pixels;
LOG_TRACE10("(%d)", pDegree);
Harness_Hook_SetFadedPalette(pDegree);
memcpy(gScratch_pixels, gCurrent_palette->pixels, 0x400u);
for (j = 0; j < 256; j++) {
Darken((tU8*)&gScratch_pixels[4 * j], pDegree);
@ -1265,6 +1267,7 @@ void FadePaletteDown() {
int i;
int start_time;
int the_time;
LOG_TRACE("()");
if (!gFaded_palette) {
gFaded_palette = 1;
@ -1289,6 +1292,7 @@ void FadePaletteUp() {
int i;
int start_time;
int the_time;
LOG_TRACE("()");
if (gFaded_palette) {
gFaded_palette = 0;
@ -2019,7 +2023,8 @@ void SaveShadeTables() {
void DisposeSavedShadeTables() {
int i;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __cdecl ShadowMode()

View File

@ -26,6 +26,7 @@
#include "opponent.h"
#include "pd/sys.h"
#include "pedestrn.h"
#include "piping.h"
#include "powerup.h"
#include "pratcam.h"
#include "raycast.h"
@ -483,7 +484,8 @@ void LoadInTrack() {
// IDA: void __cdecl DisposeTrack()
void DisposeTrack() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
FreeTrack(&gProgram_state.track_spec);
}
// IDA: void __usercall CopyMaterialColourFromIndex(br_material *pMaterial@<EAX>)
@ -614,7 +616,33 @@ void InitRace() {
// IDA: void __cdecl DisposeRace()
void DisposeRace() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
PossibleService();
DisposePiping();
PossibleService();
CloseDownPowerUps();
PossibleService();
if (!TranslationMode()) {
DisposeFont(1);
DisposeFont(2);
DisposeFont(3);
}
PossibleService();
DisposeFont(6);
DisposeFont(7);
DisposeFont(8);
DisposeFont(4);
DisposeFont(5);
PossibleService();
DisposeSavedShadeTables();
PossibleService();
DisposeSoundSources();
PossibleService();
DisposeOpponents();
PossibleService();
DisposePedestrians();
PossibleService();
DisposePratcam();
PossibleService();
}
// IDA: int __cdecl GetScreenSize()

View File

@ -1103,7 +1103,6 @@ void ReadMechanicsData(FILE* pF, tCar_spec* c) {
LOG_TRACE("(%p, %p)", pF, c);
GetALineAndDontArgue(pF, s);
LOG_DEBUG("s %s", s);
for (i = strlen(s) - 1; s[i] == ' '; --i) {
;
}
@ -1185,7 +1184,6 @@ void ReadMechanicsData(FILE* pF, tCar_spec* c) {
c->mu[1] *= sqrt((c->wpos[0].v[2] - c->cmpos.v[2]) / (c->wpos[0].v[2] - c->wpos[2].v[2]) * (c->M * 5.0));
c->mu[2] *= sqrt((c->wpos[2].v[2] - c->cmpos.v[2]) / (c->wpos[2].v[2] - c->wpos[0].v[2]) * (c->M * 5.0));
LOG_DEBUG("%f %f %f", c->mu[0], c->mu[1], c->mu[2]);
for (i = 0; i < 4; ++i) {
c->wpos[i].v[1] = c->ride_height;
}
@ -2094,7 +2092,7 @@ void LoadHeadupImages() {
tPath_name the_path;
LOG_TRACE("()");
for (i = 0; i < 31; ++i) {
for (i = 0; i < COUNT_OF(gHeadup_image_info); i++) {
PossibleService();
if (gHeadup_image_info[i].avail && (gHeadup_image_info[i].avail != eNot_net || gNet_mode) && (gHeadup_image_info[i].avail != eNet_only || !gNet_mode)) {
gHeadup_images[i] = NULL;
@ -2829,7 +2827,17 @@ void LoadOpponentsCars(tRace_info* pRace_info) {
void DisposeOpponentsCars(tRace_info* pRace_info) {
int i;
LOG_TRACE("(%p)", pRace_info);
NOT_IMPLEMENTED();
for (i = 0; i < pRace_info->number_of_racers; i++) {
PossibleService();
if (pRace_info->opponent_list[i].index >= 0) {
if (pRace_info->opponent_list[i].car_spec) {
DisposeCar(pRace_info->opponent_list[i].car_spec, pRace_info->opponent_list[i].index);
BrMemFree(pRace_info->opponent_list[i].car_spec);
}
}
}
ClearOutStorageSpace(&gTheir_cars_storage_space);
}
// IDA: void __cdecl LoadMiscStrings()
@ -3045,7 +3053,7 @@ int TestForOriginalCarmaCDinDrive() {
int paths_txt_first_char;
// Jeff: Added to optionally bypass this check
if (harness_disable_cd_check) {
if (harness_game_config.disable_cd_check) {
return 1;
}

View File

@ -12,6 +12,7 @@
#include "globvrpb.h"
#include "graphics.h"
#include "harness/config.h"
#include "harness/hooks.h"
#include "harness/trace.h"
#include "input.h"
#include "main.h"
@ -389,9 +390,6 @@ void UpdateFramePeriod(tU32* pCamera_period) {
} else {
*pCamera_period = 10;
}
// todo: FPS limiter
//usleep(40 * 1000);
}
// IDA: tU32 __cdecl GetLastTickCount()
@ -506,8 +504,6 @@ tRace_result MainGameLoop() {
ForceRebuildActiveCarList();
PrintMemoryDump(0, "ABOUT TO ENTER MAINLOOP");
double last_time = GetTotalTime() / 1000.0;
do {
frame_start_time = GetTotalTime();
CyclePollKeys();
@ -582,15 +578,16 @@ tRace_result MainGameLoop() {
CheckReplayTurnOn();
if (!gRecover_car
&& gProgram_state.prog_status == eProg_game_ongoing
&& !gRecover_timer
&& !gPalette_fade_time
&& (gNet_mode == eNet_mode_none
|| !gAction_replay_mode
|| gProgram_state.current_car.car_master_actor->t.t.mat.m[3][0] < 500.0)) {
EnsureRenderPalette();
EnsurePaletteUp();
}
DoNetGameManagement();
if (KeyIsDown(0) && !gEntering_message) {
if (KeyIsDown(KEYMAP_ESCAPE) && !gEntering_message) {
WaitForNoKeys();
if (gAction_replay_mode) {
ToggleReplay();
@ -625,15 +622,7 @@ tRace_result MainGameLoop() {
gAbandon_game = 0;
}
// Added to lock framerate to 30fps. Seems to help physics be less twitchy...
double secs = GetTotalTime();
//LOG_DEBUG("timediff %f", secs - (last_time + (1.0 / 30.0)));
// while (secs < last_time + (1.0 / 30.0) * 1000) {
// //LOG_DEBUG("skipping time...");
// secs = GetTotalTime();
// }
//usleep(50 * 1000);
//last_time += (1.0 / 30.0) * 1000;
Harness_Hook_MainGameLoop();
} while (gProgram_state.prog_status == eProg_game_ongoing
&& !MungeRaceFinished()

View File

@ -538,44 +538,43 @@ int DoVerifyQuit(int pReplace_background) {
// IDA: tMM_result __usercall DoMainMenu@<EAX>(tU32 pTime_out@<EAX>, int pSave_allowed@<EDX>, int pContinue_allowed@<EBX>)
tMM_result DoMainMenu(tU32 pTime_out, int pSave_allowed, int pContinue_allowed) {
tMM_result the_result;
LOG_TRACE("(%d, %d, %d)", pTime_out, pSave_allowed, pContinue_allowed);
if (gProgram_state.racing) {
FadePaletteDown(pTime_out);
FadePaletteDown();
}
the_result = GetMainMenuOption(pTime_out, pContinue_allowed);
switch (the_result) {
case eMM_end_game:
if (!gNet_mode) {
break;
if (gNet_mode) {
gProgram_state.prog_status = eProg_idling;
}
gProgram_state.prog_status = eProg_idling;
break;
case eMM_1_start:
if (pContinue_allowed || gAusterity_mode) {
PlayFlicsFromMemory();
}
if (!DoOnePlayerStart()) {
the_result = 0;
the_result = eMM_none;
}
if (!pContinue_allowed && !gAusterity_mode) {
break;
if (pContinue_allowed || gAusterity_mode) {
PlayFlicsFromDisk();
}
PlayFlicsFromDisk();
break;
case eMM_n_start:
if (DoMultiPlayerStart()) {
break;
if (!DoMultiPlayerStart()) {
LoadRaces(gRace_list, &gNumber_of_races, -1);
the_result = eMM_none;
}
LoadRaces(gRace_list, &gNumber_of_races, -1);
the_result = 0;
break;
case eMM_loaded:
if (!DoLoadGame(the_result)) {
the_result = 0;
if (!DoLoadGame()) {
the_result = eMM_none;
}
break;
case eMM_save:
DoSaveGame(pSave_allowed);
the_result = 0;
the_result = eMM_none;
break;
case eMM_options:
LoadSoundOptionsData();
@ -583,10 +582,9 @@ tMM_result DoMainMenu(tU32 pTime_out, int pSave_allowed, int pContinue_allowed)
FreeSoundOptionsData();
break;
case eMM_quit:
if (DoVerifyQuit(0)) {
break;
if (!DoVerifyQuit(0)) {
the_result = eMM_none;
}
the_result = 0;
break;
case eMM_recover:
SetRecovery();
@ -595,7 +593,7 @@ tMM_result DoMainMenu(tU32 pTime_out, int pSave_allowed, int pContinue_allowed)
gAbandon_game = 1;
break;
default:
break;
return the_result;
}
return the_result;
}
@ -603,6 +601,7 @@ tMM_result DoMainMenu(tU32 pTime_out, int pSave_allowed, int pContinue_allowed)
// IDA: void __usercall DoMainMenuScreen(tU32 pTime_out@<EAX>, int pSave_allowed@<EDX>, int pContinue_allowed@<EBX>)
void DoMainMenuScreen(tU32 pTime_out, int pSave_allowed, int pContinue_allowed) {
tPlayer_status old_status;
LOG_TRACE("(%d, %d, %d)", pTime_out, pSave_allowed, pContinue_allowed);
if (pContinue_allowed || gAusterity_mode) {
PlayFlicsFromDisk();

View File

@ -3,6 +3,7 @@
#include "globvrpb.h"
#include "harness/trace.h"
#include "network.h"
#include "opponent.h"
#include <stdlib.h>
int gPowerup_cost[4];
@ -142,7 +143,21 @@ void DisableCar(tCar_spec* pCar) {
// IDA: void __usercall EnableCar(tCar_spec *pCar@<EAX>)
void EnableCar(tCar_spec* pCar) {
LOG_TRACE("(%p)", pCar);
NOT_IMPLEMENTED();
if (pCar->driver_name[0]) {
if (pCar->disabled) {
pCar->disabled = 0;
ForceRebuildActiveCarList();
}
if (pCar->car_master_actor->t.t.mat.m[3][0] > 500.0) {
pCar->car_master_actor->t.t.mat.m[3][0] = pCar->car_master_actor->t.t.mat.m[3][0] - 1000.0f;
pCar->car_master_actor->t.t.mat.m[3][1] = pCar->car_master_actor->t.t.mat.m[3][1] - 1000.0f;
pCar->car_master_actor->t.t.mat.m[3][2] = pCar->car_master_actor->t.t.mat.m[3][2] - 1000.0f;
pCar->old_frame_mat.m[3][0] = pCar->car_master_actor->t.t.mat.m[3][0];
pCar->old_frame_mat.m[3][1] = pCar->car_master_actor->t.t.mat.m[3][1];
pCar->old_frame_mat.m[3][2] = pCar->car_master_actor->t.t.mat.m[3][2];
}
}
}
// IDA: void __usercall DoNetworkHeadups(int pCredits@<EAX>)

View File

@ -944,7 +944,8 @@ void InitOpponents(tRace_info* pRace_info) {
void DisposeOpponents() {
int i;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __usercall WakeUpOpponentsToTheFactThatTheStartHasBeenJumped(int pWhat_the_countdown_was@<EAX>)

View File

@ -1546,7 +1546,8 @@ void DisposePedestrians() {
int j;
tPedestrian_data* the_pedestrian;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __cdecl DoPedReport()

View File

@ -338,7 +338,8 @@ void PipeSingleDamage(int pCar_ID, tS8* pDifferences) {
// IDA: void __usercall PipeSingleSpecial(tSpecial_type pType@<EAX>)
void PipeSingleSpecial(tSpecial_type pType) {
LOG_TRACE("(%d)", pType);
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __usercall PipeSinglePedGib(int pIndex@<EAX>, br_matrix34 *pTrans@<EDX>, int pSize@<EBX>, int pGib_index@<ECX>, int pPed_index)
@ -411,7 +412,8 @@ void InitialisePiping() {
// IDA: void __cdecl DisposePiping()
void DisposePiping() {
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __cdecl InitLastDamageArrayEtc()

View File

@ -151,7 +151,8 @@ void CloseDownPowerUps() {
int i;
tPowerup* the_powerup;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __usercall DrawPowerups(tU32 pTime@<EAX>)

View File

@ -91,7 +91,8 @@ void ChangeAmbientPratcamNow(int pIndex, int pStart_chunk) {
// IDA: void __usercall ChangeAmbientPratcam(int pIndex@<EAX>)
void ChangeAmbientPratcam(int pIndex) {
LOG_TRACE("(%d)", pIndex);
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __usercall PratcamEventNow(int pIndex@<EAX>)
@ -135,7 +136,8 @@ void DisposePratcam() {
int k;
int l;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __usercall DoPratcam(tU32 pThe_time@<EAX>)

View File

@ -350,5 +350,7 @@ void DoNetRaceSummary() {
tSO_result DoEndRaceSummary(int* pFirst_summary_done, tRace_result pRace_result) {
tSO_result result;
LOG_TRACE("(%p, %d)", pFirst_summary_done, pRace_result);
NOT_IMPLEMENTED();
STUB();
return eSO_main_menu_invoked;
}

View File

@ -126,7 +126,12 @@ int DRS3ChangePitchSpeed(tS3_sound_tag pTag, tS3_pitch pNew_pitch) {
// IDA: int __usercall DRS3StopSound@<EAX>(tS3_sound_tag pSound_tag@<EAX>)
int DRS3StopSound(tS3_sound_tag pSound_tag) {
LOG_TRACE("(%d)", pSound_tag);
NOT_IMPLEMENTED();
if (gSound_enabled) {
return S3StopSound(pSound_tag);
} else {
return 0;
}
}
// IDA: int __usercall DRS3LoadSound@<EAX>(tS3_sound_id pThe_sound@<EAX>)
@ -222,7 +227,8 @@ void DisposeSoundSources() {
int toggle;
tCar_spec* the_car;
LOG_TRACE("()");
NOT_IMPLEMENTED();
STUB();
}
// IDA: tS3_sound_tag __usercall DRS3StartSound3D@<EAX>(tS3_outlet_ptr pOutlet@<EAX>, tS3_sound_id pSound@<EDX>, br_vector3 *pInitial_position@<EBX>, br_vector3 *pInitial_velocity@<ECX>, tS3_repeats pRepeats, tS3_volume pVolume, tS3_pitch pPitch, tS3_speed pSpeed)

View File

@ -1,5 +1,6 @@
#include "structur.h"
#include "car.h"
#include "controls.h"
#include "crush.h"
#include "cutscene.h"
#include "displays.h"
@ -17,8 +18,10 @@
#include "mainloop.h"
#include "mainmenu.h"
#include "netgame.h"
#include "network.h"
#include "opponent.h"
#include "piping.h"
#include "pratcam.h"
#include "racestrt.h"
#include "racesumm.h"
#include "sound.h"
@ -66,7 +69,60 @@ int NumberOfOpponentsLeft() {
// IDA: void __usercall RaceCompleted(tRace_over_reason pReason@<EAX>)
void RaceCompleted(tRace_over_reason pReason) {
LOG_TRACE("(%d)", pReason);
NOT_IMPLEMENTED();
if (!gRace_finished) {
if (gNet_mode == eNet_mode_host && pReason < eRace_over_network_victory) {
NetFinishRace(gCurrent_net_game, pReason);
}
if (pReason == eRace_over_out_of_time || pReason == eRace_over_demo) {
ChangeAmbientPratcam(35);
} else if (pReason < eRace_over_abandoned) {
ChangeAmbientPratcam(34);
}
gRace_over_reason = pReason;
if (gMap_mode) {
ToggleMap();
}
switch (gRace_over_reason) {
case eRace_over_laps:
case eRace_over_peds:
case eRace_over_opponents:
ChangeAmbientPratcam(34);
DoFancyHeadup(14);
DRS3StartSound(gIndexed_outlets[4], 8011);
break;
case eRace_over_abandoned:
if (gNet_mode == eNet_mode_client) {
gHost_abandon_game = 1;
NetFullScreenMessage(87, 0);
}
break;
case eRace_over_out_of_time:
ChangeAmbientPratcam(35);
DoFancyHeadup(13);
DRS3StartSound(gIndexed_outlets[4], 8010);
break;
case eRace_over_demo:
ChangeAmbientPratcam(35);
DoFancyHeadup(21);
break;
case eRace_over_network_victory:
ChangeAmbientPratcam(34);
DoFancyHeadup(20);
break;
case eRace_over_network_loss:
ChangeAmbientPratcam(36);
DoFancyHeadup(17);
break;
default:
break;
}
if (gNet_mode) {
gRace_finished = 8000;
} else {
gRace_finished = 4000;
}
}
}
// IDA: void __usercall Checkpoint(int pCheckpoint_index@<EAX>, int pDo_sound@<EDX>)

View File

@ -426,11 +426,7 @@ br_pixelmap* DRPixelmapLoad(char* pFile_name) {
if (the_map) {
the_map->origin_x = 0;
the_map->origin_y = 0;
lobyte = the_map->row_bytes & 0xff;
lobyte += 3;
lobyte &= 0xfc;
the_map->row_bytes = (the_map->row_bytes & 0xff00) | lobyte;
the_map->row_bytes = (the_map->row_bytes + 3) & 0xFFFC;
}
return the_map;
}
@ -446,10 +442,7 @@ br_uint_32 DRPixelmapLoadMany(char* pFile_name, br_pixelmap** pPixelmaps, br_uin
number_loaded = BrPixelmapLoadMany(pFile_name, pPixelmaps, pNum);
for (i = 0; i < number_loaded; i++) {
the_map = pPixelmaps[i];
lobyte = the_map->row_bytes & 0xff;
lobyte += 3;
lobyte &= 0xfc;
the_map->row_bytes = (the_map->row_bytes & 0xff00) | lobyte;
the_map->row_bytes = (the_map->row_bytes + 3) & 0xFFFC;
the_map->base_x = 0;
the_map->base_y = 0;
}

View File

@ -2524,7 +2524,8 @@ void FreeTrack(tTrack_spec* pTrack_spec) {
int i;
tNon_car_spec* non_car;
LOG_TRACE("(%p)", pTrack_spec);
NOT_IMPLEMENTED();
STUB();
}
// IDA: void __usercall ProcessTrack(br_actor *pWorld@<EAX>, tTrack_spec *pTrack_spec@<EDX>, br_actor *pCamera@<EBX>, br_matrix34 *pCamera_to_world_transform@<ECX>, int pRender_blends)

View File

@ -237,6 +237,7 @@ typedef enum keycodes {
} keycodes;
typedef enum keymapcodes {
KEYMAP_ESCAPE = 0,
KEYMAP_Q = 1,
KEYMAP_S = 2,
KEYMAP_L = 3,
@ -288,8 +289,6 @@ typedef enum keymapcodes {
#define d180_OVER_PI 57.29577951308232 // (180 / PI)
#define PHYSICS_STEP_TIME 40.0
#define DR_PI 3.141592653589793
#define TIME_CONV_THING 0.00050000002

View File

@ -6,5 +6,7 @@
void S3Service(int inside_cockpit, int unk1);
tS3_sound_tag S3StartSound(tS3_outlet_ptr pOutlet, tS3_sound_id pSound);
void S3StopAllOutletSounds();
int S3SoundStillPlaying(tS3_sound_tag pSound);
int S3StopSound(tS3_sound_tag pSound_tag);
#endif

View File

@ -14,4 +14,12 @@ void S3StopAllOutletSounds() {
tS3_sound_tag S3StartSound(tS3_outlet_ptr pOutlet, tS3_sound_id pSound) {
return 0;
}
int S3SoundStillPlaying(tS3_sound_tag pSound) {
return 0;
}
int S3StopSound(tS3_sound_tag pSound_tag) {
return 0;
}

View File

@ -19,17 +19,24 @@ harness_br_renderer* renderer_state;
br_pixelmap* last_dst = NULL;
br_pixelmap* last_src = NULL;
// if true, disable the original CD check code
int harness_disable_cd_check = 1;
// value between 0 and 1 - 0 is no fade, 1 is full black
float palette_fade_to_black_alpha = 0;
int back_screen_is_transparent = 0;
int rendered_scenes_this_frame = 0;
int rendered_scenes_last_frame = 0;
unsigned int last_frame_time = 0;
extern void BrPixelmapFill(br_pixelmap* dst, br_uint_32 colour);
extern unsigned int GetTotalTime();
extern uint8_t gScan_code[123][2];
// SplatPack or Carmageddon. This is where we represent the code differences between the two. For example, the intro smack file.
tHarness_game_info harness_game_info;
// Configuration options
tHarness_game_config harness_game_config;
int Harness_ProcessCommandLine(int* argc, char* argv[]);
void Harness_DetectGameMode() {
@ -54,6 +61,13 @@ void Harness_DetectGameMode() {
void Harness_Init(int* argc, char* argv[]) {
int result;
// disable the original CD check code
harness_game_config.disable_cd_check = 1;
// original physics time step. Lower values seem to work better at 30+ fps
harness_game_config.physics_step_time = 40;
// do not limit fps by default
harness_game_config.fps = 0;
Harness_ProcessCommandLine(argc, argv);
install_signal_handler(argv[0]);
@ -94,18 +108,28 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) {
for (int i = 1; i < *argc; i++) {
int handled = 0;
if (strcasecmp(argv[i], "-cdcheck") == 0) {
harness_disable_cd_check = 0;
if (strcasecmp(argv[i], "--cdcheck") == 0) {
harness_game_config.disable_cd_check = 0;
handled = 1;
} else if (strstr(argv[i], "-debug") != NULL) {
char* s = strstr(argv[i], "=");
} else if (strstr(argv[i], "--debug ") != NULL) {
char* s = strstr(argv[i], " ");
harness_debug_level = atoi(s + 1);
LOG_INFO("debug level set to %d", harness_debug_level);
handled = 1;
} else if (strstr(argv[i], "-platform") != NULL) {
platform_name = strstr(argv[i], "=") + 1;
} else if (strstr(argv[i], "--platform ") != NULL) {
platform_name = strstr(argv[i], " ") + 1;
LOG_INFO("Platform set to: %s", platform_name);
handled = 1;
} else if (strstr(argv[i], "--physics-step-time ") != NULL) {
char* s = strstr(argv[i], " ");
harness_game_config.physics_step_time = atof(s + 1);
LOG_INFO("Physics step time set to %f", harness_game_config.physics_step_time);
handled = 1;
} else if (strstr(argv[i], "--fps ") != NULL) {
char* s = strstr(argv[i], " ");
harness_game_config.fps = atoi(s + 1);
LOG_INFO("FPS limiter set to %f", harness_game_config.fps);
handled = 1;
}
if (handled) {
@ -135,12 +159,13 @@ void Harness_Hook_DOSGfxBegin() {
platform->NewWindow("Dethrace", 640, 400);
}
void Harness_ConvertPalettedPixelmapTo32Bit(uint32_t** dst, br_pixelmap* src) {
void Harness_ConvertPalettedPixelmapTo32Bit(uint32_t** dst, br_pixelmap* src, int vflip) {
uint8_t palette_index = 0;
uint8_t* data = src->pixels;
uint32_t* colors;
int x;
int y;
int dest_y;
if (!palette) {
return;
@ -151,34 +176,36 @@ void Harness_ConvertPalettedPixelmapTo32Bit(uint32_t** dst, br_pixelmap* src) {
}
// generate 32 bit texture from src + palette
for (y = 0; y < src->height; y++) {
for (x = 0; x < src->width; x++) {
palette_index = (data[y * src->row_bytes + x]);
(*dst)[y * src->width + x] = colors[palette_index];
if (vflip) {
dest_y = src->height - 1;
for (y = 0; y < src->height; y++) {
for (x = 0; x < src->width; x++) {
palette_index = (data[y * src->row_bytes + x]);
(*dst)[dest_y * src->width + x] = colors[palette_index];
}
dest_y--;
}
} else {
for (y = 0; y < src->height; y++) {
for (x = 0; x < src->width; x++) {
palette_index = (data[y * src->row_bytes + x]);
(*dst)[y * src->width + x] = colors[palette_index];
}
}
}
}
// Render 2d back buffer
void Harness_RenderScreen(br_pixelmap* dst, br_pixelmap* src) {
Harness_ConvertPalettedPixelmapTo32Bit(&screen_buffer, src);
platform->RenderFullScreenQuad(screen_buffer, back_screen_is_transparent);
platform->PollEvents();
Harness_ConvertPalettedPixelmapTo32Bit(&screen_buffer, src, 1);
platform->RenderFullScreenQuad(screen_buffer, 320, 200);
last_dst = dst;
last_src = src;
}
void Harness_Hook_BrPixelmapDoubleBuffer(br_pixelmap* dst, br_pixelmap* src) {
Harness_RenderScreen(dst, src);
platform->Swap();
back_screen_is_transparent = 0;
}
void Harness_Hook_BrDevPaletteSetOld(br_pixelmap* pm) {
palette = pm;
if (last_src) {
Harness_RenderScreen(last_dst, last_src);
platform->Swap();
}
}
void Harness_Hook_BrDevPaletteSetEntryOld(int i, br_colour colour) {
@ -193,29 +220,76 @@ void Harness_Hook_BrV1dbRendererBegin(br_v1db_state* v1db) {
v1db->renderer = (br_renderer*)renderer_state;
}
int col = 128;
void Harness_Hook_renderFaces(br_model* model, br_material* material, br_token type) {
platform->RenderModel(model, renderer_state->state.matrix.model_to_view);
}
// Begin 3d scene
void Harness_Hook_BrZbSceneRenderBegin(br_actor* world, br_actor* camera, br_pixelmap* colour_buffer, br_pixelmap* depth_buffer) {
// splat current back_screen to framebuffer
Harness_RenderScreen(NULL, colour_buffer);
// clear to transparent ready for the game to render foreground bits
BrPixelmapFill(colour_buffer, 0);
back_screen_is_transparent = 1;
rendered_scenes_this_frame++;
//current_renderer->setViewport(colour_buffer->base_x * 2, colour_buffer->base_y * 2, colour_buffer->width * 2, colour_buffer->height * 2);
platform->BeginFrame(camera, colour_buffer);
col = 0;
// if this is the first 3d scene this frame, draw the current colour_buffer (2d screen) contents to framebuffer
if (rendered_scenes_this_frame == 0) {
Harness_RenderScreen(NULL, colour_buffer);
}
// clear to transparent ready for the game to render foreground elements which we will capture later in `Harness_Hook_BrPixelmapDoubleBuffer`
BrPixelmapFill(colour_buffer, 0);
platform->BeginScene(camera, colour_buffer);
}
void Harness_Hook_BrZbSceneRenderAdd(br_actor* tree) {
}
void Harness_Hook_renderFaces(br_model* model, br_material* material, br_token type) {
platform->RenderModel(model, renderer_state->state.matrix.model_to_view);
}
void Harness_Hook_BrZbSceneRenderEnd() {
platform->EndFrame();
platform->EndScene();
}
void Harness_Hook_MainGameLoop() {
if (harness_game_config.fps == 0) {
return;
}
if (last_frame_time) {
unsigned int frame_time = GetTotalTime() - last_frame_time;
if (frame_time < 100) {
int sleep_time = (1000 / harness_game_config.fps) - frame_time;
if (sleep_time > 5) {
SDL_Delay(sleep_time);
}
}
}
last_frame_time = GetTotalTime();
}
// Called by game to swap buffers at end of frame rendering
void Harness_Hook_BrPixelmapDoubleBuffer(br_pixelmap* dst, br_pixelmap* src) {
// should we switch to fb 0 here ?
// draw the current colour_buffer (2d screen) contents
Harness_RenderScreen(dst, src);
// draw the current 3d frame buffer
if (rendered_scenes_this_frame) {
platform->RenderFrameBuffer();
}
// if the game has faded the palette, we should respect that.
// fixes screen flash during race start or recovery
if (palette_fade_to_black_alpha != 0) {
platform->RenderColorBlend(0, 0, 0, palette_fade_to_black_alpha);
}
platform->Swap();
platform->PollEvents();
// reset 3d render count
rendered_scenes_last_frame = rendered_scenes_this_frame;
rendered_scenes_this_frame = 0;
}
int Harness_Hook_KeyDown(unsigned char pScan_code) {
@ -245,4 +319,18 @@ void Harness_Hook_S3Service(int unk1, int unk2) {
}
void Harness_Hook_S3StopAllOutletSounds() {
}
void Harness_Hook_SetFadedPalette(int pDegree) {
// pDegree is 0-255 where 0 is full black and 255 is full original color.
// we convert this to an alpha blend value
palette_fade_to_black_alpha = (256 - pDegree) / 256.f;
if (rendered_scenes_last_frame > 0) {
platform->RenderFrameBuffer();
}
Harness_RenderScreen(last_dst, last_src);
platform->RenderColorBlend(0, 0, 0, palette_fade_to_black_alpha);
platform->Swap();
}

View File

@ -10,10 +10,12 @@ typedef struct tPlatform {
void (*PollEvents)();
int* (*GetKeyMap)();
int (*IsKeyDown)(unsigned char pScan_code);
void (*BeginFrame)(br_actor* camera, br_pixelmap* colour_buffer);
void (*EndFrame)();
void (*RenderFullScreenQuad)(uint32_t* src, int transparent);
void (*BeginScene)(br_actor* camera, br_pixelmap* colour_buffer);
void (*EndScene)();
void (*RenderFullScreenQuad)(uint32_t* src, int width, int height);
void (*RenderColorBlend)(float r, float g, float b, float a);
void (*RenderModel)(br_model* model, br_matrix34 model_matrix);
void (*RenderFrameBuffer)();
void (*Swap)();
void (*BufferTexture)(br_pixelmap* pm);
void (*BufferMaterial)(br_material* mat);
@ -27,6 +29,6 @@ typedef struct tCamera {
void (*setPosition)();
} tCamera;
void Harness_ConvertPalettedPixelmapTo32Bit(uint32_t** dst, br_pixelmap* src);
void Harness_ConvertPalettedPixelmapTo32Bit(uint32_t** dst, br_pixelmap* src, int vflip);
#endif

View File

@ -11,12 +11,20 @@ typedef enum tHarness_game_type {
typedef struct tHarness_game_info {
tHarness_game_type mode;
struct {
char* INTRO_SMK_FILE; // different between carmageddon and splatpack
char* GERMAN_LOADSCRN; // different between demo and full game
// different between carmageddon and splatpack
char* INTRO_SMK_FILE;
// different between demo and full game
char* GERMAN_LOADSCRN;
} defines;
} tHarness_game_info;
typedef struct tHarness_game_config {
int disable_cd_check;
float physics_step_time;
float fps;
} tHarness_game_config;
extern tHarness_game_info harness_game_info;
extern int harness_disable_cd_check;
extern tHarness_game_config harness_game_config;
#endif

View File

@ -10,6 +10,8 @@ void Harness_Init(int* argc, char* argv[]);
int Harness_Hook_KeyDown(unsigned char pScan_code);
void Harness_Hook_PDServiceSystem();
void Harness_Hook_PDSetKeyArray();
void Harness_Hook_SetFadedPalette(int pDegree);
void Harness_Hook_MainGameLoop(); // limit FPS
// BRender hooks
void Harness_Hook_DOSGfxBegin();

View File

@ -7,8 +7,10 @@ int* Null_GetKeyMap() { return NULL; }
int Null_IsKeyDown(unsigned char pScan_code) { return 0; }
void Null_BeginFrame(br_actor* camera, br_pixelmap* colour_buffer) {}
void Null_EndFrame() {}
void Null_RenderFullScreenQuad(uint32_t* src, int transparent) {}
void Null_RenderFullScreenQuad(uint32_t* src, int width, int height) {}
void Null_RenderColorBlend(float r, float g, float b, float a) {}
void Null_RenderModel(br_model* model, br_matrix34 model_matrix) {}
void Null_RenderFrameBuffer() {}
void Null_Swap() {}
void Null_BufferTexture(br_pixelmap* pm) {}
void Null_BufferMaterial(br_material* mat) {}
@ -22,7 +24,9 @@ tPlatform null_platform = {
Null_BeginFrame,
Null_EndFrame,
Null_RenderFullScreenQuad,
Null_RenderColorBlend,
Null_RenderModel,
Null_RenderFrameBuffer,
Null_Swap,
Null_BufferTexture,
Null_BufferMaterial

View File

@ -11,10 +11,12 @@ tPlatform sdl_gl_platform = {
SDLPlatform_PollEvents,
SDLPlatform_GetKeyMap,
SDLPlatform_IsKeyDown,
GLRenderer_BeginFrame,
GLRenderer_EndFrame,
GLRenderer_BeginScene,
GLRenderer_EndScene,
GLRenderer_RenderFullScreenQuad,
GLRenderer_RenderColorBlend,
GLRenderer_RenderModel,
GLRenderer_RenderFramebuffer,
GLRenderer_Swap,
GLRenderer_BufferTexture,
GLRenderer_BufferMaterial

View File

@ -29,7 +29,10 @@ GLuint screen_buffer_vao, screen_buffer_ebo;
GLuint screen_texture;
GLuint shader_program_2d;
GLuint shader_program_2d_trans;
GLuint shader_program_2d_pp;
GLuint shader_program_3d;
GLuint framebuffer_id, framebuffer_texture = 0;
unsigned int rbo;
int window_width, window_height;
@ -57,17 +60,26 @@ void LoadShaders() {
glAttachShader(shader_program_2d, vs);
glAttachShader(shader_program_2d, fs);
glLinkProgram(shader_program_2d);
glDeleteShader(fs);
fs = glCreateShader(GL_FRAGMENT_SHADER);
CompileShader(fs, fs_2d_trans);
shader_program_2d_trans = glCreateProgram();
glAttachShader(shader_program_2d_trans, vs);
glAttachShader(shader_program_2d_trans, fs);
glLinkProgram(shader_program_2d_trans);
glDeleteShader(vs);
glDeleteShader(fs);
fs = glCreateShader(GL_FRAGMENT_SHADER);
CompileShader(fs, fs_postprocess);
shader_program_2d_pp = glCreateProgram();
glAttachShader(shader_program_2d_pp, vs);
glAttachShader(shader_program_2d_pp, fs);
glLinkProgram(shader_program_2d_pp);
glDeleteShader(fs);
glDeleteShader(vs);
vs = glCreateShader(GL_VERTEX_SHADER);
fs = glCreateShader(GL_FRAGMENT_SHADER);
CompileShader(fs, fs_3d);
@ -123,10 +135,10 @@ void GLRenderer_CreateWindow(char* title, int width, int height) {
float vertices[] = {
// positions // colors // texture coords
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top right
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // bottom right
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // bottom left
-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
@ -163,13 +175,40 @@ void GLRenderer_CreateWindow(char* title, int width, int height) {
glGenTextures(1, &screen_texture);
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
glGenFramebuffers(1, &framebuffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
glClearColor(0, 0, 0, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glGenTextures(1, &framebuffer_texture);
glBindTexture(GL_TEXTURE_2D, framebuffer_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer_texture, 0);
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_PANIC("ERROR::FRAMEBUFFER:: Framebuffer is not complete!");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void GLRenderer_BeginFrame(br_actor* camera, br_pixelmap* colour_buffer) {
void GLRenderer_BeginScene(br_actor* camera, br_pixelmap* colour_buffer) {
glViewport(colour_buffer->base_x * 2, colour_buffer->base_y * 2, colour_buffer->width * 2, colour_buffer->height * 2);
@ -211,28 +250,58 @@ void GLRenderer_BeginFrame(br_actor* camera, br_pixelmap* colour_buffer) {
glUniformMatrix4fv(projection_u, 1, GL_FALSE, proj);
DebugCamera_Update();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void GLRenderer_EndFrame() {
void GLRenderer_EndScene() {
}
void GLRenderer_RenderFramebuffer() {
glViewport(0, 0, window_width, window_height);
glDisable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, framebuffer_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUseProgram(shader_program_2d_trans);
glBindVertexArray(screen_buffer_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screen_buffer_ebo);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
void GLRenderer_RenderFullScreenQuad(uint32_t* screen_buffer, int transparent) {
void GLRenderer_RenderFullScreenQuad(uint32_t* screen_buffer, int width, int height) {
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// TODO: remove fixed 320x200
glBindTexture(GL_TEXTURE_2D, screen_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 320, 200, 0, GL_BGRA, GL_UNSIGNED_BYTE, screen_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, screen_buffer);
glUseProgram(shader_program_2d_trans);
glBindVertexArray(screen_buffer_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screen_buffer_ebo);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
// GLRenderer_RenderColorBlend renders a fullscreen quad with the desired color
void GLRenderer_RenderColorBlend(float r, float g, float b, float a) {
glDisable(GL_DEPTH_TEST);
glUseProgram(shader_program_2d_pp);
GLuint model_u = glGetUniformLocation(shader_program_2d_pp, "color");
glUniform4f(model_u, r, g, b, a);
if (transparent) {
glUseProgram(shader_program_2d_trans);
} else {
glUseProgram(shader_program_2d);
}
glBindVertexArray(screen_buffer_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screen_buffer_ebo);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
@ -241,7 +310,6 @@ void GLRenderer_RenderFullScreenQuad(uint32_t* screen_buffer, int transparent) {
void GLRenderer_Swap() {
SDL_GL_SwapWindow(window);
// glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
@ -414,7 +482,7 @@ void GLRenderer_BufferMaterial(br_material* mat) {
void GLRenderer_BufferTexture(br_pixelmap* pm) {
if (!pm->stored) {
uint32_t* full_color_texture = NULL;
Harness_ConvertPalettedPixelmapTo32Bit(&full_color_texture, pm);
Harness_ConvertPalettedPixelmapTo32Bit(&full_color_texture, pm, 0);
if (full_color_texture == NULL) {
return;
}

View File

@ -5,9 +5,11 @@
#include <SDL.h>
void GLRenderer_CreateWindow(char* title, int width, int height);
void GLRenderer_BeginFrame(br_actor* camera, br_pixelmap* colour_buffer);
void GLRenderer_EndFrame();
void GLRenderer_RenderFullScreenQuad(uint32_t* screen_buffer, int transparent);
void GLRenderer_BeginScene(br_actor* camera, br_pixelmap* colour_buffer);
void GLRenderer_EndScene();
void GLRenderer_RenderFullScreenQuad(uint32_t* screen_buffer, int width, int height);
void GLRenderer_RenderColorBlend(float r, float g, float b, float a);
void GLRenderer_RenderFramebuffer();
void GLRenderer_Swap();
void GLRenderer_RenderModel(br_model* model, br_matrix34 model_matrix);
void GLRenderer_BufferTexture(br_pixelmap* pm);

View File

@ -34,6 +34,16 @@ const char* fs_2d_trans = "#version 330 core\n"
" }\n"
"}\n\0";
const char* fs_postprocess = "#version 330 core\n"
"in vec2 TexCoord;\n"
"uniform vec4 color;\n"
"layout (location = 0) out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = color;\n"
"}\n\0";
// const char* vs_3d = "#version 330 core\n"
// "layout (location = 0) in vec3 aPos;\n"
// "layout (location = 1) in vec3 aNormal;\n"

View File

@ -4,6 +4,7 @@
extern const char* vs_2d;
extern const char* fs_2d;
extern const char* fs_2d_trans;
extern const char* fs_postprocess;
extern const char* fs_3d;
extern const char* vs_3d;