#include "common.h" #include "display.h" #include // Define display/draw environments for double buffering static DISPENV disp[2]; static DRAWENV draw[2]; static int db; #define PRIMBUFLEN 131072 static u_long ot[2][OTLEN]; // Ordering tables, two arrays for double buffering. These are basically the buckets for bucket sorting of polygons. // You can also see them as "layers" in the modern 3D graphics sense, but they serve a more immediate role for polygon ordering. // Layer 0 is free for overlays, as polygons at depth 0 will be clipped. static char primbuff[2][PRIMBUFLEN]; // Primitive buffer, just a raw buffer of bytes to use as a pool for primitives static char *nextpri; 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); // Start the display in progressive mode int screenHeight; display_reset(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); // Initialize GTE InitGeom(); gte_SetGeomOffset(SCREENWIDTH >> 1, screenHeight >> 1); gte_SetGeomScreen(180); // Screen depth for FOV control. Determines the distance of the camera to the near plane. } void display_reset(u_char interlaced, int *outScreenHeight) { int screenHeight, yOffset; if (GetVideoMode() == 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; } // 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].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); nextpri = primbuff[db]; gte_SetBackColor(48, 48, 48); // Ambient light color gte_SetColorMatrix(&light_cols); // Light color (up to three different lights) 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() { DrawOTag(curOT + OTLEN - 1); // This performs a DMA transfer to quickly send all the primitives off to the GPU // 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); } void *display_allocPrim(size_t size) { if (nextpri + size > primbuff[db] + PRIMBUFLEN) return NULL; void *prim = nextpri; nextpri += size; return prim; }