commit 207b7a6bd528e78546ec04cfde07f0108f8d9029 Author: ABelliqueux Date: Thu Apr 29 18:46:10 2021 +0200 first commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..418bfe2 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +TARGET = ovl-upload +TYPE = ps-exe + +SRCS = ovl-upload.c \ +TIM/cubetex.tim \ +../common/crt0/crt0.s \ +tritex.c \ +cubetex.c \ + + +OVERLAYSCRIPT ?= overlay.ld +OVERLAYSECTION ?= .ovl0 .ovl1 + +CPPFLAGS += -I../psyq/include +LDFLAGS += -L../psyq/lib +LDFLAGS += -Wl,--start-group +LDFLAGS += -lapi +LDFLAGS += -lc +LDFLAGS += -lc2 +LDFLAGS += -lcard +LDFLAGS += -lcomb +LDFLAGS += -lds +LDFLAGS += -letc +LDFLAGS += -lgpu +LDFLAGS += -lgs +LDFLAGS += -lgte +LDFLAGS += -lgun +LDFLAGS += -lhmd +LDFLAGS += -lmath +LDFLAGS += -lmcrd +LDFLAGS += -lmcx +LDFLAGS += -lpad +LDFLAGS += -lpress +LDFLAGS += -lsio +LDFLAGS += -lsnd +LDFLAGS += -lspu +LDFLAGS += -ltap +LDFLAGS += -lcd +LDFLAGS += -Wl,--end-group + +include ../common.mk \ diff --git a/Overlay.ovl0 b/Overlay.ovl0 new file mode 100755 index 0000000..a7982cf Binary files /dev/null and b/Overlay.ovl0 differ diff --git a/Overlay.ovl1 b/Overlay.ovl1 new file mode 100755 index 0000000..4df9ca1 Binary files /dev/null and b/Overlay.ovl1 differ diff --git a/OverlayExample.bin b/OverlayExample.bin new file mode 100644 index 0000000..c62c23b Binary files /dev/null and b/OverlayExample.bin differ diff --git a/OverlayExample.cue b/OverlayExample.cue new file mode 100644 index 0000000..8ed26d4 --- /dev/null +++ b/OverlayExample.cue @@ -0,0 +1,3 @@ +FILE "OverlayExample.bin" BINARY + TRACK 01 MODE2/2352 + INDEX 01 00:00:00 diff --git a/README.md b/README.md new file mode 100644 index 0000000..77c88b2 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Ovl-upload : On-demand Overlay uploading on the PSX + +![In action!](ovl.gif) + +This example code demonstrates how to use the companion 'ovl-upload.py' script that should be provided with this file. + +Once the code is loaded on a unirom enabled PSX via a serial/USB cable, 'ovl-upload.py' listens for a specific command + +to load an overlay file on demand. + +For an explanation about overlays, see [http://psx.arthus.net/sdk/Psy-Q/DOCS/TRAINING/FALL96/overlay.pdf](http://psx.arthus.net/sdk/Psy-Q/DOCS/TRAINING/FALL96/overlay.pdf) + +For a basic example see @JaberwockySeamonstah's [https://github.com/JaberwockySeamonstah/PSXOverlayExample](https://github.com/JaberwockySeamonstah/PSXOverlayExample) + +# Thanks + +@JaberwockySeamonstah, @JonathanDotCel, @nicolasnoble, @Lameguy64 for their help and patience. + +## Set-up + +* You need to set up the Nugget+PsyQ SDK, as described here : [https://github.com/ABelliqueux/nolibgs_hello_worlds](https://github.com/ABelliqueux/nolibgs_hello_worlds) +* Clone this repo. +* Get [Unirom](https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/) + [NotPSXserial](https://github.com/JonathanDotCel/NOTPSXSerial). +* Get [mkpsxiso](https://github.com/Lameguy64/mkpsxiso). +* With your PSX on at the unirom prompt, serial/USB cable plugged, upload the default data at the right address : + +```bash +# We need debug mode for runtime data uploading + +nops /debug /dev/ttyUSB0 + +nops /fast /bin 0x8003e5c8 Overlay.ovl0 + +nops /fast /exe ovl-upload.ps-exe + +nops /slow +``` + +You should see a cube on a blue background. + +* In a terminal/cmd, launch the python script `./ovl-upload.py`. You should see a message : `Listening for incoming data...` + +* Push the **select** button on your controller. The cube should change shape ! In reality, we are loading the geometry data from another file : `Overlay.ovl1` + +Alternativly, you can use the bin/cue in an emulator or xstation. + +Helper scripts are provided for convenience and are dependent on `pcsx-redux` and `mkpsxiso` being in your $PATH. + +* `isotest.sh` will make, build the bin/cue, and open the resulting image in pcsx-redux. +* `ovly-upload-helper.sh` is a small wrapper for `nops`, hence depending on it being in your $PATH that takes args : load address, +overlay filename, ps-exe filename and optional comport/serialdevice - e.g : + +```bash +# make && +./ovly-upload-helper.sh 0x8003e5c8 Overlay.ovl0 ovl-upload.ps-exe /dev/ttyUSB0 +``` diff --git a/TIM/cubetex.tim b/TIM/cubetex.tim new file mode 100644 index 0000000..a55697e Binary files /dev/null and b/TIM/cubetex.tim differ diff --git a/config/OverlayExample.cnf b/config/OverlayExample.cnf new file mode 100644 index 0000000..7070b7f --- /dev/null +++ b/config/OverlayExample.cnf @@ -0,0 +1,4 @@ +BOOT=cdrom:\SCES_013.37;1 +TCB=4 +EVENT=10 +STACK=801FFFF0 diff --git a/config/OverlayExample.xml b/config/OverlayExample.xml new file mode 100644 index 0000000..9bab75b --- /dev/null +++ b/config/OverlayExample.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/cubetex.c b/cubetex.c new file mode 100644 index 0000000..887ba55 --- /dev/null +++ b/cubetex.c @@ -0,0 +1,136 @@ +#include "cubetex.h" + +SVECTOR modelCube_mesh[] = { + {20.0,19.999998807907104,-20.0}, + {20.0,-20.0,-20.0}, + {-20.00000238418579,-19.999996423721313,-20.0}, + {-19.999992847442627,20.000007152557373,-20.0}, + {20.000009536743164,19.99998927116394,20.0}, + {19.99998688697815,-20.000011920928955,20.0}, + {-20.000007152557373,-19.999992847442627,20.0}, + {-19.999998807907104,20.0,20.0} +}; + +SVECTOR modelCube_normal[] = { + 0.0,-0.0,-1.0,0, + 0.0,0.0,1.0,0, + 1.0,0.0,-2.384185791015625e-07,0, + -8.940696716308594e-08,-1.0,-2.9802325229866256e-07,0, + -1.0,2.384185791015625e-07,-1.4901158351676713e-07,0, + 2.6822084464583895e-07,1.0,2.3841852225814364e-07,0, + 0.0,0.0,-1.0,0, + 0.0,-0.0,1.0,0, + 1.0,-5.662441253662109e-07,3.2782537573439186e-07,0, + -4.768372150465439e-07,-1.0,8.940690321423972e-08,0, + -1.0,2.0861631355728605e-07,-1.1920931797249068e-07,0, + 2.0861631355728605e-07,1.0,1.7881397695873602e-07,0 +}; + +SVECTOR modelCube_uv[] = { + 83.71398162841797,83.71389770507812, 0, 0, + 125.03179168701172,42.396141052246094, 0, 0, + 83.71398162841797,42.396141052246094, 0, 0, + 125.03179168701172,83.71392059326172, 0, 0, + 83.71398162841797,125.03166770935059, 0, 0, + 125.03179168701172,125.03169059753418, 0, 0, + 1.0784510374069214,83.71392059326172, 0, 0, + 42.39619445800781,125.03169059753418, 0, 0, + 42.39621353149414,83.71392440795898, 0, 0, + 42.39621353149414,125.03166770935059, 0, 0, + 83.71398162841797,83.71392440795898, 0, 0, + 42.39621353149414,83.71390151977539, 0, 0, + 42.39619445800781,1.0783309936523438, 0, 0, + 1.0784281492233276,42.39611053466797, 0, 0, + 42.39619445800781,42.39612579345703, 0, 0, + 42.39619064331055,83.71392059326172, 0, 0, + 1.0784281492233276,42.396141052246094, 0, 0, + 1.0784281492233276,83.71392059326172, 0, 0, + 83.71398162841797,83.71389770507812, 0, 0, + 125.03179168701172,83.71390151977539, 0, 0, + 125.03179168701172,42.396141052246094, 0, 0, + 125.03179168701172,83.71392059326172, 0, 0, + 83.71399688720703,83.71392440795898, 0, 0, + 83.71398162841797,125.03166770935059, 0, 0, + 1.0784510374069214,83.71392059326172, 0, 0, + 1.0784281492233276,125.03169059753418, 0, 0, + 42.39619445800781,125.03169059753418, 0, 0, + 42.39621353149414,125.03166770935059, 0, 0, + 83.71398162841797,125.03169059753418, 0, 0, + 83.71398162841797,83.71392440795898, 0, 0, + 42.39619445800781,1.0783309936523438, 0, 0, + 1.0784281492233276,1.0783309936523438, 0, 0, + 1.0784281492233276,42.39611053466797, 0, 0, + 42.39619064331055,83.71392059326172, 0, 0, + 42.39619445800781,42.396141052246094, 0, 0, + 1.0784281492233276,42.396141052246094, 0, 0 +}; + +CVECTOR modelCube_color[] = { + 255,255,255, 0, + 255,255,255, 0, + 255,0,251, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,255,255, 0, + 255,255,255, 0, + 4,18,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,255,255, 0, + 254,255,23, 0, + 122,255,107, 0, + 255,255,255, 0, + 255,255,255, 0, + 255,255,255, 0, + 254,255,94, 0, + 255,255,255, 0, + 35,255,11, 0, + 255,255,255, 0, + 255,255,255, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,255,255, 0, + 254,255,23, 0, + 255,255,255, 0, + 122,255,107, 0, + 255,255,255, 0, + 54,65,255, 0, + 255,255,255, 0 +}; + +int modelCube_index[36] = { + 0,2,3, + 7,5,4, + 4,1,0, + 5,2,1, + 2,7,3, + 0,7,4, + 0,1,2, + 7,6,5, + 4,5,1, + 5,6,2, + 2,6,7, + 0,3,7 +}; + +TMESH modelCube = { + modelCube_mesh, + modelCube_normal, + modelCube_uv, + modelCube_color, + 12 +}; + +MESH Cube = { + + &modelCube, + + modelCube_index + + }; diff --git a/cubetex.h b/cubetex.h new file mode 100644 index 0000000..0c613e4 --- /dev/null +++ b/cubetex.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#ifndef custom_types + +typedef struct MESH { + + TMESH * tmesh; + + int * index; + + } MESH; + +#define custom_types + +#endif + + +extern SVECTOR modelCube_mesh[8]; + +extern SVECTOR modelCube_normal[36]; + +extern SVECTOR modelCube_uv[144]; + +extern CVECTOR modelCube_color[144]; + +extern int modelCube_index[]; + +extern TMESH modelCube; + +extern MESH Cube; diff --git a/isotest.sh b/isotest.sh new file mode 100755 index 0000000..ce4bdb4 --- /dev/null +++ b/isotest.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +make && mkpsxiso -y config/OverlayExample.xml && pcsx-redux -run -iso OverlayExample.cue diff --git a/overlay.ld b/overlay.ld new file mode 100644 index 0000000..9e43f05 --- /dev/null +++ b/overlay.ld @@ -0,0 +1,44 @@ +__heap_base = MAX(__ovl0_end, __ovl1_end); + +SECTIONS { + OVERLAY __bss_end : NOCROSSREFS SUBALIGN(4) + { + .ovlload + { + load_all_overlays_here = .; + } + .ovl0 + { + KEEP(cubetex.o(.text)) + __ovl0_ctor = .; + KEEP(cubetex.o(.text.startup._GLOBAL__*)) + KEEP(cubetex.o(.text.*)) + KEEP(cubetex.o(.rodata*)) + KEEP(cubetex.o(.sdata*)) + KEEP(cubetex.o(.data*)) + KEEP(cubetex.o(.sbss*)) + KEEP(cubetex.o(.bss*)) + KEEP(cubetex.o(.ctors)) + + . = ALIGN(4); + __ovl0_end = .; + } + + .ovl1 + { + KEEP(tritex.o(.text)) + __ovl1_ctor = .; + KEEP(tritex.o(.text.startup._GLOBAL__*)) + KEEP(tritex.o(.text.*)) + KEEP(tritex.o(.rodata*)) + KEEP(tritex.o(.sdata*)) + KEEP(tritex.o(.data*)) + KEEP(tritex.o(.sbss*)) + KEEP(tritex.o(.bss*)) + KEEP(tritex.o(.ctors)) + + . = ALIGN(4); + __ovl1_end = .; + } + } +} diff --git a/ovl-upload.c b/ovl-upload.c new file mode 100644 index 0000000..b194119 --- /dev/null +++ b/ovl-upload.c @@ -0,0 +1,440 @@ + +/* ovl-upload.c, by ABelliqueux, 04-2021 license GNU General Public License v3.0 + + This example code demonstrates how to use the companion 'ovl-upload.py' script that should be provided with this file. + + Once the code is loaded on a unirom enabled PSX via a serial/USB cable, 'ovl-upload.py' listens for a specific command + + to load an overlay file on demand. + + For an explanation about overlays, see http://psx.arthus.net/sdk/Psy-Q/DOCS/TRAINING/FALL96/overlay.pdf + + For a basic example see @JaberwockySeamonstah's https://github.com/JaberwockySeamonstah/PSXOverlayExample + + Unirom can be found here : https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1 + + with it's companion pc side software : https://github.com/JonathanDotCel/NOTPSXSerial + + Thanks to @JaberwockySeamonstah, @JonathanDotCel, @nicolasnoble, @Lameguy64 for their help and patience. + + Demonstrates: + + * Using overlays to store different data and loading them in memory as needed. + + Controls: + Select - Load alternative overlay +*/ + +#include +#include +#include +#include +#include + +// If USECD is defined, files will be loaded from the CD. Use this method for testing in an emulator. +// Additionaly, generate the bin/cue with mkpsxiso. + +//~ #define USECD + +#ifdef USECD + + #include + +#endif + +// Sample vector models + +#include "tritex.h" + +#include "cubetex.h" + +#define VMODE 0 + +#define SCREENXRES 320 + +#define SCREENYRES 240 + +#define CENTERX SCREENXRES/2 + +#define CENTERY SCREENYRES/2 + +#define OTLEN 2048 // Maximum number of OT entries + +#define PRIMBUFFLEN 32768 // Maximum number of POLY_GT3 primitives + +// Display and draw environments, double buffered + +DISPENV disp[2]; + +DRAWENV draw[2]; + +u_long ot[2][OTLEN]; // Ordering table (contains addresses to primitives) + +char primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer + +//~ int primcnt=0; // Primitive counter + +char * nextpri = primbuff[0]; // Primitive counter + +short db = 0; // Current buffer counter + +// Texture image + +extern unsigned long _binary_TIM_cubetex_tim_start[]; + +extern unsigned long _binary_TIM_cubetex_tim_end[]; + +extern unsigned long _binary_TIM_cubetex_tim_length; + +TIM_IMAGE tim_cube; + +// OVERLAYS CONFIG + +// These symbols name are defined in 'overlay.ld', l.8, l.24 and l.41 +// Use &load_all_overlays_here to get the memory adress where the overlay files are loaded. +// Those adresses you can check in the generated .map file at compile time. + +extern u_long load_all_overlays_here; + +extern u_long __lvl0_end; // Use &__lvl0_end to get end address of corresponding overlay. + +extern u_long __lvl1_end; + +//~ u_long overlaySize = 0; + +static char* overlayFile; // Will hold the name of the file to load. + +u_char overlayFileID, loadFileIDwas, loadFileID = 0; // Will hold an ID that's unique for each file. + +// Timer for the pad + +u_short timer = 0; + +// Prototypes + +void init(void); + +void display(void); + +void LoadTexture(u_long * tim, TIM_IMAGE * tparam); + +void init(){ + + // Reset the GPU before doing anything and the controller + PadInit(0); + ResetGraph(0); + + // Initialize and setup the GTE + InitGeom(); + SetGeomOffset(CENTERX, CENTERY); // x, y offset + SetGeomScreen(CENTERX); // Distance between eye and screen + + // Set the display and draw environments + SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES); + SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES); + + SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES); + SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES); + + if (VMODE) + { + SetVideoMode(MODE_PAL); + disp[0].screen.y += 8; + disp[1].screen.y += 8; + } + + setRGB0(&draw[0], 0, 0, 255); + setRGB0(&draw[1], 0, 0, 255); + + draw[0].isbg = 1; + draw[1].isbg = 1; + + PutDispEnv(&disp[db]); + PutDrawEnv(&draw[db]); + + // Init font system + FntLoad(960, 0); + FntOpen(16, 16, 196, 64, 0, 256); + + } + +void display(void){ + + DrawSync(0); + VSync(0); + + PutDispEnv(&disp[db]); + PutDrawEnv(&draw[db]); + + SetDispMask(1); + + DrawOTag(ot[db] + OTLEN - 1); + + db = !db; + + nextpri = primbuff[db]; + + + } + +void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous + OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory + ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure + + LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y + DrawSync(0); // Wait for the drawing to end + + if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT + LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y + DrawSync(0); // Wait for drawing to end + } + +} + +int main() { + + // Update this value to avoid trigger at launch + + loadFileIDwas = overlayFileID = loadFileID; + + if ( loadFileID == 0 ){ + + overlayFile = "\\cube.bin;1"; + + //~ loadFile = &level0; + + } else if ( loadFileID == 1) { + + overlayFile = "\\tri.bin;1"; + + //~ loadFile = &level1; + } + + // Load overlay from CD if definde + + #ifdef USECD + + CdInit(); + + int cdread = 0, cdsync = 1; + + cdread = CdReadFile( (char *)(overlayFile), &load_all_overlays_here, 0); + + cdsync = CdReadSync(0, 0); + + #endif + + int i; + + int PadStatus; + + int TPressed=0; + + int AutoRotate=1; + + long t, p, OTz, Flag; // t == vertex count, p == depth cueing interpolation value, OTz == value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143 + + MESH * model = &Tri; + + POLY_GT3 *poly = {0}; // pointer to a POLY_GT3 + + SVECTOR Rotate={ 0 }; // Rotation coordinates + VECTOR Trans={ 0, 0, CENTERX, 0 }; // Translation coordinates + // Scaling coordinates + VECTOR Scale={ ONE, ONE, ONE, 0 }; // ONE == 4096 + MATRIX Matrix={0}; // Matrix data for the GTE + + // Texture window + + DR_MODE * dr_mode; // Pointer to dr_mode prim + + RECT tws = {0, 0, 32, 32}; // Texture window coordinates : x, y, w, h + + init(); + + LoadTexture(_binary_TIM_cubetex_tim_start, &tim_cube); + + // Main loop + while (1) { + + // Overlay switch + + if ( loadFileID != loadFileIDwas ){ + + // Update previous file value + + loadFileIDwas = loadFileID; + + // Change file to load + + switch ( loadFileID ){ + + case 0: + + overlayFile = "\\cube.bin;1"; + + overlayFileID = 0; + + break; + + case 1: + + overlayFile = "\\tri.bin;1"; + + overlayFileID = 1; + + break; + + default: + + overlayFile = "\\cube.bin;1"; + + overlayFileID = 0; + + break; + + } + + #ifdef USECD + + cdread = CdReadFile( (char *)(overlayFile), &load_all_overlays_here, 0); + + CdReadSync(0, 0); + + #endif + + } + + // Pad button timer + + while ( timer > 0 ) { + + timer --; + + } + + // Read pad status + + PadStatus = PadRead(0); + + // If select is pressed, change overlay + + if (PadStatus & PADselect && !timer) { + + // We send the memory address where the file should be loaded, the memory address of the loadFileID, so that the screen is updated when it changes, and the file id. + + printf("load:%p:%08x:%d", &load_all_overlays_here, &loadFileID, overlayFileID); + + #ifdef USECD + + // We can do that because we only have two files + + loadFileID = !loadFileID; + + #endif + + timer = 30; + + } + + if (AutoRotate) { + Rotate.vy += 8; // Pan + Rotate.vx += 8; // Tilt + //~ Rotate.vz += 8; // Roll + } + + + // Clear the current OT + + ClearOTagR(ot[db], OTLEN); + + // Convert and set the matrixes + + RotMatrix(&Rotate, &Matrix); + + TransMatrix(&Matrix, &Trans); + + ScaleMatrix(&Matrix, &Scale); + + SetRotMatrix(&Matrix); + + SetTransMatrix(&Matrix); + + + // Render the sample vector model + t=0; + + // modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ... + + for (i = 0; i < (model->tmesh->len*3); i += 3) { + + poly = (POLY_GT3 *)nextpri; + + // Initialize the primitive and set its color values + + SetPolyGT3(poly); + + ((POLY_GT3 *)poly)->tpage = getTPage(tim_cube.mode&0x3, 0, + tim_cube.prect->x, + tim_cube.prect->y + ); + + setRGB0(poly, model->tmesh->c[i].r , model->tmesh->c[i].g , model->tmesh->c[i].b); + setRGB1(poly, model->tmesh->c[i+1].r, model->tmesh->c[i+1].g, model->tmesh->c[i+1].b); + setRGB2(poly, model->tmesh->c[i+2].r, model->tmesh->c[i+2].g, model->tmesh->c[i+2].b); + + setUV3(poly, model->tmesh->u[i].vx , model->tmesh->u[i].vy, + model->tmesh->u[i+1].vx, model->tmesh->u[i+1].vy, + model->tmesh->u[i+2].vx, model->tmesh->u[i+2].vy); + + // Rotate, translate, and project the vectors and output the results into a primitive + + OTz = RotTransPers(&model->tmesh->v[model->index[t]] , (long*)&poly->x0, &p, &Flag); + OTz += RotTransPers(&model->tmesh->v[model->index[t+1]], (long*)&poly->x1, &p, &Flag); + OTz += RotTransPers(&model->tmesh->v[model->index[t+2]], (long*)&poly->x2, &p, &Flag); + + // Sort the primitive into the OT + OTz /= 3; + if ((OTz > 0) && (OTz < OTLEN)) + AddPrim(&ot[db][OTz-2], poly); + + nextpri += sizeof(POLY_GT3); + + t+=3; + + } + + dr_mode = (DR_MODE *)nextpri; + + setDrawMode(dr_mode,1,0, getTPage(tim_cube.mode&0x3, 0, + tim_cube.prect->x, + tim_cube.prect->y), &tws); //set texture window + + AddPrim(&ot[db], dr_mode); + + nextpri += sizeof(DR_MODE); + + + FntPrint("Hello overlay!\n"); + + #ifndef USECD + + FntPrint("Overlay with id %d loaded at 0x%08x", overlayFileID, &load_all_overlays_here); + + #endif + + #ifdef USECD + + FntPrint("File: %s\n", overlayFile); + + FntPrint("Bytes read: %d", cdread); + + #endif + + FntFlush(-1); + + display(); + + } + return 0; +} diff --git a/ovl-upload.ps-exe b/ovl-upload.ps-exe new file mode 100755 index 0000000..6acb168 Binary files /dev/null and b/ovl-upload.ps-exe differ diff --git a/ovl-upload.py b/ovl-upload.py new file mode 100755 index 0000000..d28f464 --- /dev/null +++ b/ovl-upload.py @@ -0,0 +1,633 @@ +#!/usr/bin/env python + +# ovl-upload.c, by ABelliqueux, 04-2021 license GNU General Public License v3.0 + +# This working version corrected with the help of sickle : +# https://discord.com/channels/642647820683444236/663664210525290507/836029253593858060 +# Corrected script by Sickle : http://psx.arthus.net/code/rawdog.py + +# Sickle - 26/04/2021 : +# " Ooh, you were like frustratingly close dude! Few tiny issues: +# - first of your 3 rolling buffers was bugged (other 2 were spot on) +# - waiting too long between commands at points, unirom timed out +# - var i was missing the i += chunkSize so we were stuck in a loop there (e.g. tried to send a second chonk) +# - exit was gummed up with the main logic being in a while True: " + +# As suggested: +# - Removed while True: loop +# - moved rolling buffer loops to WaitForResponse() +# - reduced sleeps +# - inc var i with chunkSize + +import sys +import os +import serial +import time +import calendar +import math +import signal + +DEBUG = 0 + +SERIAL_DEVICE = '/dev/ttyUSB0' + +SERIAL_SPEED = 115200 + +# Names of the overlay files to load. +# See l.550 + +overlayFile0 = "Overlay.ovl0" + +overlayFile1 = "Overlay.ovl1" + +# Serial connection setup + +ser = serial.Serial(SERIAL_DEVICE) + +# Unirom can do 115200 and 510000 ( https://github.com/JonathanDotCel/NOTPSXSerial/blob/bce29e87cb858769fe60eb34d8eb123f9f36c8db/NOTPSXSERIAL.CS#L842 ) + +ser.baudrate = SERIAL_SPEED + +# Working directory + +cwd = os.getcwd() + +dataFolder = cwd + os.sep + +# Should we listen for commands on serial ? + +Listen = 1 + +# Will be set once unirom is in debug mode + +uniDebugMode = 0 + +# Will hold the commands received from the psx + +Command = "" + +memAddr = "" + +flagAddr = "" + +loadFile = "" + +levelId = "" + +# One byte + +#uno = int(1).to_bytes(1, byteorder='little', signed=False) + +data = 0 + +# checkSum is the checkSum for the full data + +checkSum = 0 + +# If set, it means the data transfer has been initiated + +Transfer = 0 + +# Delay between write operations. These seem to be needed for the connection not to hang. + +sleepTime = 0.08 # Seems like safe minimum + +def sig_interrupt_handler(signal, frame): + + global Run + + Run = False + +def setDEBG(): + + global sleepTime, ser, uniDebugMode + + if DEBUG: + + print("Sending DEBG command...") + + ser.write( bytes( 'DEBG' , 'ascii' ) ) + + time.sleep(sleepTime) + + # Empty in waiting buffer + + ser.reset_input_buffer() + + time.sleep(sleepTime) + + uniDebugMode = 1 + +def WaitForResponse( expectedAnswer ): + + # Get incoming data from the serial port in a rolling buffer + # when the content of the buffer corresponds to 'expectedAnswer', returns True + + global DEBUG + + responseBuffer = "" + + success = False + + while True: + + if DEBUG > 1: + + print("Waiting for data in serial input buffer.") + + # If data in serial's incoming buffer + + if ser.in_waiting: + + if DEBUG > 1: + + print("Brace yourself, data is coming...") + + # Read 1 byte + + byteValue = ser.read(1) + + # Make sure byte value is < 128 so that it can be decoded to ascii + + if byteValue[0] < 128: + + responseBuffer += byteValue.decode('ascii') + + else: + + responseBuffer += '.' + + # Always keep response buffer 4 chars long + + if len( responseBuffer ) > 4: + + # Remove first char in buffer + + responseBuffer = responseBuffer[1:] + + + # If response is ERR!, checksum check does not check, so check it again + + if responseBuffer == "ERR!": + + if DEBUG > 1: + + print("Checksum error !") + + success = False + + break + + # When expected response shows up, break from the while loop + + if responseBuffer == expectedAnswer: + + success = True + + break + if DEBUG > 1: + + print( "Got : " + responseBuffer ) + + responseBuffer = "" + + return success + +def CalculateChecksum( inBytes, skipFirstSector = False): + + returnVal = 0; + + i = 0 + + if skipFirstSector: + + i = 2048 + + while i < len( inBytes ): + + returnVal += inBytes[i]; + + i += 1 + + return returnVal; + +def WriteBytes( inData ): + + if DEBUG: + + print("Preparing to write bytes...") + + # The data needs to be split in 2K chunks + + chunkSize = 2048 + + # BEGIN WHILE DATA + + i = 0 + + while i < len( inData ): + + # BEGIN WHILE TRUE + + while True: + + # BEGIN TRY/EXCEPT + + try: + + # Calculate number of 2K chunks we're about to send + + numChunk = math.ceil( len( inData ) / chunkSize ) + + # Calculate current chunk + + currentChunk = math.ceil( (i + 1) / chunkSize) + + if DEBUG: + + print( str ( numChunk + 1 - currentChunk ) + " chunks of " + str ( chunkSize) + " bytes to send " ) + + # Avoid going out of range + + if ( i + chunkSize ) > len( inData ): + + chunkSize = len( inData ) - i + + print("Writing chunk " + str( currentChunk ) + " of " + str( numChunk ) ) + + # ~ ser.write(inData) + + chunkChecksum = 0 + + # Send inData in 2048B chunks + + for byte in range( chunkSize ): + + # Send byte + + if DEBUG > 1: + + print("Writing " + str( inData[ i + byte ].to_bytes(1, byteorder='little', signed=False) ) + " to serial..." ) + + ser.write( inData[ i + byte ].to_bytes(1, byteorder='little', signed=False) ) + + # Calculate chunk checksum + + chunkChecksum += inData[ i + byte ] + + time.sleep(sleepTime) + + if DEBUG: + + print( "Chunk cheksum : " + str( chunkChecksum ) ) + + # Wait for output buffer to be empty + # REMOVE ? Is this needed ? + + while ser.out_waiting: + + print("*") + + wait += 1 + + time.sleep(sleepTime) + + # Wait for unirom to request the checksum + + if DEBUG > 1: + + print( "Chunk " + str( currentChunk ) + " waiting for unirom to request checksum (CHEK)..." ) + + WaitForResponse( "CHEK" ) + + # Send checksum + + if DEBUG: + + print( "Sending checksum to unirom..." ); + + # ~ chunkChecksum = 170 + + bytesChunkChecksum = chunkChecksum.to_bytes( 4, byteorder='little', signed = False ) + + ser.write( bytesChunkChecksum ) + + # ~ time.sleep( sleepTime ) + + if DEBUG > 1: + + print( "Waiting for unirom to request more data (MORE)..." ) + + # Wait for unirom to request MORE inData ( next chunk ) + + if not WaitForResponse("MORE"): + + if DEBUG: + + print("ERROR ! Retrying...") + + raise Exception() + + if DEBUG: + + print( str( currentChunk ) + " chunk sent with correct checksum.") + + # Increment i from chunkSize + + i += chunkSize + + except Exception: + + continue + + # END TRY/EXCEPT + + break + + # END WHILE TRUE + + numChunk = 0 + + # END WHILE DATA + +def SendBin( inData, memAddr ): + + global sleepTime + + dataSize = len( inData ) + + if DEBUG: + + print("Data size : " + str( dataSize ) ) + + # Prepare unirom for data reception - sent "SBIN" - received : "OKV2" + + if DEBUG > 1: + + print("Sending SBIN command...") + + ser.write( bytes( 'SBIN' , 'ascii' ) ) + + time.sleep(sleepTime) + + # We're using unirom in debug mode, which means protocol version 2 is available + # Upgrade protocol - sent "UPV2" - received : "OKAY" + + ser.write( bytes( 'UPV2' , 'ascii' ) ) + + time.sleep(sleepTime) + + # Initialisation done, set flag + + # ~ Init = 1 + + # From now on, we're using the rolling buffer + if DEBUG > 1: + + print("Waiting for OKAY...") + + WaitForResponse("OKAY") + + # Calculate data checkSum + + checkSum = CalculateChecksum( inData ) + + if DEBUG : + + print("Data checkSum : " + str(checkSum) ) + + # Send memory address to load data to, size of data and checkSum + # Unirom expects unsigned longs ( 32bits ), byte endianness little + + # Convert address from string to integer, then to ulong 32b + + bytesAddr = int( memAddr, 16 ).to_bytes( 4, byteorder='little', signed=False ) + + # Write address to serial + + ser.write( bytesAddr ) + + time.sleep(sleepTime) + + # Convert and write int size to serial + + bytesSize = dataSize.to_bytes( 4, byteorder='little', signed = False ) + + ser.write( bytesSize ) + + time.sleep(sleepTime) + + # Convert and write int chekSum to serial + + bytesChk = checkSum.to_bytes( 4, byteorder='little', signed = False ) + + ser.write( bytesChk ) + + time.sleep(sleepTime) + + # Send dat data + + WriteBytes( inData ) + +def resetListener(): + + global checkSum, data, Listen, Transfer, dataSize, memAddr, loadFile, flagAddr, levelId + + memAddr = "" + + flagAddr = "" + + loadFile = "" + + checkSum = 0 + + data = 0 + + dataSize = 0 + + Transfer = 0 + + levelId = 0 + + Listen = 1 + + ser.reset_input_buffer() + + ser.reset_output_buffer() + +def main(args): + + while True: + + global checkSum, data, Listen, Transfer, dataSize, memAddr, loadFile, flagAddr, levelId + + # Flush serial buffers to avoid residual data + + ser.reset_input_buffer() + + ser.reset_output_buffer() + + inputBuffer = "" + + # Listen to incomming connections on serial + + if Listen: + + print("Listening for incoming data...") + + if DEBUG > 1: + + print("memAddr : " + str(memAddr) + " - loadFile" + loadFile ) + + while True: + + # If data on serial, fill buffer + + while ser.in_waiting: + + inputBuffer += ser.read().decode('ascii') + + if inputBuffer: + + if DEBUG: + + print( "Incoming data : " + inputBuffer ) + + # parse command CMD:ARG1:ARG2(:ARGn) + + argList = [] + + argList = inputBuffer.split(':') + + # Send command + + if argList[0] == "load" and len(argList) == 4: + + if len(argList[1]) < 8 or len(argList[2]) < 8: + + if DEBUG: + + print("Wrong data format, aborting...") + + break + + memAddr = argList[1] + + flagAddr = argList[2] + + loadFile = argList[3] + + ser.reset_input_buffer() + + inputBuffer = "" + + if DEBUG > 1: + + print( memAddr + " - " + flagAddr + " - " + loadFile ) + + Listen = 0 + + break + + else: + + ser.reset_input_buffer() + + inputBuffer = "" + + break + + if memAddr and loadFile: + + # Remove separator and ';1' at end of the string + + # ~ fileClean = loadFile.split(';')[0][1:] + fileID = loadFile + + print("Received addresses and file ID : " + memAddr + " - " + flagAddr + " - " + fileID) + + # TODO : replace with a proper level naming scheme + # right now, we're receiving currently loaded file + # so we have to switch manually here. + + binFileName = "" + + if fileID == "0": + + binFileName = overlayFile1 + + levelId = 1 + + if fileID == "1": + + binFileName = overlayFile0 + + levelId = 0 + + if DEBUG: + + print( + + "Load Data to : " + memAddr + "\n" + + + "Reset flag at: " + flagAddr + "\n" + + + "File : " + loadFile + "\n" + + + "Bin : " + binFileName + " - ID : " + str(levelId) + + ) + + # Open file as binary if bin filename is defined + + if binFileName: + + binFile = open( dataFolder + binFileName, 'rb' ) + + data = binFile.read() + + Transfer = 1 + + else: + + print(" No filename provided, doing nothing ") + + resetListener() + + # If Init was set, initialize transfer and send data + + if Transfer: + + print("Initializing data transfer...") + + if not uniDebugMode: + + # Set unirom to debugmode - sent : "DEBG" - received : "DEBGOKAY" + + setDEBG() + + # Send level data + + SendBin( data, memAddr ) + + # Set level changed flag + + if DEBUG: + + print("Sending value " + str( levelId.to_bytes(1, byteorder='little', signed=False) ) + " to " + flagAddr ) + + time.sleep( sleepTime ) + + SendBin( levelId.to_bytes(1, byteorder='little', signed=False) , flagAddr) + + # Reset everything + + resetListener() + + print("DONE!") + + return 0 + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) diff --git a/ovl.gif b/ovl.gif new file mode 100644 index 0000000..b91f414 Binary files /dev/null and b/ovl.gif differ diff --git a/ovly-upload-helper.sh b/ovly-upload-helper.sh new file mode 100755 index 0000000..1aabf82 --- /dev/null +++ b/ovly-upload-helper.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +nops /debug $4 + +nops /fast /bin $1 $2 $4 + +nops /fast /exe $3 $4 + +nops /slow $4 diff --git a/tritex.c b/tritex.c new file mode 100644 index 0000000..f870fa8 --- /dev/null +++ b/tritex.c @@ -0,0 +1,84 @@ +#include "tritex.h" + +SVECTOR modelTri_mesh[] = { + { 0,20,0 }, + { 20,-20,20 }, + { 20,-20,-20 }, + { -20,-20,-20 }, + { -20,-20,20 } +}; + +SVECTOR modelTri_normal[] = { + 0,-4096,0, 0, + -2714,1430,-2714, 0, + -2714,1430,2714, 0, + 2714,1430,2714, 0, + 2714,1430,-2714, 0 +}; + +SVECTOR modelTri_uv[] = { + 125,84, 0, 0, + 84,125, 0, 0, + 125,125, 0, 0, + 42,84, 0, 0, + 1,42, 0, 0, + 1,84, 0, 0, + 125,84, 0, 0, + 84,84, 0, 0, + 84,125, 0, 0, + 1,84, 0, 0, + 1,125, 0, 0, + 42,125, 0, 0, + 42,125, 0, 0, + 84,125, 0, 0, + 84,84, 0, 0, + 42,1, 0, 0, + 1,1, 0, 0, + 1,42, 0, 0 +}; + +CVECTOR modelTri_color[] = { + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,255,255, 0, + 255,255,255, 0, + 254,255,94, 0, + 255,255,255, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,5,7, 0, + 255,255,255, 0, + 255,255,255, 0, + 254,255,23, 0, + 255,255,255, 0, + 122,255,107, 0 +}; + +int modelTri_index[18] = { + 4,2,1, + 0,4,1, + 4,3,2, + 1,2,0, + 2,3,0, + 0,3,4 +}; + +TMESH modelTri = { + modelTri_mesh, + modelTri_normal, + modelTri_uv, + modelTri_color, + 6 +}; + +MESH Tri = { + + &modelTri, + + modelTri_index + + }; diff --git a/tritex.h b/tritex.h new file mode 100644 index 0000000..8b78966 --- /dev/null +++ b/tritex.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +#ifndef custom_types + +typedef struct MESH { + + TMESH * tmesh; + + int * index; + + } MESH; + +#define custom_types + +#endif + +extern SVECTOR modelTri_mesh[8]; + +extern SVECTOR modelTri_normal[36]; + +extern SVECTOR modelTri_uv[144]; + +extern CVECTOR modelTri_color[144]; + +extern int modelTri_index[]; + +extern TMESH modelTri; + +extern MESH Tri;