diff --git a/src/SB/Core/x/xCamera.cpp b/src/SB/Core/x/xCamera.cpp index d04d64e09..ca929d706 100644 --- a/src/SB/Core/x/xCamera.cpp +++ b/src/SB/Core/x/xCamera.cpp @@ -6,6 +6,8 @@ #include "xScene.h" #include "xCollideFast.h" #include "xScrFx.h" +#include "zGlobals.h" +#include "zGrid.h" #include "iMath.h" @@ -29,6 +31,8 @@ static xMat4x3 sCameraFXMatOld; cameraFX sCameraFX[10]; cameraFXTableEntry sCameraFXTable[3] = {}; +zGlobals globals; + static void xCameraFXInit(); void add_camera_tweaks(); @@ -466,8 +470,417 @@ void SweptSphereHitsCameraEnt(xScene*, xRay3* ray, xQCData* qcd, xEnt* ent, void } static void _xCameraUpdate(xCamera* cam, F32 dt) +// NONMATCH("https://decomp.me/scratch/2q6zO") { - // lol nope + if (!cam->tgt_mat) + return; + + static F32 last_dt = 1.0f / 60; + + xCam_worldtocyl(cam->dcur, cam->hcur, cam->pcur, cam->tgt_mat, &cam->mat.pos, cam->flags); + + F32 wcvx = cam->mat.pos.x - cam->omat.pos.x; + F32 wcvy = cam->mat.pos.y - cam->omat.pos.y; + F32 wcvz = cam->mat.pos.z - cam->omat.pos.z; + F32 m = 1.0f / last_dt; + wcvx *= m; + wcvy *= m; + wcvz *= m; + + cam->omat.pos = cam->mat.pos; + + xCam_buildbasis(cam); + + F32 dcv = wcvx * cam->mbasis.at.x + wcvz * cam->mbasis.at.z; + F32 hcv = wcvy; + F32 pcv = wcvx * cam->mbasis.right.x + wcvz * cam->mbasis.right.z; + wcvx *= dt; + wcvy *= dt; + wcvz *= dt; + + cam->mat.pos.x += wcvx; + cam->mat.pos.y += wcvy; + cam->mat.pos.z += wcvz; + + if (cam->flags & 0x1) + { + F32 tnext = cam->tmr - dt; + if (tnext <= 0.0f) + { + cam->flags &= ~0x1; + cam->tmr = 0.0f; + cam->omat.pos = cam->mat.pos; + } + else + { + F32 dtg = cam->dgoal - cam->dcur; + F32 htg = cam->hgoal - cam->hcur; + F32 ptg = (cam->dgoal + cam->dcur) * xDangleClamp(cam->pgoal - cam->pcur) * 0.5f; + F32 dsv, hsv, psv; + if (tnext <= cam->tm_dec) + { + F32 T_inv = 1.0f / cam->tmr; + dsv = (2.0f * dtg - dcv * dt) * T_inv; + hsv = (2.0f * htg - hcv * dt) * T_inv; + psv = (2.0f * ptg - pcv * dt) * T_inv; + } + else if (tnext <= cam->tm_acc) + { + F32 T_inv = 1.0f / (2.0f * cam->tmr - dt - cam->tm_dec); + dsv = (2.0f * dtg - dcv * dt) * T_inv; + hsv = (2.0f * htg - hcv * dt) * T_inv; + psv = (2.0f * ptg - pcv * dt) * T_inv; + } + else + { + F32 it = cam->tm_acc + (cam->tmr - dt) - cam->tm_dec; + F32 ot = 2.0f / (cam->tmr + cam->tm_acc - cam->tm_dec); + F32 T_inv = 1.0f / (cam->tmr - cam->tm_acc); + dsv = (2.0f * dtg - (dtg * ot + cam->depv) * 0.5f * it - dcv * dt) * T_inv; + hsv = (2.0f * htg - (htg * ot + cam->hepv) * 0.5f * it - hcv * dt) * T_inv; + psv = (2.0f * ptg - (ptg * ot + cam->pepv) * 0.5f * it - pcv * dt) * T_inv; + } + F32 dpv = dsv - dcv; + F32 hpv = hsv - hcv; + F32 ppv = psv - pcv; + F32 vax = cam->mbasis.right.x * ppv + cam->mbasis.at.x * dpv; + F32 vay = cam->mbasis.right.y * ppv + hpv; + F32 vaz = cam->mbasis.right.z * ppv + cam->mbasis.at.z * dpv; + vax *= dt; + vay *= dt; + vaz *= dt; + cam->mat.pos.x += vax; + cam->mat.pos.y += vay; + cam->mat.pos.z += vaz; + cam->tmr = tnext; + } + } + else + { + if (cam->flags & 0x2) + { + if (xeq(cam->dcur / cam->dgoal, 1.0f, 1e-5f)) + { + } + else + { + F32 dtg = cam->dgoal - cam->dcur; + xCam_CorrectD(cam, dtg, dcv, dt); + } + } + else if (cam->dmax > cam->dmin) + { + if (cam->dcur < cam->dmin) + { + F32 dtg = cam->dmin - cam->dcur; + xCam_CorrectD(cam, dtg, dcv, dt); + } + else if (cam->dcur > cam->dmax) + { + F32 dtg = cam->dmax - cam->dcur; + xCam_CorrectD(cam, dtg, dcv, dt); + } + } + + if (cam->flags & 0x4) + { + if (xeq(cam->hcur / cam->hgoal, 1.0f, 1e-5f)) + { + } + else + { + F32 htg = cam->hgoal - cam->hcur; + xCam_CorrectH(cam, htg, hcv, dt); + } + } + else if (cam->hmax > cam->hmin) + { + if (cam->hcur < cam->hmin) + { + F32 htg = cam->hmin - cam->hcur; + xCam_CorrectH(cam, htg, hcv, dt); + } + else if (cam->hcur > cam->hmax) + { + F32 htg = cam->hmax - cam->hcur; + xCam_CorrectH(cam, htg, hcv, dt); + } + } + + if (cam->flags & 0x8) + { + if (xeq(cam->pcur / cam->pgoal, 1.0f, 1e-5f)) + { + } + else + { + F32 ptg = cam->dcur * xDangleClamp(cam->pgoal - cam->pcur); + xCam_CorrectP(cam, ptg, pcv, dt); + } + } + else if (cam->pmax > cam->pmin) + { + F32 dphi = xDangleClamp(cam->pmax - cam->pcur); + F32 dplo = xDangleClamp(cam->pmin - cam->pcur); + if (dplo > 0.0f && (dphi > 0.0f || xabs(dplo) <= xabs(dphi))) + { + F32 ptg = (1e-5f + dplo) * cam->dcur; + xCam_CorrectP(cam, ptg, pcv, dt); + } + else if (dphi < 0.0f) + { + F32 ptg = (dphi - 1e-5f) * cam->dcur; + xCam_CorrectP(cam, ptg, pcv, dt); + } + else + { + xCam_DampP(cam, pcv, dt); + } + } + else + { + xCam_DampP(cam, pcv, dt); + } + } + + if (cam->flags & 0x80) + { + xVec3 oeu, eu; + xMat3x3GetEuler(&cam->mat, &eu); + xMat3x3GetEuler(&cam->omat, &oeu); + + F32 m = 1.0f / last_dt; + F32 ycv = m * xDangleClamp(eu.x - oeu.x); + F32 pcv = m * xDangleClamp(eu.y - oeu.y); + F32 rcv = m * xDangleClamp(eu.z - oeu.z); + ycv *= cam->yaw_ccv; + pcv *= cam->pitch_ccv; + rcv *= cam->roll_ccv; + + cam->omat = cam->mat; + cam->yaw_cur += ycv * dt; + cam->pitch_cur += pcv * dt; + cam->roll_cur += rcv * dt; + + if (cam->flags & 0x40) + { + F32 tnext = cam->ltmr - dt; + if (tnext <= 0.0f) + { + cam->flags &= ~0x40; + cam->ltmr = 0.0f; + } + else + { + F32 ytg = xDangleClamp(cam->yaw_goal - cam->yaw_cur); + F32 ptg = xDangleClamp(cam->pitch_goal - cam->pitch_cur); + F32 rtg = xDangleClamp(cam->roll_goal - cam->roll_cur); + F32 ysv, psv, rsv; + if (tnext <= cam->ltm_dec) + { + F32 T_inv = 1.0f / cam->ltmr; + ysv = (2.0f * ytg - ycv * dt) * T_inv; + psv = (2.0f * ptg - pcv * dt) * T_inv; + rsv = (2.0f * rtg - rcv * dt) * T_inv; + } + else if (tnext <= cam->ltm_acc) + { + F32 T_inv = 1.0f / (2.0f * cam->ltmr - dt - cam->ltm_dec); + ysv = (2.0f * ytg - ycv * dt) * T_inv; + psv = (2.0f * ptg - pcv * dt) * T_inv; + rsv = (2.0f * rtg - rcv * dt) * T_inv; + } + else + { + F32 it = cam->ltm_acc + (cam->ltmr - dt) - cam->ltm_dec; + F32 ot = 2.0f / (cam->ltmr + cam->ltm_acc - cam->ltm_dec); + F32 T_inv = 1.0f / (cam->ltmr - cam->ltm_acc); + ysv = ((2.0f * ytg - (ytg * ot + cam->yaw_epv) * 0.5f * it) - ycv * dt) * T_inv; + psv = + ((2.0f * ptg - (ptg * ot + cam->pitch_epv) * 0.5f * it) - pcv * dt) * T_inv; + rsv = + ((2.0f * rtg - (rtg * ot + cam->roll_epv) * 0.5f * it) - rcv * dt) * T_inv; + } + F32 ypv = ysv - ycv; + F32 ppv = psv - pcv; + F32 rpv = rsv - rcv; + cam->yaw_cur += ypv * dt; + cam->pitch_cur += ppv * dt; + cam->roll_cur += rpv * dt; + xMat3x3Euler(&cam->mat, cam->yaw_cur, cam->pitch_cur, cam->roll_cur); + cam->ltmr = tnext; + } + } + else + { + if (xeq(cam->yaw_cur, cam->yaw_goal, 1e-5f)) + { + } + else + { + F32 ytg = xDangleClamp(cam->yaw_goal - cam->yaw_cur); + xCam_CorrectYaw(cam, ytg, ycv, dt); + } + + if (xeq(cam->pitch_cur, cam->pitch_goal, 1e-5f)) + { + } + else + { + F32 ptg = xDangleClamp(cam->pitch_goal - cam->pitch_cur); + xCam_CorrectPitch(cam, ptg, pcv, dt); + } + + if (xeq(cam->roll_cur, cam->roll_goal, 1e-5f)) + { + } + else + { + F32 rtg = xDangleClamp(cam->roll_goal - cam->roll_cur); + xCam_CorrectRoll(cam, rtg, rcv, dt); + } + + xMat3x3Euler(&cam->mat, cam->yaw_cur, cam->pitch_cur, cam->roll_cur); + } + } + else + { + xQuatFromMat(&cam->orn_cur, &cam->mat); + + xQuat oq; + xQuatFromMat(&oq, &cam->omat); + + xQuat qdiff_o_c; + xQuatDiff(&qdiff_o_c, &oq, &cam->orn_cur); + + xRot rot_cv; + xQuatToAxisAngle(&qdiff_o_c, &rot_cv.axis, &rot_cv.angle); + rot_cv.angle *= m; + rot_cv.angle = 0.0f; // lol + + cam->omat = cam->mat; + + xVec3 f; + xMat3x3RMulVec(&f, cam->tgt_mat, &cam->focus); + xVec3AddTo(&f, &cam->tgt_mat->pos); + + xVec3 v; + F32 dist; + xVec3NormalizeDistXZMacro(&v, &cam->mat.pos, &cam->tgt_mat->pos, &dist); + v.y = 0.0f; + + if (cam->tgt_mat->at.x * v.x + cam->tgt_mat->at.y * v.y + cam->tgt_mat->at.z * v.z < 0.0f) + { + F32 mpx = f.x - cam->tgt_mat->pos.x; + F32 mpy = f.y - cam->tgt_mat->pos.y; + F32 mpz = f.z - cam->tgt_mat->pos.z; + F32 s = (mpx * v.x + mpy * v.y + mpz * v.z) * -2.0f; + mpx = v.x * s; + mpy = v.y * s; + mpz = v.z * s; + f.x += mpx; + f.y += mpy; + f.z += mpz; + } + + xMat3x3 des_mat; + xMat3x3LookAt(&des_mat, &f, &cam->mat.pos); + + xMat3x3 latgt; + xMat3x3LookAt(&latgt, &cam->tgt_mat->pos, &cam->mat.pos); + + F32 ang_dist = xacos(latgt.at.x * des_mat.at.x + latgt.at.y * des_mat.at.y + + latgt.at.z * des_mat.at.z); + + if (ang_dist > DEG2RAD(30.0f)) + { + xQuat a; + xQuatFromMat(&a, &latgt); + + xQuat b; + xQuatFromMat(&b, &des_mat); + + xQuat o; + F32 s = PI - ang_dist; + if (s < DEG2RAD(90.0f)) + { + if (s > DEG2RAD(5.0f)) + { + xQuatSlerp(&o, &a, &b, s / ang_dist); + } + else + { + o = a; + } + } + else + { + xQuatSlerp(&o, &a, &b, DEG2RAD(30.0f) / ang_dist); + } + + xQuatToMat(&o, &des_mat); + } + + xQuat desq; + xQuatFromMat(&desq, &des_mat); + + xCameraLook(cam, 0, &desq, 0.25f, 0.0f, 0.0f); + + xQuat difq; + xQuatConj(&difq, &cam->orn_cur); + xQuatMul(&difq, &difq, &desq); + + xQuat newq; + xQuatSlerp(&newq, &cam->orn_cur, &desq, 25.5f * dt); + xQuatToMat(&newq, &cam->mat); + } + + while (xcam_do_collis && sCamCollis) + { + xSweptSphere sws; + + xVec3 tgtpos; + tgtpos.x = cam->tgt_mat->pos.x; + tgtpos.y = 0.7f + cam->tgt_mat->pos.y; + tgtpos.z = cam->tgt_mat->pos.z; + + xSweptSpherePrepare(&sws, &tgtpos, &cam->mat.pos, 0.07f); + xSweptSphereToEnv(&sws, globals.sceneCur->env); + + xRay3 ray; + xVec3Copy(&ray.origin, &sws.start); + xVec3Sub(&ray.dir, &sws.end, &sws.start); + + ray.max_t = xVec3Length(&ray.dir); + + F32 one_len = 1.0f / MAX(ray.max_t, 1e-5f); + xVec3SMul(&ray.dir, &ray.dir, one_len); + + ray.flags = 0x800; + if (!(ray.flags & 0x400)) + { + ray.flags |= 0x400; + ray.min_t = 0.0f; + } + + xRayHitsGrid(&colls_grid, globals.sceneCur, &ray, SweptSphereHitsCameraEnt, &sws.qcd, &sws); + xRayHitsGrid(&colls_oso_grid, globals.sceneCur, &ray, SweptSphereHitsCameraEnt, &sws.qcd, + &sws); + + if (sws.curdist != sws.dist) + { + F32 stopdist = MAX(sws.curdist, 0.6f); + cam->mat.pos.x = ray.origin.x + stopdist * ray.dir.x; + cam->mat.pos.y = ray.origin.y + stopdist * ray.dir.y; + cam->mat.pos.z = ray.origin.z + stopdist * ray.dir.z; + } + + break; + } + + last_dt = dt; + + iCameraUpdatePos(cam->lo_cam, &cam->mat); } void xCameraUpdate(xCamera* cam, F32 dt) @@ -1098,7 +1511,153 @@ void xBinaryCamera::stop() } void xBinaryCamera::update(F32 dt) +// NONMATCH("https://decomp.me/scratch/c9iST") { + xVec3& A = camera->mat.pos; + const xVec3& B = *s1; + const xVec3& C = *s2; + + xVec3 CA = { 0.0f, 0.0f, 0.0f }; + CA.x = A.x - C.x; + CA.z = A.z - C.z; + + F32 dCA = CA.length(); + if (dCA < 0.01f) + { + CA.assign(A.x - B.x, 0.0f, A.z - B.z).right_normalize(); + dCA = 0.01f; + } + else + { + CA /= dCA; + } + + F32 yaw_start = xatan2(B.x - A.x, B.z - A.z); + F32 yaw_end; + if (dCA > s2_radius) + { + xVec3 Q1, Q2; + bound_sphere_xz(Q1, Q2, C, s2_radius, CA, dCA); + F32 yaw_Q1 = xatan2(Q1.x - A.x, Q1.z - A.z); + F32 yaw_Q2 = xatan2(Q2.x - A.x, Q2.z - A.z); + F32 dyaw1 = xrmod(yaw_Q1 - yaw_start + PI) - PI; + F32 dyaw2 = xrmod(yaw_Q2 - yaw_start + PI) - PI; + + F32 fov = DEG2RAD(1.0f) * xCameraGetFOV(camera) * 0.5f + cfg.margin_angle; + fov = range_limit(fov, 0.0f, PI); + F32 max_dyaw = 0.5f * xabs(dyaw2 - dyaw1); + if (max_dyaw > fov) + { + yaw_end = xatan2(C.x - B.x, C.z - B.z); + } + else if (dyaw1 >= dyaw2) + { + yaw_end = xatan2(C.x - B.x, C.z - B.z); + } + else if (dyaw1 >= -fov) + { + if (dyaw2 <= fov) + { + yaw_end = yaw_start; + } + else + { + yaw_end = yaw_start + (dyaw2 - fov); + } + } + else + { + yaw_end = yaw_start + (dyaw1 + fov); + } + } + else + { + yaw_end = xatan2(C.x - B.x, C.z - B.z); + } + + F32 sstick = 1.0f - xexp(-cfg.stick_speed * dt); + _tagxPad::analog_data& stick = globals.pad0->analog[1]; + + stick_offset.x += (cfg.stick_yaw_vel * stick.offset.x * dt - stick_offset.x) * sstick; + yaw_end += stick_offset.x; + + F32 yaw_diff = xrmod(yaw_end - yaw_start + PI) - PI; + F32 max_yaw_diff = cfg.max_yaw_vel * dt; + if (xabs(yaw_diff) > max_yaw_diff) + { + if (yaw_diff < 0.0f) + { + if (max_yaw_diff > 0.0f) + { + max_yaw_diff = -max_yaw_diff; + } + } + else + { + if (max_yaw_diff < 0.0f) + { + max_yaw_diff = -max_yaw_diff; + } + } + yaw_end = yaw_start + max_yaw_diff; + } + + stick_offset.y += (stick.offset.y - stick_offset.y) * sstick; + + F32 d, h, hf; + if (stick_offset.y > 0.0f) + { + F32 s = stick_offset.y; + d = xlerp(cfg.zone_rest.distance, cfg.zone_below.distance, s); + h = xlerp(cfg.zone_rest.height, cfg.zone_below.height, s); + hf = xlerp(cfg.zone_rest.height_focus, cfg.zone_below.height_focus, s); + } + else + { + F32 s = -stick_offset.y; + d = xlerp(cfg.zone_rest.distance, cfg.zone_above.distance, s); + h = xlerp(cfg.zone_rest.height, cfg.zone_above.height, s); + hf = xlerp(cfg.zone_rest.height_focus, cfg.zone_above.height_focus, s); + } + + xVec3 end_loc = { 0.0f, 0.0f, 0.0f }; + end_loc.x = B.x - d * isin(yaw_end); + end_loc.y = B.y + h; + end_loc.z = B.z - d * icos(yaw_end); + + F32 sloc = 1.0f - xexp(-cfg.move_speed * dt); + + xVec3 cam_loc = { 0.0f, 0.0f, 0.0f }; + cam_loc.x = xlerp(A.x, end_loc.x, sloc); + cam_loc.y = xlerp(A.y, end_loc.y, sloc); + cam_loc.z = xlerp(A.z, end_loc.z, sloc); + + xVec3 heading = { 0.0f, 0.0f, 0.0f }; + heading.x = B.x - end_loc.x; + heading.y = B.y - end_loc.y + hf; + heading.z = B.z - end_loc.z; + + F32 heading_dist2 = heading.length2(); + if (heading_dist2 >= 0.001f) + { + heading /= xsqrt(heading_dist2); + + xQuat end_dir; + xMat3x3 mat; + xMat3x3LookVec(&mat, &heading.invert()); + xQuatFromMat(&end_dir, &mat); + + F32 sdir = 1.0f - xexp(-cfg.turn_speed * dt); + xQuatSlerp(&cam_dir, &cam_dir, &end_dir, sdir); + } + + xMat3x3 mat; + xQuatToMat(&cam_dir, &mat); + + xCameraMove(camera, cam_loc); + xCameraRotate(camera, mat, 0.0f, 0.0f, 0.0f); + + render_debug(); } void xCameraSetFOV(xCamera* cam, F32 fov) diff --git a/src/SB/Core/x/xCamera.h b/src/SB/Core/x/xCamera.h index 17a8a9d53..c12240f5e 100644 --- a/src/SB/Core/x/xCamera.h +++ b/src/SB/Core/x/xCamera.h @@ -286,6 +286,7 @@ void xCameraMove(xCamera* cam, const xVec3& loc); void xCameraMove(xCamera* cam, const xVec3& loc, F32 maxSpeed); void xCameraFOV(xCamera* cam, F32 fov, F32 maxSpeed, F32 dt); void xCameraRotate(xCamera* cam, const xMat3x3& m, F32 time, F32 accel, F32 decl); +void xCameraLook(xCamera* cam, U32 flags, const xQuat* orn_goal, F32 tm, F32 tm_acc, F32 tm_dec); void xCameraLookYPR(xCamera* cam, U32 flags, F32 yaw, F32 pitch, F32 roll, F32 tm, F32 tm_acc, F32 tm_dec); F32 xCameraGetFOV(const xCamera* cam); diff --git a/src/SB/Core/x/xCollide.h b/src/SB/Core/x/xCollide.h index 6d0084383..3805878bd 100644 --- a/src/SB/Core/x/xCollide.h +++ b/src/SB/Core/x/xCollide.h @@ -126,6 +126,7 @@ struct xScene; void xCollideInit(xScene* sc); void xCollideCalcTri(xCollis::tri_data&, const xModelInstance&, const xVec3&, const xVec3&); S32 xSweptSphereToBox(xSweptSphere* sws, xBox* box, xMat4x3* mat); +S32 xSweptSphereToEnv(xSweptSphere* sws, xEnv* env); S32 xSweptSphereToModel(xSweptSphere* sws, RpAtomic* model, RwMatrix* mat); S32 xSweptSphereToScene(xSweptSphere* sws, xScene* sc, xEnt* mover, U8 collType); void xSweptSpherePrepare(xSweptSphere* sws, xVec3* start, xVec3* end, F32 radius); diff --git a/src/SB/Core/x/xEntMotion.cpp b/src/SB/Core/x/xEntMotion.cpp index 475fe16ea..1a2ddecf3 100644 --- a/src/SB/Core/x/xEntMotion.cpp +++ b/src/SB/Core/x/xEntMotion.cpp @@ -1,11 +1,17 @@ #include "xDebug.h" +#include "xDraw.h" #include "xEntMotion.h" +#include "xEntMotionAsset.h" #include "xMath.h" +#include "xMath3.h" +#include "xMathInlines.h" #include "xPad.h" #include "xScene.h" #include "xSpline.h" +#include "zMovePoint.h" + #include static void xEntMotionDebugIPad(xEntMotion* xem); @@ -48,9 +54,9 @@ void xEntMotionInit(xEntMotion* motion, xEnt* owner, xEntMotionAsset* asset) motion->er.p = 1.0f; } - motion->er.brt = motion->er.et + motion->er.wet; + motion->er.brt = motion->er.et + motion->er.wet; motion->er.ert = motion->er.brt + motion->er.rt; - motion->er.p = motion->er.ert + motion->er.wrt; + motion->er.p = motion->er.ert + motion->er.wrt; } else if (motion->type == XENTMOTION_TYPE_ORB) { @@ -143,13 +149,13 @@ void xEntMotionReset(xEntMotion* motion, xScene* sc) } else if (motion->type == XENTMOTION_TYPE_ORB) { - xVec3Copy(&motion->orb.orig, (xVec3 *)&motion->owner->model->Mat->pos); + xVec3Copy(&motion->orb.orig, (xVec3*)&motion->owner->model->Mat->pos); } else if (motion->type == XENTMOTION_TYPE_PEN) { xVec3 a, b, c; - modlpos = (xVec3 *)&motion->owner->model->Mat->pos; + modlpos = (xVec3*)&motion->owner->model->Mat->pos; modlrot = (xMat4x3*)motion->owner->model->Mat; aspen = &motion->asset->pen; @@ -183,25 +189,26 @@ void xEntMotionReset(xEntMotion* motion, xScene* sc) if ((ownr != NULL) && (ownr->frame != NULL) && (ownr->model != NULL)) { - xVec3Copy(&mech->apos, (xVec3 *)&ownr->model->Mat->pos); + xVec3Copy(&mech->apos, (xVec3*)&ownr->model->Mat->pos); if (mkasst->sld_axis == 0) { - xVec3Copy(&mech->dir, (xVec3 *)&ownr->model->Mat->right); + xVec3Copy(&mech->dir, (xVec3*)&ownr->model->Mat->right); } else if (mkasst->sld_axis == 1) { - xVec3Copy(&mech->dir, (xVec3 *)&ownr->model->Mat->up); + xVec3Copy(&mech->dir, (xVec3*)&ownr->model->Mat->up); } else { - xVec3Copy(&mech->dir, (xVec3 *)&ownr->model->Mat->at); + xVec3Copy(&mech->dir, (xVec3*)&ownr->model->Mat->at); } xVec3SMul(&mech->bpos, &mech->dir, mkasst->sld_dist); xVec3AddTo(&mech->bpos, &mech->apos); - mech->ss = mkasst->sld_dist / -((mkasst->sld_acc_tm + mkasst->sld_dec_tm) * 0.5f - mkasst->sld_tm); + mech->ss = mkasst->sld_dist / + -((mkasst->sld_acc_tm + mkasst->sld_dec_tm) * 0.5f - mkasst->sld_tm); mech->tsfd = mkasst->sld_tm - mkasst->sld_dec_tm; mech->tsbd = mkasst->sld_tm - mkasst->sld_acc_tm; @@ -394,6 +401,139 @@ void xEntMPGetNext(xEntMotion* motion, xMovePoint* prev, xScene* sc) } } +U32 xQuatEquals(const xQuat* a, const xQuat* b); // Should be linked weakly + +static void xEntMPMove(xEntMotion* motion, xScene* sc, F32 dt, xEntFrame* frame) +{ + xEntMPData* mp = &motion->mp; + + if (mp->dest == mp->src || !mp->dest) + return; + + if (motion->tmr > 0.0f) + { + motion->tmr -= dt; + return; + } + + frame->mode = 2; + + F32 newdist = mp->curdist + mp->speed * dt; + if (newdist >= mp->dist) + { + frame->dpos.x = mp->dest->pos->x - frame->mat.pos.x; + frame->dpos.y = mp->dest->pos->y - frame->mat.pos.y; + frame->dpos.z = mp->dest->pos->z - frame->mat.pos.z; + + if (motion->asset->mp.flags & 0x1) + { + xEntMotionStop(motion); + } + + xMovePoint* prev = mp->src; + mp->src = mp->dest; + xEntMPGetNext(motion, prev, sc); + + motion->tmr = mp->src->asset->delay; + return; + } + + mp->curdist = newdist; + + F32 qdot; + xVec3 tgt, dir, bank; + xQuat quat, qold; + xMat3x3 tmpmat; + if (mp->spl) + { + F32 u = xSpline3_EvalArcApprox(mp->spl, newdist, 0, &tgt); + + if (motion->asset->flags & 1) + { + xSpline3_EvalSeg(mp->spl, u, 1, &dir); + if (motion->asset->use_banking == 1) + { + xSpline3_EvalSeg(mp->spl, u, 2, &bank); + } + + if (xVec3Length2(&dir) < 0.000001f) + { + if (u < 0.1f) + u += 0.01f; + else + u -= 0.01f; + xSpline3_EvalSeg(mp->spl, u, 1, &dir); + if (motion->asset->use_banking == 1) + { + xSpline3_EvalSeg(mp->spl, u, 2, &bank); + } + } + + if (motion->asset->use_banking != 1) + { + xVec3Inv(&dir, &dir); + xMat3x3LookVec(&tmpmat, &dir); + } + else + { + xVec3 gravity = { 0.0f, -sc->gravity, 0.0f }; + + bank = bank * mp->speed * 0.01f + gravity; + dir.normalize(); + bank -= dir * bank.dot(dir); + bank.normalize(); + + tmpmat.at = dir; + tmpmat.right = bank.cross(dir); + tmpmat.up = bank; + } + + xQuatFromMat(&quat, &tmpmat); + xQuatFromMat(&qold, &frame->mat); + + qdot = xQuatDot(&quat, &qold); + if (qdot < 0.0f) + { + xQuatFlip(&quat, &quat); + qdot = -qdot; + } + if (qdot > 1.0f) + { + qdot = 1.0f; + } + qdot = 2.0f * xacos(qdot); + + if (qdot <= PI * dt) + { + frame->mode |= 0x10; + (xMat3x3) frame->mat = tmpmat; + } + else + { + qdot = PI * dt / qdot; + xQuatSlerp(&quat, &qold, &quat, qdot); + xQuatNormalize(&quat, &quat); + xQuatToMat(&quat, &frame->mat); + } + } + } + else + { + xVec3Lerp(&tgt, mp->src->pos, mp->dest->pos, mp->curdist / mp->dist); + + if ((motion->asset->flags & 1) && !xQuatEquals(&mp->aquat, &mp->bquat)) + { + xQuatSlerp(&quat, &mp->aquat, &mp->bquat, MIN(1.0f, 2.0f * (mp->curdist / mp->dist))); + xQuatToMat(&quat, &frame->mat); + frame->mode |= 0x10; + } + } + + frame->dpos.x = tgt.x - frame->mat.pos.x; + frame->dpos.y = tgt.y - frame->mat.pos.y; + frame->dpos.z = tgt.z - frame->mat.pos.z; +} + static void xEntPenMove(xEntMotion* motion, xScene* sc, F32 dt, xEntFrame* frame) { xEntPenData* pen = &motion->pen; @@ -799,7 +939,7 @@ void xEntMotionTranslate(xEntMotion* motion, const xVec3* dpos, xMat4x3* dmat) { xMat4x3Toworld(&motion->mech.apos, dmat, &motion->mech.apos); xMat4x3Toworld(&motion->mech.bpos, dmat, &motion->mech.bpos); - xMat3x3RMulVec(&motion->mech.dir, dmat, &motion->mech.dir); + xMat3x3RMulVec(&motion->mech.dir, dmat, &motion->mech.dir); } } else @@ -889,27 +1029,27 @@ static void xEntMotionDebugWrite(const xEntMotion* xem) switch (xem->type) { - case XENTMOTION_TYPE_ER: - gps = "extend/retract"; - break; - case XENTMOTION_TYPE_ORB: - gps = "orbital"; - break; - case XENTMOTION_TYPE_SPL: - gps = "spline"; - break; - case XENTMOTION_TYPE_MP: - gps = "movepoint"; - break; - case XENTMOTION_TYPE_MECH: - gps = "mechanism"; - break; - case XENTMOTION_TYPE_PEN: - gps = "pendulum"; - break; - default: - gps = "????"; - break; + case XENTMOTION_TYPE_ER: + gps = "extend/retract"; + break; + case XENTMOTION_TYPE_ORB: + gps = "orbital"; + break; + case XENTMOTION_TYPE_SPL: + gps = "spline"; + break; + case XENTMOTION_TYPE_MP: + gps = "movepoint"; + break; + case XENTMOTION_TYPE_MECH: + gps = "mechanism"; + break; + case XENTMOTION_TYPE_PEN: + gps = "pendulum"; + break; + default: + gps = "????"; + break; } xprintf("type: %s\n", gps); @@ -929,175 +1069,241 @@ static void xEntMotionDebugWrite(const xEntMotion* xem) switch (xem->type) { - case XENTMOTION_TYPE_ER: - xprintf("a: <%.3f %.3f %.3f>\n", xem->er.a.x, xem->er.a.y, xem->er.a.z); - xprintf("b: <%.3f %.3f %.3f>\n", xem->er.b.x, xem->er.b.y, xem->er.b.z); - xprintf("b-a: <%.3f %.3f %.3f>\n", xem->asset->er.ext_dpos.x, xem->asset->er.ext_dpos.y, xem->asset->er.ext_dpos.z); - xprintf("ext_tm: %.3f\n", xem->er.et); - xprintf("ret_tm: %.3f\n", xem->er.rt); - xprintf("wait_et: %.3f\n", xem->er.wet); - xprintf("wait_rt: %.3f\n", xem->er.wrt); - xprintf("period: %.3f\n", xem->er.p); + case XENTMOTION_TYPE_ER: + xprintf("a: <%.3f %.3f %.3f>\n", xem->er.a.x, xem->er.a.y, xem->er.a.z); + xprintf("b: <%.3f %.3f %.3f>\n", xem->er.b.x, xem->er.b.y, xem->er.b.z); + xprintf("b-a: <%.3f %.3f %.3f>\n", xem->asset->er.ext_dpos.x, xem->asset->er.ext_dpos.y, + xem->asset->er.ext_dpos.z); + xprintf("ext_tm: %.3f\n", xem->er.et); + xprintf("ret_tm: %.3f\n", xem->er.rt); + xprintf("wait_et: %.3f\n", xem->er.wet); + xprintf("wait_rt: %.3f\n", xem->er.wrt); + xprintf("period: %.3f\n", xem->er.p); + break; + case XENTMOTION_TYPE_ORB: + xprintf("c: <%.3f %.3f %.3f>\n", xem->orb.c.x, xem->orb.c.y, xem->orb.c.z); + xprintf("a: %.3f\n", xem->orb.a); + xprintf("b: %.3f\n", xem->orb.b); + xprintf("p: %.3f\n", xem->orb.p); + xprintf("w: %.3f\n", xem->orb.w); + break; + case XENTMOTION_TYPE_MP: + if (xem->mp.src != NULL) + { + gps = xSceneID2Name(g_xSceneCur, xem->mp.src->id); + } + else + { + gps = ""; + } + + xprintf("src-mp: %s\n", gps); + + if (xem->mp.dest != NULL) + { + gps = xSceneID2Name(g_xSceneCur, xem->mp.dest->id); + } + else + { + gps = ""; + } + + xprintf("dest-mp: %s\n", gps); + xprintf("dist: %.3f\n", xem->mp.dist); + xprintf("speed: %.3f\n", xem->mp.speed); + break; + case XENTMOTION_TYPE_MECH: + switch (xem->asset->mech.type) + { + case 0: + gps = "slide"; break; - case XENTMOTION_TYPE_ORB: - xprintf("c: <%.3f %.3f %.3f>\n", xem->orb.c.x, xem->orb.c.y, xem->orb.c.z); - xprintf("a: %.3f\n", xem->orb.a); - xprintf("b: %.3f\n", xem->orb.b); - xprintf("p: %.3f\n", xem->orb.p); - xprintf("w: %.3f\n", xem->orb.w); + case 1: + gps = "rot"; break; - case XENTMOTION_TYPE_MP: - if (xem->mp.src != NULL) - { - gps = xSceneID2Name(g_xSceneCur, xem->mp.src->id); - } - else - { - gps = ""; - } + case 2: + gps = "slide_rot"; + break; + case 3: + gps = "slide_then_rot"; + break; + case 4: + gps = "rot_then_slide"; + break; + } + + xprintf("type: %s\n", gps); + xprintf("returns: %s", xbtoa(xem->asset->mech.flags & 1)); + + if (xem->asset->mech.flags & 1) + { + xprintf(" ret_delay: %.3f", xem->asset->mech.ret_delay); + } + + xprintf("\n"); + xprintf("continuous: %s", xbtoa(!(xem->asset->mech.flags & 2))); - xprintf("src-mp: %s\n", gps); + if (!(xem->asset->mech.flags & 2)) + { + xprintf(" end_delay: %.3f", xem->asset->mech.post_ret_delay); + } + + xprintf("\n"); - if (xem->mp.dest != NULL) + switch (xem->mech.state) + { + case 0: + if (xem->asset->mech.type == 2) { - gps = xSceneID2Name(g_xSceneCur, xem->mp.dest->id); + gps = "sliding + rotating forth"; } else { - gps = ""; + gps = "sliding forth"; } - - xprintf("dest-mp: %s\n", gps); - xprintf("dist: %.3f\n", xem->mp.dist); - xprintf("speed: %.3f\n", xem->mp.speed); break; - case XENTMOTION_TYPE_MECH: - switch (xem->asset->mech.type) + case 1: + gps = "rotating forth"; + break; + case 2: + gps = "waiting to return"; + break; + case 3: + if (xem->asset->mech.type == 2) { - case 0: - gps = "slide"; - break; - case 1: - gps = "rot"; - break; - case 2: - gps = "slide_rot"; - break; - case 3: - gps = "slide_then_rot"; - break; - case 4: - gps = "rot_then_slide"; - break; + gps = "sliding + rotating back"; } - - xprintf("type: %s\n", gps); - xprintf("returns: %s", xbtoa(xem->asset->mech.flags & 1)); - - if (xem->asset->mech.flags & 1) + else { - xprintf(" ret_delay: %.3f", xem->asset->mech.ret_delay); + gps = "sliding back"; } + break; + case 4: + gps = "rotating back"; + break; + case 5: + gps = "waiting to begin again"; + break; + case 6: + gps = "done"; + break; + case 7: + gps = "undone"; + break; + } - xprintf("\n"); - xprintf("continuous: %s", xbtoa(!(xem->asset->mech.flags & 2))); + xprintf("state: %s\n", gps); - if (!(xem->asset->mech.flags & 2)) - { - xprintf(" end_delay: %.3f", xem->asset->mech.post_ret_delay); - } + if (xem->asset->mech.type != 1) + { + gps = xem->asset->mech.sld_axis == 0 ? "X" : xem->asset->mech.sld_axis == 1 ? "Y" : "Z"; + + xprintf("slide_axis: %s", gps); + xprintf(" slide_dist: %.3f\n", xem->asset->mech.sld_dist); + xprintf("slide_tm: %.3f", xem->asset->mech.sld_tm); + xprintf(" slide_speed: %.3f\n", xem->mech.ss); + xprintf("slide_acc_tm: %.3f", xem->asset->mech.sld_acc_tm); + xprintf(" slide_dec_tm: %.3f\n", xem->asset->mech.sld_dec_tm); + xprintf("slide_bd_tm: %.3f", xem->mech.tsbd); + xprintf(" slide_fd_tm: %.3f\n", xem->mech.tsfd); + xprintf("start_pos: <%.3f %.3f %.3f>\n", xem->mech.apos.x, xem->mech.apos.y, + xem->mech.apos.z); + xprintf("end_pos: <%.3f %.3f %.3f>\n", xem->mech.bpos.x, xem->mech.bpos.y, + xem->mech.bpos.z); + xprintf("dir: <%.3f %.3f %.3f>\n", xem->mech.dir.x, xem->mech.dir.y, + xem->mech.dir.z); + } - xprintf("\n"); + if (xem->asset->mech.type != 0) + { + gps = xem->asset->mech.rot_axis == 0 ? "X" : xem->asset->mech.rot_axis == 1 ? "Y" : "Z"; + + xprintf("rot_axis: %s", gps); + xprintf(" rot_dist: %.3f\n", xem->asset->mech.rot_dist); + xprintf("rot_tm: %.3f", xem->asset->mech.rot_tm); + xprintf(" rot_speed: %.3f\n", (xem->mech.sr * 180.0f) / PI); + xprintf("rot_acc_tm: %.3f", xem->asset->mech.rot_acc_tm); + xprintf(" rot_dec_tm: %.3f\n", xem->asset->mech.rot_dec_tm); + xprintf("rot_bd_tm: %.3f", xem->mech.trbd); + xprintf(" rot_fd_tm: %.3f\n", xem->mech.trfd); + xprintf("arot: %.3f\n", (xem->mech.arot * 180.0f) / PI); + xprintf("brot: %.3f\n", (xem->mech.brot * 180.0f) / PI); + } + break; + case XENTMOTION_TYPE_PEN: + xprintf("top: <%.3f %.3f %.3f>\n", xem->pen.top.x, xem->pen.top.y, xem->pen.top.z); + xprintf("length: %.3f\n", xem->asset->pen.len); + xprintf("period: %.3f\n", xem->asset->pen.period); + xprintf("phase: %.3f\n", (xem->asset->pen.phase * 180.0f) / PI); + xprintf("range: %.3f\n", (xem->asset->pen.range * 180.0f) / PI); + xprintf("w: %.3f\n", xem->pen.w); + break; + } +} + +static void xEntMotionDebugDraw(const xEntMotion* xem) +//NONMATCH("https://decomp.me/scratch/j2sCX") +{ + if (xem->owner && xem->target) + { + xDrawSetColor(g_NEON_GREEN); + xDrawLine(xEntGetPos(xem->owner), xEntGetPos(xem->target)); + } - switch (xem->mech.state) + switch (xem->type) + { + case k_XENTMOTIONTYPE_ER: + xDrawSetColor(g_NEON_RED); + xDrawLine(&xem->er.a, &xem->er.b); + break; + case k_XENTMOTIONTYPE_ORBIT: + if (xem->owner) + { + xDrawSetColor(g_NEON_RED); + xDrawLine(&xem->orb.c, xEntGetPos(xem->owner)); + } + break; + case k_XENTMOTIONTYPE_MP: + { + xDrawSetColor(g_PIMP_GOLD); + xMovePoint* xmp = xem->mp.dest; + if (xmp) + { + for (U16 idx = 0; idx < xMovePointGetNumPoints(xmp); idx++) { - case 0: - if (xem->asset->mech.type == 2) - { - gps = "sliding + rotating forth"; - } - else + xMovePoint* omp = xMovePointGetPoint(xmp, idx); + if (omp != xem->mp.src) { - gps = "sliding forth"; + xDrawLine(xMovePointGetPos(xmp), xMovePointGetPos(omp)); } - break; - case 1: - gps = "rotating forth"; - break; - case 2: - gps = "waiting to return"; - break; - case 3: - if (xem->asset->mech.type == 2) - { - gps = "sliding + rotating back"; - } - else + for (U16 jdx = 0; jdx < xMovePointGetNumPoints(omp); jdx++) { - gps = "sliding back"; + xMovePoint* pmp = xMovePointGetPoint(omp, jdx); + xDrawLine(xMovePointGetPos(omp), xMovePointGetPos(pmp)); } - break; - case 4: - gps = "rotating back"; - break; - case 5: - gps = "waiting to begin again"; - break; - case 6: - gps = "done"; - break; - case 7: - gps = "undone"; - break; } - - xprintf("state: %s\n", gps); - - if (xem->asset->mech.type != 1) - { - gps = xem->asset->mech.sld_axis == 0 ? "X" : - xem->asset->mech.sld_axis == 1 ? "Y" : "Z"; - - xprintf("slide_axis: %s", gps); - xprintf(" slide_dist: %.3f\n", xem->asset->mech.sld_dist); - xprintf("slide_tm: %.3f", xem->asset->mech.sld_tm); - xprintf(" slide_speed: %.3f\n", xem->mech.ss); - xprintf("slide_acc_tm: %.3f", xem->asset->mech.sld_acc_tm); - xprintf(" slide_dec_tm: %.3f\n", xem->asset->mech.sld_dec_tm); - xprintf("slide_bd_tm: %.3f", xem->mech.tsbd); - xprintf(" slide_fd_tm: %.3f\n", xem->mech.tsfd); - xprintf("start_pos: <%.3f %.3f %.3f>\n", xem->mech.apos.x, xem->mech.apos.y, xem->mech.apos.z); - xprintf("end_pos: <%.3f %.3f %.3f>\n", xem->mech.bpos.x, xem->mech.bpos.y, xem->mech.bpos.z); - xprintf("dir: <%.3f %.3f %.3f>\n", xem->mech.dir.x, xem->mech.dir.y, xem->mech.dir.z); - } - - if (xem->asset->mech.type != 0) - { - gps = xem->asset->mech.rot_axis == 0 ? "X" : - xem->asset->mech.rot_axis == 1 ? "Y" : "Z"; - - xprintf("rot_axis: %s", gps); - xprintf(" rot_dist: %.3f\n", xem->asset->mech.rot_dist); - xprintf("rot_tm: %.3f", xem->asset->mech.rot_tm); - xprintf(" rot_speed: %.3f\n", (xem->mech.sr * 180.0f) / PI); - xprintf("rot_acc_tm: %.3f", xem->asset->mech.rot_acc_tm); - xprintf(" rot_dec_tm: %.3f\n", xem->asset->mech.rot_dec_tm); - xprintf("rot_bd_tm: %.3f", xem->mech.trbd); - xprintf(" rot_fd_tm: %.3f\n", xem->mech.trfd); - xprintf("arot: %.3f\n", (xem->mech.arot * 180.0f) / PI); - xprintf("brot: %.3f\n", (xem->mech.brot * 180.0f) / PI); - } - break; - case XENTMOTION_TYPE_PEN: - xprintf("top: <%.3f %.3f %.3f>\n", xem->pen.top.x, xem->pen.top.y, xem->pen.top.z); - xprintf("length: %.3f\n", xem->asset->pen.len); - xprintf("period: %.3f\n", xem->asset->pen.period); - xprintf("phase: %.3f\n", (xem->asset->pen.phase * 180.0f) / PI); - xprintf("range: %.3f\n", (xem->asset->pen.range * 180.0f) / PI); - xprintf("w: %.3f\n", xem->pen.w); - break; + } + if (xem->mp.src && xem->mp.dest) + { + xDrawSetColor(g_NEON_RED); + xDrawLine(xMovePointGetPos(xem->mp.src), xMovePointGetPos(xem->mp.dest)); + } + break; + } + case k_XENTMOTIONTYPE_MECH: + xDrawSetColor(g_NEON_RED); + xDrawLine(&xem->mech.apos, &xem->mech.bpos); + break; + case k_XENTMOTIONTYPE_PEND: + if (xem->owner) + { + xDrawSetColor(g_NEON_RED); + xDrawLine(&xem->pen.top, xEntGetPos(xem->owner)); + } + break; } } + void xEntMotionDebugDraw(const xEntMotion*); _tagxPad* gDebugPad; @@ -1172,10 +1378,6 @@ F32 xQuatDot(const xQuat* a, const xQuat* b) return xVec3Dot(&a->v, &b->v) + a->s * b->s; } -void xDrawLine(const xVec3* start, const xVec3* end) -{ -} - void xDrawSetColor(iColor_tag color) { } @@ -1213,7 +1415,7 @@ static void xEntMotionDebugIPad(xEntMotion* xem) { xEntReset(xem->owner); } - xEntMotionReset(xem,g_xSceneCur); + xEntMotionReset(xem, g_xSceneCur); } if (gDebugPad->pressed & 0x20000) { @@ -1226,4 +1428,4 @@ static void xEntMotionDebugIPad(xEntMotion* xem) xEntMotionStop(xem); } } -} \ No newline at end of file +} diff --git a/src/SB/Core/x/xEntMotionAsset.h b/src/SB/Core/x/xEntMotionAsset.h new file mode 100644 index 000000000..24f84b531 --- /dev/null +++ b/src/SB/Core/x/xEntMotionAsset.h @@ -0,0 +1,35 @@ +#pragma once + +#include "xVec3.h" + +enum +{ + k_XENTMOTIONMECH_SLIDE, + k_XENTMOTIONMECH_ROT, + k_XENTMOTIONMECH_SLIDE_ROT, + k_XENTMOTIONMECH_SLIDE_THEN_ROT, + k_XENTMOTIONMECH_ROT_THEN_SLIDE +}; + +enum +{ + k_XENTMOTIONMECH_RETURNS = (1 << 0), + k_XENTMOTIONMECH_ONCE = (1 << 1), +}; + +enum +{ + k_XENTMOTIONTYPE_ER, + k_XENTMOTIONTYPE_ORBIT, + k_XENTMOTIONTYPE_SPLINE, + k_XENTMOTIONTYPE_MP, + k_XENTMOTIONTYPE_MECH, + k_XENTMOTIONTYPE_PEND, + k_XENTMOTIONTYPE_NONE +}; + +enum +{ + k_XENTMOTION_0x1 = (1 << 0), + k_XENTMOTION_STOPPED = (1 << 2) +}; diff --git a/src/SB/Core/x/xMath.h b/src/SB/Core/x/xMath.h index b580bd8a2..156a6fbff 100644 --- a/src/SB/Core/x/xMath.h +++ b/src/SB/Core/x/xMath.h @@ -13,6 +13,7 @@ #define xfeq0(x) (((x) >= -1e-5f) && ((x) <= 1e-5f)) #define CLAMP(x, a, b) (MAX((a), MIN((x), (b)))) +#define xlerp(a, b, t) ((a) + (t) * ((b) - (a))) #define SQR(x) ((x) * (x)) diff --git a/src/SB/Core/x/xMath3.h b/src/SB/Core/x/xMath3.h index 02068cb80..fc7728676 100644 --- a/src/SB/Core/x/xMath3.h +++ b/src/SB/Core/x/xMath3.h @@ -160,6 +160,7 @@ void xQuatToMat(const xQuat* q, xMat3x3* m); void xQuatDiff(xQuat* o, const xQuat* a, const xQuat* b); F32 xQuatGetAngle(const xQuat* q); void xQuatFromMat(xQuat* q, const xMat3x3* m); +void xQuatToAxisAngle(const xQuat* q, xVec3* a, F32* t); void xQuatSlerp(xQuat* q, const xQuat* a, const xQuat* b, F32 t); void xQuatConj(xQuat* o, const xQuat* q); void xQuatCopy(xQuat*, const xQuat*); diff --git a/src/SB/Core/x/xPad.cpp b/src/SB/Core/x/xPad.cpp index 7786ae06f..65e79310a 100644 --- a/src/SB/Core/x/xPad.cpp +++ b/src/SB/Core/x/xPad.cpp @@ -1,5 +1,13 @@ #include "xPad.h" +#include "xMathInlines.h" + +#include "zMenu.h" +#include "zScene.h" +#include "zGame.h" +#include "zGameExtras.h" +#include "zGlobals.h" + #include #include @@ -53,6 +61,157 @@ void xPadRumbleEnable(S32 idx, S32 enable) } } +S32 xPadUpdate(S32 idx, F32 time_passed) +{ + U32 new_on = 0; + + if (zScene_ScreenAdjustMode()) + { + xPadAnalogIsDigital(0, 0); + } + else if (zMenuRunning() || zGameIsPaused() || zGame_HackIsGallery()) + { + xPadAnalogIsDigital(0, 0); + } + else + { + xPadAnalogIsDigital(0, 0); + } + + _tagxPad* p = &mPad[idx]; + + if (!iPadUpdate(p, &new_on)) + { + p->pressed = 0; + p->released = 0; + return 1; + } + + if ((p->flags & 0x10) && (p->flags & 0x1)) + { + U32 fake_dpad = 0; + if (p->analog1.x >= 50) + { + fake_dpad |= 0x20; + } + else if (p->analog1.x <= -50) + { + fake_dpad |= 0x80; + } + if (p->analog1.y >= 50) + { + fake_dpad |= 0x40; + } + else if (p->analog1.y <= -50) + { + fake_dpad |= 0x10; + } + if (fake_dpad == 0) + { + p->al2d_timer = 0.0f; + } + else + { + p->al2d_timer -= time_passed; + if (p->al2d_timer <= 0.0f) + { + new_on |= fake_dpad; + p->al2d_timer = 0.35f; + } + } + } +#ifdef DEBUGRELEASE + static S32 submap = 0; + if (submap) + { + SubMapAll((S32*)&new_on, p); + } +#endif + + p->pressed = new_on & ~p->on; + p->released = p->on & ~new_on; + p->on = new_on; + + for (S32 i = 0; i < 22; i++) + { + if (p->pressed & (1 << i)) + { + p->down_tmr[i] = 0.0f; + } + else if (p->released & (1 << i)) + { + p->up_tmr[i] = 0.0f; + } + if (p->on & (1 << i)) + { + p->down_tmr[i] += time_passed; + } + else + { + p->up_tmr[i] += time_passed; + } + } + + if (p->flags & 0x10) + { + if (!(p->on & 0x10) && !(p->on & 0x40) && !(p->on & 0x80) && !(p->on & 0x20)) + { + p->d_timer = 0.0f; + } + else + { + p->d_timer -= time_passed; + if (p->d_timer <= 0.0f) + { + p->d_timer = 0.35f; + if (p->on & 0x10) + { + p->pressed |= 0x10; + } + else if (p->on & 0x40) + { + p->pressed |= 0x40; + } + if (p->on & 0x80) + { + p->pressed |= 0x80; + } + else if (p->on & 0x20) + { + p->pressed |= 0x20; + } + } + } + } + + return 1; +} + +void xPadNormalizeAnalog(_tagxPad& pad, S32 inner_zone, S32 outer_zone) +{ + const _tagPadAnalog* src = &pad.analog1; + for (S32 i = 0; i < 2; i++) + { + pad.analog[i].offset.x = + normalize_analog(src[i].x, -outer_zone, outer_zone, 0, -inner_zone, inner_zone); + pad.analog[i].offset.y = + normalize_analog(src[i].y, -outer_zone, outer_zone, 0, -inner_zone, inner_zone); + if (pad.analog[i].offset.x == 0.0f && pad.analog[i].offset.y == 0.0f) + { + pad.analog[i].mag = 0.0f; + pad.analog[i].dir.assign(1.0f, 0.0f); + pad.analog[i].ang = 0.0f; + } + else + { + pad.analog[i].mag = pad.analog[i].offset.length(); + pad.analog[i].dir = pad.analog[i].offset; + pad.analog[i].dir /= pad.analog[i].mag; + pad.analog[i].ang = xatan2(pad.analog[i].dir.y, pad.analog[i].dir.x); + } + } +} + void xPadAnalogIsDigital(S32 idx, S32 enable) { if (idx != 0) diff --git a/src/SB/Core/x/xPad.h b/src/SB/Core/x/xPad.h index c4ef619f5..b70084246 100644 --- a/src/SB/Core/x/xPad.h +++ b/src/SB/Core/x/xPad.h @@ -35,16 +35,16 @@ struct _tagPadAnalog S8 y; }; -struct analog_data -{ - xVec2 offset; - xVec2 dir; - F32 mag; - F32 ang; -}; - struct _tagxPad { + struct analog_data + { + xVec2 offset; + xVec2 dir; + F32 mag; + F32 ang; + }; + S8 value[22]; // Offset: 0x16 @@ -110,4 +110,7 @@ S32 xPadAddRumble(S32 idx, _tagRumbleType type, F32 time, S32 replace, U32 fxfla void xPadAnalogIsDigital(F32, F32); +inline F32 normalize_analog(S32 v, S32 v_min, S32 v_max, S32 dead_center, S32 dead_min, + S32 dead_max); + #endif diff --git a/src/SB/Core/x/xString.cpp b/src/SB/Core/x/xString.cpp index 95ad1f06e..c923392bf 100644 --- a/src/SB/Core/x/xString.cpp +++ b/src/SB/Core/x/xString.cpp @@ -1,4 +1,5 @@ #include "xString.h" +#include "rwplcore.h" #include "xMath.h" #include @@ -47,6 +48,56 @@ U32 xStrHashCat(U32 prefix, const char* str) return hash; } +char* xStrTok(char* string, const char* control, char** nextoken) +{ + U8* str; + U8* ctrl; + U8 map[32]; + S32 count; + + for (S32 i = 0; i < 32; i++) + { + map[i] = 0; + } + + ctrl = (U8*)control; + + do + { + map[*ctrl >> 3] |= 1 << (*ctrl & 0x7); + } while (*ctrl++ != '\0'); + + str = (string) ? (U8*)string : (U8*)*nextoken; + + while (map[(*str >> 3) & 0x1F] & (1 << (*str & 0x7)) && *str != '\0') + { + str++; + } + + string = (char*)str; + + while (*str != '\0') + { + if (map[(*str >> 3) & 0x1F] & (1 << (*str & 0x7))) + { + *str = '\0'; + str++; + break; + } + + str++; + } + + *nextoken = (char*)str; + + if (string == (char*)str) + { + string = NULL; + } + + return string; +} + char* xStrupr(char* string) { char* p = string; @@ -67,6 +118,85 @@ namespace U32 tolower(S32 param_1); } // namespace +S32 xStrParseFloatList(F32* dest, const char* strbuf, S32 max) +{ + char* str = (char*)strbuf; + S32 index; + S32 digits; + bool negate; + char* numstart; + char savech; + + if (!str) + { + return 0; + } + + for (index = 0; *str != '\0' && index < max; index++) + { + while (*str == '\t' || *str == ' ' || *str == '[' || *str == ']' || *str == '{' || + *str == '}' || *str == '(' || *str == ')' || *str == '+' || *str == ',' || + *str == ':' || *str == ';') + { + str++; + } + + if (*str == '\0') + { + return index; + } + + if (*str == '-') + { + negate = TRUE; + str++; + + while (*str == '\t' || *str == ' ') + { + str++; + } + } + else + { + negate = FALSE; + } + + numstart = str; + digits = 0; + + while ((*str >= '0' && *str <= '9') || *str == '.' || *str == 'E' || *str == 'e' || + *str == 'f') + { + if (*str >= '0' && *str <= '9') + { + digits++; + } + + str++; + } + + if (digits == 0) + { + return index; + } + + savech = *str; + + *str = '\0'; + *dest = xatof(numstart); + + if (negate) + { + *dest = -*dest; + } + + *str = savech; + dest++; + } + + return index; +} + S32 imemcmp(void const* d1, void const* d2, size_t size) { const char* s1 = (char*)d1; @@ -79,8 +209,8 @@ S32 imemcmp(void const* d1, void const* d2, size_t size) if (cval1 != cval2) { return cval1 - cval2; -} -} + } + } return 0; } @@ -93,9 +223,9 @@ namespace } U32 tolower(S32 param_1) -{ - return param_1 | ((param_1 >> 1) & 32); -} + { + return param_1 | ((param_1 >> 1) & 32); + } } // End anonymous namespace S32 icompare(const substr& s1, const substr& s2) @@ -104,7 +234,7 @@ S32 icompare(const substr& s1, const substr& s2) S32 result = imemcmp(s1.text, s2.text, len); switch (result) { - case 0: + case 0: if (s1.size == s2.size) { result = 0; diff --git a/src/SB/Core/x/xVec3Inlines.h b/src/SB/Core/x/xVec3Inlines.h index ddc252c85..b89883cae 100644 --- a/src/SB/Core/x/xVec3Inlines.h +++ b/src/SB/Core/x/xVec3Inlines.h @@ -21,6 +21,34 @@ F32 xVec3LengthFast(F32 x, F32 y, F32 z); F32 xVec3LengthFast(const xVec3* vec); void xVec3AddScaled(xVec3* o, const xVec3* v, F32 s); +#define xVec3NormalizeDistXZMacro(o, a, b, dist) \ + MACRO_START \ + { \ + F32 dx__ = (b)->x - (a)->x; \ + F32 dz__ = (b)->z - (a)->z; \ + F32 dist2 = SQR(dx__) + SQR(dz__); \ + if (xeq(dist2, 1.0f, 1e-5f)) \ + { \ + (o)->x = dx__; \ + (o)->z = dz__; \ + *(dist) = 1.0f; \ + } \ + else if (xeq(dist2, 0.0f, 1e-5f)) \ + { \ + (o)->x = 0.0f; \ + (o)->z = 0.0f; \ + *(dist) = 0.0f; \ + } \ + else \ + { \ + *(dist) = xsqrt(dist2); \ + F32 dist_inv = 1.0f / *(dist); \ + (o)->x = dx__ * dist_inv; \ + (o)->z = dz__ * dist_inv; \ + } \ + } \ + MACRO_STOP + inline void xVec3SMulBy(xVec3* v, F32 s) { v->x *= s; @@ -35,6 +63,4 @@ inline void xVec3SubFrom(xVec3* o, const xVec3* v) o->z -= v->z; } -F32 LERP(F32 dt, xVec3*, xVec3*, xVec3*); - #endif diff --git a/src/SB/Core/x/xpkrsvc.cpp b/src/SB/Core/x/xpkrsvc.cpp index 18fb512a2..598d8d805 100644 --- a/src/SB/Core/x/xpkrsvc.cpp +++ b/src/SB/Core/x/xpkrsvc.cpp @@ -716,7 +716,7 @@ S32 PKR_LoadLayer(st_PACKER_READ_DATA* pr, en_LAYER_TYPE layer) return 0; } -void* PKR_LoadAsset(st_PACKER_READ_DATA* pr, U32 aid, char*, void*) +void* PKR_LoadAsset(st_PACKER_READ_DATA* pr, U32 aid, const char*, void*) { return PKR_FindAsset(pr, aid); } diff --git a/src/SB/Core/x/xserializer.cpp b/src/SB/Core/x/xserializer.cpp index 86dd7d15a..caa12a767 100644 --- a/src/SB/Core/x/xserializer.cpp +++ b/src/SB/Core/x/xserializer.cpp @@ -1,38 +1,33 @@ #include "xserializer.h" +#include "xMemMgr.h" #include "xutil.h" #include static S32 g_serinit; -static st_XSERIAL_DATA_PRIV g_xserdata = {0, NULL, 0, NULL, NULL, NULL}; +static st_XSERIAL_DATA_PRIV g_xserdata = { 0, NULL, 0, NULL, NULL, NULL }; -static S32 g_tbl_onbit[32] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; +static S32 g_tbl_onbit[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static S32 g_tbl_clear[32] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; +static S32 g_tbl_clear[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static void xSER_init_tables(); static st_SERIAL_CLIENTINFO* XSER_get_client(U32 idtag); static S32 xSER_xsgclt_svinfo_ver(void*, st_XSAVEGAME_DATA*, S32* cur_space, S32* max_fullgame); static S32 xSER_xsgclt_svproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_WRITECONTEXT* wctxt); -static S32 xSER_xsgclt_ldproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, U32, S32); -static S32 xSER_xsgclt_svinfo_clt(void* cltdata, st_XSAVEGAME_DATA*, S32* cur_space, S32* max_fullgame); -static S32 xSER_xsgclt_svproc_clt(void* cltdata, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_WRITECONTEXT* wctxt); -static S32 xSER_xsgclt_ldproc_clt(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, U32 idtag, S32); +static S32 xSER_xsgclt_ldproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, + U32, S32); +static S32 xSER_xsgclt_svinfo_clt(void* cltdata, st_XSAVEGAME_DATA*, S32* cur_space, + S32* max_fullgame); +static S32 xSER_xsgclt_svproc_clt(void* cltdata, st_XSAVEGAME_DATA* xsg, + st_XSAVEGAME_WRITECONTEXT* wctxt); +static S32 xSER_xsgclt_ldproc_clt(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, + U32 idtag, S32); static S32 xSER_xsgclt_svproc_fill(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_WRITECONTEXT* wctxt); static S32 xSER_xsgclt_svinfo_fill(void*, st_XSAVEGAME_DATA*, S32* cur_space, S32* max_fullgame); -static S32 xSER_xsgclt_ldproc_fill(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, U32, S32); - +static S32 xSER_xsgclt_ldproc_fill(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, + U32, S32); S32 xSerialStartup(S32 count, st_SERIAL_PERCID_SIZE* sizeinfo) { @@ -42,7 +37,7 @@ S32 xSerialStartup(S32 count, st_SERIAL_PERCID_SIZE* sizeinfo) xSER_init_tables(); xSER_init_buffers(count, sizeinfo); } - + return g_serinit; } @@ -51,7 +46,7 @@ S32 xSerialShutdown() return g_serinit--; } -void xSerialTraverse(S32(*func)(U32, xSerial*)) +void xSerialTraverse(S32 (*func)(U32, xSerial*)) { xSerial xser; @@ -102,7 +97,7 @@ S32 xSerial::Write(char* data, S32 elesize, S32 n) if (n < 0) { S32 bidx = 0; - for (S32 i = 0; i < nbit; i++) + for (S32 i = 0; i < nbit; i++) { S32* iptr = (S32*)data; wrbit(*iptr & g_tbl_onbit[bidx]); @@ -282,7 +277,7 @@ S32 xSerial::rdbit() { st_SERIAL_CLIENTINFO* clt = ctxtdata; - if (bittally + 1 > clt->actsize * 8 ) + if (bittally + 1 > clt->actsize * 8) { warned = TRUE; return 0; @@ -327,9 +322,63 @@ static void xSER_init_tables() } } -void xSER_init_buffers(S32 count, st_SERIAL_PERCID_SIZE* sizeinfo) +static void xSER_init_buffers(S32 count, st_SERIAL_PERCID_SIZE* sizeinfo) +//NONMATCH("https://decomp.me/scratch/uex0C") { - // TODO + st_XSERIAL_DATA_PRIV* xsd = &g_xserdata; + S32 i = 0; + S32 tally = 0; + S32 sicnt = 0; + st_SERIAL_PERCID_SIZE* sitmp = NULL; + st_SERIAL_CLIENTINFO* tmp_clt = NULL; + + XOrdInit(&g_xserdata.cltlist, count, 0); + + xsd->cltbuf = + (st_SERIAL_CLIENTINFO*)xMemAlloc(gActiveHeap, count * sizeof(st_SERIAL_CLIENTINFO), 0); + memset(xsd->cltbuf, 0, count * sizeof(st_SERIAL_CLIENTINFO)); + xsd->cltnext = xsd->cltbuf; + + sitmp = sizeinfo; + while (sitmp->idtag != 0) + { + tally += (sitmp->needsize + 3) & ~3; + sicnt++; + sitmp++; + } + tally += (count - sicnt) * 400; + + xsd->bitbuf = (S32*)xMemAlloc(gActiveHeap, tally, 0); + memset(xsd->bitbuf, 0, tally); + + xsd->buf_bytcnt = tally; + + sitmp = sizeinfo; + tally = 0; + tmp_clt = xsd->cltnext; + while (sitmp->idtag != 0) + { + tmp_clt->idtag = sitmp->idtag; + tmp_clt->trueoff = tally; + tmp_clt->actsize = (sitmp->needsize + 3) & ~3; + tmp_clt->membuf = xsd->bitbuf + tally / 4; + XOrdAppend(&xsd->cltlist, tmp_clt); + tally += tmp_clt->actsize; + sitmp++; + tmp_clt++; + } + XOrdSort(&xsd->cltlist, xSER_ord_compare); + xsd->cltnext = tmp_clt; + + for (i = sicnt; i < count; i++) + { + tmp_clt->idtag = 0; + tmp_clt->trueoff = tally; + tmp_clt->actsize = 400; + tmp_clt->membuf = xsd->bitbuf + tally / 4; + tally += tmp_clt->actsize; + tmp_clt++; + } } // non-matching @@ -339,7 +388,7 @@ static S32 xSER_ord_compare(void* e1, void* e2) { return -1; } - + if (*(U32*)e2 < *(U32*)e1) { return 1; @@ -354,7 +403,7 @@ static S32 xSER_ord_test(const void* key, void* elt) { return -1; } - + if (*(U32*)elt < *(U32*)key) { return 1; @@ -423,7 +472,8 @@ static S32 xSER_xsgclt_svproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_WR return 1; } -static S32 xSER_xsgclt_ldproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, U32, S32) +static S32 xSER_xsgclt_ldproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, + U32, S32) { st_XSERIAL_DATA_PRIV* xsd = &g_xserdata; S32 ver = 0; @@ -435,21 +485,24 @@ static S32 xSER_xsgclt_ldproc_ver(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_RE return 1; } -static S32 xSER_xsgclt_svinfo_clt(void* cltdata, st_XSAVEGAME_DATA*, S32* cur_space, S32* max_fullgame) +static S32 xSER_xsgclt_svinfo_clt(void* cltdata, st_XSAVEGAME_DATA*, S32* cur_space, + S32* max_fullgame) { *cur_space = *(S32*)((S32)cltdata + 12); *max_fullgame = *(S32*)((S32)cltdata + 12); return 1; } -static S32 xSER_xsgclt_svproc_clt(void* cltdata, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_WRITECONTEXT* wctxt) +static S32 xSER_xsgclt_svproc_clt(void* cltdata, st_XSAVEGAME_DATA* xsg, + st_XSAVEGAME_WRITECONTEXT* wctxt) { st_SERIAL_CLIENTINFO* clt = XSER_get_client(*(U32*)cltdata); xSGWriteData(xsg, wctxt, (char*)clt->membuf, clt->actsize); return 1; } -static S32 xSER_xsgclt_ldproc_clt(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, U32 idtag, S32) +static S32 xSER_xsgclt_ldproc_clt(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, + U32 idtag, S32) { if ((g_xserdata.flg_info & 1) == 0) { @@ -461,14 +514,15 @@ static S32 xSER_xsgclt_ldproc_clt(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_RE static S32 xSER_xsgclt_svproc_fill(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_WRITECONTEXT* wctxt) { - char filbuf[9] = { 'R', 'y', 'a', 'n', 'N', 'e', 'i', 'l', '\x00'}; + char filbuf[9] = { 'R', 'y', 'a', 'n', 'N', 'e', 'i', 'l', '\x00' }; xSGWriteData(xsg, wctxt, (char*)&filbuf, 8); return 1; } -static S32 xSER_xsgclt_ldproc_fill(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, U32, S32) +static S32 xSER_xsgclt_ldproc_fill(void*, st_XSAVEGAME_DATA* xsg, st_XSAVEGAME_READCONTEXT* rctxt, + U32, S32) { - char filbuf[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + char filbuf[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if ((g_xserdata.flg_info & 1) == 0) { xSGReadData(xsg, rctxt, (char*)&filbuf, 8); diff --git a/src/SB/Core/x/xserializer.h b/src/SB/Core/x/xserializer.h index 9f6744bd5..9949f2211 100644 --- a/src/SB/Core/x/xserializer.h +++ b/src/SB/Core/x/xserializer.h @@ -70,7 +70,8 @@ S32 xSerialStartup(S32, st_SERIAL_PERCID_SIZE*); S32 xSerialShutdown(); void xSerialTraverse(S32 (*func)(U32 clientID, xSerial* xser)); void xSerialWipeMainBuffer(); -void xSER_init_buffers(S32 count, st_SERIAL_PERCID_SIZE* sizeinfo); +static void xSER_init_buffers(S32 count, st_SERIAL_PERCID_SIZE* sizeinfo); S32 xSerial_svgame_register(st_XSAVEGAME_DATA* sgctxt, en_SAVEGAME_MODE mode); +static S32 xSER_ord_compare(void* e1, void* e2); #endif diff --git a/src/SB/Game/zMovePoint.cpp b/src/SB/Game/zMovePoint.cpp index 0f0e1a80a..6bd002c13 100644 --- a/src/SB/Game/zMovePoint.cpp +++ b/src/SB/Game/zMovePoint.cpp @@ -120,8 +120,3 @@ F32 zMovePointGetDelay(const zMovePoint* m) { return xMovePointGetDelay((xMovePoint*)m); } - -inline F32 xMovePointGetDelay(const xMovePoint* m) -{ - return m->delay; -} diff --git a/src/SB/Game/zMovePoint.h b/src/SB/Game/zMovePoint.h index 5cd6b372e..388ec8559 100644 --- a/src/SB/Game/zMovePoint.h +++ b/src/SB/Game/zMovePoint.h @@ -43,6 +43,20 @@ F32 zMovePointGetNext(const zMovePoint* current, const zMovePoint* prev, zMovePo xVec3* hdng); xVec3* zMovePointGetPos(const zMovePoint* m); F32 zMovePointGetDelay(const zMovePoint* m); -F32 xMovePointGetDelay(const xMovePoint* m); + +inline U16 xMovePointGetNumPoints(const xMovePoint* m) +{ + return m->asset->numPoints; +} + +inline xMovePoint* xMovePointGetPoint(const xMovePoint* m, U16 n) +{ + return m->nodes[n]; +} + +inline F32 xMovePointGetDelay(const xMovePoint* m) +{ + return m->delay; +} #endif diff --git a/src/SB/Game/zScene.h b/src/SB/Game/zScene.h index a944ab351..142bcd747 100644 --- a/src/SB/Game/zScene.h +++ b/src/SB/Game/zScene.h @@ -70,4 +70,6 @@ void zSceneSetOldScreenAdj(); U32 zScene_ScreenAdjustMode(); void zSceneSpawnRandomBubbles(); +U32 zScene_ScreenAdjustMode(); + #endif