// Tab stops = 4 spaces #include "syscall.h" typedef signed char PsxInt8; typedef unsigned char PsxUInt8; typedef signed short PsxInt16; typedef unsigned short PsxUInt16; typedef signed int PsxInt32; typedef unsigned int PsxUInt32; typedef char bool; #define true 1 #define false 0 #include "fontdata.h" /*PsxUInt16 clut[] = { 0x0000, 0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff, 0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff,0x7fff}; */ #define SPR_X 512 void loadfont(); void nop(); bool p2gpucommand(PsxUInt32*x, PsxUInt32*y, char c, bool* bQuit, PsxUInt32 x0); void WaitGPU(); void Clear_(void) { } void gpuInit(void) { SendGPU(0); /* Some kind of reset ? */ Clear_(); SendGPU(0x05000000); /* Display offset */ WaitGPU(); SendGPU(0x03000000); /* Display Mask (enable display) */ Clear_(); SendGPU(0x06c60260); /* Screen horizontal start/end (0/256) */ Clear_(); SendGPU(0x07040010); /* Screen vertical start/end (0/240) */ Clear_(); SendGPU(0x08000000); /* Display mode, 256x240/NTSC/noninterlaced */ Clear_(); GPU_cw(0xe10006cf); /* Draw on display area / dither on / texture page */ Clear_(); //0xe10006cf GPU_cw(0xe3000000); /* Draw Area x, y (0,0) */ Clear_(); GPU_cw(0xe407429f); /* Draw Area w, h (...,...) */ // GPU_cw(0xe407ffff); /* Draw Area w, h (1023,511) */ Clear_(); GPU_cw(0xe5000000); /* Draw Offset (0,0) */ Clear_(); } void loadfont() { int i; WaitGPU(); mem2vram(SPR_X,0,256,64,(long*)fontdata); // WaitGPU(); // mem2vram(0, 0x01ff, 0x0010, 0x0001, (long*)clut); // For some bizzare reason, we have to send a bunch of commands (anything) // before anything else will be recognized after a mem2vram... // Spent the better part of 10 hrs trying odd things because this was // misbehaving... // for (i=0; i<16; i++) GPU_cw(0); } // Does nothing, just takes a cpu cycle or two void nop() { } /* Verbosely displays the current graphics status. Calls GetGPUStatus() and interprets. Author : Jimb Esser */ void DisplayStatus() { PsxUInt32 s = GetGPUStatus(); PsxUInt32 t; printf("Status : 0x%X :\n", s); t = s & 0xf; printf(" Texture Page: x:%d y:%d ", t*64, (s&0x10)?256:0); s = s >> 5; printf("abr: %d ", s&0x3); s = s>>2; printf("texpage : "); switch (s & 0x3) { case 0: printf("4bit CLUT"); break; case 1: printf("8bit CLUT"); break; case 2: printf("15bit"); break; } s = s >> 2; printf(" dither: %s\n", (s&1)?"on":"off"); s = s >> 1; printf(" draw2display: %s", (s&1)?"on":"off"); s = s >> 1; printf(" applymask: %s", (s&1)?"on":"off"); s = s >> 1; printf(" nodraw2mask: %s\n", (s&1)?"on":"off"); s = s >> 1; s = s >> 3; // unused bits; if (s&1) { printf(" 384x"); } else { switch ((s >> 1)&3) { case 0: printf(" 256x"); break; case 1: printf(" 320x"); break; case 2: printf(" 512x"); break; case 3: printf(" 640x"); break; } } s = s >> 3; printf("%d ", (s&1)?480:240); s = s >> 1; printf("%s ", (s&1)?"PAL":"NTSC"); s = s >> 1; printf("%s ", (s&1)?"24bit":"15bit"); s = s >> 1; printf("Interlace %s, ", (s&1)?"on":"off"); s = s >> 1; printf("Display %s, ", (s&1)?"off":"on"); s = s >> 1; s = s >> 2; // Unused bits printf("GPU %s, ", (s&1)?"idle":"busy"); s = s >> 1; printf("img %s,\n", (s&1)?"ready":"not ready"); s = s >> 1; printf("Command %s, ", (s&1)?"ready":"not ready"); s = s >> 1; printf("DMA: "); switch (s&3) { case 0: printf("off"); break; case 1: printf("unknown"); break; case 2: printf("CPU->GPU"); break; case 3: printf("GPU->CPU"); break; } s = s >> 2; printf(", drawing %s\n", (s&1)?"odd":"even"); s = s >> 1; } /* Waits for the Command Ready bit of the GPU status to be flagged */ void WaitGPU() { PsxUInt32 v1=0; while (v1==0) { v1 = GetGPUStatus(); v1 = v1 & 0x10000000; } } /* Prints characters using the font loaded with loadfont() listed above by drawing 2 8x8 sprites for each 8x16 text character. Author: Jimb Esser Original Code: doomed@c64.org|psx.rules.org */ void printGPU(char *s, PsxUInt32 x, PsxUInt32 y, PsxInt32 color) { char *c = s; bool bContinueLooping; bool bNext; PsxUInt32 x0 = x; PsxUInt32 y0 = y; PsxUInt32 command, param1, param2; PsxUInt32 u, v; // Texture coords PsxUInt32 clut = 0; // Color LookUp Table (not used) SendGPU(0x04000000); // DMA transfer off command WaitGPU(); GPU_cw(0xe1000700 | (SPR_X >> 6)); // Draw mode settings - pass in address of texture page DisplayStatus(); // Start assembling the command to send to the GPU. // Type $74 is an 8x8 sprite // Take the color as the second half command = 0x74 << 24 | color; // command characters if (*c < 0x20) { p2gpucommand(&x, &y, *c, &bContinueLooping, x0); } bContinueLooping=true; while (bContinueLooping) { // find texture coords // get loworder 5 bits * 8 // same as u = *c % 32 (32 chars per line in the font texture) u = (*c & 0x001f) << 3; // get highorder 3 bits * 16 // same as u = *c / 32 (32 chars per line in the font texture) v = *c>>5; v = v<<4; // Top half of the letter param2 = (v << 8) | u | clut; // Combine them all into a command parameter // Output X,Y coords param1 = (y << 16) | x; // Wait for the GPU to be ready, and then send commands WaitGPU(); GPU_cw(command); GPU_cw(param1); GPU_cw(param2); // printf("sent %X,%X,%X\n", t1, t8, t9); // Bottom half of the letter // Texture coords param2 = ((v+8) << 8) | u | clut; // Combine them all into a command parameter // Output X,Y coords param1 = ((y+8) << 16) | x; WaitGPU(); GPU_cw(command); GPU_cw(param1); GPU_cw(param2); // For a proportional font, we'd feed the width here x = x + 8; // Grab the next character bNext=true; while (bNext) { bNext=false; c++; if (*c < 20) { bNext = p2gpucommand(&x, &y, *c, &bContinueLooping, x0); } } } // while (continuelooping) } bool p2gpucommand(PsxUInt32*x, PsxUInt32*y, char c, bool* bQuit, PsxUInt32 x0) { if (c==0) { *bQuit=false; return false; } // Linefeed if (c==0x0a) { *y = *y + 0x10; return true; } // Carriage return if (c==0x0d) { *x = x0; return true; } return true; } int main(int argc,char **argv) { int i; char s[255] = "Testing\r\n some text"; char s2[255] = "In different\r\n colors!"; long t[3] = {0x7C2F8F8F, 0x00200020, 0x7FC02020}; gpuInit(); loadfont(); printGPU(s, 0x20, 0x20, 0x00ffffff); printGPU(s2, 0x20, 0x80, 0x007f2fff); printf("Done.\n"); while (1); }