diff options
| author | John Wilbert M. Villamor <lameguy64@gmail.com> | 2020-04-24 19:01:28 +0800 |
|---|---|---|
| committer | John Wilbert M. Villamor <lameguy64@gmail.com> | 2020-04-24 19:01:28 +0800 |
| commit | 1aa0e17df7c325a41de8cf8a57f52ed853f08bf3 (patch) | |
| tree | 5ec7f69ca0104f2b0a41e2ee7d3cb0cf0c9c54c5 /examples/graphics | |
| parent | e82da2abe4c264d4b48a48d79cf9b8e4c4fb8ab6 (diff) | |
| download | psn00bsdk-1aa0e17df7c325a41de8cf8a57f52ed853f08bf3.tar.gz | |
Refined toolchain instructions, organized examples, added automatic retry for CdRead(), added FIOCSCAN ioctl in psxsio TTY driver, added tty and console examples.
Diffstat (limited to 'examples/graphics')
26 files changed, 2670 insertions, 0 deletions
diff --git a/examples/graphics/balls/ball16c.h b/examples/graphics/balls/ball16c.h new file mode 100644 index 0000000..c79f273 --- /dev/null +++ b/examples/graphics/balls/ball16c.h @@ -0,0 +1,16 @@ +unsigned int ball16c_size=192; +unsigned char ball16c[] = { +0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10, +0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d, +0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a, +0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01, +0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32, +0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52, +0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31, +0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4, +0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce, +0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7, +0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e, +0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4, +0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00 +}; diff --git a/examples/graphics/balls/ball16c.tim b/examples/graphics/balls/ball16c.tim Binary files differnew file mode 100644 index 0000000..e2a5d17 --- /dev/null +++ b/examples/graphics/balls/ball16c.tim diff --git a/examples/graphics/balls/main.c b/examples/graphics/balls/main.c new file mode 100644 index 0000000..89c8063 --- /dev/null +++ b/examples/graphics/balls/main.c @@ -0,0 +1,228 @@ +/* + * LibPSn00b Example Programs + * + * Balls Example + * 2019 Meido-Tek Productions / PSn00bSDK Project + * + * Draws a bunch of ball sprites that bounce around the screen, + * along with a ball snake that might be difficult to see. + * + * + * Example by Lameguy64 + * + * Changelog: + * + * November 20, 2018 - Initial version. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <psxetc.h> +#include <psxgte.h> +#include <psxgpu.h> +#include "ball16c.h" + + +#define MAX_BALLS 1024 + +#define OT_LEN 8 + +#define SCREEN_XRES 640 +#define SCREEN_YRES 480 + +#define CENTER_X SCREEN_XRES/2 +#define CENTER_Y SCREEN_YRES/2 + + +/* Display and drawing environments */ +DISPENV disp; +DRAWENV draw; + +char pribuff[2][65536]; /* Primitive packet buffers */ +unsigned int ot[2][OT_LEN]; /* Ordering tables */ +char *nextpri; /* Pointer to next packet buffer offset */ +int db = 0; /* Double buffer index */ + + +/* Ball struct and array */ +typedef struct { + short x,y; + short xdir,ydir; + unsigned char r,g,b,p; +} BALL_TYPE; + +BALL_TYPE balls[MAX_BALLS]; + + +/* TIM image parameters for loading the ball texture and drawing sprites */ +TIM_IMAGE tim; + + +void init() { + + int i; + + /* Reset GPU (also installs event handler for VSync) */ + printf("Init GPU... "); + ResetGraph( 0 ); + printf("Done.\n"); + + + printf("Set video mode... "); + + /* Set display and draw environment parameters */ + SetDefDispEnv( &disp, 0, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &draw, 0, 0, SCREEN_XRES, SCREEN_YRES ); + disp.isinter = 1; /* Enable interlace (required for hires) */ + + /* Set clear color, area clear and dither processing */ + setRGB0( &draw, 63, 0, 127 ); + draw.isbg = 1; + draw.dtd = 1; + + /* Apply the display and drawing environments */ + PutDispEnv( &disp ); + PutDrawEnv( &draw ); + + /* Enable video output */ + SetDispMask( 1 ); + + printf("Done.\n"); + + + /* Upload the ball texture */ + printf("Upload texture... "); + GetTimInfo( (unsigned int*)ball16c, &tim ); /* Get TIM parameters */ + + LoadImage( tim.prect, tim.paddr ); /* Upload texture to VRAM */ + if( tim.mode & 0x8 ) { + LoadImage( tim.crect, tim.caddr ); /* Upload CLUT if present */ + } + + printf("Done.\n"); + + + /* Calculate ball positions */ + printf("Calculating balls... "); + + for(i=0; i<MAX_BALLS; i++) { + + balls[i].x = (rand()%624); + balls[i].y = (rand()%464); + balls[i].xdir = 1-(rand()%3); + balls[i].ydir = 1-(rand()%3); + if( !balls[i].xdir ) balls[i].xdir = 1; + if( !balls[i].ydir ) balls[i].ydir = 1; + balls[i].xdir *= 2; + balls[i].ydir *= 2; + balls[i].r = (rand()%256); + balls[i].g = (rand()%256); + balls[i].b = (rand()%256); + + } + + printf("Done.\n"); + +} + +int main(int argc, const char* argv[]) { + + SPRT_16 *sprt; + DR_TPAGE *tpri; + + int i,counter=0; + + + /* Init graphics and stuff before doing anything else */ + init(); + + + /* Main loop */ + printf("Entering loop...\n"); + + while(1) { + + /* Clear ordering table and set start address of primitive */ + /* buffer for next frame */ + ClearOTagR( ot[db], OT_LEN ); + nextpri = pribuff[db]; + + /* Sort a balls snake */ + sprt = (SPRT_16*)nextpri; + srand( 64 ); + for( i=0; i<32; i++ ) { + + setSprt16( sprt ); + setXY0( sprt, + (CENTER_X-8)+(isin((counter-(i<<4))<<3)>>5), + (CENTER_Y-8)-(icos((counter-(i<<2))<<3)>>5) ); + setRGB0( sprt, rand()%256, rand()%256, rand()%256 ); + setUV0( sprt, 0, 0 ); + setClut( sprt, tim.crect->x, tim.crect->y ); + + addPrim( ot[db]+(OT_LEN-1), sprt ); + sprt++; + + } + + /* Sort the balls */ + for( i=0; i<MAX_BALLS; i++ ) { + + setSprt16( sprt ); + setXY0( sprt, balls[i].x, balls[i].y ); + setRGB0( sprt, balls[i].r, balls[i].g, balls[i].b ); + setUV0( sprt, 0, 0 ); + setClut( sprt, tim.crect->x, tim.crect->y ); + + addPrim( ot[db]+(OT_LEN-1), sprt ); + sprt++; + + balls[i].x += balls[i].xdir; + balls[i].y += balls[i].ydir; + + if( ( balls[i].x+16 ) > 640 ) { + balls[i].xdir = -2; + } else if( balls[i].x < 0 ) { + balls[i].xdir = 2; + } + + if( ( balls[i].y+16 ) > 480 ) { + balls[i].ydir = -2; + } else if( balls[i].y < 0 ) { + balls[i].ydir = 2; + } + + } + nextpri = (char*)sprt; + + + /* Sort a TPage primitive so the sprites will draw pixels from */ + /* the correct texture page in VRAM */ + tpri = (DR_TPAGE*)nextpri; + setDrawTPage( tpri, 0, 0, + getTPage(0, 0, tim.prect->x, tim.prect->y )); + addPrim( ot[db]+(OT_LEN-1), tpri ); + nextpri += sizeof(DR_TPAGE); + + /* Wait for GPU and VSync */ + DrawSync( 0 ); + VSync( 0 ); + + /* Since draw.isbg is non-zero this clears the screen */ + PutDrawEnv( &draw ); + + /* Begin drawing the new frame */ + DrawOTag( ot[db]+(OT_LEN-1) ); + + /* Alternate to the next buffer */ + db = !db; + + /* Increment counter for the snake animation */ + counter++; + + } + + return 0; + +} diff --git a/examples/graphics/balls/makefile b/examples/graphics/balls/makefile new file mode 100644 index 0000000..50ed0f1 --- /dev/null +++ b/examples/graphics/balls/makefile @@ -0,0 +1,60 @@ +include ../../sdk-common.mk + +# Project target name +TARGET = balls.elf + +# Searches for C, C++ and S (assembler) files in local directory +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +# Determine object files +OFILES = $(addprefix build/,$(CFILES:.c=.o)) \ + $(addprefix build/,$(CPPFILES:.cpp=.o)) \ + $(addprefix build/,$(AFILES:.s=.o)) + +# Project specific include and library directories +# (use -I for include dirs, -L for library dirs) +INCLUDE += +LIBDIRS += + +# Libraries to link +LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc + +# C compiler flags +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections + +# C++ compiler flags +CPPFLAGS = $(CFLAGS) -fno-exceptions + +# Assembler flags +AFLAGS = -g -msoft-float + +# Linker flags +LDFLAGS = -g -Ttext=0x80010000 -gc-sections \ + -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x + +# Toolchain programs +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.cpp + @mkdir -p $(dir $@) + $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/graphics/billboard/billboard.c b/examples/graphics/billboard/billboard.c new file mode 100644 index 0000000..bba5dda --- /dev/null +++ b/examples/graphics/billboard/billboard.c @@ -0,0 +1,260 @@ +/* + * LibPSn00b Example Programs + * + * GTE Billboarding Sprites Example + * 2019 Meido-Tek Productions / PSn00bSDK Project + * + * Displays a bunch of sprites placed on the screen using 3D coordinates + * that scale according to the distance from the screen. This is a quick + * modification of the GTE cube example. + * + * Billboard sprites are useful for 2D projectiles flying across 3D space, + * particle effects such as smoke as well as characters and objects + * represented as 2D sprites. + * + * Example by Lameguy64 + * + * Changelog: + * + * Sep 24, 2019 - Initial version. + * + */ + +#include <stdio.h> +#include <psxgpu.h> +#include <psxgte.h> +#include <inline_c.h> + +/* OT and Packet Buffer sizes */ +#define OT_LEN 256 +#define PACKET_LEN 1024 + +/* Screen resolution */ +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +/* Screen center position */ +#define CENTERX SCREEN_XRES>>1 +#define CENTERY SCREEN_YRES>>1 + + +/* Double buffer structure */ +typedef struct { + DISPENV disp; /* Display environment */ + DRAWENV draw; /* Drawing environment */ + int ot[OT_LEN]; /* Ordering table */ + char p[PACKET_LEN]; /* Packet buffer */ +} DB; + +/* Double buffer variables */ +DB db[2]; +int db_active = 0; +char *db_nextpri; + +extern int tim_image[]; +TIM_IMAGE tim; + +/* For easier handling of vertex indices */ +typedef struct { + short v0,v1,v2,v3; +} INDEX; + +/* Sprite position vertices */ +SVECTOR verts[] = { + { -50, -50, -50, 0 }, + { 50, -50, -50, 0 }, + { -50, 50, -50, 0 }, + { 50, 50, -50, 0 }, + { 50, -50, 50, 0 }, + { -50, -50, 50, 0 }, + { 50, 50, 50, 0 }, + { -50, 50, 50, 0 } +}; + + +/* Function declarations */ +void init(); +void display(); + + +/* Main function */ +int main() { + + int i,p,sz; + + SVECTOR rot = { 0 }; /* Rotation vector for Rotmatrix */ + VECTOR pos = { 0, 0, 160 }; /* Translation vector for TransMatrix */ + MATRIX mtx,lmtx; /* Rotation matrices for geometry and lighting */ + + POLY_FT4 *quad; /* Flat shaded quad primitive pointer */ + SVECTOR spos; + + /* Init graphics and GTE */ + init(); + + + /* Main loop */ + while( 1 ) { + + /* Set rotation and translation to the matrix */ + RotMatrix( &rot, &mtx ); + TransMatrix( &mtx, &pos ); + + /* Set rotation and translation matrix */ + gte_SetRotMatrix( &mtx ); + gte_SetTransMatrix( &mtx ); + + /* Make the sprites revolve around */ + rot.vy += 16; + rot.vz += 16; + + /* Draw the sprites */ + quad = (POLY_FT4*)db_nextpri; + + for( i=0; i<8; i++ ) { + + // Load the 3D coordinate of the sprite to GTE + gte_ldv0(&verts[i]); + + // Rotation, Translation and Perspective Single + gte_rtps(); + + // Store depth + gte_stsz(&p); + + // Don't sort sprite if depth is zero + // (or divide by zero will happen later) + if( p > 0 ) { + + // Store result to position vector + gte_stsxy2(&spos); + + // Calculate sprite size, the divide operation might be a + // performance killer but it's likely faster than performing + // a lookat operation between sprite and camera, which some + // billboard sprite implementations use. + sz = (16*CENTERX)/p; + + // Prepare quad primitive + setPolyFT4(quad); + + // Set quad coordinates + setXY4(quad, + spos.vx-sz, spos.vy-sz, + spos.vx+sz, spos.vy-sz, + spos.vx-sz, spos.vy+sz, + spos.vx+sz, spos.vy+sz); + + // Set color + setRGB0(quad, 128, 128, 128); + + // Set tpage + quad->tpage = getTPage(tim.mode&0x8, 0, tim.prect->x, tim.prect->y); + + // Set CLUT + setClut(quad, tim.crect->x, tim.crect->y); + + // Set texture coordinates + setUVWH(quad, 0, 0, 64, 64); + + /* Sort primitive to the ordering table */ + addPrim(db[db_active].ot+(p>>2), quad); + + /* Advance to make another primitive */ + quad++; + + } + } + + /* Update nextpri variable */ + /* (IMPORTANT if you plan to sort more primitives after this) */ + db_nextpri = (char*)quad; + + /* Swap buffers and draw the primitives */ + display(); + + } + + return 0; + +} + +void init() { + + /* Reset the GPU, also installs a VSync event handler */ + ResetGraph( 0 ); + + /* Set display and draw environment areas */ + /* (display and draw areas must be separate, otherwise hello flicker) */ + SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + + /* Enable draw area clear and dither processing */ + setRGB0( &db[0].draw, 63, 0, 127 ); + db[0].draw.isbg = 1; + db[0].draw.dtd = 1; + + + /* Define the second set of display/draw environments */ + SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES ); + + setRGB0( &db[1].draw, 63, 0, 127 ); + db[1].draw.isbg = 1; + db[1].draw.dtd = 1; + + + /* Apply the drawing environment of the first double buffer */ + PutDrawEnv( &db[0].draw ); + + + /* Clear both ordering tables to make sure they are clean at the start */ + ClearOTagR( db[0].ot, OT_LEN ); + ClearOTagR( db[1].ot, OT_LEN ); + + /* Set primitive pointer address */ + db_nextpri = db[0].p; + + /* Initialize the GTE */ + InitGeom(); + + /* Set GTE offset (recommended method of centering) */ + gte_SetGeomOffset( CENTERX, CENTERY ); + + /* Set screen depth (basically FOV control, W/2 works best) */ + gte_SetGeomScreen( CENTERX ); + + GetTimInfo(tim_image, &tim); + + LoadImage(tim.prect, tim.paddr); + DrawSync(0); + + LoadImage(tim.crect, tim.caddr); + DrawSync(0); + +} + +void display() { + + /* Wait for GPU to finish drawing and vertical retrace */ + DrawSync( 0 ); + VSync( 0 ); + + /* Swap buffers */ + db_active ^= 1; + db_nextpri = db[db_active].p; + + /* Clear the OT of the next frame */ + ClearOTagR( db[db_active].ot, OT_LEN ); + + /* Apply display/drawing environments */ + PutDrawEnv( &db[db_active].draw ); + PutDispEnv( &db[db_active].disp ); + + /* Enable display */ + SetDispMask( 1 ); + + /* Start drawing the OT of the last buffer */ + DrawOTag( db[1-db_active].ot+(OT_LEN-1) ); + +}
\ No newline at end of file diff --git a/examples/graphics/billboard/makefile b/examples/graphics/billboard/makefile new file mode 100644 index 0000000..d6add7a --- /dev/null +++ b/examples/graphics/billboard/makefile @@ -0,0 +1,39 @@ +include ../../sdk-common.mk + +TARGET = billboard.elf + +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) + +INCLUDE += +LIBDIRS += + +LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) -fno-exceptions +AFLAGS = -g -msoft-float +LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x + +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/graphics/billboard/texture64.tim b/examples/graphics/billboard/texture64.tim Binary files differnew file mode 100644 index 0000000..d3aff3a --- /dev/null +++ b/examples/graphics/billboard/texture64.tim diff --git a/examples/graphics/billboard/tim.s b/examples/graphics/billboard/tim.s new file mode 100644 index 0000000..1fa8d69 --- /dev/null +++ b/examples/graphics/billboard/tim.s @@ -0,0 +1,7 @@ +.section .data + +.global tim_image +.type tim_image, @object +tim_image: + .incbin "texture64.tim" +
\ No newline at end of file diff --git a/examples/graphics/fpscam/clip.c b/examples/graphics/fpscam/clip.c new file mode 100644 index 0000000..7f2b780 --- /dev/null +++ b/examples/graphics/fpscam/clip.c @@ -0,0 +1,108 @@ +/* Polygon clip detection code + * + * The polygon clipping logic is based on the Cohen-Sutherland algorithm, but + * only the off-screen detection logic is used to determine which polygon edges + * are off-screen. + * + * In tri_clip, the following edges are checked as follows: + * + * |\ + * | \ + * | \ + * | \ + * |-------- + * + * In quad_clip, the following edges are checked as follows: + * + * |---------| + * | \ / | + * | \ / | + * | / \ | + * | / \ | + * |---------| + * + * The inner portion of the quad is checked, otherwise the quad will be + * culled out if the camera faces right into it, where all four edges + * are off-screen at once. + * + */ + +#include "clip.h" + +#define CLIP_LEFT 1 +#define CLIP_RIGHT 2 +#define CLIP_TOP 4 +#define CLIP_BOTTOM 8 + +int test_clip(RECT *clip, short x, short y) { + + // Tests which corners of the screen a point lies outside of + + int result = 0; + + if ( x < clip->x ) { + result |= CLIP_LEFT; + } + + if ( x >= (clip->x+(clip->w-1)) ) { + result |= CLIP_RIGHT; + } + + if ( y < clip->y ) { + result |= CLIP_TOP; + } + + if ( y >= (clip->y+(clip->h-1)) ) { + result |= CLIP_BOTTOM; + } + + return result; + +} + +int tri_clip(RECT *clip, DVECTOR *v0, DVECTOR *v1, DVECTOR *v2) { + + // Returns non-zero if a triangle is outside the screen boundaries + + short c[3]; + + c[0] = test_clip(clip, v0->vx, v0->vy); + c[1] = test_clip(clip, v1->vx, v1->vy); + c[2] = test_clip(clip, v2->vx, v2->vy); + + if ( ( c[0] & c[1] ) == 0 ) + return 0; + if ( ( c[1] & c[2] ) == 0 ) + return 0; + if ( ( c[2] & c[0] ) == 0 ) + return 0; + + return 1; +} + +int quad_clip(RECT *clip, DVECTOR *v0, DVECTOR *v1, DVECTOR *v2, DVECTOR *v3) { + + // Returns non-zero if a quad is outside the screen boundaries + + short c[4]; + + c[0] = test_clip(clip, v0->vx, v0->vy); + c[1] = test_clip(clip, v1->vx, v1->vy); + c[2] = test_clip(clip, v2->vx, v2->vy); + c[3] = test_clip(clip, v3->vx, v3->vy); + + if ( ( c[0] & c[1] ) == 0 ) + return 0; + if ( ( c[1] & c[2] ) == 0 ) + return 0; + if ( ( c[2] & c[3] ) == 0 ) + return 0; + if ( ( c[3] & c[0] ) == 0 ) + return 0; + if ( ( c[0] & c[2] ) == 0 ) + return 0; + if ( ( c[1] & c[3] ) == 0 ) + return 0; + + return 1; +}
\ No newline at end of file diff --git a/examples/graphics/fpscam/clip.h b/examples/graphics/fpscam/clip.h new file mode 100644 index 0000000..3b428bb --- /dev/null +++ b/examples/graphics/fpscam/clip.h @@ -0,0 +1,27 @@ +#ifndef _CLIP_H +#define _CLIP_H + +#include <psxgte.h> +#include <psxgpu.h> + +/* tri_clip + * + * Returns non-zero if a triangle (v0, v1, v2) is outside 'clip'. + * + * clip - Clipping area + * v0,v1,v2 - Triangle coordinates + * + */ +int tri_clip(RECT *clip, DVECTOR *v0, DVECTOR *v1, DVECTOR *v2); + +/* quad_clip + * + * Returns non-zero if a quad (v0, v1, v2, v3) is outside 'clip'. + * + * clip - Clipping area + * v0,v1,v2,v3 - Quad coordinates + * + */ +int quad_clip(RECT *clip, DVECTOR *v0, DVECTOR *v1, DVECTOR *v2, DVECTOR *v3); + +#endif // _CLIP_H
\ No newline at end of file diff --git a/examples/graphics/fpscam/lookat.c b/examples/graphics/fpscam/lookat.c new file mode 100644 index 0000000..d7c9ce4 --- /dev/null +++ b/examples/graphics/fpscam/lookat.c @@ -0,0 +1,40 @@ +// LookAt matrix code (may be implemented into libpsxgte soon) + +#include "lookat.h" + +void crossProduct(SVECTOR *v0, SVECTOR *v1, VECTOR *out) { + + out->vx = ((v0->vy*v1->vz)-(v0->vz*v1->vy))>>12; + out->vy = ((v0->vz*v1->vx)-(v0->vx*v1->vz))>>12; + out->vz = ((v0->vx*v1->vy)-(v0->vy*v1->vx))>>12; + +} + +void LookAt(VECTOR *eye, VECTOR *at, SVECTOR *up, MATRIX *mtx) { + + VECTOR taxis; + SVECTOR zaxis; + SVECTOR xaxis; + SVECTOR yaxis; + VECTOR pos; + VECTOR vec; + + setVector(&taxis, at->vx-eye->vx, at->vy-eye->vy, at->vz-eye->vz); + VectorNormalS(&taxis, &zaxis); + crossProduct(&zaxis, up, &taxis); + VectorNormalS(&taxis, &xaxis); + crossProduct(&zaxis, &xaxis, &taxis); + VectorNormalS(&taxis, &yaxis); + + mtx->m[0][0] = xaxis.vx; mtx->m[1][0] = yaxis.vx; mtx->m[2][0] = zaxis.vx; + mtx->m[0][1] = xaxis.vy; mtx->m[1][1] = yaxis.vy; mtx->m[2][1] = zaxis.vy; + mtx->m[0][2] = xaxis.vz; mtx->m[1][2] = yaxis.vz; mtx->m[2][2] = zaxis.vz; + + pos.vx = -eye->vx;; + pos.vy = -eye->vy;; + pos.vz = -eye->vz;; + + ApplyMatrixLV(mtx, &pos, &vec); + TransMatrix(mtx, &vec); + +}
\ No newline at end of file diff --git a/examples/graphics/fpscam/lookat.h b/examples/graphics/fpscam/lookat.h new file mode 100644 index 0000000..c57e50a --- /dev/null +++ b/examples/graphics/fpscam/lookat.h @@ -0,0 +1,19 @@ +#ifndef _LOOKAT_H +#define _LOOKAT_H + +#include <psxgte.h> +#include <psxgpu.h> + +/* LookAt + * + * Generates a matrix that looks from 'eye' to 'at'. + * + * eye - Position of viewpoint + * at - Position to 'look at' from viewpoint + * up - Vector that defines the 'up' direction + * mtx - Matrix output + * + */ +void LookAt(VECTOR *eye, VECTOR *at, SVECTOR *up, MATRIX *mtx); + +#endif // _LOOKAT_H
\ No newline at end of file diff --git a/examples/graphics/fpscam/main.c b/examples/graphics/fpscam/main.c new file mode 100644 index 0000000..9dedf06 --- /dev/null +++ b/examples/graphics/fpscam/main.c @@ -0,0 +1,678 @@ +/* + * LibPSn00b Example Programs + * + * First-Person and Look-At Camera Example + * 2019 Meido-Tek Productions / PSn00bSDK Project + * + * Demonstrates both a first person perspective camera implementation with + * full six degrees of movement using fixed point integer math and a look-at + * tracking perspective. This example also shows how to use BIOS controller + * functions and how to parse analog controller input. + * + * Controls: + * Up - Look up + * Down - Look down + * Left - Look left + * Right - Look right + * Triangle - Move forward + * Cross - Move backward + * Square - Strafe left + * Circle - Strafe right + * R1 - Slide up + * R2 - Slide down + * L1 - Look at cube + * Select - Exit program (only works with CD loaders) + * + * + * Example by Lameguy64 + * + * Changelog: + * + * July 18, 2019 - Initial version. + * + * Sep 24, 2019 - Added camera position display and _boot() exit. + * + */ + +#include <stdio.h> +#include <psxgpu.h> +#include <psxgte.h> +#include <psxpad.h> +#include <psxapi.h> +#include <psxetc.h> +#include <inline_c.h> + +#include "clip.h" +#include "lookat.h" + +// OT and Packet Buffer sizes +#define OT_LEN 1024 +#define PACKET_LEN 8192 + +// Screen resolution +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +// Screen center position +#define CENTERX SCREEN_XRES>>1 +#define CENTERY SCREEN_YRES>>1 + + +// Double buffer structure +typedef struct { + DISPENV disp; // Display environment + DRAWENV draw; // Drawing environment + int ot[OT_LEN]; // Ordering table + char p[PACKET_LEN]; // Packet buffer +} DB; + +// Double buffer variables +DB db[2]; +int db_active = 0; +char *db_nextpri; +RECT screen_clip; + +// Pad data buffer +char pad_buff[2][34]; + + +// For easier handling of vertex indexes +typedef struct { + short v0,v1,v2,v3; +} INDEX; + +// Cube vertices +SVECTOR cube_verts[] = { + { -100, -100, -100, 0 }, + { 100, -100, -100, 0 }, + { -100, 100, -100, 0 }, + { 100, 100, -100, 0 }, + { 100, -100, 100, 0 }, + { -100, -100, 100, 0 }, + { 100, 100, 100, 0 }, + { -100, 100, 100, 0 } +}; + +// Cube face normals +SVECTOR cube_norms[] = { + { 0, 0, -ONE, 0 }, + { 0, 0, ONE, 0 }, + { 0, -ONE, 0, 0 }, + { 0, ONE, 0, 0 }, + { -ONE, 0, 0, 0 }, + { ONE, 0, 0, 0 } +}; + +// Cube vertex indices +INDEX cube_indices[] = { + { 0, 1, 2, 3 }, + { 4, 5, 6, 7 }, + { 5, 4, 0, 1 }, + { 6, 7, 3, 2 }, + { 0, 2, 5, 7 }, + { 3, 1, 6, 4 } +}; + +// Number of faces of cube +#define CUBE_FACES 6 + + +// Light color matrix +// Each column represents the color matrix of each light source and is +// used as material color when using gte_ncs() or multiplied by a +// source color when using gte_nccs(). 4096 is 1.0 in this matrix +// A column of zeroes effectively disables the light source. +MATRIX color_mtx = { + ONE, 0, 0, // Red + 0, 0, 0, // Green + ONE, 0, 0 // Blue +}; + +// Light matrix +// Each row represents a vector direction of each light source. +// An entire row of zeroes effectively disables the light source. +MATRIX light_mtx = { + /* X, Y, Z */ + -2048 , -2048 , -2048, + 0 , 0 , 0, + 0 , 0 , 0 +}; + + +// Function declarations +void init(); +void display(); +void sort_cube(MATRIX *mtx, VECTOR *pos, SVECTOR *rot); + + +// Main function +int main() { + + int i,p,xy_temp; + int px,py; + + SVECTOR rot; // Rotation vector for cube + VECTOR pos; // Position vector for cube + + SVECTOR verts[17][17]; // Vertex array for floor + + VECTOR cam_pos; // Camera position (in fixed point integers) + VECTOR cam_rot; // Camera view angle (in fixed point integers) + int cam_mode; // Camera mode (between first-person and look-at) + + VECTOR tpos; // Translation value for matrix calculations + SVECTOR trot; // Rotation value for matrix calculations + MATRIX mtx,lmtx; // Rotation matrices for geometry and lighting + + PADTYPE *pad; // Pad structure pointer for parsing controller + + POLY_F4 *pol4; // Flat shaded quad primitive pointer + + + // Init graphics and GTE + init(); + + + // Set coordinates to the vertex array for the floor + for( py=0; py<17; py++ ) { + for( px=0; px<17; px++ ) { + + setVector( &verts[py][px], + (100*(px-8))-50, + 0, + (100*(py-8))-50 ); + + } + } + + + // Camera default coordinates + setVector( &cam_pos, 0, ONE*-200, 0 ); + setVector( &cam_rot, 0, 0, 0 ); + + + // Main loop + while( 1 ) { + + // Set pad buffer data to pad pointer + pad = (PADTYPE*)&pad_buff[0][0]; + + // Parse controller input + cam_mode = 0; + + // Divide out fractions of camera rotation + trot.vx = cam_rot.vx >> 12; + trot.vy = cam_rot.vy >> 12; + trot.vz = cam_rot.vz >> 12; + + if( pad->stat == 0 ) { + + // For digital pad, dual-analog and dual-shock + if( ( pad->type == 0x4 ) || ( pad->type == 0x5 ) || ( pad->type == 0x7 ) ) { + + // The button status bits are inverted, + // so 0 means pressed in this case + + // Look controls + if( !(pad->btn&PAD_UP) ) { + + // Look up + cam_rot.vx -= ONE*8; + + } else if( !(pad->btn&PAD_DOWN) ) { + + // Look down + cam_rot.vx += ONE*8; + + } + + if( !(pad->btn&PAD_LEFT) ) { + + // Look left + cam_rot.vy += ONE*8; + + } else if( !(pad->btn&PAD_RIGHT) ) { + + // Look right + cam_rot.vy -= ONE*8; + + } + + // Movement controls + if( !(pad->btn&PAD_TRIANGLE) ) { + + // Move forward + cam_pos.vx -= (( isin( trot.vy )*icos( trot.vx ) )>>12)<<2; + cam_pos.vy += isin( trot.vx )<<2; + cam_pos.vz += (( icos( trot.vy )*icos( trot.vx ) )>>12)<<2; + + } else if( !(pad->btn&PAD_CROSS) ) { + + // Move backward + cam_pos.vx += (( isin( trot.vy )*icos( trot.vx ) )>>12)<<2; + cam_pos.vy -= isin( trot.vx )<<2; + cam_pos.vz -= (( icos( trot.vy )*icos( trot.vx ) )>>12)<<2; + + } + + if( !(pad->btn&PAD_SQUARE ) ) { + + // Slide left + cam_pos.vx -= icos( trot.vy )<<2; + cam_pos.vz -= isin( trot.vy )<<2; + + } else if( !(pad->btn&PAD_CIRCLE ) ) { + + // Slide right + cam_pos.vx += icos( trot.vy )<<2; + cam_pos.vz += isin( trot.vy )<<2; + + } + + if( !(pad->btn&PAD_R1) ) { + + // Slide up + cam_pos.vx -= (( isin( trot.vy )*isin( trot.vx ) )>>12)<<2; + cam_pos.vy -= icos( trot.vx )<<2; + cam_pos.vz += (( icos( trot.vy )*isin( trot.vx ) )>>12)<<2; + + } + + if( !(pad->btn&PAD_R2) ) { + + // Slide down + cam_pos.vx += (( isin( trot.vy )*isin( trot.vx ) )>>12)<<2; + cam_pos.vy += icos( trot.vx )<<2; + cam_pos.vz -= (( icos( trot.vy )*isin( trot.vx ) )>>12)<<2; + + } + + // Look at cube + if( !(pad->btn&PAD_L1) ) { + + cam_mode = 1; + + } + + if( !(pad->btn&PAD_SELECT) ) { + _boot(); + } + + } + + // For dual-analog and dual-shock (analog input) + if( ( pad->type == 0x5 ) || ( pad->type == 0x7 ) ) { + + // Moving forwards and backwards + if( ( (pad->ls_y-128) < -16 ) || ( (pad->ls_y-128) > 16 ) ) { + + cam_pos.vx += ((( isin( trot.vy )*icos( trot.vx ) )>>12)*(pad->ls_y-128))>>5; + cam_pos.vy -= (isin( trot.vx )*(pad->ls_y-128))>>5; + cam_pos.vz -= ((( icos( trot.vy )*icos( trot.vx ) )>>12)*(pad->ls_y-128))>>5; + + } + + // Strafing left and right + if( ( (pad->ls_x-128) < -16 ) || ( (pad->ls_x-128) > 16 ) ) { + cam_pos.vx += (icos( trot.vy )*(pad->ls_x-128))>>5; + cam_pos.vz += (isin( trot.vy )*(pad->ls_x-128))>>5; + } + + // Look up and down + if( ( (pad->rs_y-128) < -16 ) || ( (pad->rs_y-128) > 16 ) ) { + cam_rot.vx += (pad->rs_y-128)<<9; + } + + // Look left and right + if( ( (pad->rs_x-128) < -16 ) || ( (pad->rs_x-128) > 16 ) ) { + cam_rot.vy -= (pad->rs_x-128)<<9; + } + + } + + } + + // Print out some info + FntPrint(-1, "BUTTONS=%04x\n", pad->btn); + FntPrint(-1, "X=%d Y=%d Z=%d\n", + cam_pos.vx>>12, + cam_pos.vy>>12, + cam_pos.vz>>12); + FntPrint(-1, "RX=%d RY=%d\n", + cam_rot.vx>>12, + cam_rot.vy>>12); + + // First-person camera mode + if( cam_mode == 0 ) { + + // Set rotation to the matrix + RotMatrix( &trot, &mtx ); + + // Divide out the fractions of camera coordinates and invert + // the sign, so camera coordinates will line up to world + // (or geometry) coordinates + tpos.vx = -cam_pos.vx >> 12; + tpos.vy = -cam_pos.vy >> 12; + tpos.vz = -cam_pos.vz >> 12; + + // Apply rotation of matrix to translation value to achieve a + // first person perspective + ApplyMatrixLV( &mtx, &tpos, &tpos ); + + // Set translation matrix + TransMatrix( &mtx, &tpos ); + + // Tracking mode + } else { + + // Vector that defines the 'up' direction of the camera + SVECTOR up = { 0, -ONE, 0 }; + + // Divide out fractions of camera coordinates + tpos.vx = cam_pos.vx >> 12; + tpos.vy = cam_pos.vy >> 12; + tpos.vz = cam_pos.vz >> 12; + + // Look at the cube + LookAt(&tpos, &pos, &up, &mtx); + + } + + // Set rotation and translation matrix + gte_SetRotMatrix( &mtx ); + gte_SetTransMatrix( &mtx ); + + // Draw the floor + pol4 = (POLY_F4*)db_nextpri; + + for( py=0; py<16; py++ ) { + for( px=0; px<16; px++ ) { + + // Load first three vertices to GTE + gte_ldv3( + &verts[py][px], + &verts[py][px+1], + &verts[py+1][px] ); + + gte_rtpt(); + + gte_avsz3(); + gte_stotz( &p ); + + if( ( (p>>2) >= OT_LEN ) || ( (p>>2) <= 0 ) ) + continue; + + setPolyF4( pol4 ); + + // Set the projected vertices to the primitive + gte_stsxy0( &pol4->x0 ); + gte_stsxy1( &pol4->x1 ); + gte_stsxy2( &pol4->x2 ); + + // Compute the last vertex and set the result + gte_ldv0( &verts[py+1][px+1] ); + gte_rtps(); + gte_stsxy( &pol4->x3 ); + + // Test if quad is off-screen, discard if so + // Clipping is important as it not only prevents primitive + // overflows (tends to happen on textured polys) but also + // saves packet buffer space and speeds up rendering. + if( quad_clip( &screen_clip, + (DVECTOR*)&pol4->x0, (DVECTOR*)&pol4->x1, + (DVECTOR*)&pol4->x2, (DVECTOR*)&pol4->x3 ) ) + continue; + + gte_avsz4(); + gte_stotz( &p ); + + if((px+py)&0x1) { + setRGB0( pol4, 128, 128, 128 ); + } else { + setRGB0( pol4, 255, 255, 255 ); + } + + addPrim( db[db_active].ot+(p>>2), pol4 ); + pol4++; + + } + } + + // Update nextpri variable (very important) + db_nextpri = (char*)pol4; + + + // Position the cube going around the floor bouncily + setVector( &pos, + isin( rot.vy )>>4, + -300+(isin( rot.vy<<2 )>>5), + icos( rot.vy )>>3 ); + + // Sort cube + sort_cube( &mtx, &pos, &rot ); + + // Make the cube SPEEN + rot.vx += 8; + rot.vy += 8; + + + // Flush text to drawing area + FntFlush(-1); + + // Swap buffers and draw the primitives + display(); + + } + + return 0; + +} + +void sort_cube(MATRIX *mtx, VECTOR *pos, SVECTOR *rot) { + + int i,p; + POLY_F4 *pol4; + + // Object and light matrix for object + MATRIX omtx,lmtx; + + // Set object rotation and position + RotMatrix( rot, &omtx ); + TransMatrix( &omtx, pos ); + + // Multiply light matrix to object matrix + MulMatrix0( &light_mtx, &omtx, &lmtx ); + + // Set result to GTE light matrix + gte_SetLightMatrix( &lmtx ); + + // Composite coordinate matrix transform, so object will be rotated and + // positioned relative to camera matrix (mtx), so it'll appear as + // world-space relative. + CompMatrixLV( mtx, &omtx, &omtx ); + + // Save matrix + PushMatrix(); + + // Set matrices + gte_SetRotMatrix( &omtx ); + gte_SetTransMatrix( &omtx ); + + // Sort the cube + pol4 = (POLY_F4*)db_nextpri; + + for( i=0; i<CUBE_FACES; i++ ) { + + // Load the first 3 vertices of a quad to the GTE + gte_ldv3( + &cube_verts[cube_indices[i].v0], + &cube_verts[cube_indices[i].v1], + &cube_verts[cube_indices[i].v2] ); + + // Rotation, Translation and Perspective Triple + gte_rtpt(); + + // Compute normal clip for backface culling + gte_nclip(); + + // Get result + gte_stopz( &p ); + + // Skip this face if backfaced + if( p < 0 ) + continue; + + // Calculate average Z for depth sorting + gte_avsz3(); + gte_stotz( &p ); + + // Skip if clipping off + // (the shift right operator is to scale the depth precision) + if( ((p>>2) <= 0) || ((p>>2) >= OT_LEN) ) + continue; + + // Initialize a quad primitive + setPolyF4( pol4 ); + + // Set the projected vertices to the primitive + gte_stsxy0( &pol4->x0 ); + gte_stsxy1( &pol4->x1 ); + gte_stsxy2( &pol4->x2 ); + + // Compute the last vertex and set the result + gte_ldv0( &cube_verts[cube_indices[i].v3] ); + gte_rtps(); + gte_stsxy( &pol4->x3 ); + + // Test if quad is off-screen, discard if so + if( quad_clip( &screen_clip, + (DVECTOR*)&pol4->x0, (DVECTOR*)&pol4->x1, + (DVECTOR*)&pol4->x2, (DVECTOR*)&pol4->x3 ) ) + continue; + + // Load primitive color even though gte_ncs() doesn't use it. + // This is so the GTE will output a color result with the + // correct primitive code. + gte_ldrgb( &pol4->r0 ); + + // Load the face normal + gte_ldv0( &cube_norms[i] ); + + // Normal Color Single + gte_ncs(); + + // Store result to the primitive + gte_strgb( &pol4->r0 ); + + gte_avsz4(); + gte_stotz( &p ); + + // Sort primitive to the ordering table + addPrim( db[db_active].ot+(p>>2), pol4 ); + + // Advance to make another primitive + pol4++; + + } + + // Update nextpri + db_nextpri = (char*)pol4; + + // Restore matrix + PopMatrix(); + +} + +void init() { + + // Reset the GPU, also installs a VSync event handler + ResetGraph( 0 ); + + // Set display and draw environment areas + // (display and draw areas must be separate, otherwise hello flicker) + SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + + // Enable draw area clear and dither processing + setRGB0( &db[0].draw, 63, 0, 127 ); + db[0].draw.isbg = 1; + db[0].draw.dtd = 1; + + + // Define the second set of display/draw environments + SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES ); + + setRGB0( &db[1].draw, 63, 0, 127 ); + db[1].draw.isbg = 1; + db[1].draw.dtd = 1; + + // Apply the drawing environment of the first double buffer + PutDrawEnv( &db[0].draw ); + + // Clear both ordering tables to make sure they are clean at the start + ClearOTagR( db[0].ot, OT_LEN ); + ClearOTagR( db[1].ot, OT_LEN ); + + // Set primitive pointer address + db_nextpri = db[0].p; + + // Set clip region + setRECT( &screen_clip, 0, 0, SCREEN_XRES, SCREEN_YRES ); + + + // Initialize the GTE + InitGeom(); + + // Set GTE offset (recommended method of centering) + gte_SetGeomOffset( CENTERX, CENTERY ); + + // Set screen depth (basically FOV control, W/2 works best) + gte_SetGeomScreen( CENTERX ); + + // Set light ambient color and light color matrix + gte_SetBackColor( 63, 63, 63 ); + gte_SetColorMatrix( &color_mtx ); + + + // Init BIOS pad driver and set pad buffers (buffers are updated + // automatically on every V-Blank) + InitPAD(&pad_buff[0][0], 34, &pad_buff[1][0], 34); + + // Start pad + StartPAD(); + + // Don't make pad driver acknowledge V-Blank IRQ (recommended) + ChangeClearPAD(0); + + // Load font and open a text stream + FntLoad(960, 0); + FntOpen(0, 8, 320, 216, 0, 100); + +} + +void display() { + + // Wait for GPU to finish drawing and vertical retrace + DrawSync( 0 ); + VSync( 0 ); + + // Swap buffers + db_active ^= 1; + db_nextpri = db[db_active].p; + + // Clear the OT of the next frame + ClearOTagR( db[db_active].ot, OT_LEN ); + + // Apply display/drawing environments + PutDrawEnv( &db[db_active].draw ); + PutDispEnv( &db[db_active].disp ); + + // Enable display + SetDispMask( 1 ); + + // Start drawing the OT of the last buffer + DrawOTag( db[1-db_active].ot+(OT_LEN-1) ); + +} + diff --git a/examples/graphics/fpscam/makefile b/examples/graphics/fpscam/makefile new file mode 100644 index 0000000..339bb91 --- /dev/null +++ b/examples/graphics/fpscam/makefile @@ -0,0 +1,39 @@ +include ../../sdk-common.mk + +TARGET = fpscam.elf + +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) + +INCLUDE += +LIBDIRS += + +LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) -fno-exceptions +AFLAGS = -g -msoft-float +LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x + +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/graphics/gte/main.c b/examples/graphics/gte/main.c new file mode 100644 index 0000000..432ef95 --- /dev/null +++ b/examples/graphics/gte/main.c @@ -0,0 +1,313 @@ +/* + * LibPSn00b Example Programs + * + * GTE Graphics Example + * 2019 Meido-Tek Productions / PSn00bSDK Project + * + * Renders a spinning 3D cube with light source calculation + * using GTE macros. + * + * + * Example by Lameguy64 + * + * Changelog: + * + * Jan 26, 2019 - Initial version. + * + */ + +#include <stdio.h> +#include <psxgpu.h> +#include <psxgte.h> +#include <inline_c.h> + +/* OT and Packet Buffer sizes */ +#define OT_LEN 256 +#define PACKET_LEN 1024 + +/* Screen resolution */ +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +/* Screen center position */ +#define CENTERX SCREEN_XRES>>1 +#define CENTERY SCREEN_YRES>>1 + + +/* Double buffer structure */ +typedef struct { + DISPENV disp; /* Display environment */ + DRAWENV draw; /* Drawing environment */ + int ot[OT_LEN]; /* Ordering table */ + char p[PACKET_LEN]; /* Packet buffer */ +} DB; + +/* Double buffer variables */ +DB db[2]; +int db_active = 0; +char *db_nextpri; + + +/* For easier handling of vertex indices */ +typedef struct { + short v0,v1,v2,v3; +} INDEX; + +/* Cube vertices */ +SVECTOR cube_verts[] = { + { -100, -100, -100, 0 }, + { 100, -100, -100, 0 }, + { -100, 100, -100, 0 }, + { 100, 100, -100, 0 }, + { 100, -100, 100, 0 }, + { -100, -100, 100, 0 }, + { 100, 100, 100, 0 }, + { -100, 100, 100, 0 } +}; + +/* Cube face normals */ +SVECTOR cube_norms[] = { + { 0, 0, -ONE, 0 }, + { 0, 0, ONE, 0 }, + { 0, -ONE, 0, 0 }, + { 0, ONE, 0, 0 }, + { -ONE, 0, 0, 0 }, + { ONE, 0, 0, 0 } +}; + +/* Cube vertex indices */ +INDEX cube_indices[] = { + { 0, 1, 2, 3 }, + { 4, 5, 6, 7 }, + { 5, 4, 0, 1 }, + { 6, 7, 3, 2 }, + { 0, 2, 5, 7 }, + { 3, 1, 6, 4 } +}; + +/* Number of faces of cube */ +#define CUBE_FACES 6 + + +/* Light color matrix */ +/* Each column represents the color matrix of each light source and is */ +/* used as material color when using gte_ncs() or multiplied by a */ +/* source color when using gte_nccs(). 4096 is 1.0 in this matrix */ +/* A column of zeroes disables the light source. */ +MATRIX color_mtx = { + ONE, 0, 0, /* Red */ + ONE, 0, 0, /* Green */ + ONE, 0, 0 /* Blue */ +}; + +/* Light matrix */ +/* Each row represents a vector direction of each light source. */ +/* An entire row of zeroes disables the light source. */ +MATRIX light_mtx = { + /* X, Y, Z */ + -2048 , -2048 , -2048, + 0 , 0 , 0, + 0 , 0 , 0 +}; + + +/* Function declarations */ +void init(); +void display(); + + +/* Main function */ +int main() { + + int i,p,xy_temp; + + SVECTOR rot = { 0 }; /* Rotation vector for Rotmatrix */ + VECTOR pos = { 0, 0, 400 }; /* Translation vector for TransMatrix */ + MATRIX mtx,lmtx; /* Rotation matrices for geometry and lighting */ + + POLY_F4 *pol4; /* Flat shaded quad primitive pointer */ + + + /* Init graphics and GTE */ + init(); + + + /* Main loop */ + while( 1 ) { + + /* Set rotation and translation to the matrix */ + RotMatrix( &rot, &mtx ); + TransMatrix( &mtx, &pos ); + + /* Multiply light matrix by rotation matrix so light source */ + /* won't appear relative to the model's rotation */ + MulMatrix0( &light_mtx, &mtx, &lmtx ); + + /* Set rotation and translation matrix */ + gte_SetRotMatrix( &mtx ); + gte_SetTransMatrix( &mtx ); + + /* Set light matrix */ + gte_SetLightMatrix( &lmtx ); + + /* Make the cube SPEEN */ + rot.vx += 16; + rot.vz += 16; + + + /* Draw the cube */ + pol4 = (POLY_F4*)db_nextpri; + + for( i=0; i<CUBE_FACES; i++ ) { + + /* Load the first 3 vertices of a quad to the GTE */ + gte_ldv3( + &cube_verts[cube_indices[i].v0], + &cube_verts[cube_indices[i].v1], + &cube_verts[cube_indices[i].v2] ); + + /* Rotation, Translation and Perspective Triple */ + gte_rtpt(); + + /* Compute normal clip for backface culling */ + gte_nclip(); + + /* Get result*/ + gte_stopz( &p ); + + /* Skip this face if backfaced */ + if( p < 0 ) + continue; + + /* Calculate average Z for depth sorting */ + gte_avsz4(); + gte_stotz( &p ); + + /* Skip if clipping off */ + /* (the shift right operator is to scale the depth precision) */ + if( (p>>2) > OT_LEN ) + continue; + + /* Initialize a quad primitive */ + setPolyF4( pol4 ); + + /* Set the projected vertices to the primitive */ + gte_stsxy0( &pol4->x0 ); + gte_stsxy1( &pol4->x1 ); + gte_stsxy2( &pol4->x2 ); + + /* Compute the last vertex and set the result */ + gte_ldv0( &cube_verts[cube_indices[i].v3] ); + gte_rtps(); + gte_stsxy( &pol4->x3 ); + + /* Load primitive color even though gte_ncs() doesn't use it. */ + /* This is so the GTE will output a color result with the */ + /* correct primitive code. */ + gte_ldrgb( &pol4->r0 ); + + /* Load the face normal */ + gte_ldv0( &cube_norms[i] ); + + /* Normal Color Single */ + gte_ncs(); + + /* Store result to the primitive */ + gte_strgb( &pol4->r0 ); + + /* Sort primitive to the ordering table */ + addPrim( db[db_active].ot+(p>>2), pol4 ); + + /* Advance to make another primitive */ + pol4++; + + } + + /* Update nextpri variable */ + /* (IMPORTANT if you plan to sort more primitives after this) */ + db_nextpri = (char*)pol4; + + /* Swap buffers and draw the primitives */ + display(); + + } + + return 0; + +} + +void init() { + + /* Reset the GPU, also installs a VSync event handler */ + ResetGraph( 0 ); + + /* Set display and draw environment areas */ + /* (display and draw areas must be separate, otherwise hello flicker) */ + SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + + /* Enable draw area clear and dither processing */ + setRGB0( &db[0].draw, 63, 0, 127 ); + db[0].draw.isbg = 1; + db[0].draw.dtd = 1; + + + /* Define the second set of display/draw environments */ + SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES ); + + setRGB0( &db[1].draw, 63, 0, 127 ); + db[1].draw.isbg = 1; + db[1].draw.dtd = 1; + + + /* Apply the drawing environment of the first double buffer */ + PutDrawEnv( &db[0].draw ); + + + /* Clear both ordering tables to make sure they are clean at the start */ + ClearOTagR( db[0].ot, OT_LEN ); + ClearOTagR( db[1].ot, OT_LEN ); + + /* Set primitive pointer address */ + db_nextpri = db[0].p; + + /* Initialize the GTE */ + InitGeom(); + + /* Set GTE offset (recommended method of centering) */ + gte_SetGeomOffset( CENTERX, CENTERY ); + + /* Set screen depth (basically FOV control, W/2 works best) */ + gte_SetGeomScreen( CENTERX ); + + /* Set light ambient color and light color matrix */ + gte_SetBackColor( 63, 63, 63 ); + gte_SetColorMatrix( &color_mtx ); + +} + +void display() { + + /* Wait for GPU to finish drawing and vertical retrace */ + DrawSync( 0 ); + VSync( 0 ); + + /* Swap buffers */ + db_active ^= 1; + db_nextpri = db[db_active].p; + + /* Clear the OT of the next frame */ + ClearOTagR( db[db_active].ot, OT_LEN ); + + /* Apply display/drawing environments */ + PutDrawEnv( &db[db_active].draw ); + PutDispEnv( &db[db_active].disp ); + + /* Enable display */ + SetDispMask( 1 ); + + /* Start drawing the OT of the last buffer */ + DrawOTag( db[1-db_active].ot+(OT_LEN-1) ); + +}
\ No newline at end of file diff --git a/examples/graphics/gte/makefile b/examples/graphics/gte/makefile new file mode 100644 index 0000000..8b3f81f --- /dev/null +++ b/examples/graphics/gte/makefile @@ -0,0 +1,39 @@ +include ../../sdk-common.mk + +TARGET = gte.elf + +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) + +INCLUDE += +LIBDIRS += + +LIBS = -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) -fno-exceptions +AFLAGS = -g -msoft-float +LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x + +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/graphics/render2tex/blendpattern-16c.png b/examples/graphics/render2tex/blendpattern-16c.png Binary files differnew file mode 100644 index 0000000..74ac945 --- /dev/null +++ b/examples/graphics/render2tex/blendpattern-16c.png diff --git a/examples/graphics/render2tex/blendpattern-16c.tim b/examples/graphics/render2tex/blendpattern-16c.tim Binary files differnew file mode 100644 index 0000000..2fff580 --- /dev/null +++ b/examples/graphics/render2tex/blendpattern-16c.tim diff --git a/examples/graphics/render2tex/blendpattern.png b/examples/graphics/render2tex/blendpattern.png Binary files differnew file mode 100644 index 0000000..49af62c --- /dev/null +++ b/examples/graphics/render2tex/blendpattern.png diff --git a/examples/graphics/render2tex/main.c b/examples/graphics/render2tex/main.c new file mode 100644 index 0000000..6ae450a --- /dev/null +++ b/examples/graphics/render2tex/main.c @@ -0,0 +1,649 @@ +/* + * LibPSn00b Example Programs + * + * Off-screen Render to Texture Example + * 2019 Meido-Tek Productions / PSn00bSDK Project + * + * Demonstrates quick render to texture for multi-texture style effects, + * view screens and more. This example also shows how to use multiple + * ordering tables and chaining them together so it can all be rendered + * with a single DrawOTag() call. + * + * Example by Lameguy64 + * + * Changelog: + * + * Oct 26, 2019 - Initial version. + * + */ + +#include <stdio.h> +#include <psxgpu.h> +#include <psxgte.h> +#include <inline_c.h> + + +/* OT and Packet Buffer sizes */ +#define OT_LEN 256 +#define PACKET_LEN 1024 + + +/* Screen resolution */ +/* (note: display/draw code is hardcoded for double buffer) */ +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + + +/* Screen center position */ +#define CENTERX SCREEN_XRES>>1 +#define CENTERY SCREEN_YRES>>1 + + +/* Double buffer structure */ +typedef struct DB +{ + DISPENV disp; /* Display environment */ + DRAWENV draw; /* Drawing environment */ + int ot[OT_LEN]; /* Main ordering table */ + int sub_ot[2][4]; /* Second ordering table for r2t stuff */ + char p[PACKET_LEN]; /* Packet buffer */ +} DB; + + +/* Double buffer variables */ +DB db[2]; +int db_active = 0; +char *db_nextpri; + + +/* For easier handling of vertex indices */ +typedef struct { + short v0,v1,v2,v3; +} INDEX; + +/* Cube vertices */ +SVECTOR cube_verts[] = { + { -100, -100, -100, 0 }, + { 100, -100, -100, 0 }, + { -100, 100, -100, 0 }, + { 100, 100, -100, 0 }, + { 100, -100, 100, 0 }, + { -100, -100, 100, 0 }, + { 100, 100, 100, 0 }, + { -100, 100, 100, 0 } +}; + +/* Cube face normals */ +SVECTOR cube_norms[] = { + { 0, 0, -ONE, 0 }, + { 0, -ONE, 0, 0 }, + { 0, 0, ONE, 0 }, + { 0, ONE, 0, 0 }, + { ONE, 0, 0, 0 }, + { -ONE, 0, 0, 0 } +}; + +/* Cube vertex indices */ +INDEX cube_indices[] = { + { 0, 1, 2, 3 }, + { 5, 4, 0, 1 }, + { 4, 5, 6, 7 }, + { 6, 7, 3, 2 }, + { 3, 1, 6, 4 }, + { 0, 2, 5, 7 } +}; + +/* Number of cube faces */ +#define CUBE_FACES 6 + +/* Light color matrix */ +MATRIX color_mtx = { + ONE, 0, 0, /* Red */ + ONE, 0, 0, /* Green */ + ONE, 0, 0 /* Blue */ +}; + +/* Light matrix */ +MATRIX light_mtx = { + /* X, Y, Z */ + -2048 , -2048 , -2048, + 0 , 0 , 0, + 0 , 0 , 0 +}; + + +/* Reference texture data */ +extern int tim_blendpattern[]; + + +/* TPage and CLUT values */ +unsigned short rendertex_tpage; /* For the render to texture cube */ +unsigned short bpattern_tpage; /* For the scrolling blending pattern */ +unsigned short bpattern_clut; + + +/* Function declarations */ +void init(); +void display(); + +/* This function sorts a cube that is drawn + * to an offscreen area specified by *area */ +void sort_cube(int *ot, RECT *area); +void sort_multitex(int *ot, RECT *area, int count); + +/* Main function */ +int main() { + + int i,p,xy_temp; + int count = 0; + + SVECTOR rot = { 0 }; /* Rotation vector for Rotmatrix */ + VECTOR pos = { 0, 0, 400 }; /* Translation vector for TransMatrix */ + MATRIX mtx,lmtx; /* Rotation matrices for geometry and lighting */ + + VECTOR spos = { 0, 0, 250 }; + SVECTOR srot = { 0 }; + + RECT texarea,area,dtexarea; + RECT cubearea; + + POLY_FT4 *pol4; /* Flat shaded quad primitive pointer */ + + + /* Init graphics and GTE */ + init(); + + setRECT(&area, 704, 0, 64, 64); + setRECT(&cubearea, 704, 64, 64, 64); + + setRECT(&texarea, 0, 0, 64>>3, 64>>3); + setRECT(&dtexarea, 0, 0, 0, 0); + + rendertex_tpage = getTPage(2, 0, area.x, area.y); + + /* Main loop */ + while( 1 ) { + + /* Sort multi-texture stuff */ + sort_multitex(db[db_active].ot+(OT_LEN-1), &area, count); + + /* Matrix stuff for render to texture cube */ + RotMatrix( &srot, &mtx ); + TransMatrix( &mtx, &spos ); + + MulMatrix0( &light_mtx, &mtx, &lmtx ); + + gte_SetRotMatrix( &mtx ); + gte_SetTransMatrix( &mtx ); + gte_SetLightMatrix( &lmtx ); + + /* Reduce FOV to fit in area and sort cube */ + gte_SetGeomScreen(32); + + sort_cube(db[db_active].ot+(OT_LEN-1), &cubearea); + + gte_SetGeomScreen(CENTERX); + + + /* Set rotation and translation to the matrix */ + RotMatrix( &rot, &mtx ); + TransMatrix( &mtx, &pos ); + + /* Multiply light matrix by rotation matrix so light source */ + /* won't appear relative to the model's rotation */ + MulMatrix0( &light_mtx, &mtx, &lmtx ); + + /* Set rotation and translation matrix */ + gte_SetRotMatrix( &mtx ); + gte_SetTransMatrix( &mtx ); + + /* Set light matrix */ + gte_SetLightMatrix( &lmtx ); + + /* Make the cube SPEEN */ + rot.vx += 4; + rot.vz += 4; + + srot.vx += 8; + srot.vy += 8; + srot.vz -= 8; + + /* Draw the cube */ + pol4 = (POLY_FT4*)db_nextpri; + + for( i=0; i<CUBE_FACES; i++ ) { + + /* Load the first 3 vertices of a quad to the GTE */ + gte_ldv3( + &cube_verts[cube_indices[i].v0], + &cube_verts[cube_indices[i].v1], + &cube_verts[cube_indices[i].v2] ); + + /* Rotation, Translation and Perspective Triple */ + gte_rtpt(); + + /* Compute normal clip for backface culling */ + gte_nclip(); + + /* Get result*/ + gte_stopz( &p ); + + /* Skip this face if backfaced */ + if( p < 0 ) + continue; + + /* Calculate average Z for depth sorting */ + gte_avsz4(); + gte_stotz( &p ); + + /* Skip if clipping off */ + /* (the shift right operator is to scale the depth precision) */ + if( (p>>2) > OT_LEN ) + continue; + + /* Initialize a quad primitive */ + setPolyFT4( pol4 ); + + /* Set the projected vertices to the primitive */ + gte_stsxy0( &pol4->x0 ); + gte_stsxy1( &pol4->x1 ); + gte_stsxy2( &pol4->x2 ); + + /* Compute the last vertex and set the result */ + gte_ldv0( &cube_verts[cube_indices[i].v3] ); + gte_rtps(); + gte_stsxy( &pol4->x3 ); + + /* Load primitive color even though gte_ncs() doesn't use it. */ + /* This is so the GTE will output a color result with the */ + /* correct primitive code. */ + gte_ldrgb( &pol4->r0 ); + + /* Load the face normal */ + gte_ldv0( &cube_norms[i] ); + + /* Normal Color Single */ + gte_ncs(); + + /* Store result to the primitive */ + gte_strgb( &pol4->r0 ); + + // Map to render to texture texture + pol4->tpage = rendertex_tpage; + if( (i&0x1) == 0 ) + setUVWH(pol4, 0, 0, 63, 63); + else + setUVWH(pol4, 0, 64, 63, 63); + + + /* Sort primitive to the ordering table */ + addPrim( db[db_active].ot+(p>>2), pol4 ); + + /* Advance to make another primitive */ + pol4++; + + } + + /* Update nextpri variable */ + /* (IMPORTANT if you plan to sort more primitives after this) */ + db_nextpri = (char*)pol4; + + /* Swap buffers and draw the primitives */ + display(); + + count++; + + } + + return 0; + +} + +void init() { + + TIM_IMAGE tim; + + /* Reset the GPU, also installs a VSync event handler */ + ResetGraph( 0 ); + + /* Set display and draw environment areas */ + /* (display and draw areas must be separate, otherwise hello flicker) */ + SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + + /* Enable draw area clear and dither processing */ + setRGB0( &db[0].draw, 63, 0, 127 ); + db[0].draw.isbg = 1; + db[0].draw.dtd = 1; + + + /* Define the second set of display/draw environments */ + SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES ); + + setRGB0( &db[1].draw, 63, 0, 127 ); + db[1].draw.isbg = 1; + db[1].draw.dtd = 1; + + + /* Apply the drawing environment of the first double buffer */ + PutDrawEnv( &db[0].draw ); + + + /* Clear both ordering tables to make sure they are clean at the start */ + ClearOTagR( db[0].ot, OT_LEN ); + ClearOTagR( db[1].ot, OT_LEN ); + ClearOTagR( db[0].sub_ot[0], 4 ); + ClearOTagR( db[0].sub_ot[1], 4 ); + ClearOTagR( db[1].sub_ot[0], 4 ); + ClearOTagR( db[1].sub_ot[1], 4 ); + + /* Set primitive pointer address */ + db_nextpri = db[0].p; + + /* Initialize the GTE */ + InitGeom(); + + /* Set GTE offset (recommended method of centering) */ + gte_SetGeomOffset( CENTERX, CENTERY ); + + /* Set screen depth (basically FOV control, W/2 works best) */ + gte_SetGeomScreen( CENTERX ); + + /* Set light ambient color and light color matrix */ + gte_SetBackColor( 63, 63, 63 ); + gte_SetColorMatrix( &color_mtx ); + + GetTimInfo(tim_blendpattern, &tim); + if( tim.mode & 0x8 ) + { + LoadImage( tim.crect, tim.caddr ); /* Upload CLUT if present */ + } + LoadImage( tim.prect, tim.paddr ); /* Upload texture to VRAM */ + + bpattern_tpage = getTPage(0, 1, tim.prect->x, tim.prect->y); + bpattern_clut = getClut(tim.crect->x, tim.crect->y); + +} + +void display() { + + /* Wait for GPU to finish drawing and vertical retrace */ + DrawSync( 0 ); + VSync( 0 ); + + /* Swap buffers */ + db_active ^= 1; + db_nextpri = db[db_active].p; + + /* Clear the OT of the next frame */ + ClearOTagR( db[db_active].ot, OT_LEN ); + ClearOTagR( db[db_active].sub_ot[0], 4 ); + ClearOTagR( db[db_active].sub_ot[1], 4 ); + + /* Apply display/drawing environments */ + PutDrawEnv( &db[db_active].draw ); + PutDispEnv( &db[db_active].disp ); + + /* Enable display */ + SetDispMask( 1 ); + + /* Start drawing the OT of the last buffer */ + DrawOTag( db[1-db_active].ot+(OT_LEN-1) ); + +} + +void sort_multitex(int *ot, RECT *area, int count) +{ + DR_TPAGE *ptpage; + FILL *pfill; + DR_AREA *parea; + DR_TWIN *ptwin; + DR_OFFSET *poffs; + + SPRT *psprt; + + /* Texture window constraint */ + /* (coordinates specified in units of 8 pixels) */ + RECT texwindow = { 0, 0, 64>>3, 64>>3 }; + + /* Sort the sub OT to the specified OT level */ + addPrims( + ot, /* Target OT */ + db[db_active].sub_ot[0]+3, /* Start of OT to sort */ + db[db_active].sub_ot[0]); /* End of OT to sort */ + + + /* Sort a FILL primitive to clear the off-screen area */ + pfill = (FILL*)db_nextpri; + setFill(pfill); + setXY0(pfill, area->x, area->y); + setWH(pfill, 64, 64); + setRGB0(pfill, 0, 0, 0); + addPrim(db[db_active].sub_ot[0]+3, pfill); + db_nextpri += sizeof(FILL); + + + /* Sort draw area primitives to set the drawing target */ + parea = (DR_AREA*)db_nextpri; + + setDrawArea(parea, area); /* Sets to off-screen area */ + addPrim(db[db_active].sub_ot[0]+3, parea); + parea++; + + setDrawArea(parea, /* Reverts to draw area */ + &db[1-db_active].draw.clip); + addPrim(db[db_active].sub_ot[0]+1, parea); + parea++; + db_nextpri = (char*)parea; + + + /* Sort offset primitives to set the drawing offset to the target */ + poffs = (DR_OFFSET*)db_nextpri; + + setDrawOffset(poffs, area->x, area->y); /* Sets to off-screen area */ + addPrim(db[db_active].sub_ot[0]+3, poffs); + poffs++; + + setDrawOffset(poffs, /* Reverts to draw area */ + db[1-db_active].draw.clip.x, + db[1-db_active].draw.clip.y); + addPrim(db[db_active].sub_ot[0]+1, poffs); + poffs++; + db_nextpri = (char*)poffs; + + + /* This sets the active texture page for the SPRT primitives */ + ptpage = (DR_TPAGE*)db_nextpri; + setDrawTPage(ptpage, 1, 0, bpattern_tpage); + addPrim(db[db_active].sub_ot[0]+3, ptpage); + ptpage++; + db_nextpri = (char*)ptpage; + + + /* Sort a DR_TWIN primitive to wrap texture coordinates to 64x64 */ + ptwin = (DR_TWIN*)db_nextpri; + + setTexWindow(ptwin, &texwindow); /* Set window constraint */ + addPrim(db[db_active].sub_ot[0]+3, ptwin); + ptwin++; + + texwindow.w = 0; /* Clear window constraint */ + texwindow.h = 0; + setTexWindow(ptwin, &texwindow); + addPrim(db[db_active].sub_ot[0]+1, ptwin); + ptwin++; + db_nextpri = (char*)ptwin; + + + /* Sort blending and scrolling sprites layering over one another */ + psprt = (SPRT*)db_nextpri; + + /* Sort pattern in green scrolling up-left */ + setSprt(psprt); + setSemiTrans(psprt, 1); + setXY0(psprt, 0, 0); + setWH(psprt, 64, 64); + setUV0(psprt, (count>>1)&0x3F, count&0x3F); + setRGB0(psprt, 0, 91, 0); + psprt->clut = bpattern_clut; + addPrim(db[db_active].sub_ot[0]+1, psprt); + psprt++; + + /* Sort pattern in blue scrolling up-right*/ + setSprt(psprt); + setSemiTrans(psprt, 1); + setXY0(psprt, 0, 0); + setWH(psprt, 64, 64); + setUV0(psprt, (-count>>1)&0x3F, (count>>1)&0x3F); + setRGB0(psprt, 0, 0, 91); + psprt->clut = bpattern_clut; + addPrim(db[db_active].sub_ot[0]+1, psprt); + psprt++; + + /* Sort pattern in red scrolling down-right */ + setSprt(psprt); + setSemiTrans(psprt, 1); + setXY0(psprt, 0, 0); + setWH(psprt, 64, 64); + setUV0(psprt, (-count>>1)&0x3F, (-count>>1)&0x3F); + setRGB0(psprt, 91, 0, 0); + psprt->clut = bpattern_clut; + addPrim(db[db_active].sub_ot[0]+1, psprt); + psprt++; + + /* Sort pattern in grey scrolling up-left */ + setSprt(psprt); + setXY0(psprt, 0, 0); + setWH(psprt, 64, 64); + setUV0(psprt, count&0x3F, (count>>1)&0x3F); + setRGB0(psprt, 64, 64, 64); + psprt->clut = bpattern_clut; + addPrim(db[db_active].sub_ot[0]+1, psprt); + psprt++; + + db_nextpri = (char*)psprt; + +} + +void sort_cube(int *ot, RECT *area) +{ + int i,p; + POLY_FT4* pol4; + FILL* pfill; + DR_AREA* parea; + DR_OFFSET* poffs; + + addPrims( + ot, + db[db_active].sub_ot[1]+3, + db[db_active].sub_ot[1]); + + pfill = (FILL*)db_nextpri; + setFill(pfill); + setXY0(pfill, area->x, area->y); + setWH(pfill, 64, 64); + setRGB0(pfill, 128, 91, 0); + addPrim(db[db_active].sub_ot[1]+3, pfill); + db_nextpri += sizeof(FILL); + + parea = (DR_AREA*)db_nextpri; + setDrawArea(parea, area); + addPrim(db[db_active].sub_ot[1]+3, parea); + parea++; + setDrawArea(parea, &db[1-db_active].draw.clip); + addPrim(db[db_active].sub_ot[1]+1, parea); + parea++; + db_nextpri = (char*)parea; + + poffs = (DR_OFFSET*)db_nextpri; + setDrawOffset(poffs, area->x, area->y); + addPrim(db[db_active].sub_ot[1]+3, poffs); + poffs++; + setDrawOffset(poffs, db[1-db_active].draw.clip.x, db[1-db_active].draw.clip.y); + addPrim(db[db_active].sub_ot[1]+1, poffs); + poffs++; + db_nextpri = (char*)poffs; + + + gte_SetGeomOffset(32, 32); + + // Sort the cube + pol4 = (POLY_FT4*)db_nextpri; + + for( i=0; i<CUBE_FACES; i++ ) { + + // Load the first 3 vertices of a quad to the GTE + gte_ldv3( + &cube_verts[cube_indices[i].v0], + &cube_verts[cube_indices[i].v1], + &cube_verts[cube_indices[i].v2] ); + + // Rotation, Translation and Perspective Triple + gte_rtpt(); + + // Compute normal clip for backface culling + gte_nclip(); + + // Get result + gte_stopz( &p ); + + // Skip this face if backfaced + if( p < 0 ) + continue; + + // Calculate average Z for depth sorting + gte_avsz3(); + gte_stotz( &p ); + + // Skip if clipping off + // (the shift right operator is to scale the depth precision) + /*if( ((p>>6) <= 0) || ((p>>6) >= 4) ) + continue;*/ + + // Initialize a quad primitive + setPolyFT4( pol4 ); + + // Set the projected vertices to the primitive + gte_stsxy0( &pol4->x0 ); + gte_stsxy1( &pol4->x1 ); + gte_stsxy2( &pol4->x2 ); + + // Compute the last vertex and set the result + gte_ldv0( &cube_verts[cube_indices[i].v3] ); + gte_rtps(); + gte_stsxy( &pol4->x3 ); + + // Load primitive color even though gte_ncs() doesn't use it. + // This is so the GTE will output a color result with the + // correct primitive code. + gte_ldrgb( &pol4->r0 ); + + // Load the face normal + gte_ldv0( &cube_norms[i] ); + + // Normal Color Single + gte_ncs(); + + // Store result to the primitive + gte_strgb( &pol4->r0 ); + + gte_avsz4(); + gte_stotz( &p ); + + pol4->tpage = rendertex_tpage; + setUVWH(pol4, 0, 0, 63, 63); + + // Sort primitive to the ordering table + addPrim( db[db_active].sub_ot[1]+1, pol4 ); + + // Advance to make another primitive + pol4++; + + } + + // Update nextpri + db_nextpri = (char*)pol4; + + gte_SetGeomOffset(CENTERX, CENTERY); +}
\ No newline at end of file diff --git a/examples/graphics/render2tex/makefile b/examples/graphics/render2tex/makefile new file mode 100644 index 0000000..aaa3b1d --- /dev/null +++ b/examples/graphics/render2tex/makefile @@ -0,0 +1,39 @@ +include ../../sdk-common.mk + +TARGET = render2tex.elf + +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) + +INCLUDE += +LIBDIRS += + +LIBS = -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lgcc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) -fno-exceptions +AFLAGS = -g -msoft-float +LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x + +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/graphics/render2tex/texture.s b/examples/graphics/render2tex/texture.s new file mode 100644 index 0000000..e786dce --- /dev/null +++ b/examples/graphics/render2tex/texture.s @@ -0,0 +1,9 @@ +# Assembler file for including the texture file in a more elegant manner + +.section .data + +.global tim_blendpattern +.type tim_blendpattern, @object +tim_blendpattern: + .incbin "blendpattern-16c.tim" +
\ No newline at end of file diff --git a/examples/graphics/rgb24/bunpattern.tim b/examples/graphics/rgb24/bunpattern.tim Binary files differnew file mode 100644 index 0000000..f233453 --- /dev/null +++ b/examples/graphics/rgb24/bunpattern.tim diff --git a/examples/graphics/rgb24/main.c b/examples/graphics/rgb24/main.c new file mode 100644 index 0000000..9f1a647 --- /dev/null +++ b/examples/graphics/rgb24/main.c @@ -0,0 +1,52 @@ +/* LibPSn00b Example Programs + * Part of the PSn00bSDK Project + * + * RGB24 Example by Lameguy64 + * + * + * This example demonstrates the 24-bit color mode of the PS1. This mode is + * not practical for gameplay as the GPU can only draw graphics primitives + * in 16-bit color depth so this feature would normally be used only for + * fullscreen graphic illustrations or FMV sequences. + * + * + * Changelog: + * + * 05-03-2019 - Initial version. + * + */ + +#include <stdio.h> +#include <psxgte.h> +#include <psxgpu.h> + +// So data from tim.s can be accessed +extern unsigned int tim_image[]; + +int main() { + + DISPENV disp; + TIM_IMAGE tim; + + // Reset GPU + ResetGraph(0); + + // Setup 640x480 24-bit video mode + SetDefDispEnv(&disp, 0, 0, 640, 480); + disp.isrgb24 = 1; + disp.isinter = 1; + + // Apply and enable display + PutDispEnv(&disp); + SetDispMask(1); + + // Upload image to VRAM + GetTimInfo(tim_image, &tim); + LoadImage(tim.prect, tim.paddr); + DrawSync(0); + + while(1) { + } + + return 0; +}
\ No newline at end of file diff --git a/examples/graphics/rgb24/makefile b/examples/graphics/rgb24/makefile new file mode 100644 index 0000000..61ef24f --- /dev/null +++ b/examples/graphics/rgb24/makefile @@ -0,0 +1,41 @@ +include ../../sdk-common.mk + +TARGET = rgb24.elf + +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) + +INCLUDE += +LIBDIRS += + +LIBS = -lpsxgpu -lpsxapi -lc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) -fno-exceptions +AFLAGS = -g -msoft-float +LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x + +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.tim + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/graphics/rgb24/tim.s b/examples/graphics/rgb24/tim.s new file mode 100644 index 0000000..a4432d9 --- /dev/null +++ b/examples/graphics/rgb24/tim.s @@ -0,0 +1,7 @@ +.section .data + +.global tim_image +.type tim_image, @object +tim_image: + .incbin "bunpattern.tim" +
\ No newline at end of file |
