Skip to content

Commit

Permalink
Implement cockpit view (dethrace-labs#279)
Browse files Browse the repository at this point in the history
* Cockpit camera position now correctly follows parent actor

* Fixes MungeSkyModel, updates BR_MODU enum

* fixes incorrect blending in cockpit view

* Tidy naming, adds unsigned

Co-authored-by: Anonymous Maarten <madebr@users.noreply.github.com>
  • Loading branch information
dethrace-labs and madebr committed Feb 18, 2023
1 parent 83ba373 commit e567903
Show file tree
Hide file tree
Showing 19 changed files with 239 additions and 176 deletions.
18 changes: 9 additions & 9 deletions src/BRSRC13/CORE/V1DB/modrend.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
#include "harness/trace.h"

render_style_cbfn RenderStyleCalls[8] = {
renderFaces, /* BR_RSTYLE_DEFAULT */
nullRender, /* BR_RSTYLE_NONE */
renderPoints, /* BR_RSTYLE_POINTS */
renderEdges, /* BR_RSTYLE_EDGES */
renderFaces, /* BR_RSTYLE_FACES */
renderFaces, /* BR_RSTYLE_DEFAULT */
nullRender, /* BR_RSTYLE_NONE */
renderPoints, /* BR_RSTYLE_POINTS */
renderEdges, /* BR_RSTYLE_EDGES */
renderFaces, /* BR_RSTYLE_FACES */
boundingBoxRenderPoints, /* BR_RSTYLE_BOUNDING_POINTS */
boundingBoxRenderEdges, /* BR_RSTYLE_BOUNDING_EDGES */
boundingBoxRenderFaces, /* BR_RSTYLE_BOUNDING_FACES */
boundingBoxRenderEdges, /* BR_RSTYLE_BOUNDING_EDGES */
boundingBoxRenderFaces, /* BR_RSTYLE_BOUNDING_FACES */
};

v11face bounds_faces[12] = {
Expand Down Expand Up @@ -64,13 +64,13 @@ br_model bounds_model = {
// IDA: void __usercall renderFaces(br_actor *actor@<EAX>, br_model *model@<EDX>, br_material *material@<EBX>, void *render_data@<ECX>, br_uint_8 style, int on_screen)
void renderFaces(br_actor* actor, br_model* model, br_material* material, void* render_data, br_uint_8 style, int on_screen) {
LOG_TRACE9("(%p, %p, %p, %p, %d, %d)", actor, model, material, render_data, style, on_screen);
Harness_Hook_renderFaces(actor, model, material, BRT_TRIANGLE);
Harness_Hook_renderActor(actor, model, material, BRT_TRIANGLE);
}

// IDA: void __usercall renderEdges(br_actor *actor@<EAX>, br_model *model@<EDX>, br_material *material@<EBX>, void *render_data@<ECX>, br_uint_8 style, int on_screen)
void renderEdges(br_actor* actor, br_model* model, br_material* material, void* render_data, br_uint_8 style, int on_screen) {
LOG_TRACE("(%p, %p, %p, %p, %d, %d)", actor, model, material, render_data, style, on_screen);
NOT_IMPLEMENTED();
Harness_Hook_renderActor(actor, model, material, BRT_LINE);
}

// IDA: void __usercall renderPoints(br_actor *actor@<EAX>, br_model *model@<EDX>, br_material *material@<EBX>, void *render_data@<ECX>, br_uint_8 style, int on_screen)
Expand Down
14 changes: 7 additions & 7 deletions src/BRSRC13/CORE/V1DB/prepmesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,13 +607,13 @@ void BrModelUpdate(br_model* model, br_uint_16 flags) {
if (model->faces == NULL || model->vertices == NULL) {
BrFailure("BrModelUpdate: model has no faces or vertices (%s)", model->identifier != NULL ? model->identifier : "<NULL>");
}
if (flags & BR_MODU_UNKNOWN) {
flags |= BR_MODU_NORMALS;
if (flags & BR_MODU_PIVOT) {
flags |= BR_MODU_VERTEX_POSITIONS;
}
if (model->flags & (BR_MODF_KEEP_ORIGINAL | BR_MODF_GENERATE_TAGS)) {
model->flags |= BR_MODF_UPDATEABLE;
}
if (!(model->flags & BR_MODF_CUSTOM_BOUNDS) && (flags & (BR_MODU_MATERIALS | BR_MODU_GROUPS | BR_MODU_NORMALS))) {
if (!(model->flags & BR_MODF_CUSTOM_BOUNDS) && (flags & (BR_MODU_PRIMITIVE_COLOURS | BR_MODU_VERTEX_NORMALS | BR_MODU_VERTEX_POSITIONS))) {
PrepareBoundingRadius(model);
PrepareBoundingBox(model);
}
Expand Down Expand Up @@ -651,19 +651,19 @@ void BrModelUpdate(br_model* model, br_uint_16 flags) {
} else {

// some additional code paths might exist, but maybe not used?
if (flags != BR_MODU_NORMALS) {
if (flags != BR_MODU_VERTEX_POSITIONS) {
TELL_ME_IF_WE_PASS_THIS_WAY();
}

v11m = model->prepared;

if (model->vertices && (flags & BR_MODU_NORMALS)) {
if (model->vertices && (flags & BR_MODU_VERTEX_POSITIONS)) {
for (g = 0; g < v11m->ngroups; g++) {
for (v = 0; v < v11m->groups[g].nvertices; v++) {
fvp = &v11m->groups[g].vertices[v];
vp = model->vertices + v11m->groups[g].vertex_user[v];

if (flags & BR_MODU_NORMALS) {
if (flags & BR_MODU_VERTEX_POSITIONS) {
fvp->p.v[0] = vp->p.v[0] - model->pivot.v[0];
fvp->p.v[1] = vp->p.v[1] - model->pivot.v[1];
fvp->p.v[2] = vp->p.v[2] - model->pivot.v[2];
Expand All @@ -672,7 +672,7 @@ void BrModelUpdate(br_model* model, br_uint_16 flags) {
}
}

if (flags & BR_MODU_NORMALS) {
if (flags & BR_MODU_VERTEX_POSITIONS) {
if (!(model->flags & BR_MODF_CUSTOM_NORMALS)) {
RegenerateVertexNormals(v11m);
}
Expand Down
35 changes: 33 additions & 2 deletions src/BRSRC13/CORE/V1DB/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,38 @@ void BrDbSceneRenderBegin(br_actor* world, br_actor* camera) {
br_token vtos_type;
br_uint_32 dummy;
LOG_TRACE("(%p, %p)", world, camera);
NOT_IMPLEMENTED();

// this is not complete
STUB_ONCE();

/*
* Collect transforms from camera to root
*
* Make a stack of cumulative transforms for each level between
* the camera and the root - this is so that model->view
* transforms can use the shortest route, rather than via the root
*/
for (i = 0; i < BR_ASIZE(v1db.camera_path); i++) {
v1db.camera_path[i].a = NULL;
}

i = camera->depth;
a = camera;
BrMatrix34Identity(&v1db.camera_path[i].m);
v1db.camera_path[i].transform_type = BR_TRANSFORM_IDENTITY;

for (; (i > 0) && (a != world); a = a->parent, i--) {
BrTransformToMatrix34(&tfm, &a->t);
BrMatrix34Mul(&v1db.camera_path[i - 1].m, &v1db.camera_path[i].m, &tfm);

v1db.camera_path[i - 1].transform_type = BrTransformCombineTypes(v1db.camera_path[i].transform_type, a->t.type);

v1db.camera_path[i].a = a;
}

if (world != a) {
// BrFailure("camera is not in world hierachy");
}
}

// IDA: br_renderbounds_cbfn* __cdecl BrDbSetRenderBoundsCallback(br_renderbounds_cbfn *new_cbfn)
Expand All @@ -291,7 +322,7 @@ void SetViewport(br_pixelmap* buffer) {
void BrZbSceneRenderBegin(br_actor* world, br_actor* camera, br_pixelmap* colour_buffer, br_pixelmap* depth_buffer) {
// LOG_TRACE("(%p, %p, %p, %p)", world, camera, colour_buffer, depth_buffer);

// BrDbSceneRenderBegin(world, camera);
BrDbSceneRenderBegin(world, camera);
Harness_Hook_BrZbSceneRenderBegin(world, camera, colour_buffer, depth_buffer);
}

Expand Down
2 changes: 1 addition & 1 deletion src/BRSRC13/include/brender/br_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

#define BrDegreeToRadian(d) ((br_scalar)((d) * (PI / 180.0)))

#define BrDegreeToAngle(d) ((br_angle)(long)((d) * (65536.0f / 360.0f))) // "d * 182.044444444"
#define BrDegreeToAngle(d) ((br_angle)(long)((d) * (65536.0f / 360.0f))) // "d * 182.044444444"
#define BrAngleToDegrees(a) ((br_angle)(long)((a) * (360.0f / 65536.0f))) // "d * 0.0054931640625"

#define BR_SCALAR(x) ((br_scalar)(x))
Expand Down
34 changes: 20 additions & 14 deletions src/BRSRC13/include/brender/br_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2648,13 +2648,13 @@ typedef struct resource_header { // size: 24
br_uint_8 size_m;
br_uint_8 size_l;
#else
br_uint_8 size_l; // @12
br_uint_8 size_m; // @13
br_uint_8 size_h; // @14
br_uint_8 size_l; // @12
br_uint_8 size_m; // @13
br_uint_8 size_h; // @14
#endif
br_uint_8 class; // @15
void* magic_ptr; // @16
br_uint_32 magic_num; // @20
br_uint_8 class; // @15
void* magic_ptr; // @16
br_uint_32 magic_num; // @20
} resource_header;
#pragma pack(pop)

Expand Down Expand Up @@ -2952,14 +2952,20 @@ enum {
* Flags to BrModelUpdate()
*/
enum {
BR_MODU_NORMALS = 0x0001,
BR_MODU_EDGES = 0x0002,
BR_MODU_RADIUS = 0x0004,
BR_MODU_GROUPS = 0x0008,
BR_MODU_BOUNDING_BOX = 0x0010,
BR_MODU_MATERIALS = 0x0020,
BR_MODU_UNKNOWN = 0x0100, /* Added by Jeff. Referred to in code */
BR_MODU_ALL = 0x7fff
BR_MODU_VERTEX_POSITIONS = 0x0001,
BR_MODU_VERTEX_COLOURS = 0x0002,
BR_MODU_VERTEX_MAPPING = 0x0004,
BR_MODU_VERTEX_NORMALS = 0x0008,
BR_MODU_PRIMITIVE_MATERIALS = 0x0010,
BR_MODU_PRIMITIVE_COLOURS = 0x0020,
BR_MODU_VERTICES = 0x0040,
BR_MODU_FACES = 0x0080,
BR_MODU_PIVOT = 0x0100,
BR_MODU_PREPARED = 0x0200,
BR_MODU_PRIMITIVE_EQUATIONS = 0x0400,
BR_MODU_ALL = 0x7FFF,

_BR_MODU_RESERVED = 0x8000
};

/*
Expand Down
6 changes: 3 additions & 3 deletions src/DETHRACE/common/crush.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ void CrushModel(tCar_spec* pCar, int pModel_index, br_actor* pActor, br_vector3*
void JitModelUpdate(br_actor* actor, br_model* model, br_material* material, void* render_data, br_uint_8 style, int on_screen) {
LOG_TRACE("(%p, %p, %p, %p, %d, %d)", actor, model, material, render_data, style, on_screen);

BrModelUpdate(model, BR_MODU_NORMALS);
BrModelUpdate(model, BR_MODU_VERTEX_POSITIONS);
model->flags &= ~(BR_MODF_CUSTOM);
BrZbModelRender(actor, model, material, style, BrOnScreenCheck(&model->bounds), 0);
}
Expand Down Expand Up @@ -483,8 +483,8 @@ void TotallyRepairACar(tCar_spec* pCar) {
memcpy(the_car_actor->actor->model->vertices,
the_car_actor->undamaged_vertices,
the_car_actor->actor->model->nvertices * sizeof(br_vertex));
// FIXME: BrModelUpdate(..., BR_MODU_EDGES | BR_MODU_NORMALS) fails on TELL_ME_IF_WE_PASS_THIS_WAY
// BrModelUpdate(the_car_actor->actor->model, BR_MODU_EDGES | BR_MODU_NORMALS);
// FIXME: BrModelUpdate(..., BR_MODU_VERTEX_COLOURS | BR_MODU_VERTEX_POSITIONS) fails on TELL_ME_IF_WE_PASS_THIS_WAY
// BrModelUpdate(the_car_actor->actor->model, BR_MODU_VERTEX_COLOURS | BR_MODU_VERTEX_POSITIONS);
BrModelUpdate(the_car_actor->actor->model, BR_MODU_ALL);
if (pipe_vertex_count != 0 && IsActionReplayAvailable()) {
PipeSingleModelGeometry(pCar->car_ID, j, pipe_vertex_count, pipe_array);
Expand Down
85 changes: 48 additions & 37 deletions src/DETHRACE/common/depth.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,27 +180,27 @@ void MungeSkyModel(br_actor* pCamera, br_model* pModel) {
LOG_TRACE("(%p, %p)", pCamera, pModel);

camera_data = pCamera->type_data;

tan_half_fov = Tan(camera_data->field_of_view / 2);
// BR_ANGLE_RAD(atan2f(tan_half_fov, camera_data->aspect / 2));
horizon_half_width = (camera_data->yon_z - 1.f) * tan_half_fov;
sky_distance = camera_data->yon_z - 1.f;
horizon_half_width = sky_distance * tan_half_fov;
horizon_half_height = horizon_half_width * camera_data->aspect;
horizon_half_diag = BR_LENGTH2(horizon_half_width, horizon_half_height);
min_angle = BR_ANGLE_RAD(atan2f(horizon_half_diag, camera_data->yon_z - 1.f));
edge_u = EdgeU(gSky_image_width, 2 * min_angle, BR_ANGLE_DEG(10));
gSky_width = 2.f * horizon_half_width;
gSky_height = 2.f * horizon_half_height;
horizon_half_diag = sqrtf(horizon_half_height * horizon_half_height + horizon_half_width * horizon_half_width);
half_diag_fov = BrRadianToAngle(atan2f(horizon_half_diag, sky_distance));
edge_u = EdgeU(gSky_image_width, 2 * half_diag_fov, BR_ANGLE_DEG(10));
narrow_u = edge_u / 2.f;
gSky_width = horizon_half_width * 2.f;
gSky_height = horizon_half_height * 2.f;
gSky_x_multiplier = CalculateWrappingMultiplier(gSky_width, camera_data->yon_z);
gSky_y_multiplier = CalculateWrappingMultiplier(gSky_height, camera_data->yon_z);

for (vertex = 0; vertex < 88; vertex += 4) {
pModel->vertices[vertex].map.v[0] = -edge_u;
}
for (vertex = 1; vertex < 88; vertex += 4) {
pModel->vertices[vertex].map.v[0] = -edge_u / 2.f;
pModel->vertices[vertex].map.v[0] = -narrow_u;
}
for (vertex = 2; vertex < 88; vertex += 4) {
pModel->vertices[vertex].map.v[0] = edge_u / 2.f;
pModel->vertices[vertex].map.v[0] = narrow_u;
}
for (vertex = 3; vertex < 88; vertex += 4) {
pModel->vertices[vertex].map.v[0] = edge_u;
Expand All @@ -209,7 +209,7 @@ void MungeSkyModel(br_actor* pCamera, br_model* pModel) {
pModel->vertices[vertex].p.v[0] = -horizon_half_diag;
}
for (vertex = 1; vertex < 88; vertex += 4) {
pModel->vertices[vertex].p.v[0] = -horizon_half_diag / 2.f;
pModel->vertices[vertex].p.v[0] = -(horizon_half_diag / 2.f);
}
for (vertex = 2; vertex < 88; vertex += 4) {
pModel->vertices[vertex].p.v[0] = horizon_half_diag / 2.f;
Expand All @@ -218,31 +218,39 @@ void MungeSkyModel(br_actor* pCamera, br_model* pModel) {
pModel->vertices[vertex].p.v[0] = horizon_half_diag;
}
PossibleService();
angle_range = -(gSky_image_underground + (BR_ANGLE_DEG(90) - min_angle));
for (vertex = 0; vertex < 2; vertex++) {
angle = vertex * angle_range / 2 - (BR_ANGLE_DEG(90) + min_angle);
pModel->vertices[0 + 4 * vertex].p.v[1] = sinf(BrAngleToRadian(angle)) * (camera_data->yon_z - 1.f);
pModel->vertices[0 + 4 * vertex].p.v[2] = -cosf(BrAngleToRadian(angle)) * (camera_data->yon_z - 1.f);
}
for (vertex = 0; vertex < 18; vertex++) {
angle = vertex * gSky_image_height / 18 - gSky_image_height;
pModel->vertices[8 + 4 * vertex].p.v[1] = sinf(BrAngleToRadian(angle)) * (camera_data->yon_z - 1.f);
pModel->vertices[8 + 4 * vertex].p.v[2] = -cosf(BrAngleToRadian(angle)) * (camera_data->yon_z - 1.f);
}
for (vertex = 0; vertex < 2; vertex++) {
angle = vertex * (min_angle + BR_ANGLE_DEG(90) - (gSky_image_height - gSky_image_underground)) - (gSky_image_height - gSky_image_underground);
pModel->vertices[80 + 4 * vertex].p.v[1] = sinf(BrAngleToRadian(angle)) * (camera_data->yon_z - 1.f);
pModel->vertices[80 + 4 * vertex].p.v[2] = -cosf(BrAngleToRadian(angle)) * (camera_data->yon_z - 1.f);
angle_range = -gSky_image_underground - (-BR_ANGLE_DEG(90) - half_diag_fov);
for (band = 0; band < 2u; band++) {
vertex = 4 * band;
angle = -BR_ANGLE_DEG(90) - half_diag_fov + angle_range * band / 2;
pModel->vertices[vertex].p.v[1] = sinf(BrAngleToRadian(angle)) * sky_distance;
pModel->vertices[vertex].p.v[2] = -cosf(BrAngleToRadian(angle)) * sky_distance;
}
min_angle = -gSky_image_underground;
angle_range = gSky_image_height;
nbands = 18;
for (band = 0; band < nbands; band++) {
vertex = 4 * band + 8;
pModel->vertices[vertex].p.v[1] = sinf(BrAngleToRadian(min_angle + angle_range * band / nbands)) * sky_distance;
pModel->vertices[vertex].p.v[2] = -cosf(BrAngleToRadian(min_angle + angle_range * band / nbands)) * sky_distance;
}
min_angle = gSky_image_height - gSky_image_underground;
angle_range = half_diag_fov + BR_ANGLE_DEG(90) - (gSky_image_height - gSky_image_underground);
for (band = 0; band <= 1u; band++) {
vertex = 4 * band + 80;
angle = min_angle + angle_range * band;
pModel->vertices[vertex].p.v[1] = sinf(BrAngleToRadian(angle)) * sky_distance;
pModel->vertices[vertex].p.v[2] = -cosf(BrAngleToRadian(angle)) * sky_distance;
}
PossibleService();
for (band = 0; band < 22; band++) {
for (vertex = 1; vertex < 4; vertex++) {
pModel->vertices[4 * band + vertex].p.v[1] = pModel->vertices[vertex].p.v[1];
pModel->vertices[4 * band + vertex].p.v[2] = pModel->vertices[vertex].p.v[2];
for (band = 0; band <= 21u; ++band) {
vertex = 4 * band;
for (stripe = 1; stripe < 4u; ++stripe) {
pModel->vertices[vertex + stripe].p.v[1] = pModel->vertices[vertex].p.v[1];
pModel->vertices[vertex + stripe].p.v[2] = pModel->vertices[vertex].p.v[2];
}
}
// FIXME: unknown model flag disabled
BrModelUpdate(pModel, BR_MODU_ALL & ~0x80);

BrModelUpdate(pModel, BR_MODU_ALL & ~BR_MODU_VERTEX_NORMALS);
}

// IDA: br_model* __usercall CreateHorizonModel@<EAX>(br_actor *pCamera@<EAX>)
Expand Down Expand Up @@ -331,12 +339,18 @@ void InitDepthEffects() {
FatalError(kFatalError_FindSkyMaterial_S, "HORIZON.MAT"); // 2nd argument added
}
gHorizon_material->index_blend = BrPixelmapAllocate(BR_PMT_INDEX_8, 256, 256, NULL, 0);
BrTableAdd(gHorizon_material->index_blend);

// HACK: moved below loop
// BrTableAdd(gHorizon_material->index_blend);
for (i = 0; i < 256; i++) {
for (j = 0; j < 256; j++) {
*((tU8*)gHorizon_material->index_blend->pixels + 256 * i + j) = j;
}
}
// HACK: this should be above the for loop. Haven't been able to figure out how this is working in OG, as changes made to the pixelmap
// don't update the stored copy without calling `BrTableUpdate`.
BrTableAdd(gHorizon_material->index_blend);

gHorizon_material->flags |= BR_MATF_PERSPECTIVE;
BrMaterialAdd(gHorizon_material);
gForward_sky_model = CreateHorizonModel(gCamera);
Expand Down Expand Up @@ -371,9 +385,6 @@ void DoDepthByShadeTable(br_pixelmap* pRender_buffer, br_pixelmap* pDepth_buffer
int render_line_skip;
LOG_TRACE("(%p, %p, %p, %d, %d, %d)", pRender_buffer, pDepth_buffer, pShade_table, pShade_table_power, pStart, pEnd);

// Added to ensure we've copied the framebuffer+depthbuffer back into main memory
Harness_Hook_FlushRenderer();

too_near = 0xffff - (1 << pStart);
shade_table_pixels = pShade_table->pixels;
depth_shift_amount = pShade_table_power + 8 - pStart - pEnd;
Expand Down Expand Up @@ -514,7 +525,7 @@ void DoHorizon(br_pixelmap* pRender_buffer, br_pixelmap* pDepth_buffer, br_actor
br_actor* actor;
LOG_TRACE("(%p, %p, %p, %p)", pRender_buffer, pDepth_buffer, pCamera, pCamera_to_world);

yaw = BR_ANGLE_RAD(atan2f(pCamera_to_world->m[2][0], pCamera_to_world->m[2][2]));
yaw = BrRadianToAngle(atan2f(pCamera_to_world->m[2][0], pCamera_to_world->m[2][2]));
if (!gProgram_state.cockpit_on && !(gAction_replay_mode && gAction_replay_camera_mode)) {
return;
}
Expand Down
Loading

0 comments on commit e567903

Please sign in to comment.