Browse Source

First genuine result: combined view and projection matrices allow camera controls in Quake coordinate system with aspect ratio correction.

master
Nico de Poel 3 years ago
parent
commit
43adc7c90f
  1. 93
      main.c

93
main.c

@ -76,8 +76,8 @@ typedef struct
ps1texture_t front, back;
} ps1skin_t;
ps1mdl_t playerModel = { .position = { -200, 160, 400 }, .rotation = { 0 } };
ps1mdl_t shamblerModel = { .position = { 200, 160, 400 }, .rotation = { 0 } };
ps1mdl_t playerModel = { .position = { -200, 200, -160 }, .rotation = { 0 } };
ps1mdl_t shamblerModel = { .position = { 100, 200, -160 }, .rotation = { 0 } };
ps1skin_t playerSkin, shamblerSkin;
const MATRIX identity = {
@ -87,6 +87,13 @@ const MATRIX identity = {
0, 0, 0,
};
const MATRIX quake_swizzle = {
ONE, 0, 0,
0, 0, -ONE,
0, ONE, 0,
0, 0, 0,
};
MATRIX light_cols = {
ONE, 0, 0,
ONE, 0, 0,
@ -361,7 +368,7 @@ static int fakeLight(const int *norm)
SVECTOR outPos;
void drawModel(ps1mdl_t *model, ps1skin_t *skin, int frameCounter)
void drawModel(MATRIX *view_matrix, ps1mdl_t *model, ps1skin_t *skin, int frameCounter)
{
ps1texture_t *tex;
short u0, u1, u2, uoffs, voffs;
@ -375,52 +382,18 @@ void drawModel(ps1mdl_t *model, ps1skin_t *skin, int frameCounter)
int *scale = model->header->scale;
int *translate = model->header->translate;
// Expected order of things:
// - Initial scale matrix to correct aspect ratio
// - Coordinate system swizzle (scale) (can probably be combined with the above)
// - Camera inverse translation
// - Camera inverse rotation (apply on top of camera translation)
// - Multiply light matrix (lights will be in Quake coordinate system)
// - Push matrix
// - Entity local rotation
// - Entity local translation
// - Model internal scale
// - Model internal translate
// - Render
// - Pop matrix
// TODO: this can all probably be done much more efficiently with the CompMatrixLV function. Doing it manually first though to better understand it.
MATRIX cam_mtx = identity;
//VECTOR cam_inv_pos = { -cam_pos.vx, -cam_pos.vy, -cam_pos.vz };
ScaleMatrixL(&cam_mtx, &aspect_scale); // Aspect ratio correction
//TransMatrix(&cam_mtx, &cam_inv_pos);
//MATRIX cam_rot_mtx;
//SVECTOR cam_inv_rot = { -cam_rot.vx, -cam_rot.vy, -cam_rot.vz, 0 };
//RotMatrix(&cam_inv_rot, &cam_rot_mtx);
//MulMatrix(&cam_mtx, &cam_rot_mtx);
MATRIX light_mtx;
// MulMatrix0(&light_dirs, &cam_mtx, &light_mtx);
// gte_SetLightMatrix(&light_mtx);
MATRIX model_mtx;
RotMatrix(&model->rotation, &model_mtx);
TransMatrix(&model_mtx, &model->position);
MulMatrix(&model_mtx, &cam_mtx);
MATRIX light_mtx;
MulMatrix0(&light_dirs, &model_mtx, &light_mtx);
gte_SetLightMatrix(&light_mtx);
// Model internal scale and translate, to transform vertices from [0..255] range to a larger dynamic range with appropriate world-relative size
// Swizzle the coordinates because Quake Z is up
// Finding the appropriate scale range here is tricky. Without the << 2 scale the vertex coordinates become so small that you lose depth precision.
MATRIX local_mtx = { .m = { ONE << 2, 0, 0, 0, 0, -ONE << 2, 0, ONE << 2, 0 }, .t = { 0 } };
ScaleMatrixL(&local_mtx, (VECTOR*)scale);
TransMatrix(&local_mtx, (VECTOR*)translate);
MulMatrix(&model_mtx, &local_mtx);
CompMatrixLV(view_matrix, &model_mtx, &model_mtx);
PushMatrix();
// TODO: set these after setting up camera, then use PushMatrix + CompMatrixLV for entities?
gte_SetRotMatrix(&model_mtx);
gte_SetTransMatrix(&model_mtx);
@ -499,6 +472,8 @@ void drawModel(ps1mdl_t *model, ps1skin_t *skin, int frameCounter)
addPrim(ot[db] + depth, poly);
nextpri += sizeof(POLY_GT3);
}
PopMatrix();
}
void drawStuff(int counter)
@ -515,8 +490,38 @@ void drawStuff(int counter)
gte_SetBackColor(48, 48, 48); // Ambient light color
gte_SetColorMatrix(&light_cols); // Light color (up to three different lights)
drawModel(&playerModel, &playerSkin, counter >> 2);
drawModel(&shamblerModel, &shamblerSkin, counter >> 2);
// Expected order of things:
// - Initial scale matrix to correct aspect ratio
// - Coordinate system swizzle (scale) (can probably be combined with the above)
// - Camera inverse translation
// - Camera inverse rotation (apply on top of camera translation)
// - Multiply light matrix (lights will be in Quake coordinate system)
// - Push matrix
// - Entity local rotation
// - Entity local translation
// - Model internal scale
// - Model internal translate
// - Render
// - Pop matrix
MATRIX proj_matrix = quake_swizzle; // Swizzle coordinates so that everything is in Quake coordinate system (Z up)
ScaleMatrixL(&proj_matrix, &aspect_scale); // Apply aspect ratio correction for the current resolution
MATRIX view_matrix;
SVECTOR trot = { 0, 0, 0, 0 }; // TODO: camera rotation (in Quake coordinates)
VECTOR tpos = { 0, 0, 0 }; // TODO: camera position (in Quake coordinates)
RotMatrix(&trot, &view_matrix); // Set camera rotation part of the view matrix
ApplyMatrixLV(&view_matrix, &tpos, &tpos); // Apply camera rotation to camera position
TransMatrix(&view_matrix, &tpos); // Apply transformed position to the translation part of the view matrix
// Compose view and projection matrices to obtain a combined view-projection matrix
CompMatrixLV(&proj_matrix, &view_matrix, &view_matrix);
gte_SetRotMatrix(&view_matrix);
gte_SetTransMatrix(&view_matrix);
drawModel(&view_matrix, &playerModel, &playerSkin, counter >> 2);
drawModel(&view_matrix, &shamblerModel, &shamblerSkin, counter >> 2);
}
// Main function, program entrypoint
@ -531,8 +536,6 @@ int main(int argc, const char *argv[])
counter = 0;
while(1)
{
playerModel.rotation.vz = (counter << 2) % ONE;
drawStuff(counter);
// Update display

Loading…
Cancel
Save