201 lines
11 KiB
C
201 lines
11 KiB
C
#include <psx.h>
|
||
#include <camera.h>
|
||
#include <math.h>
|
||
#include <physics.h>
|
||
#include <space.h>
|
||
|
||
void getCameraXZ(int * x, int * z, int actorX, int actorZ, int angle, int distance) {
|
||
// Using Nic's Costable : https://github.com/grumpycoders/Balau/blob/master/tests/test-Handles.cc#L20-L102
|
||
// https://godbolt.org/z/q6cMcj
|
||
*x = (actorX << 12) + (distance * nsin(angle));
|
||
*z = (actorZ << 12) - (distance * ncos(angle));
|
||
};
|
||
void getCameraXZY(int * x, int * z, int * y, int actorX, int actorZ, int actorY, int angle, int angleX, int distance) {
|
||
// Using Nic's Costable : https://github.com/grumpycoders/Balau/blob/master/tests/test-Handles.cc#L20-L102
|
||
// https://godbolt.org/z/q6cMcj
|
||
*x = (actorX << 12) + (distance * nsin(angle));
|
||
*z = (actorZ << 12) - (distance * ( ( ncos(angle) * ncos(angleX) ) >> 12 ) );
|
||
*y = (actorY << 12) - (distance * nsin(angleX));
|
||
};
|
||
void getCameraZY( int * z, int * y, int actorZ, int actorY, int angleX, int distance) {
|
||
*z = (actorZ << 12) - (distance * ncos(angleX));
|
||
*y = (actorY << 12) - (distance * nsin(angleX));
|
||
};
|
||
// @Will : you might want to use sin/cos to move the camera in a circle but you could do that by moving it along it’s tangent and then clamping the distance
|
||
void applyCamera( CAMERA * cam ) {
|
||
//~ VECTOR vec; // Vector that holds the output values of the following instructions
|
||
RotMatrix_gte(dc_camRot, dc_camMat); // Convert rotation angle in psx units (360° == 4096) to rotation matrix)
|
||
gte_ApplyMatrix(dc_camMat, dc_camPos, dc_wrklvector); // Multiply matrix by vector pos and output to vec
|
||
TransMatrix(dc_camMat, dc_wrklvector); // Apply transform vector
|
||
gte_SetRotMatrix(dc_camMat); // Set Rotation matrix
|
||
gte_SetTransMatrix(dc_camMat); // Set Transform matrix
|
||
};
|
||
void setCameraPos( CAMERA * camera, SVECTOR * pos, SVECTOR * rot ) {
|
||
copyVector(dc_camPos, pos);
|
||
copyVector(dc_camRot, rot);
|
||
};
|
||
void setCameraMode(LEVEL * curLvl, CAMERA * camera, VECTOR * posToActor, VECTOR * angle, VECTOR * angleCam, short *curCamAngle, int camMode, int * lerping){
|
||
int dist = 0;
|
||
short cameraSpeed = 40;
|
||
|
||
if(camMode < 4 ) {
|
||
*lerping = 0;
|
||
}
|
||
switch (camMode){
|
||
// Camera follows actor
|
||
case 0 :
|
||
dist = CAM_DIST_TO_ACT;
|
||
setVector(dc_camPos, -(camera->x/ONE), -(camera->y/ONE), -(camera->z/ONE));
|
||
angle->vy = -(curLvl->actorPtr->rot.vy / 2) + angleCam->vy;
|
||
// Camera horizontal and vertical position
|
||
getCameraZY(&camera->z, &camera->y, curLvl->actorPtr->pos.vz, curLvl->actorPtr->pos.vy, angle->vx, dist);
|
||
getCameraXZ(&camera->x, &camera->z, curLvl->actorPtr->pos.vx, curLvl->actorPtr->pos.vz, angle->vy, dist);
|
||
break;
|
||
|
||
// Camera rotates continuously around actor
|
||
case 1 :
|
||
// Set distance between cam and actor
|
||
dist = CAM_DIST_TO_ACT;
|
||
// Set camera position
|
||
setVector(dc_camPos, -(camera->x/ONE), CAM_DIST_TO_GND, -(camera->z/ONE));
|
||
// Find new camera position
|
||
getCameraXZ(&camera->x, &camera->z, curLvl->actorPtr->pos.vx, curLvl->actorPtr->pos.vz, angle->vy, dist);
|
||
// Set rotation amount
|
||
angle->vy += 10;
|
||
break;
|
||
|
||
// Fixed Camera angle
|
||
case 2 :
|
||
// If BG images exist
|
||
if (curLvl->camPtr->tim_data){
|
||
// Check which side of the line the actor is on (World space)
|
||
checkLineW( &curLvl->camAngles[ *curCamAngle ]->fw.v3, &curLvl->camAngles[ *curCamAngle ]->fw.v2, curLvl->actorPtr);
|
||
if ( curLvl->camAngles[ *curCamAngle ]->fw.v0.vx ) {
|
||
// If actor in camAngle->fw area of screen
|
||
if ( checkLineW( &curLvl->camAngles[ *curCamAngle ]->fw.v3, &curLvl->camAngles[ *curCamAngle ]->fw.v2, curLvl->actorPtr) == -1 &&
|
||
( checkLineW( &curLvl->camAngles[ *curCamAngle ]->bw.v2, &curLvl->camAngles[ *curCamAngle ]->bw.v3, curLvl->actorPtr) >= 0 )
|
||
) {
|
||
if (*curCamAngle < 5) {
|
||
(*curCamAngle)++;
|
||
curLvl->camPtr = curLvl->camAngles[ *curCamAngle ];
|
||
LoadTexture(curLvl->camPtr->tim_data, curLvl->camPtr->BGtim);
|
||
}
|
||
}
|
||
}
|
||
if ( curLvl->camAngles[ *curCamAngle ]->bw.v0.vx ) {
|
||
// If actor in camAngle->bw area of screen
|
||
if ( checkLineW( &curLvl->camAngles[ *curCamAngle ]->fw.v3, &curLvl->camAngles[ *curCamAngle ]->fw.v2, curLvl->actorPtr) >= 0 &&
|
||
checkLineW( &curLvl->camAngles[ *curCamAngle ]->bw.v2, &curLvl->camAngles[ *curCamAngle ]->bw.v3, curLvl->actorPtr) == -1
|
||
) {
|
||
if (*curCamAngle > 0) {
|
||
(*curCamAngle)--;
|
||
curLvl->camPtr = curLvl->camAngles[ *curCamAngle ];
|
||
LoadTexture(curLvl->camPtr->tim_data, curLvl->camPtr->BGtim);
|
||
}
|
||
}
|
||
}
|
||
// Find screen space coordinates
|
||
worldToScreen( &curLvl->actorPtr->pos, &curLvl->actorPtr->pos2D );
|
||
}
|
||
setCameraPos(camera, &curLvl->camPtr->campos->pos, &curLvl->camPtr->campos->rot);
|
||
break;
|
||
|
||
// Fixed Camera with actor tracking
|
||
case 3 :
|
||
// Using precalc sqrt
|
||
dist = psqrt( (posToActor->vx * posToActor->vx ) + (posToActor->vz * posToActor->vz) );
|
||
// Set camera position
|
||
setVector(dc_camPos, 190, CAM_DIST_TO_GND, 180);
|
||
break;
|
||
// Flyby mode with LERP from camStart to camEnd
|
||
case 4 :
|
||
// If key pos exist for camera
|
||
if (curLvl->camPath->len) {
|
||
// Lerping sequence has not begun
|
||
if (!lerping){
|
||
// Set cam start position ( first key pos )
|
||
copyVector(camera->pos, &curLvl->camPath->points[curLvl->camPath->cursor]);
|
||
// Lerping sequence is starting
|
||
*lerping = 1;
|
||
// Set cam pos index to 0
|
||
curLvl->camPath->pos = 0;
|
||
}
|
||
// Pre calculated sqrt ( see psqrt() )
|
||
dist = psqrt( (posToActor->vx * posToActor->vx ) + (posToActor->vz * posToActor->vz));
|
||
// Fixed point precision 2^12 == 4096
|
||
int precision = 12;
|
||
setVector( camera->pos,
|
||
lerpD(curLvl->camPath->points[curLvl->camPath->cursor].vx << precision, curLvl->camPath->points[curLvl->camPath->cursor+1].vx << precision, curLvl->camPath->pos << precision) >> precision,
|
||
lerpD(curLvl->camPath->points[curLvl->camPath->cursor].vy << precision, curLvl->camPath->points[curLvl->camPath->cursor+1].vy << precision, curLvl->camPath->pos << precision) >> precision,
|
||
lerpD(curLvl->camPath->points[curLvl->camPath->cursor].vz << precision, curLvl->camPath->points[curLvl->camPath->cursor+1].vz << precision, curLvl->camPath->pos << precision) >> precision
|
||
);
|
||
// Linearly increment the lerp factor
|
||
curLvl->camPath->pos += 20;
|
||
// If camera has reached next key pos, reset pos index, move cursor to next key pos
|
||
if (curLvl->camPath->pos > (1 << precision) ){
|
||
curLvl->camPath->pos = 0;
|
||
curLvl->camPath->cursor ++;
|
||
}
|
||
// Last key pos is reached, reset cursor to first key pos, lerping sequence is over
|
||
if ( curLvl->camPath->cursor == curLvl->camPath->len - 1 ){
|
||
lerping = 0;
|
||
curLvl->camPath->cursor = 0;
|
||
}
|
||
} else {
|
||
// if no key pos exists, switch to next camMode
|
||
camMode ++;
|
||
}
|
||
break;
|
||
// Camera "on a rail" - cam is tracking actor, and moving with constraints on all axis
|
||
case 5 :
|
||
// track actor. If theta (actor/cam rotation angle) is above or below an arbitrary angle,
|
||
// move cam so that the angle doesn't increase/decrease anymore.
|
||
if (curLvl->camPath->len) {
|
||
// Lerping sequence has not begun
|
||
if (!lerping){
|
||
// Set cam start position ( first key pos )
|
||
copyVector(dc_camPos, &curLvl->camPath->points[curLvl->camPath->cursor]);
|
||
// Lerping sequence is starting
|
||
*lerping = 1;
|
||
// Set cam pos index to 0
|
||
curLvl->camPath->pos = 0;
|
||
}
|
||
// Pre calculated sqrt ( see psqrt() )
|
||
dist = psqrt( (posToActor->vx * posToActor->vx ) + (posToActor->vz * posToActor->vz));
|
||
// Fixed point precision 2^12 == 4096
|
||
short precision = 12;
|
||
setVector( camera->pos,
|
||
lerpD(curLvl->camPath->points[curLvl->camPath->cursor].vx << precision, curLvl->camPath->points[curLvl->camPath->cursor+1].vx << precision, curLvl->camPath->pos << precision) >> precision,
|
||
lerpD(curLvl->camPath->points[curLvl->camPath->cursor].vy << precision, curLvl->camPath->points[curLvl->camPath->cursor+1].vy << precision, curLvl->camPath->pos << precision) >> precision,
|
||
lerpD(curLvl->camPath->points[curLvl->camPath->cursor].vz << precision, curLvl->camPath->points[curLvl->camPath->cursor+1].vz << precision, curLvl->camPath->pos << precision) >> precision
|
||
);
|
||
// Ony move cam if position is between first curLvl->camPath->vx and last curLvl->camPath->vx
|
||
if ( dc_actorRot->vy < -50 && dc_camPos->vx > curLvl->camPath->points[curLvl->camPath->len - 1].vx ) {
|
||
// Clamp curLvl->camPath position to cameraSpeed
|
||
curLvl->camPath->pos += dist < cameraSpeed ? 0 : cameraSpeed ;
|
||
}
|
||
if ( dc_actorRot->vy > 50 && dc_camPos->vx > curLvl->camPath->points[curLvl->camPath->cursor].vx ) {
|
||
curLvl->camPath->pos -= dist < cameraSpeed ? 0 : cameraSpeed;
|
||
}
|
||
// If camera has reached next key pos, reset pos index, move cursor to next key pos
|
||
if (curLvl->camPath->pos > (1 << precision) ){
|
||
curLvl->camPath->pos = 0;
|
||
curLvl->camPath->cursor ++;
|
||
}
|
||
if (curLvl->camPath->pos < -100 ){
|
||
curLvl->camPath->pos = 1 << precision;
|
||
curLvl->camPath->cursor --;
|
||
}
|
||
// Last key pos is reached, reset cursor to first key pos, lerping sequence is over
|
||
if ( curLvl->camPath->cursor == curLvl->camPath->len - 1 || curLvl->camPath->cursor < 0 ){
|
||
*lerping = 0;
|
||
curLvl->camPath->cursor = 0;
|
||
}
|
||
} else {
|
||
// if no key pos exists, switch to next camMode
|
||
camMode ++;
|
||
}
|
||
break;
|
||
}
|
||
};
|