From 6e47f226c95e6fdeb9bc058facb85c95c8d5f1af Mon Sep 17 00:00:00 2001 From: MysterD Date: Wed, 27 Apr 2022 19:43:55 -0700 Subject: [PATCH] WIP: uncapped framerate 5 --- src/game/rendering_graph_node.c | 112 +++++++++++++++++++++----------- src/game/rendering_graph_node.h | 11 ++++ src/game/shadow.c | 61 +++++++++++++---- src/game/skybox.c | 27 ++++---- 4 files changed, 149 insertions(+), 62 deletions(-) diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 33e042e6..a4ec8159 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -38,7 +38,7 @@ * - Script node (Cannon overlay) * */ - + #define MATRIX_STACK_SIZE 32 s16 gMatStackIndex; @@ -155,6 +155,11 @@ Vtx* gBackgroundSkyboxVerts[3][3] = { 0 }; Mtx* gBackgroundSkyboxMtx = NULL; struct GraphNodeRoot* sBackgroundNodeRoot = NULL; +#define MAX_SHADOW_NODES 128 +struct ShadowInterp sShadowInterp[MAX_SHADOW_NODES] = { 0 }; +struct ShadowInterp* gShadowInterpCurrent = NULL; +static u8 sShadowInterpCount = 0; + struct { Gfx *pos; void *mtx; @@ -189,6 +194,8 @@ void patch_mtx_before(void) { sBackgroundNode = NULL; gBackgroundSkyboxGfx = NULL; } + + sShadowInterpCount = 0; } void patch_mtx_interpolated(f32 delta) { @@ -232,6 +239,20 @@ void patch_mtx_interpolated(f32 delta) { gCurGraphNodeRoot = rootCopy; } + struct GraphNodeObject* savedObj = gCurGraphNodeObject; + for (s32 i = 0; i < sShadowInterpCount; i++) { + struct ShadowInterp* interp = &sShadowInterp[i]; + gShadowInterpCurrent = interp; + Vec3f posInterp; + delta_interpolate_vec3f(posInterp, interp->shadowPosPrev, interp->shadowPos, delta); + if (i == 0) { + printf("XXX: %f <--> %f == %f\n", interp->shadowPosPrev[1], interp->shadowPos[1], posInterp[1]); + } + gCurGraphNodeObject = interp->obj; + create_shadow_below_xyz(posInterp[0], posInterp[1], posInterp[2], interp->shadowScale, interp->node->shadowSolidity, interp->node->shadowType); + } + gCurGraphNodeObject = savedObj; + for (s32 i = 0; i < gMtxTblSize; i++) { Gfx *pos = gMtxTbl[i].pos; delta_interpolate_mtx(&gMtxTbl[i].interp, (Mtx*) gMtxTbl[i].mtxPrev, (Mtx*) gMtxTbl[i].mtx, delta); @@ -241,6 +262,7 @@ void patch_mtx_interpolated(f32 delta) { gSPDisplayList(pos++, gMtxTbl[i].displayList); } } + } /** @@ -250,7 +272,7 @@ static u8 increment_mat_stack() { Mtx *mtx = alloc_display_list(sizeof(*mtx)); Mtx *mtxPrev = alloc_display_list(sizeof(*mtxPrev)); if (mtx == NULL || mtxPrev == NULL) { return FALSE; } - + gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); mtxf_to_mtx(mtxPrev, gMatStackPrev[gMatStackIndex]); @@ -446,10 +468,10 @@ static void geo_process_switch(struct GraphNodeSwitchCase *node) { */ static void geo_process_camera(struct GraphNodeCamera *node) { Mat4 cameraTransform; - + // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } - + Mtx *rollMtx = alloc_display_list(sizeof(*rollMtx)); if (rollMtx == NULL) { return; } @@ -477,7 +499,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) { // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + if (node->fnNode.node.children != 0) { gCurGraphNodeCamera = node; node->matrixPtr = &gMatStack[gMatStackIndex]; @@ -497,7 +519,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) { static void geo_process_translation_rotation(struct GraphNodeTranslationRotation *node) { Mat4 mtxf; Vec3f translation; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } @@ -505,10 +527,10 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); - + // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -526,7 +548,7 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation static void geo_process_translation(struct GraphNodeTranslation *node) { Mat4 mtxf; Vec3f translation; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } @@ -534,10 +556,10 @@ static void geo_process_translation(struct GraphNodeTranslation *node) { mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); - + // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -554,7 +576,7 @@ static void geo_process_translation(struct GraphNodeTranslation *node) { */ static void geo_process_rotation(struct GraphNodeRotation *node) { Mat4 mtxf; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } @@ -569,10 +591,10 @@ static void geo_process_rotation(struct GraphNodeRotation *node) { mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); vec3s_copy(node->prevRotation, node->rotation); node->prevTimestamp = gGlobalTimer; - + // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -590,7 +612,7 @@ static void geo_process_rotation(struct GraphNodeRotation *node) { static void geo_process_scale(struct GraphNodeScale *node) { Vec3f scaleVec; Vec3f prevScaleVec; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } @@ -603,7 +625,7 @@ static void geo_process_scale(struct GraphNodeScale *node) { // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -621,12 +643,12 @@ static void geo_process_scale(struct GraphNodeScale *node) { */ static void geo_process_billboard(struct GraphNodeBillboard *node) { Vec3f translation; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } - + s16 nextMatStackIndex = gMatStackIndex + 1; - + vec3s_to_vec3f(translation, node->translation); mtxf_billboard(gMatStack[nextMatStackIndex], gMatStack[gMatStackIndex], translation, gCurGraphNodeCamera->roll); @@ -646,7 +668,7 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) { // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -792,10 +814,10 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { Vec3f translation; Vec3s rotationPrev; Vec3f translationPrev; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } - + u16 *animAttribute = gCurrAnimAttribute; u8 animType = gCurAnimType; @@ -813,7 +835,7 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { mtxf_rotate_xyz_and_translate(matrix, translationPrev, rotationPrev); mtxf_mul(gMatStackPrev[gMatStackIndex + 1], matrix, gMatStackPrev[gMatStackIndex]); - + // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -886,7 +908,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { Vec3f shadowPosPrev; Vec3f animOffset; f32 shadowScale; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } @@ -949,30 +971,44 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer; } + if (sShadowInterpCount < MAX_SHADOW_NODES) { + struct ShadowInterp* interp = &sShadowInterp[sShadowInterpCount++]; + gShadowInterpCurrent = interp; + interp->gfx = NULL; + interp->node = node; + interp->shadowScale = shadowScale; + interp->obj = gCurGraphNodeObject; + vec3f_copy(interp->shadowPos, shadowPos); + vec3f_copy(interp->shadowPosPrev, shadowPosPrev); + } else { + gShadowInterpCurrent = NULL; + } + Gfx *shadowListPrev = create_shadow_below_xyz(shadowPosPrev[0], shadowPosPrev[1], shadowPosPrev[2], shadowScale, node->shadowSolidity, node->shadowType); - Gfx *shadowList = create_shadow_below_xyz(shadowPos[0], shadowPos[1], shadowPos[2], shadowScale, - node->shadowSolidity, node->shadowType); - if (shadowListPrev != NULL && shadowList != NULL) { + if (gShadowInterpCurrent != NULL) { + gShadowInterpCurrent->gfx = shadowListPrev; + } + + if (shadowListPrev != NULL) { mtxf_translate(mtxf, shadowPos); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, *gCurGraphNodeCamera->matrixPtr); - mtxf_translate(mtxf, shadowPosPrev); mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, *gCurGraphNodeCamera->matrixPtrPrev); - + // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } if (gShadowAboveWaterOrLava == TRUE) { - geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList), + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowListPrev), (void *) VIRTUAL_TO_PHYSICAL(shadowListPrev), 4); } else if (gMarioOnIceOrCarpet == TRUE) { - geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList), + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowListPrev), (void *) VIRTUAL_TO_PHYSICAL(shadowListPrev), 5); } else { - geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList), + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowListPrev), (void *) VIRTUAL_TO_PHYSICAL(shadowListPrev), 6); } gMatStackIndex--; @@ -1034,7 +1070,7 @@ static s32 obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { // This multiplication should really be performed on 4:3 as well, // but the issue will be more apparent on widescreen. hScreenEdge *= GFX_DIMENSIONS_ASPECT_RATIO; - + s16 cullingRadius = 300; struct GraphNode *geo = node->sharedChild; if (geo != NULL && geo->type == GRAPH_NODE_TYPE_CULLING_RADIUS) { @@ -1260,7 +1296,7 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { Mat4 mat; Vec3f translation; Vec3f scalePrev; - + // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } @@ -1304,10 +1340,10 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { if (node->fnNode.func != NULL) { node->fnNode.func(GEO_CONTEXT_HELD_OBJ, &node->fnNode.node, (struct AllocOnlyPool *) gMatStack[gMatStackIndex + 1]); } - + // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - + gGeoTempState.type = gCurAnimType; gGeoTempState.enabled = gCurAnimEnabled; gGeoTempState.frame = gCurrAnimFrame; @@ -1461,7 +1497,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) Mtx *initialMatrix = alloc_display_list(sizeof(*initialMatrix)); if (initialMatrix == NULL) { return; } - + gMatStackIndex = 0; gCurAnimType = 0; vec3s_set(viewport->vp.vtrans, node->x * 4, node->y * 4, 511); @@ -1493,7 +1529,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&sViewportPrev)); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gMatStackFixed[gMatStackIndex]), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - + gCurGraphNodeRoot = node; if (node->node.children != NULL) { geo_process_node_and_siblings(node->node.children); diff --git a/src/game/rendering_graph_node.h b/src/game/rendering_graph_node.h index b0851aa9..321560d1 100644 --- a/src/game/rendering_graph_node.h +++ b/src/game/rendering_graph_node.h @@ -33,4 +33,15 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor); void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b); void interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b); +struct ShadowInterp { + Gfx* gfx; + Vec3f shadowPos; + Vec3f shadowPosPrev; + Vtx *verts; + Gfx *displayList; + struct GraphNodeShadow *node; + f32 shadowScale; + struct GraphNodeObject *obj; +}; + #endif // RENDERING_GRAPH_NODE_H diff --git a/src/game/shadow.c b/src/game/shadow.c index 12da7b59..1099bd53 100644 --- a/src/game/shadow.c +++ b/src/game/shadow.c @@ -16,6 +16,9 @@ // Avoid Z-fighting #define find_floor_height_and_data 0.4 + find_floor_height_and_data +extern u8 gRenderingInterpolated; +extern struct ShadowInterp* gShadowInterpCurrent; + /** * @file shadow.c * This file implements a self-contained subsystem used to draw shadows. @@ -114,6 +117,39 @@ s8 gMarioOnIceOrCarpet; s8 sMarioOnFlyingCarpet; s16 sSurfaceTypeBelowShadow; +static Vtx* shadow_get_or_alloc_verts(u8 vertCount) { + if (gRenderingInterpolated) { + if (gShadowInterpCurrent == NULL) { + return NULL; + } + return gShadowInterpCurrent->verts; + } else { + Vtx* verts = alloc_display_list(vertCount * sizeof(Vtx)); + if (gShadowInterpCurrent) { + gShadowInterpCurrent->verts = verts; + } + return verts; + } + return NULL; +} + +static Gfx* shadow_get_or_alloc_display_list(u8 dlCount) { + if (gRenderingInterpolated) { + if (gShadowInterpCurrent == NULL) { + return NULL; + } + return gShadowInterpCurrent->displayList; + } else { + Gfx *displayList = alloc_display_list(dlCount * sizeof(Gfx)); + if (gShadowInterpCurrent) { + gShadowInterpCurrent->displayList = displayList; + } + return displayList; + } + return NULL; + +} + /** * Let (oldZ, oldX) be the relative coordinates of a point on a rectangle, * assumed to be centered at the origin on the standard SM64 X-Z plane. This @@ -622,8 +658,8 @@ Gfx *create_shadow_player(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 soli return NULL; } - verts = alloc_display_list(9 * sizeof(Vtx)); - displayList = alloc_display_list(5 * sizeof(Gfx)); + verts = shadow_get_or_alloc_verts(9); + displayList = shadow_get_or_alloc_display_list(5); if (verts == NULL || displayList == NULL) { return NULL; } @@ -650,8 +686,8 @@ Gfx *create_shadow_circle_9_verts(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, return NULL; } - verts = alloc_display_list(9 * sizeof(Vtx)); - displayList = alloc_display_list(5 * sizeof(Gfx)); + verts = shadow_get_or_alloc_verts(9); + displayList = shadow_get_or_alloc_display_list(5); if (verts == NULL || displayList == NULL) { return 0; @@ -676,8 +712,8 @@ Gfx *create_shadow_circle_4_verts(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, return NULL; } - verts = alloc_display_list(4 * sizeof(Vtx)); - displayList = alloc_display_list(5 * sizeof(Gfx)); + verts = shadow_get_or_alloc_verts(4); + displayList = shadow_get_or_alloc_display_list(5); if (verts == NULL || displayList == NULL) { return 0; @@ -709,8 +745,8 @@ Gfx *create_shadow_circle_assuming_flat_ground(f32 xPos, f32 yPos, f32 zPos, s16 distBelowFloor = floorHeight - yPos; } - verts = alloc_display_list(4 * sizeof(Vtx)); - displayList = alloc_display_list(5 * sizeof(Gfx)); + verts = shadow_get_or_alloc_verts(4); + displayList = shadow_get_or_alloc_display_list(5); if (verts == NULL || displayList == NULL) { return 0; @@ -738,8 +774,8 @@ Gfx *create_shadow_spike_ext(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 s return NULL; } - verts = alloc_display_list(4 * sizeof(Vtx)); - displayList = alloc_display_list(5 * sizeof(Gfx)); + verts = shadow_get_or_alloc_verts(4); + displayList = shadow_get_or_alloc_display_list(5); if (verts == NULL || displayList == NULL) { return 0; @@ -757,8 +793,9 @@ Gfx *create_shadow_spike_ext(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 s * underneath the shadow is totally flat. */ Gfx *create_shadow_rectangle(f32 halfWidth, f32 halfLength, f32 relY, u8 solidity) { - Vtx *verts = alloc_display_list(4 * sizeof(Vtx)); - Gfx *displayList = alloc_display_list(5 * sizeof(Gfx)); + Vtx *verts = shadow_get_or_alloc_verts(4); + Gfx *displayList = shadow_get_or_alloc_display_list(5); + f32 frontLeftX, frontLeftZ, frontRightX, frontRightZ, backLeftX, backLeftZ, backRightX, backRightZ; if (verts == NULL || displayList == NULL) { diff --git a/src/game/skybox.c b/src/game/skybox.c index 88620750..86534385 100644 --- a/src/game/skybox.c +++ b/src/game/skybox.c @@ -45,10 +45,10 @@ * first, in a display list with the Z buffer disabled */ struct Skybox { - /// The camera's yaw, from 0 to 65536, which maps to 0 to 360 degrees - u16 yaw; - /// The camera's pitch, which is bounded by +-16384, which maps to -90 to 90 degrees - s16 pitch; + /// The camera's yaw, from 0 to (M_PI*2), which maps to 0 to 360 degrees + f32 yaw; + /// The camera's pitch, which is bounded by +-(M_PI/2), which maps to -90 to 90 degrees + f32 pitch; /// The skybox's X position in world space f32 scaledX; /// The skybox's Y position in world space @@ -138,11 +138,11 @@ u8 sSkyboxColors[][3] = { * (how far is the camera rotated from 0, scaled 0 to 1) * * (the screen width) */ -s32 calculate_skybox_scaled_x(s8 player, f32 fov) { +f32 calculate_skybox_scaled_x(s8 player, f32 fov) { f32 yaw = sSkyBoxInfo[player].yaw; //! double literals are used instead of floats - f32 scaledX = SCREEN_WIDTH * 360.0 * yaw / (fov * 65536.0); + f32 scaledX = SCREEN_WIDTH * 180.0 * yaw / (fov * M_PI); if (scaledX > SKYBOX_WIDTH) { scaledX -= (s32) scaledX / SKYBOX_WIDTH * SKYBOX_WIDTH; @@ -156,9 +156,9 @@ s32 calculate_skybox_scaled_x(s8 player, f32 fov) { * fov may have been used in an earlier version, but the developers changed the function to always use * 90 degrees. */ -s32 calculate_skybox_scaled_y(s8 player, UNUSED f32 fov) { +f32 calculate_skybox_scaled_y(s8 player, UNUSED f32 fov) { // Convert pitch to degrees. Pitch is bounded between -90 (looking down) and 90 (looking up). - f32 pitchInDegrees = (f32) sSkyBoxInfo[player].pitch * 360.0 / 65535.0; + f32 pitchInDegrees = sSkyBoxInfo[player].pitch * 180.0 / M_PI; // Scale by 360 / fov f32 degreesToScale = 360.0f * pitchInDegrees / 90.0; @@ -193,7 +193,7 @@ static s32 get_top_left_tile_idx(s8 player) { * into an x and y by modulus and division by SKYBOX_COLS. x and y are then scaled by * SKYBOX_TILE_WIDTH to get a point in world space. */ -Vtx *make_skybox_rect(s32 tileIndex, s8 colorIndex, s32 row, s32 col, s8 player) { +Vtx *make_skybox_rect(s32 tileIndex, s8 colorIndex, s32 row, s32 col) { extern Vtx* gBackgroundSkyboxVerts[3][3]; Vtx *verts; @@ -242,7 +242,7 @@ void draw_skybox_tile_grid(Gfx **dlist, s8 background, s8 player, s8 colorIndex) texture = (Texture*)(*(SkyboxTexture *) segmented_to_virtual(sSkyboxTextures[background]))[tileIndex]; } - Vtx *vertices = make_skybox_rect(tileIndex, colorIndex, row, col, player); + Vtx *vertices = make_skybox_rect(tileIndex, colorIndex, row, col); gLoadBlockTexture((*dlist)++, 32, 32, G_IM_FMT_RGBA, texture); gSPVertex((*dlist)++, VIRTUAL_TO_PHYSICAL(vertices), 4, 0); @@ -342,8 +342,11 @@ Gfx *create_skybox_facing_camera(s8 player, s8 background, f32 fov, //! fov is always set to 90.0f. If this line is removed, then the game crashes because fov is 0 on //! the first frame, which causes a floating point divide by 0 fov = 90.0f; - sSkyBoxInfo[player].yaw = atan2s(cameraFaceZ, cameraFaceX); - sSkyBoxInfo[player].pitch = atan2s(sqrtf(cameraFaceX * cameraFaceX + cameraFaceZ * cameraFaceZ), cameraFaceY); + + sSkyBoxInfo[player].yaw = (M_PI / 2.0) - atan2(cameraFaceZ, cameraFaceX); + if (sSkyBoxInfo[player].yaw < 0) { sSkyBoxInfo[player].yaw += M_PI * 2.0; } + sSkyBoxInfo[player].pitch = (M_PI / 2.0) - atan2(sqrtf(cameraFaceX * cameraFaceX + cameraFaceZ * cameraFaceZ), cameraFaceY); + sSkyBoxInfo[player].scaledX = calculate_skybox_scaled_x(player, fov); sSkyBoxInfo[player].scaledY = calculate_skybox_scaled_y(player, fov); sSkyBoxInfo[player].upperLeftTile = get_top_left_tile_idx(player);