aboutsummaryrefslogtreecommitdiff
path: root/examples/graphics/render2tex
diff options
context:
space:
mode:
authorJohn Wilbert M. Villamor <lameguy64@gmail.com>2020-04-24 19:01:28 +0800
committerJohn Wilbert M. Villamor <lameguy64@gmail.com>2020-04-24 19:01:28 +0800
commit1aa0e17df7c325a41de8cf8a57f52ed853f08bf3 (patch)
tree5ec7f69ca0104f2b0a41e2ee7d3cb0cf0c9c54c5 /examples/graphics/render2tex
parente82da2abe4c264d4b48a48d79cf9b8e4c4fb8ab6 (diff)
downloadpsn00bsdk-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/render2tex')
-rw-r--r--examples/graphics/render2tex/blendpattern-16c.pngbin0 -> 385 bytes
-rw-r--r--examples/graphics/render2tex/blendpattern-16c.timbin0 -> 2112 bytes
-rw-r--r--examples/graphics/render2tex/blendpattern.pngbin0 -> 826 bytes
-rw-r--r--examples/graphics/render2tex/main.c649
-rw-r--r--examples/graphics/render2tex/makefile39
-rw-r--r--examples/graphics/render2tex/texture.s9
6 files changed, 697 insertions, 0 deletions
diff --git a/examples/graphics/render2tex/blendpattern-16c.png b/examples/graphics/render2tex/blendpattern-16c.png
new file mode 100644
index 0000000..74ac945
--- /dev/null
+++ b/examples/graphics/render2tex/blendpattern-16c.png
Binary files differ
diff --git a/examples/graphics/render2tex/blendpattern-16c.tim b/examples/graphics/render2tex/blendpattern-16c.tim
new file mode 100644
index 0000000..2fff580
--- /dev/null
+++ b/examples/graphics/render2tex/blendpattern-16c.tim
Binary files differ
diff --git a/examples/graphics/render2tex/blendpattern.png b/examples/graphics/render2tex/blendpattern.png
new file mode 100644
index 0000000..49af62c
--- /dev/null
+++ b/examples/graphics/render2tex/blendpattern.png
Binary files differ
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