3dcam-headers/3dcam-cosTable-lerp-atantable-psqrt-nodpq-quads.c

1069 lines
40 KiB
C
Raw Normal View History

2021-02-03 15:23:20 +01:00
// 3dcam
// With huge help from @NicolasNoble : https://discord.com/channels/642647820683444236/646765703143227394/796876392670429204
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <libgte.h>
#include <libgpu.h>
#include <libetc.h>
#include <stdio.h>
// Precalculated sin/cos values
//~ #include "psin.c"
//~ #include "pcos.c"
#include "atan.c"
// Sample vector model
#include "coridor.c"
//~ #include "gnd.c"
#define VMODE 0
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define OTLEN 256 // Maximum number of OT entries
#define PRIMBUFFLEN 2260 * sizeof(POLY_GT3) // Maximum number of POLY_GT3 primitives
// atantable
#define SWAP(a,b,c) {(c)=(a); (a)=(b); (b)=(c);} // swap(x, y, buffer)
//~ extern ushort rcossin_tbl[];
// Display and draw environments, double buffered
DISPENV disp[2];
DRAWENV draw[2];
u_long ot[2][OTLEN] = {0}; // Ordering table (contains addresses to primitives)
char primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer
//~ int primcnt=0; // Primitive counter
char * nextpri = primbuff[0]; // Primitive counter
char db = 0; // Current buffer counter
CVECTOR BGc = {50, 50, 75, 0};
VECTOR BKc = {100, 100, 100, 0};
// Local color matrix
//~ static MATRIX cmat = {
//~ /* light source #0, #1, #2, */
//~ ONE, 0, 0, /* R */
//~ 0, ONE, 0, /* G */
//~ 0, 0, ONE, /* B */
//~ };
//~ // local light matrix : Direction and reach of each light source.
//~ // Each light is aligned with the axis, hence direction is in the same coordinate system as the PSX (Y-axis down)
//~ // One == 4096 is reach/intensity of light source
//~ static MATRIX lgtmat = {
//~ // X Y Z
//~ ONE, 0, 0, // Light 0
//~ 0,0,0, // Light 1
//~ 0,0,0 // Light 2
//~ };
// Light
//~ MATRIX rottrans;
MATRIX rotlgt;
SVECTOR lgtang = {0, 0, 0};
MATRIX light;
//~ SVECTOR lgtang = {1024, -512, 1024};
static int m_cosTable[512]; // precalc costable
static const unsigned int DC_2PI = 2048; // this is from gere : https://github.com/grumpycoders/Balau/blob/master/tests/test-Handles.cc#L20-L102
static const unsigned int DC_PI = 1024;
static const unsigned int DC_PI2 = 512;
short vs;
typedef struct{
int x, xv; // x: current value += xv : new value
int y, yv; // x,y,z, vx, vy, vz are in PSX units (ONE == 4096)
int z, zv;
int pan, panv;
int tilt, tiltv;
int rol;
VECTOR pos;
SVECTOR rot;
SVECTOR dvs;
MATRIX mat;
} CAMERA;
CAMERA camera = {
0,0,
0,0,
0,0,
0,0,
0,0,
0,
{0,0,0},
{0,0,0},
{0,0,0}
};
//~ //vertex anim
//~ typedef struct {
//~ int nframes; // number of frames e.g 20
//~ int nvert; // number of vertices e.g 21
//~ SVECTOR data[]; // vertex pos as SVECTORs e.g 20 * 21 SVECTORS
//~ } VANIM;
//Pad
int pressed = 0;
// Cam stuff
int camMode = 2;
long timeB = 0;
u_long triCount = 0;
2021-02-03 15:35:51 +01:00
2021-02-03 15:23:20 +01:00
// Prototypes
// Sin/Cos Table
void generateTable(void);
int ncos(u_int t);
int nsin(u_int t);
// Atan table
int patan(int x, int y);
//sqrt
u_int psqrt(u_int n);
2021-02-03 15:35:51 +01:00
// PSX setup
2021-02-03 15:23:20 +01:00
void init(void);
void display(void);
2021-02-03 15:35:51 +01:00
// Utils
void LoadTexture(u_long * tim, TIM_IMAGE * tparam);
int cliptest3(short * v1);
int lerp(int start, int end, int factor); // FIXME : not working as it should
SVECTOR SVlerp(SVECTOR start, SVECTOR end, int factor); // FIXME
// Camera
2021-02-03 15:23:20 +01:00
void getCameraXZ(int * x, int * z, int actorX, int actorZ, int angle, int distance);
void applyCamera(CAMERA * cam);
void setCameraPos(VECTOR pos, SVECTOR rot);
2021-02-03 15:35:51 +01:00
// Physics
2021-02-03 15:23:20 +01:00
VECTOR getCollision(BODY one, BODY two);
2021-02-03 15:35:51 +01:00
void applyAcceleration(BODY * actor);
2021-02-03 15:23:20 +01:00
void callback();
int main() {
// Mesh stuff
int i;
long t, p, OTz, OTc, Flag, nclip; // t == vertex count, p == depth cueing interpolation value, OTz == value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143
POLY_GT3 * poly;
2021-02-03 16:20:34 +01:00
//~ // Poly subdiv
//~ DIVPOLYGON3 div = { 0 };
//~ div.pih = SCREENXRES;
//~ div.piv = SCREENYRES;
2021-02-03 15:23:20 +01:00
CVECTOR outCol ={0,0,0,0};
CVECTOR outCol1 ={0,0,0,0};
CVECTOR outCol2 ={0,0,0,0};
MATRIX Cmatrix = {0};
init();
generateTable();
VSyncCallback(callback);
//~ SetLightMatrix(&LLM);
SetColorMatrix(&cmat);
SetBackColor(BKc.vx,BKc.vy,BKc.vz);
//~ SetFarColor(BGc.r, BGc.g, BGc.b);
SetFogNearFar(1200, 1600, SCREENXRES);
for (int k = 0; k < sizeof(meshes)/sizeof(TMESH *); k++){
LoadTexture(meshes[k]->tim_data, meshes[k]->tim);
}
// physics
short physics = 1;
long time = 0;
2021-02-03 16:20:34 +01:00
//~ long sec = 0;
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
//~ long d1y, d2y;
//~ long d1x, d2x;
//~ long d1z, d2z;
2021-02-03 15:23:20 +01:00
// Actor start pos
modelobject_body.position.vx = modelobject_pos.vx = 50;
2021-02-03 16:20:34 +01:00
// Cam stuff
2021-02-03 15:23:20 +01:00
VECTOR posToActor = {0, 0, 0, 0}; // position of camera relative to actor
VECTOR theta = {0, 0, 0, 0}; // rotation angles for the camera to point at actor
2021-02-03 16:20:34 +01:00
int angle = 0; //PSX units = 4096 == 360° = 2Pi
int dist = 0; //PSX units
2021-02-03 15:23:20 +01:00
int lerping = 0;
// Vertex anim
//~ SVECTOR interpCache[5];
SVECTOR a,b,c = {0,0,0,0};
2021-02-03 16:20:34 +01:00
short timediv = 1;
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
int atime = 0;
2021-02-03 15:23:20 +01:00
for (int k = 0; k < sizeof(meshes)/sizeof(meshes[0]); k++){
triCount += meshes[k]->tmesh->len;
}
// Main loop
while (1) {
//~ timeB = time;
time ++;
timediv = 2;
if (time % timediv == 0){
atime ++;
}
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
//~ timediv = 1;
long dt;
//~ // Physics
//~ if (time%2 == 0){
2021-02-03 16:20:34 +01:00
// using libgte ratan (slower)
2021-02-03 15:23:20 +01:00
//~ theta.vy = -ratan2(posToActor.vx, posToActor.vz) ;
//~ theta.vx = 1024 - ratan2(dist, posToActor.vy);
2021-02-03 16:20:34 +01:00
// using atantable (faster)
2021-02-03 15:23:20 +01:00
theta.vy = patan(posToActor.vx, posToActor.vz) / 16 - 1024 ;
theta.vx = patan(dist, posToActor.vy)/16;
if(camMode != 2){
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
camera.rot.vy = theta.vy;
// using csin/ccos, no need for theta
2021-02-03 16:20:34 +01:00
//~ camera.rot.vy = angle;
2021-02-03 15:23:20 +01:00
camera.rot.vx = theta.vx;
}
if(camMode != 4){
lerping = 0;
}
if(camMode == 0){ // Camera follows actor with lerp for rotations
dist = 150;
camera.pos.vx = -(camera.x/ONE);
//~ camera.pos.vy = -(camera.y/ONE);
camera.pos.vz = -(camera.z/ONE);
getCameraXZ(&camera.x, &camera.z, modelobject_pos.vx, modelobject_pos.vz, angle, dist);
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
angle += lerp(camera.rot.vy, modelobject_rot.vy, 128);
}
if (camMode == 1){ // mode 1 : Camera rotates continuously
dist = 150;
camera.pos.vx = -(camera.x/ONE);
//~ camera.pos.vy = -(camera.y/ONE);
camera.pos.vz = -(camera.z/ONE);
getCameraXZ(&camera.x, &camera.z, modelobject_pos.vx, modelobject_pos.vz, angle, dist);
angle += 10;
}
if (camMode == 3){ // mode 3 : Fixed Camera with actor tracking
2021-02-03 16:20:34 +01:00
// Using libgte sqrt ( slower)
2021-02-03 15:23:20 +01:00
//~ dist = SquareRoot0( (posToActor.vx * posToActor.vx ) + (posToActor.vz * posToActor.vz) );
2021-02-03 16:20:34 +01:00
// Using precalc sqrt
2021-02-03 15:23:20 +01:00
dist = psqrt( (posToActor.vx * posToActor.vx ) + (posToActor.vz * posToActor.vz) );
camera.pos.vx = 290;
camera.pos.vz = 100;
camera.pos.vy = 180;
}
if (camMode == 2){ // mode 2 : Fixed Camera
setCameraPos(camStartPos.pos, camStartPos.rot);
}
if(camMode == 4){ // Flyby mode from camStart to camEnd
if (!lerping){
// Set cam start position
camera.pos.vx = camPath.points[camPath.cursor].vx;
camera.pos.vy = camPath.points[camPath.cursor].vy;
camera.pos.vz = camPath.points[camPath.cursor].vz;
lerping = 1;
}
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
// Pre calculated sqrt ( see psqrt() )
dist = psqrt( (posToActor.vx * posToActor.vx ) + (posToActor.vz * posToActor.vz) );
short r = camPath.points[camPath.cursor+1].vx - camera.pos.vx;
short s = camPath.points[camPath.cursor+1].vy - camera.pos.vy;
short t = camPath.points[camPath.cursor+1].vz - camera.pos.vz;
2021-02-03 16:20:34 +01:00
// FIXME : the lerp function is incorrect
2021-02-03 15:23:20 +01:00
//~ camera.pos.vx += lerp(camPath.points[camPath.cursor].vx, camPath.points[camPath.cursor+1].vx, 64);
//~ camera.pos.vy += lerp(camPath.points[camPath.cursor].vy, camPath.points[camPath.cursor+1].vy, 64);
//~ camera.pos.vz += lerp(camPath.points[camPath.cursor].vz, camPath.points[camPath.cursor+1].vz, 64);
2021-02-03 16:20:34 +01:00
// easeOut
2021-02-03 15:23:20 +01:00
camera.pos.vx += lerp(camera.pos.vx, camPath.points[camPath.cursor+1].vx, 128);
camera.pos.vy += lerp(camera.pos.vy, camPath.points[camPath.cursor+1].vy, 128);
camera.pos.vz += lerp(camera.pos.vz, camPath.points[camPath.cursor+1].vz, 128);
//~ if ( camera.pos.vx <= camPath.points[camPath.cursor+1].vx ||
//~ camera.pos.vy >= camPath.points[camPath.cursor+1].vy ||
//~ camera.pos.vz <= camPath.points[camPath.cursor+1].vz){
//~ camPath.cursor ++;
//~ }
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
if ( camera.pos.vx + r == camPath.points[camPath.cursor+1].vx &&
camera.pos.vy + s == camPath.points[camPath.cursor+1].vy &&
camera.pos.vz + t == camPath.points[camPath.cursor+1].vz){
camPath.cursor ++;
}
if ( camPath.cursor == camPath.len - 1 ){
lerping = 0;
camPath.cursor = 0;
}
}
//~ dt = time/180+1 - time/180;
if (physics){
if(time%2 == 0){
for ( int k = 0; k < sizeof(meshes)/sizeof(meshes[0]);k ++){
if ( *meshes[k]->isRigidBody == 1 ) {
2021-02-03 15:35:51 +01:00
applyAcceleration(meshes[k]->body);
2021-02-03 15:23:20 +01:00
VECTOR col;
2021-02-03 16:20:34 +01:00
// Get col with level ( modelgnd_body )
2021-02-03 15:23:20 +01:00
col = getCollision( *meshes[k]->body , modelgnd_body);
2021-02-03 16:20:34 +01:00
// If !col, keep moving
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
if ( !col.vx ){ meshes[k]->pos->vx = meshes[k]->body->position.vx; }
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
if ( !col.vy ){ meshes[k]->pos->vy = meshes[k]->body->position.vy + 15; } // FIXME : Why the 15px offset ?
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
if ( !col.vz ){ meshes[k]->pos->vz = meshes[k]->body->position.vz; }
// If col with wall, change direction
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
if ( col.vx ) { meshes[k]->body->gForce.vx *= -1; }
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
if ( col.vy ) { meshes[k]->body->gForce.vy *= -1; }
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
if ( col.vz ) { meshes[k]->body->gForce.vz *= -1; }
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
// If col, reset velocity
if ( col.vx ||
col.vy ||
col.vz
2021-02-03 15:23:20 +01:00
) {
meshes[k]->body->velocity.vy = meshes[k]->body->velocity.vx = meshes[k]->body->velocity.vz = 0;
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
}
}
}
}
}
// Camera setup
// position of cam relative to actor
posToActor.vx = modelobject_pos.vx + camera.pos.vx;
posToActor.vz = modelobject_pos.vz + camera.pos.vz;
posToActor.vy = modelobject_pos.vy + camera.pos.vy;
// find dist between actor and cam
//~ dist = csqrt((posToActor.vx * posToActor.vx * 4096) + (posToActor.vz * posToActor.vz * 4096));
//~ dist = SquareRoot0( (posToActor.vx * posToActor.vx ) + (posToActor.vz * posToActor.vz) );
// find angles between cam and actor
//~ theta.vy = ratan2(posToActor.vx, posToActor.vz);
//~ theta.vx = 1024 - ratan2(dist, posToActor.vy);
//~ camera.rot.vy = - theta.vy;
// using csin/ccos, no need for theta
// camera.rot.vy = angle;
//~ camera.rot.vx = theta.vx;
//~ applyCamera(&camera);
// Clear the current OT
ClearOTagR(ot[db], OTLEN);
for (int k = 0; k < sizeof(meshes)/sizeof(meshes[0]); k++){
// Render the sample vector model
t=0;
2021-02-03 16:20:34 +01:00
// If rigidbdy, apply rot/transform matrix
2021-02-03 15:23:20 +01:00
if (*meshes[k]->isRigidBody){
2021-02-03 16:20:34 +01:00
//~ PushMatrix(); // Push current matrix on the stack (real slow -> dma transfer )
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
RotMatrix_gte(meshes[k]->rot, meshes[k]->mat); // Apply rotation matrix
TransMatrix(meshes[k]->mat, meshes[k]->pos); // Apply translation matrix
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
//~ MulMatrix0(&camera.mat, meshes[k]->mat, meshes[k]->mat);
CompMatrix(&camera.mat, meshes[k]->mat, meshes[k]->mat); // Was using &PolyMatrix instead of meshes[k]->mat
2021-02-03 15:23:20 +01:00
2021-02-03 16:20:34 +01:00
SetRotMatrix(meshes[k]->mat); // Set default rotation matrix - Was using &PolyMatrix instead of meshes[k]->mat
SetTransMatrix(meshes[k]->mat); // Was using &PolyMatrix instead of meshes[k]->mat
2021-02-03 15:23:20 +01:00
}
// modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...
for (i = 0; i < (meshes[k]->tmesh->len * 3); i += 3) {
poly = (POLY_GT3 *)nextpri;
SetPolyGT3(poly);
// Can use ?
//~ RotMeshPrimS_GCT3();
if (*meshes[k]->isPrism){
2021-02-03 16:20:34 +01:00
// Use current DRAWENV clip as TPAGE
2021-02-03 15:23:20 +01:00
((POLY_GT3 *)poly)->tpage = getTPage(meshes[k]->tim->mode&0x3, 0,
2021-02-03 16:20:34 +01:00
draw[db].clip.x,
draw[db].clip.y
2021-02-03 15:23:20 +01:00
);
2021-02-03 16:20:34 +01:00
// Use projected coordinates (results from RotAverage...) as UV coords and clamp them to 0-255,0-224
2021-02-03 15:23:20 +01:00
setUV3(poly, (poly->x0 < 0? 0 : poly->x0 > 255? 255 : poly->x0),
(poly->y0 < 0? 0 : poly->y0 > 224? 224 : poly->y0),
(poly->x1 < 0? 0 : poly->x1 > 255? 255 : poly->x1),
(poly->y1 < 0? 0 : poly->y1 > 224? 224 : poly->y1),
(poly->x2 < 0? 0 : poly->x2 > 255? 255 : poly->x2),
(poly->y2 < 0? 0 : poly->y2 > 224? 224 : poly->y2)
);
} else {
2021-02-03 16:20:34 +01:00
// Use regular TPAGE
2021-02-03 15:23:20 +01:00
((POLY_GT3 *)poly)->tpage = getTPage(meshes[k]->tim->mode&0x3, 0,
meshes[k]->tim->prect->x,
meshes[k]->tim->prect->y
);
2021-02-03 16:20:34 +01:00
// Use model UV coordinates
2021-02-03 15:23:20 +01:00
setUV3(poly, meshes[k]->tmesh->u[i].vx , meshes[k]->tmesh->u[i].vy + meshes[k]->tim->prect->y,
meshes[k]->tmesh->u[i+1].vx, meshes[k]->tmesh->u[i+1].vy + meshes[k]->tim->prect->y,
meshes[k]->tmesh->u[i+2].vx, meshes[k]->tmesh->u[i+2].vy + meshes[k]->tim->prect->y);
}
2021-02-03 16:20:34 +01:00
// If Vertex Anim flag
2021-02-03 15:23:20 +01:00
if (*meshes[k]->isAnim){
2021-02-03 16:20:34 +01:00
// FIXME : SLERP VERTEX ANIM
2021-02-03 15:23:20 +01:00
//~ SVECTOR a,b,c = {0,0,0,0};
//~ for (int f = 0; f < 5; f++){
//~ interpCache[f] = SVlerp( (SVECTOR) meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]], (SVECTOR) meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]], 2048);
//~ interpCache[f+1] = SVlerp( (SVECTOR) meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]], (SVECTOR) meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]], 2048);
//~ interpCache[f+2] = SVlerp( (SVECTOR) meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]], (SVECTOR) meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]], 2048);
//~ }
//~ SVECTOR start = meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]];
//~ SVECTOR end = meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]];
//~ if (a.vx != 0 && b.vx != 0 && c.vx != 0){
//~ SVECTOR d,e,f;
//~ d = SVlerp( (SVECTOR) a, (SVECTOR) meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]], 2048);
//~ e = SVlerp( (SVECTOR) b, (SVECTOR) meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t+1]], 2048);
//~ f = SVlerp( (SVECTOR) c, (SVECTOR) meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t+2]], 2048);
//~ addVector( &a , &d );
//~ addVector( &b , &e );
//~ addVector( &c , &f );
//~ } else {
//~ a = (SVECTOR) meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]];
//~ b = (SVECTOR) meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t+1]];
//~ c = (SVECTOR) meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t+2]];
//~ }
//~ a.vx = lerp(start.vx, end.vx, 2048);
//~ a.vy = lerp(meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]].vy, meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]].vy, 2048);
//~ a.vz = lerp(meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]].vz, meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]].vz, 2048);
//~ b = meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t+1]];
//~ c = meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t+2]];
//~ SVlerp(meshes[k]->anim->data[ 0 * modelCylindre_anim.nvert + meshes[k]->index[t]], meshes[k]->anim->data[ 10 * modelCylindre_anim.nvert + meshes[k]->index[t]],64, a);
//~ SVlerp(meshes[k]->anim->data[ 0 * modelCylindre_anim.nvert + meshes[k]->index[t+1]], meshes[k]->anim->data[ 10 * modelCylindre_anim.nvert + meshes[k]->index[t+1]],64, b);
//~ SVlerp(meshes[k]->anim->data[ 0 * modelCylindre_anim.nvert + meshes[k]->index[t+2]], meshes[k]->anim->data[ 10 * modelCylindre_anim.nvert + meshes[k]->index[t+2]],64, c);
//~ FntPrint("%d %d %d\n", meshes[k]->anim->data[0 * modelCylindre_anim.nvert + meshes[k]->index[t]].vz, meshes[k]->anim->data[10 * modelCylindre_anim.nvert + meshes[k]->index[t]].vz, a.vz);
//~ FntPrint("%d %d %d\n", c.vx, c.vy, c.vz);
//~ FntPrint("%d %d %d\n", a.vx, b.vx, c.vx);
2021-02-03 16:20:34 +01:00
// Rotate, translate, and project the vectors and output the results into a primitive
//~ OTz = RotTransPers(&meshes[k]->tmesh->v[meshes[k]->index[t]] , (long*)&poly->x0, meshes[k]->p, &Flag);
//~ OTz += RotTransPers(&meshes[k]->tmesh->v[meshes[k]->index[t+1]], (long*)&poly->x1, meshes[k]->p, &Flag);
//~ OTz += RotTransPers(&meshes[k]->tmesh->v[meshes[k]->index[t+2]], (long*)&poly->x2, meshes[k]->p, &Flag);
// Use anim vertex's positions
OTz = RotAverage3(
&meshes[k]->anim->data[ atime%19 * modelCylindre_anim.nvert + meshes[k]->index[t]],
&meshes[k]->anim->data[ atime%19 * modelCylindre_anim.nvert + meshes[k]->index[t+1]],
&meshes[k]->anim->data[ atime%19 * modelCylindre_anim.nvert + meshes[k]->index[t+2]],
(long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2,
meshes[k]->p,
&Flag
);
2021-02-03 15:23:20 +01:00
} else {
2021-02-03 16:20:34 +01:00
// Use model's regular vertex pos
2021-02-03 15:23:20 +01:00
OTz = RotAverage3(
&meshes[k]->tmesh->v[meshes[k]->index[t]],
&meshes[k]->tmesh->v[meshes[k]->index[t+1]],
&meshes[k]->tmesh->v[meshes[k]->index[t+2]],
(long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2,
meshes[k]->p,
&Flag
);
}
2021-02-03 16:20:34 +01:00
// FIXME : Polygon subdiv
2021-02-03 15:23:20 +01:00
//~ OTc = OTz>>4;
//~ if (OTc < 15) {
//~ if (OTc > 5) div.ndiv = 1; else div.ndiv = 2;
//~ DivideGT3(
//~ // Vertex coord
//~ &meshes[k]->tmesh->v[meshes[k]->index[t]],
//~ &meshes[k]->tmesh->v[meshes[k]->index[t+1]],
//~ &meshes[k]->tmesh->v[meshes[k]->index[t+2]],
//~ // UV coord
//~ meshes[k]->tmesh->u[i],
//~ meshes[k]->tmesh->u[i+1],
//~ meshes[k]->tmesh->u[i+2],
//~ // Color
//~ meshes[k]->tmesh->c[i],
//~ meshes[k]->tmesh->c[i+1],
//~ meshes[k]->tmesh->c[i+2],
//~ // Gpu packet
//~ poly,
//~ &ot[db][OTz],
//~ &div);
//~ // Increment primitive list pointer
//~ nextpri += ( (sizeof(POLY_GT4) + 2) / 3 ) * (( 1 << ( div.ndiv )) << ( div.ndiv ));
//NumPrims += ((1<<(div.ndiv))<<(div.ndiv));
//~ }
2021-02-03 16:20:34 +01:00
// Interpolate a primary color vector and far color
// If vertex anim has updated normals
2021-02-03 15:23:20 +01:00
//~ if (*meshes[k]->isAnim){
//~ NormalColorDpq(&meshes[k]->anim->normals[ atime%19 * modelCylindre_anim.nvert + meshes[k]->index[t]], &meshes[k]->tmesh->c[meshes[k]->index[t]], *meshes[k]->p, &outCol);
//~ NormalColorDpq(&meshes[k]->anim->normals[ atime%19 * modelCylindre_anim.nvert + meshes[k]->index[t+1]], &meshes[k]->tmesh->c[meshes[k]->index[t+1]], *meshes[k]->p, &outCol1);
//~ NormalColorDpq(&meshes[k]->anim->normals[ atime%19 * modelCylindre_anim.nvert + meshes[k]->index[t+2]], &meshes[k]->tmesh->c[meshes[k]->index[t+2]], *meshes[k]->p, &outCol2);
//~ } else {
NormalColorDpq(&meshes[k]->tmesh->n[meshes[k]->index[t]] , &meshes[k]->tmesh->c[meshes[k]->index[t]], *meshes[k]->p, &outCol);
NormalColorDpq(&meshes[k]->tmesh->n[meshes[k]->index[t+1]], &meshes[k]->tmesh->c[meshes[k]->index[t+1]], *meshes[k]->p, &outCol1);
NormalColorDpq(&meshes[k]->tmesh->n[meshes[k]->index[t+2]], &meshes[k]->tmesh->c[meshes[k]->index[t+2]], *meshes[k]->p, &outCol2);
//~ }
2021-02-03 16:20:34 +01:00
// Other methods
//~ NormalColorDpq3(&meshes[k]->tmesh->n[i],
//~ &meshes[k]->tmesh->n[i+1],
//~ &meshes[k]->tmesh->n[i+2],
//~ &meshes[k]->tmesh->c[i],
//~ *meshes[k]->p,
//~ &outCol,&outCol1,&outCol2
//~ );
2021-02-03 15:23:20 +01:00
//~ DpqColor3(&meshes[k]->tmesh->c[i],
//~ &meshes[k]->tmesh->c[i+1],
//~ &meshes[k]->tmesh->c[i+2],
//~ *meshes[k]->p,
//~ &outCol,&outCol1,&outCol2
//~ );
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
if (*meshes[k]->isPrism){
2021-02-03 16:20:34 +01:00
// Use un-interpolated (i.e: no light, no fog) colors
setRGB0(poly, meshes[k]->tmesh->c[i].r, meshes[k]->tmesh->c[i+1].g, meshes[k]->tmesh->c[i+2].b);
setRGB1(poly, meshes[k]->tmesh->c[i+1].r, meshes[k]->tmesh->c[i+1].g, meshes[k]->tmesh->c[i+1].b);
setRGB2(poly, meshes[k]->tmesh->c[i+2].r, meshes[k]->tmesh->c[i+2].g, meshes[k]->tmesh->c[i+2].b);
2021-02-03 15:23:20 +01:00
} else {
setRGB0(poly, outCol.r, outCol.g , outCol.b);
setRGB1(poly, outCol1.r, outCol1.g, outCol1.b);
setRGB2(poly, outCol2.r, outCol2.g, outCol2.b);
}
// Sort the primitive into the OT
//~ OTz /= 3;
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
// cliptest3((short *)&meshes[k]->tmesh->v[meshes[k]->index[t]])
//~ if ((OTz > 0) && (OTz < OTLEN) && (*meshes[k]->p < 2048)){
if ((OTz > 0) && (OTz < OTLEN) && (*meshes[k]->p < 4096)){
AddPrim(&ot[db][OTz-2], poly); // OTz - 2
}
nextpri += sizeof(POLY_GT3);
t+=3;
//~ if (*meshes[k]->isRigidBody){
2021-02-03 16:20:34 +01:00
//~ PopMatrix(); // Pull previous matrix from stack (slow)
//~ }
2021-02-03 15:23:20 +01:00
}
2021-02-03 16:20:34 +01:00
// Find and apply light rotation matrix
2021-02-03 15:23:20 +01:00
RotMatrix(&lgtang, &rotlgt);
MulMatrix0(&lgtmat, &rotlgt, &light);
SetLightMatrix(&light);
2021-02-03 16:20:34 +01:00
applyCamera(&camera);
2021-02-03 15:23:20 +01:00
}
FntPrint("Time : %d %d dt :%d\n",time, atime, dt);
FntPrint("Tricount: %d OTz: %d\nOTc: %d, p: %d\n",triCount, OTz, OTc, *meshes[2]->p);
FntPrint("isPrism: %d\n", *meshobject.isPrism);
FntPrint("L1: %d %d %d\n", light.m[0][0],light.m[0][1],light.m[0][2]);
FntPrint("L2: %d %d %d\n", light.m[1][0],light.m[1][1],light.m[1][2]);
FntPrint("L3: %d %d %d\n", light.m[2][0],light.m[2][1],light.m[2][2]);
2021-02-03 16:20:34 +01:00
2021-02-03 15:23:20 +01:00
FntFlush(-1);
display();
//~ frame = VSync(-1);
}
return 0;
}
void init(){
// Reset the GPU before doing anything and the controller
PadInit(0);
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX, CENTERY); // x, y offset
SetGeomScreen(CENTERX); // Distance between eye and screen
// Set the display and draw environments
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], BGc.r, BGc.g, BGc.b);
setRGB0(&draw[1], BGc.r, BGc.g, BGc.b);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Init font system
FntLoad(960, 0);
FntOpen(16, 180, 240, 96, 0, 512);
}
void display(void){
DrawSync(0);
vs = VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
// Nic's function
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 * ONE) + (distance * nsin(angle));
*z = (actorZ * ONE) - (distance * ncos(angle));
//~ *x = (actorX * ONE) + (distance * csin(angle));
//~ *z = (actorZ * ONE) - (distance * ccos(angle)); // Z is pointing away from the eye
// @soapy https://discord.com/channels/642647820683444236/663664210525290507/797188403748929547
//~ *x = (actorX * ONE) + (distance * rcossin_tbl[(angle & 0xFFFU) * 2]);
//~ *z = (actorZ * ONE) - (distance * rcossin_tbl[(angle & 0xFFFU) * 2 + 1]); // Z is pointing away from the eye
// Using precalculated psin and pcos
//~ *x = (actorX * ONE) + (distance * psin[angle]);
//~ *z = (actorZ * ONE) - (distance * pcos[angle]); // Z is pointing away from the eye
}
// @Will : you might want to use sin/cos to move the camera in a circle but you could do that by moving it along its tangent and then clamping the distance
void applyCamera(CAMERA * cam){
VECTOR vec; // Vector that holds the output values of the following instructions
RotMatrix_gte(&cam->rot, &cam->mat); // Convert rotation angle in psx units (360° == 4096) to rotation matrix)
ApplyMatrixLV(&cam->mat, &cam->pos, &vec); // Multiply matrix by vector pos and output to vec
TransMatrix(&cam->mat, &vec); // Apply transform vector
SetRotMatrix(&cam->mat); // Set Rotation matrix
SetTransMatrix(&cam->mat); // Set Transform matrix
}
void setCameraPos(VECTOR pos, SVECTOR rot){
camera.pos = pos;
camera.rot = rot;
};
void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory
ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure
LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y
DrawSync(0); // Wait for the drawing to end
if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT
LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y
DrawSync(0); // Wait for drawing to end
}
}
int lerp(int start, int end, int factor){
// lerp interpolated cam movement
// InBetween = Value 1 + ( ( Value2 - Value1 ) * lerpValue ) ;
// lerpValue should be a float between 0 and 1.
// This'll have to be a fixed point value between 0-4096
// easeOut
//~ return ( ( start ) + ( end - start ) * factor ) / 4096;
// easeIn
return ( ( start ) + ( end - start ) * factor ) / 4096;
// kinda linear
//~ return (( start ) + ( end - start )) * factor / 4096;
}
SVECTOR SVlerp(SVECTOR start, SVECTOR end, int factor){
SVECTOR output = {0,0,0,0};
output.vx = lerp(start.vx, end.vx, factor);
output.vy = lerp(start.vy, end.vy, factor);
output.vz = lerp(start.vz, end.vz, factor);
return output;
}
VECTOR getCollision(BODY one, BODY two){
VECTOR d1, d2, col;
d1.vx = (one.position.vx - one.max.vx) - (two.position.vx + two.min.vx);
d1.vy = (one.position.vy - one.min.vy) - (two.position.vy + two.min.vy);
d1.vz = (one.position.vz - one.max.vz) - (two.position.vz + two.min.vz);
d2.vx = (two.position.vx + two.max.vx) - (one.position.vx + one.max.vx);
d2.vy = (two.position.vy + two.max.vy) - (one.position.vy + one.max.vy);
d2.vz = (two.position.vz + two.max.vz) - (one.position.vz + one.max.vz);
2021-02-03 16:20:34 +01:00
col.vx = !(d1.vx >= 0 && d2.vx >= 0);
col.vy = !(d1.vy >= 0 && d2.vy >= 0);
col.vz = !(d1.vz >= 0 && d2.vz >= 0);
2021-02-03 15:23:20 +01:00
return col;
}
2021-02-03 15:35:51 +01:00
void applyAcceleration(BODY * actor){
short dt = 1;
2021-02-03 15:23:20 +01:00
2021-02-03 15:35:51 +01:00
VECTOR acceleration = {actor->gForce.vx / actor->mass, actor->gForce.vy / actor->mass, actor->gForce.vz / actor->mass};
actor->velocity.vx += acceleration.vx * dt;
actor->velocity.vy += acceleration.vy * dt;
actor->velocity.vz += acceleration.vz * dt;
actor->position.vx += actor->velocity.vx * dt;
actor->position.vy += actor->velocity.vy * dt;
actor->position.vz += actor->velocity.vz * dt;
}
2021-02-03 15:23:20 +01:00
// A few notes on the following code :
int ncos(unsigned int t) {
t %= DC_2PI;
int r;
if (t < DC_PI2) {
r = m_cosTable[t];
} else if (t < DC_PI) {
r = -m_cosTable[DC_PI - 1 - t];
} else if (t < (DC_PI + DC_PI2)) {
r = -m_cosTable[t - DC_PI];
} else {
r = m_cosTable[DC_2PI - 1 - t];
};
return r >> 12;
};
// sin(x) = cos(x - pi / 2)
int nsin(unsigned int t) {
t %= DC_2PI;
if (t < DC_PI2){
return ncos(t + DC_2PI - DC_PI2);
};
return ncos(t - DC_PI2);
};
// f(n) = cos(n * 2pi / 2048) <- 2048 is == DC_2PI value
// f(n) = 2 * f(1) * f(n - 1) - f(n - 2)
void generateTable(void){
m_cosTable[0] = 16777216; // 2^24 * cos(0 * 2pi / 2048) => 2^24 * 1 = 2^24 : here, 2^24 defines the precision we want after the decimal point
static const long long C = 16777137; // 2^24 * cos(1 * 2pi / 2048) = C = f(1);
m_cosTable[1] = C;
for (int i = 2; i < 512; i++){
m_cosTable[i] = ((C * m_cosTable[i - 1]) >> 23) - m_cosTable[i - 2];
m_cosTable[511] = 0;
}
};
// https://github.com/Arsunt/TR2Main/blob/411cacb35914c616cb7960c0e677e00c71c7ee88/3dsystem/phd_math.cpp#L432
int patan(int x, int y){
int result;
int swapBuf;
int flags = 0;
// if either x or y are 0, return 0
if( x == 0 && y == 0){
return 0;
}
if( x < 0 ) {
flags |= 4;
x = -x;
}
if ( y < 0 ) {
flags |= 2;
y = -y;
}
if ( y > x ) {
flags |= 1;
SWAP(x, y ,swapBuf);
}
result = AtanBaseTable[flags] + AtanAngleTable[0x800 * y / x];
if ( result < 0 ){
result = -result;
return result;
}
}
u_int psqrt(u_int n){
u_int result = 0;
u_int base = 0x40000000;
u_int basedResult;
for( ; base != 0; base >>= 2 ) {
for( ; base != 0; base >>= 2 ) {
basedResult = base + result;
result >>= 1;
if( basedResult > n ) {
break;
}
n -= basedResult;
result |= base;
}
}
return result;
}
int cliptest3(short *v1)
{
if( v1[0]<0 && v1[2]<0 && v1[4]<0 ) return 0;
if( v1[1]<0 && v1[3]<0 && v1[5]<0 ) return 0;
if( v1[0] > SCREENXRES && v1[2] > SCREENXRES && v1[4] > SCREENXRES) return 0;
if( v1[1] > SCREENYRES && v1[3] > SCREENYRES && v1[5] > SCREENYRES) return 0;
return 1;
}
void callback(){
int pad = PadRead(0);
if (pad & PADRright && !pressed){
if(camMode < 4){
camMode += 1;
} else {
setCameraPos(camStartPos.pos, camStartPos.rot);
camPath.cursor = 0;
camMode = 0;
}
pressed = 1;
}
if (!(pad & PADRright)){
pressed = 0;
}
if (pad & PADRdown){
lgtang.vy += 32;
//~ lgtang.vx += 32;
}
if (pad & PADRup){
lgtang.vz += 32;
//~ lgtang.vx += 32;
}
//~ RotMatrix(&lgtang, &rotlgt);
//~ MulMatrix(&rotlgt, &rottrans);
if (pad & PADLdown && !pressed){
if (*meshobject.isPrism){
*meshobject.isPrism = 0;
} else {
*meshobject.isPrism = 1;
}
pressed = 1;
}
if (!pad & PADLdown){
pressed = 0;
}
}