commit 57b07ae84f682ceddade00a4cddc83d16d20d182 Author: Nico de Poel Date: Tue Sep 6 00:02:48 2022 +0200 First import of some cool bits of 2D graphics diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e524d79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ba452a5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +# PSn00bSDK example CMake script +# (C) 2021 spicyjpeg - MPL licensed + +cmake_minimum_required(VERSION 3.20) + +project( + PSn00bSDK-template + LANGUAGES C CXX ASM + VERSION 1.0.0 + DESCRIPTION "PSn00bSDK template" + HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" +) + +psn00bsdk_add_executable(template STATIC main.c) + +psn00bsdk_target_incbin(template PRIVATE tim_player128 player128.tim) +psn00bsdk_target_incbin(template PRIVATE tim_player16bpp player128-16.tim) +psn00bsdk_target_incbin(template PRIVATE tim_shambler shambler128.tim) + +psn00bsdk_add_cd_image( + iso # Target name + template # Output file name (= template.bin + template.cue) + iso.xml # Path to config file + DEPENDS template +) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..d08b334 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,23 @@ +{ + "version": 2, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "displayName": "Default configuration", + "description": "Use this preset to build the project using PSn00bSDK.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_TOOLCHAIN_FILE": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake", + "PSN00BSDK_TC": "", + "PSN00BSDK_TARGET": "mipsel-none-elf" + } + } + ] +} diff --git a/iso.xml b/iso.xml new file mode 100644 index 0000000..477c636 --- /dev/null +++ b/iso.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..f89b179 --- /dev/null +++ b/main.c @@ -0,0 +1,252 @@ +/* + * 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 +#include +#include +#include +#include + +#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; +} diff --git a/player128-16.tim b/player128-16.tim new file mode 100644 index 0000000..574d39c Binary files /dev/null and b/player128-16.tim differ diff --git a/player128.tim b/player128.tim new file mode 100644 index 0000000..443265e Binary files /dev/null and b/player128.tim differ diff --git a/shambler128.tim b/shambler128.tim new file mode 100644 index 0000000..dc5a572 Binary files /dev/null and b/shambler128.tim differ diff --git a/system.cnf b/system.cnf new file mode 100644 index 0000000..e221726 --- /dev/null +++ b/system.cnf @@ -0,0 +1,4 @@ +BOOT=cdrom:\template.exe;1 +TCB=4 +EVENT=10 +STACK=801FFFF0