First little test project for PS1 programming using PSn00bSDK
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.
 
 

252 lines
6.7 KiB

/*
* LibPSn00b Example Programs
*
* Hello World Example
* 2019-2020 Meido-Tek Productions / PSn00bSDK Project
*
* The obligatory hello world example normally included in nearly every
* SDK package. This example should also get you started in how to manage
* the display using psxgpu.
*
* Example by Lameguy64
*
*
* Changelog:
*
* January 1, 2020 - Initial version
*/
#include <stdio.h>
#include <sys/types.h>
#include <psxetc.h>
#include <psxgte.h>
#include <psxgpu.h>
#define OTLEN 8
// Define display/draw environments for double buffering
DISPENV disp[2];
DRAWENV draw[2];
int db;
u_long ot[2][OTLEN]; // Ordering tables, two arrays for double buffering. These are basically "layers" for drawing.
char primbuff[2][32768]; // Primitive buffer, just a raw buffer of bytes to use as a pool for primitives
char *nextpri;
extern u_long tim_player128[];
extern u_long tim_player16bpp[];
extern u_long tim_shambler[];
TIM_IMAGE playerTex;
TIM_IMAGE shamblerTex;
void loadTexture(u_long* tim, TIM_IMAGE* tparam)
{
GetTimInfo(tim, tparam);
// This freezes up if the TIM image has weird dimensions, such as the ones from Quake...
LoadImage(tparam->prect, tparam->paddr);
// Upload CLUT for palettized images
if (tparam->mode & 0x8)
{
LoadImage(tparam->crect, tparam->caddr);
}
DrawSync(0);
}
// Init function
void init(void)
{
// This not only resets the GPU but it also installs the library's
// ISR subsystem to the kernel
ResetGraph(0);
// Define display environments, first on top and second on bottom
SetDefDispEnv(&disp[0], 0, 0, 320, 240);
SetDefDispEnv(&disp[1], 0, 240, 320, 240);
// Define drawing environments, first on bottom and second on top
SetDefDrawEnv(&draw[0], 0, 240, 320, 240);
SetDefDrawEnv(&draw[1], 0, 0, 320, 240);
// Set and enable clear color
setRGB0(&draw[0], 96, 0, 96);
setRGB0(&draw[1], 96, 0, 96);
draw[0].isbg = 1;
draw[1].isbg = 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 of 100 characters
FntOpen(0, 8, 320, 224, 0, 100);
nextpri = primbuff[0];
loadTexture(tim_player128, &playerTex);
loadTexture(tim_player16bpp, &playerTex);
loadTexture(tim_shambler, &shamblerTex);
// Set texture page for the entire drawing environment. Nice in some cases perhaps, but not what we need.
//draw[0].tpage = getTPage(playerTex.mode & 0x3, 0, playerTex.prect->x, playerTex.prect->y);
//draw[1].tpage = getTPage(playerTex.mode & 0x3, 0, playerTex.prect->x, playerTex.prect->y);
}
// Display function
void display(void)
{
// Wait for all drawing to complete
// TODO: this should be interleaved with the double buffered ordering table draw commands, to minimize CPU idle time while waiting for the GPU
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(ot[db] + OTLEN - 1); // This performs a DMA transfer to quickly send all the primitives off to the GPU
// Flip buffer index
db = !db;
nextpri = primbuff[db];
}
static void lerpcol(int r0, int g0, int b0, int r1, int g1, int b1, int lerp, int* rout, int* gout, int* bout) // lerp = 0-4096
{
int invlerp = 4096 - lerp;
*rout = (r0 * invlerp + r1 * lerp) >> 12;
*gout = (g0 * invlerp + g1 * lerp) >> 12;
*bout = (b0 * invlerp + b1 * lerp) >> 12;
}
void addTile(int x, int y, int w, int h, int r, int g, int b)
{
// Initialize tile primitive
TILE *tile = (TILE*)nextpri;
setTile(tile);
setXY0(tile, x, y);
setWH(tile, w, h);
setRGB0(tile, r, g, b);
addPrim(ot[db], tile);
nextpri += sizeof(TILE);
}
void addColoredTriangle(int x0, int y0, int x1, int y1, int x2, int y2, unsigned int rgb0, unsigned int rgb1, unsigned int rgb2)
{
POLY_G3 *poly = (POLY_G3*)nextpri;
setPolyG3(poly);
setXY3(poly, x0, y0, x1, y1, x2, y2);
setRGB0(poly, (rgb0 >> 16) & 0xFF, (rgb0 >> 8) & 0xFF, rgb0 & 0xFF);
setRGB1(poly, (rgb1 >> 16) & 0xFF, (rgb1 >> 8) & 0xFF, rgb1 & 0xFF);
setRGB2(poly, (rgb2 >> 16) & 0xFF, (rgb2 >> 8) & 0xFF, rgb2 & 0xFF);
addPrim(ot[db], poly);
nextpri += sizeof(POLY_G3);
}
void addTexturedTriangle(int x0, int y0, int x1, int y1, int x2, int y2, short u0, short v0, short u1, short v1, short u2, short v2, TIM_IMAGE *img)
{
short uoffs = (img->prect->x % 64) << (2 - (img->mode & 0x3));
short voffs = (img->prect->y & 0xFF);
POLY_FT3 *poly = (POLY_FT3*)nextpri;
setPolyFT3(poly);
setXY3(poly, x0, y0, x1, y1, x2, y2);
setUV3(poly, uoffs + u0, voffs + v0, uoffs + u1, voffs + v1, uoffs + u2, voffs + v2);
setRGB0(poly, 128, 128, 128);
setClut(poly, img->crect->x, img->crect->y);
setTPage(poly, img->mode & 0x3, 0, img->prect->x, img->prect->y);
addPrim(ot[db], poly);
nextpri += sizeof(POLY_FT3);
}
void addTexturedSprite(int x, int y, int w, int h, TIM_IMAGE *img)
{
short uoffs = (img->prect->x % 64) << (2 - (img->mode & 0x3));
short voffs = (img->prect->y & 0xFF);
SPRT *sprite = (SPRT*)nextpri;
setSprt(sprite);
setXY0(sprite, x, y);
setWH(sprite, w, h);
setUV0(sprite, uoffs, voffs);
setClut(sprite, img->crect->x, img->crect->y);
setRGB0(sprite, 128, 128, 128);
addPrim(ot[db], sprite);
nextpri += sizeof(SPRT);
DR_TPAGE *tpage = (DR_TPAGE*)nextpri;
setDrawTPage(tpage, 0, 1, getTPage(img->mode & 0x3, 0, img->prect->x, img->prect->y));
addPrim(ot[db], tpage);
nextpri += sizeof(DR_TPAGE);
}
void drawStuff(int counter)
{
ClearOTagR(ot[db], OTLEN);
// Print the obligatory hello world and counter to show that the
// program isn't locking up to the last created text stream
FntPrint(-1, "HELLO WORLD\n");
FntPrint(-1, "COUNTER=%d, SIN=%d\n", counter, isin(counter));
FntPrint(-1, "Image x %d y %d w %d h %d mode 0x%x\n", playerTex.prect->x, playerTex.prect->y, playerTex.prect->w, playerTex.prect->h, playerTex.mode);
// Draw the last created text stream
FntFlush(-1);
int r, g, b;
lerpcol(255, 255, 0, 255, 0, 0, (icos(counter * 32) + 4096) >> 1, &r, &g, &b);
addTile(32, 32, 64, 64, r, g, b);
lerpcol(0, 255, 255, 0, 255, 0, (icos(counter * 24 + 512) + 4096) >> 1, &r, &g, &b);
addTile(128, 160, 48, 48, r, g, b);
addColoredTriangle(260, 140, 220, 220, 300, 220, 0xFF0000, 0x00FF00, 0x0000FF);
addTexturedTriangle(260, 40, 220, 120, 300, 120, 0, 94, 74, 124, 58, 1, &playerTex);
addTexturedSprite(20, 140, 80, 80, &playerTex);
addTexturedSprite(80, 40, 154, 114, &shamblerTex);
}
// Main function, program entrypoint
int main(int argc, const char *argv[])
{
int counter;
// Init stuff
init();
// Main loop
counter = 0;
while(1)
{
drawStuff(counter);
// Update display
display();
// Increment the counter
counter++;
}
return 0;
}