aboutsummaryrefslogtreecommitdiff
path: root/examples/graphics/tilesasm/main.c
diff options
context:
space:
mode:
authorspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2022-01-17 17:55:09 +0100
committerspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2022-01-17 17:55:09 +0100
commite9475e283a82665fe6c19bebc3318b5084f15a2e (patch)
tree5740f396d10a9580c3a39ca536544436898ff1b6 /examples/graphics/tilesasm/main.c
parentde38196a978548b61c4b45115d24ef743b9eef90 (diff)
parent08de895e8582dbc70b639ae5f511ab9ebfb4d68a (diff)
downloadpsn00bsdk-e9475e283a82665fe6c19bebc3318b5084f15a2e.tar.gz
Merge branch 'master' of github.com:Lameguy64/PSn00bSDK into latest-commit
Diffstat (limited to 'examples/graphics/tilesasm/main.c')
-rw-r--r--examples/graphics/tilesasm/main.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/examples/graphics/tilesasm/main.c b/examples/graphics/tilesasm/main.c
new file mode 100644
index 0000000..7f7c7fe
--- /dev/null
+++ b/examples/graphics/tilesasm/main.c
@@ -0,0 +1,425 @@
+/*
+ * LibPSn00b Example Programs
+ *
+ * Drawing Tile-maps with Assembler Routines
+ * 2022 Meido-Tek Productions / PSn00bSDK Project
+ *
+ * Example by John "Lameguy" Wilbert Villamor (Lameguy64)
+ *
+ * Demonstrates the use of assembler code to write a high-speed graphics
+ * routine that draws a 2D tile-map by generating SPRT_16 primitives.
+ * The assembler routine is called from a compiled C module in a manner no
+ * different to calling a C routine... A program written in this manner is
+ * known as mixed-language programming which includes other programming
+ * languages, not just assembly.
+ *
+ * This example also demonstrates using assembler files to include data files
+ * into a program as arrays (see 'data.s'). Arguably much more elegant and
+ * convenient than converting files to C headers like in the old days.
+ *
+ * The tile data and drawing is handled in a manner similar to that of the
+ * tile-map drawing functions in libgs where the map data consists of 16-bit
+ * words with 0xFFFF being a transparent tile, with each tile entry defined
+ * by an array of structs specifying the tpage, clut and u,v coordinates for
+ * each tile number. This provides flexibility with how the tile data will be
+ * organized in the framebuffer.
+ *
+ * Per-pixel clipping of the tile-map is actually not performed by the
+ * DrawTiles function but rather with DR_AREA primitives. This method
+ * eliminates code overhead from performing the clipping operations in
+ * software and thus, yields the fastest possible performance for tile
+ * sorting. Use of the DR_AREA primitive must be handled with care, as
+ * setting it beyond the display buffers could overwrite textures and
+ * CLUT data.
+ *
+ * Changelog:
+ *
+ * January 16, 2022 - Initial version.
+ *
+ * Controls:
+ *
+ * D-pad - Scroll tile-map
+ * L1 (hold) - Move tile-map window with D-pad (must be shrunk first)
+ * L2 (hold) - Resize tile-map window with D-pad
+ *
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <psxetc.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxapi.h>
+#include <psxpad.h>
+
+/*
+ * Constants for convenience
+ */
+#define OT_LEN 4 /* Number of ordering table entries */
+#define PKTBUFF_LEN 32768 /* Size of packet buffer (in bytes) */
+
+/* Define display/draw environments for double buffering */
+DISPENV disp[2];
+DRAWENV draw[2];
+int db;
+
+/* Define the ordering table and packet buffer arrays */
+long ot[2][OT_LEN];
+char pkt[2][PKTBUFF_LEN];
+
+/* Next packet pointer for primitive generation */
+char *pkt_addr;
+
+/* Pad data buffer */
+char pad_buff[2][34];
+
+/*
+ * Tile definition structure (to define VRAM coordinates of tiles)
+ */
+typedef struct _TILEDEF
+{
+ u_char u,v; // Texture coordinates of tile
+ u_short clut; // CLUT number of tile
+ u_short pad; // Padding
+ u_short tpage; // Texture page number
+} TILEDEF;
+
+/*
+ * Tile info structure (for drawing function)
+ */
+typedef struct _TILEINFO
+{
+ RECT window; // Drawing window of tile info (only cull, not clip)
+ TILEDEF *tiles; // Pointer to TILEDEF array
+ u_short *mapdata; // Pointer to 16-bit map data
+ u_short map_w; // Tile map dimensions
+ u_short map_h;
+} TILEINFO;
+
+/* Define array of tiledefs */
+TILEDEF tiles[256];
+
+/*
+ * Declarations for data.s
+ */
+extern u_long tim_tileset[];
+
+/*
+ * Declarations for drawtiles.s
+ */
+extern u_char *DrawTiles(int scroll_x, int scroll_y,
+ TILEINFO *info, long *ot, u_char *pri);
+
+/*
+ * Init function
+ */
+void init(void)
+{
+ TIM_IMAGE tim;
+
+ int i,tx,ty;
+
+ // 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], 0, 96, 0);
+ setRGB0(&draw[1], 0, 96, 0);
+ draw[0].isbg = 1;
+ draw[1].isbg = 1;
+
+ // Setup buffer counter, packet pointer and ordering tables
+ db = 0;
+ pkt_addr = pkt[db];
+
+ // Clear ordering tables
+ ClearOTagR(ot[0], OT_LEN);
+ ClearOTagR(ot[1], OT_LEN);
+
+ // Load test font
+ FntLoad(960, 0);
+
+ // Open up a test font text stream of 100 characters
+ FntOpen(0, 8, 320, 224, 0, 100);
+
+ // Upload tileset TIM
+ GetTimInfo((u_long*)tim_tileset, &tim); /* Get TIM parameters */
+ LoadImage(tim.prect, tim.paddr); /* Upload texture to VRAM */
+ if( tim.mode & 0x8 ) /* Upload CLUT if present */
+ LoadImage(tim.crect, tim.caddr);
+
+ // Initialize tiledefs with coords to the tileset TIM
+ i = 0;
+ for(ty=0; ty<16; ty++)
+ {
+ for(tx=0; tx<16; tx++)
+ {
+ tiles[i].u = tx<<4;
+ tiles[i].v = ty<<4;
+ tiles[i].tpage = getTPage(tim.mode & 3, 0,
+ tim.prect->x, tim.prect->y);
+ tiles[i].clut = getClut(tim.crect->x, tim.crect->y);
+ i++;
+ }
+ }
+
+ // Initialize pads
+ InitPAD(&pad_buff[0][0], 34, &pad_buff[1][0], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+} /* init */
+
+/*
+ * Display function
+ */
+void display(void)
+{
+ // Wait for all drawing to complete
+ DrawSync(0);
+
+ // Wait for vertical sync to cap the logic to 60fps (or 50 in PAL mode)
+ // and avoid screen tearing
+ VSync(0);
+
+ // Switch pages
+ PutDispEnv(&disp[db]);
+ PutDrawEnv(&draw[db]);
+
+ // Begin drawing of the ordering table
+ DrawOTag(ot[db]+(OT_LEN-1));
+
+ // Toggle buffer index
+ db = !db;
+
+ // Clear next ordering table array
+ ClearOTagR(ot[db], OT_LEN);
+
+ // Reset packet pointer
+ pkt_addr = pkt[db];
+
+ // Enable display output, ResetGraph() disables it by default
+ SetDispMask(1);
+
+} /* display */
+
+/*
+ * Initializes a randomly generated tile map
+ */
+void initdata(u_short *tiledata, int w, int h)
+{
+ int tx,ty;
+
+ for(ty=0; ty<h; ty++)
+ {
+ srand(200+ty);
+ for(tx=0; tx<w; tx++)
+ {
+ *tiledata = rand() & 0xFF;
+ tiledata++;
+ }
+ }
+
+} /* initdata */
+
+/*
+ * Simple line sorting function
+ */
+void sortLine(int x1, int y1, int x2, int y2, long *ot)
+{
+ LINE_F2 *line_pkt;
+
+ line_pkt = (LINE_F2*)pkt_addr;
+ setLineF2(line_pkt);
+ setXY2(line_pkt, x1, y1, x2, y2);
+ setRGB0(line_pkt, 255, 255, 255);
+ addPrim(ot, line_pkt);
+ line_pkt++;
+
+ pkt_addr = (char*)line_pkt;
+
+} /* sortLine */
+
+/*
+ * Simple box sorting function
+ */
+void sortBox(RECT *rect)
+{
+ sortLine(rect->x, rect->y,
+ rect->x, rect->y+rect->h,
+ ot[db]);
+ sortLine(rect->x+rect->w, rect->y,
+ rect->x+rect->w, rect->y+rect->h,
+ ot[db]);
+ sortLine(rect->x, rect->y,
+ rect->x+rect->w, rect->y,
+ ot[db]);
+ sortLine(rect->x, rect->y+rect->h,
+ rect->x+rect->w, rect->y+rect->h, ot[db]);
+
+} /* sortBox */
+
+/*
+ * Sorts a draw area primitive for hardware clipping
+ */
+void sortDrawEnv(RECT *drawarea)
+{
+ DR_AREA *drawpkt;
+
+ drawpkt = (DR_AREA*)pkt_addr;
+ setDrawArea(drawpkt, drawarea);
+ addPrim(ot[db], drawpkt);
+ pkt_addr += sizeof(DR_AREA);
+
+} /* sortDrawEnv */
+
+/*
+ * Main function
+ */
+int main(int argc, const char *argv[])
+{
+ u_short *tiledata;
+ TILEINFO tileinfo;
+ PADTYPE *pad;
+ RECT cliprect;
+
+ int i,scroll_x,scroll_y;
+
+ /* Init stuff */
+ init();
+
+ /* Allocate buffer for tile data */
+ tiledata = (u_short*)malloc((256*256)<<1);
+
+ /* Generate a random tilemap of values 0-255 */
+ initdata(tiledata, 256, 256);
+
+ /* Define the TILEINFO struct */
+ tileinfo.window.x = 0;
+ tileinfo.window.y = 0;
+ tileinfo.window.w = 320;
+ tileinfo.window.h = 240;
+ tileinfo.tiles = tiles;
+ tileinfo.mapdata = tiledata;
+ tileinfo.map_w = 256;
+ tileinfo.map_h = 256;
+
+ /* Main loop */
+ scroll_x = 0;
+ scroll_y = 0;
+
+ while(1)
+ {
+ /* Handle inputs */
+ pad = (PADTYPE*)&pad_buff[0][0];
+
+ if( pad->stat == 0 )
+ {
+ if( ( pad->type == 0x4 ) ||
+ ( pad->type == 0x5 ) ||
+ ( pad->type == 0x7 ) )
+ {
+ if( !(pad->btn&PAD_L1) ) /* Window resize */
+ {
+ if( !(pad->btn&PAD_UP) && ( tileinfo.window.y > 0 ) )
+ {
+ tileinfo.window.y--;
+ }
+ i = tileinfo.window.y+tileinfo.window.h;
+ if( !(pad->btn&PAD_DOWN) && ( i < disp[db].disp.h ) )
+ {
+ tileinfo.window.y++;
+ }
+ if( !(pad->btn&PAD_LEFT) && ( tileinfo.window.x > 0 ) )
+ {
+ tileinfo.window.x--;
+ }
+ i = tileinfo.window.x+tileinfo.window.w;
+ if( !(pad->btn&PAD_RIGHT) && ( i < disp[db].disp.w ) )
+ {
+ tileinfo.window.x++;
+ }
+ }
+ else if( !(pad->btn&PAD_L2) ) /* Window move */
+ {
+ if( !(pad->btn&PAD_UP) && ( tileinfo.window.h > 0 ) )
+ {
+ tileinfo.window.h--;
+ }
+ i = tileinfo.window.y+tileinfo.window.h;
+ if( !(pad->btn&PAD_DOWN) && ( i < disp[db].disp.h ) )
+ {
+ tileinfo.window.h++;
+ }
+ if( !(pad->btn&PAD_LEFT) && ( tileinfo.window.w > 0 ) )
+ {
+ tileinfo.window.w--;
+ }
+ i = tileinfo.window.y+tileinfo.window.h;
+ if( !(pad->btn&PAD_RIGHT) && ( i < disp[db].disp.w ) )
+ {
+ tileinfo.window.w++;
+ }
+ }
+ else /* Scrolling */
+ {
+ if( !(pad->btn&PAD_UP) )
+ {
+ scroll_y-=2;
+ }
+ if( !(pad->btn&PAD_DOWN) )
+ {
+ scroll_y+=2;
+ }
+ if( !(pad->btn&PAD_LEFT) )
+ {
+ scroll_x-=2;
+ }
+ if( !(pad->btn&PAD_RIGHT) )
+ {
+ scroll_x+=2;
+ }
+ }
+ }
+ }
+
+ /* Draw a box around the tile-map window */
+ sortBox(&tileinfo.window);
+
+ /* Sort default clipping (this is processed last) */
+ sortDrawEnv(&draw[db].clip);
+
+ /* Sort the tiles */
+ pkt_addr = DrawTiles(scroll_x, scroll_y,
+ &tileinfo, ot[db], pkt_addr);
+
+ /* Sort clipping to the tile window */
+ cliprect = tileinfo.window;
+ cliprect.y += draw[db].clip.y;
+ sortDrawEnv(&cliprect);
+
+ /* Print stats */
+ FntPrint(-1, "X=%d Y=%d\n", scroll_x, scroll_y);
+ FntPrint(-1, "WINDOW POS. (%d,%d)\n",
+ tileinfo.window.x, tileinfo.window.y);
+ FntPrint(-1, "WINDOW SIZE (%d,%d)\n",
+ tileinfo.window.w, tileinfo.window.h);
+ FntFlush(-1);
+
+ /* Refresh display */
+ display();
+ }
+
+ return 0;
+
+} /* main */