Quake BSP renderer for PS1
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

188 lines
5.2 KiB

#include "common.h"
#include "display.h"
#include <inline_c.h>
// Define display/draw environments for double buffering
static DISPENV disp[2];
static DRAWENV draw[2];
static int db;
static u_long ot[2][OTLEN]; // Ordering tables, two arrays for double buffering. These are basically the buckets for bucket sorting of polygons.
const MATRIX identity = {
ONE, 0, 0,
0, ONE, 0,
0, 0, ONE,
0, 0, 0,
};
// Transform to change the coordinate system from PS1 Default (Y down, Z forward) to Quake (Z up, Y forward)
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,
ONE, 0, 0
};
MATRIX light_dirs = {
ONE, 0, 0,
0, 0, 0,
0, 0, 0
};
MATRIX vp_matrix;
u_long *curOT;
// Scale X coordinates to correct the aspect ratio for the chosen resolution
VECTOR aspect_scale = { SCREENWIDTH * ONE / 320, ONE, ONE };
void display_init()
{
// This not only resets the GPU but it also installs the library's
// ISR subsystem to the kernel
ResetGraph(0);
// Initialize GTE
InitGeom();
gte_SetGeomScreen(180); // Screen depth for FOV control. Determines the distance of the camera to the near plane.
// Start the display in progressive mode
int screenHeight;
display_reset(GetVideoMode(), 0, &screenHeight);
// Set and enable clear color
setRGB0(&draw[0], 49, 77, 121);
setRGB0(&draw[1], 49, 77, 121);
draw[0].isbg = 1;
draw[0].dtd = 1;
draw[1].isbg = 1;
draw[1].dtd = 1;
// Clear double buffer counter
db = 0;
// Apply the GPU environments
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Load test font
FntLoad(960, 0);
// Open up a test font text stream
FntOpen(0, 8, SCREENWIDTH, screenHeight, 0, 512);
}
void display_reset(int mode, u_char interlaced, int *outScreenHeight)
{
if (mode != GetVideoMode())
SetVideoMode(mode);
int screenHeight, yOffset;
if (mode == MODE_NTSC)
{
screenHeight = SCREENHEIGHT_NTSC;
yOffset = (240 - SCREENHEIGHT_NTSC) >> 1; // Vertically center the image for NTSC displays
// Scale Y coordinates to correct the aspect ratio for NTSC's typical visible screen area
aspect_scale.vy = 224 * ONE / 240;
}
else // MODE_PAL
{
screenHeight = SCREENHEIGHT_PAL;
yOffset = (288 - SCREENHEIGHT_PAL) >> 1; // Vertically center the image for PAL displays
// Scale Y coordinates to correct the aspect ratio for PAL's non-square pixels
aspect_scale.vy = 256 * ONE / 240;
}
if (interlaced)
{
screenHeight <<= 1;
yOffset <<= 1;
aspect_scale.vy <<= 1;
// Define display environments, interlaced images cover the same area in VRAM
SetDefDispEnv(&disp[0], 0, 0, SCREENWIDTH, screenHeight);
SetDefDispEnv(&disp[1], 0, 0, SCREENWIDTH, screenHeight);
// Define drawing environments, interlaced images cover the same area in VRAM
SetDefDrawEnv(&draw[0], 0, 0, SCREENWIDTH, screenHeight);
SetDefDrawEnv(&draw[1], 0, 0, SCREENWIDTH, screenHeight);
disp[0].isinter = disp[1].isinter = 1;
}
else
{
// Define display environments, first on top and second on bottom
SetDefDispEnv(&disp[0], 0, 0, SCREENWIDTH, screenHeight);
SetDefDispEnv(&disp[1], 0, screenHeight, SCREENWIDTH, screenHeight);
// Define drawing environments, first on bottom and second on top
SetDefDrawEnv(&draw[0], 0, screenHeight, SCREENWIDTH, screenHeight);
SetDefDrawEnv(&draw[1], 0, 0, SCREENWIDTH, screenHeight);
disp[0].isinter = disp[1].isinter = 0;
}
disp[0].screen.y = disp[1].screen.y = yOffset;
disp[0].screen.h = disp[1].screen.h = screenHeight;
gte_SetGeomOffset(SCREENWIDTH >> 1, screenHeight >> 1);
if (outScreenHeight != NULL)
*outScreenHeight = screenHeight;
}
void display_start()
{
curOT = ot[db];
ClearOTagR(curOT, OTLEN);
mem_prim_reset(db);
gte_SetBackColor(48, 48, 48); // Ambient light color
gte_SetColorMatrix(&light_cols); // Light color (up to three different lights)
gte_SetLightMatrix(&identity);
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 = { -cam_rot.vx, -cam_rot.vy, -cam_rot.vz, 0 }; // Inverse camera rotation (in Quake coordinates)
VECTOR tpos = { -cam_pos.vx, -cam_pos.vy, -cam_pos.vz }; // Inverse camera position (in Quake coordinates)
RotMatrixQ(&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, &vp_matrix);
}
void display_finish()
{
// Flip buffer index
db = !db;
// Wait for all drawing to complete
DrawSync(0);
// Wait for vertical sync to cap the logic to 60fps (or 50 in PAL mode)
// and prevent screen tearing
VSync(0);
// Switch pages
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Enable display output, ResetGraph() disables it by default
SetDispMask(1);
DrawOTag(curOT + OTLEN - 1); // This performs a DMA transfer to quickly send all the primitives off to the GPU
}