diff options
| author | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
|---|---|---|
| committer | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
| commit | 7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch) | |
| tree | c28d0748652ad4b4222309e46e6cfc82c0906220 /examples/mandel | |
| parent | a2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff) | |
| download | psxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz | |
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'examples/mandel')
| -rw-r--r-- | examples/mandel/Makefile | 7 | ||||
| -rw-r--r-- | examples/mandel/mandel.c | 347 |
2 files changed, 354 insertions, 0 deletions
diff --git a/examples/mandel/Makefile b/examples/mandel/Makefile new file mode 100644 index 0000000..74759a0 --- /dev/null +++ b/examples/mandel/Makefile @@ -0,0 +1,7 @@ +PROJNAME = mandel + +include ../project.mk + +$(PROJNAME)_extra: + +$(PROJNAME)_clean_extra: diff --git a/examples/mandel/mandel.c b/examples/mandel/mandel.c new file mode 100644 index 0000000..77eda4e --- /dev/null +++ b/examples/mandel/mandel.c @@ -0,0 +1,347 @@ +/* + * Simple fractal generator for the PlayStation + * + * by Giuseppe Gatta + * Placed in the Public Domain. + * + * Consider enabling compiler optimizations, for instance this code is much faster + * if you add -O3 to the gcc command line. + * + * The fractals are rendered at a 160x120 resolution in an array in memory, + * then this array is uploaded to video memory and handled as 8-bit image data. + * We render at 160x120 to speed rendering up because the PlayStation is a slow machine + * for doing this kind of thing. + * + * A sprite primitive is used to display the image data on the screen, and the primitive + * is scaled twice horizontally and vertically to cover the 320x240 screen with a 160x120 + * image. + * + * The fractal drawing code by default also exploits the simmetry of the Mandrelbot + * and Tricorn sets to further speed rendering up (2x). To have a real rendering of + * the Burning Ship fractal, though, you must disable simmetry because that fractal + * does not have this property. + * + * This is the description of the controls of this program: + * + * SELECT - Toggle palette (Red->Green->Blue->Yellow->Violet->Red->...) + * START - Render fractal + * X - Toggle type of fractal to render (Mandelbrot->Tricorn->Burning Ship->Mandelbrot->...) + * O - Toggle simmetry (on the screen as 'S') + * LEFT - Decrease multibrot power (displayed on the screen as 'M') + * RIGHT - Increase multibrot power + * UP - Decrease number of maximum iterations (on the screen as 'I') + * DOWN - Increase number of maximum iterations + */ + +#include <psx.h> +#include <stdio.h> + +unsigned char fractal_image_data[120][160]; +unsigned int prim_list[0x4000]; +unsigned short clut_buf[256]; + +volatile int frac_x=0, frac_y=0; + +enum +{ + FRAC_MANDELBROT, // Normal mandelbrot + FRAC_TRICORN, + FRAC_BSHIP, + FRAC_TF, + + FRAC_NOSIMM = 0x200, +}; + +/* + * Code based on http://reocities.com/CapeCanaveral/5003/mandel.htm + */ + +void mandrelbrot_int(int width, int height, int maxI, int type, int M) +{ + #define FIXSIZE 25 + #define mul(a,b) ((((long long)a)*(b))>>FIXSIZE) + #define fixpt(a) ((int)(((a)*(1<<FIXSIZE)))) + #define integer(a) (((a)+(1<<(FIXSIZE-1)))>>FIXSIZE) + + int x0,y0,x1,y1,p,q,xn; + double xmin=-2.5,ymin=-1.5,xmax=1.5,ymax=1.5,xs,ys; + int i,x,y,t; + int m; + + xs=(xmax-xmin)/width; + ys=(ymax-ymin)/height; + + t = type & 0xff; + + for (y=0;y<((type&FRAC_NOSIMM)?height:(height/2));y++) + { + for (x=0;x<width;x++) + { + p=fixpt(xmin+x*xs); // c_re + q=fixpt(ymin+y*ys); + xn=0; + x0=0; + y0=0; + i=0; + + while ((mul(xn,xn)+mul(y0,y0))<fixpt(4) && ++i<maxI) + { + switch(t) + { + case FRAC_BSHIP: + if(x0<0)x0=-x0; + if(y0<0)y0=-y0; + break; + case FRAC_TRICORN: + y0=-y0; + break; + } + + x1=x0; + y1=y0; + + for(m=1;m<M;m++) + { + xn=mul(x0,x1) - mul(y0,y1); + y0=mul(y0,x1) + mul(x0,y1); + x0=xn; + } + + x0=xn; + x0+=p; + y0+=q; + } + + if (i==maxI) i=1; + fractal_image_data[y][x] = (i*256)/maxI; + + if(!(type & FRAC_NOSIMM)) + fractal_image_data[(height-1)-y][x] = (i*256)/maxI; + } + } +} + +volatile int display_is_old = 1; +volatile int time_counter = 0; + +void prog_vblank_handler() +{ + display_is_old = 1; + time_counter++; +} + +int frac_type = FRAC_MANDELBROT; +unsigned int frac_maxI = 64; +int frac_M=2; + +const char *frac_type_string[] = + { "Mandelbrot", + "Tricorn", + "BurningShip"}; + +GsSprite frac_sprite; + +int main() +{ + int x, dbuf=0; + + int waspal=0; + int wastype=0; + int wasrender=0; + int wassimm=0; + int wasMm=0,wasMp=0, wasIm=0, wasIp=0; + int rendering_time = -1; + + unsigned short padbuf; + + PSX_InitEx(PSX_INIT_CD); + + GsInit(); + GsSetList(prim_list); + GsClearMem(); + GsSetVideoMode(320, 240, EXAMPLES_VMODE); + GsLoadFont(768, 0, 768, 256); + SetVBlankHandler(prog_vblank_handler); + +// Fill & upload CLUTs + +// Red CLUT + for(x = 0; x < 256; x++) + clut_buf[x] = ((x*4)>255?255:x*4)>>3; + + LoadImage(clut_buf, 512, 256, 256, 1); + while(GsIsDrawing()); + +// Green CLUT + for(x = 0; x < 256; x++) + clut_buf[x] = (((x*4)>255?255:x*4)>>3)<<5; + + LoadImage(clut_buf, 512, 257, 256, 1); + while(GsIsDrawing()); + +// Blue CLUT + for(x = 0; x < 256; x++) + clut_buf[x] = (((x*4)>255?255:x*4)>>3)<<10; + + LoadImage(clut_buf, 512, 258, 256, 1); + while(GsIsDrawing()); + + +// Yellow CLUT + for(x = 0; x < 256; x++) + { + clut_buf[x] = ((x*4)>255?255:x*4)>>3; + clut_buf[x]|= clut_buf[x]<<5; + } + + LoadImage(clut_buf, 512, 259, 256, 1); + while(GsIsDrawing()); + +// Violet CLUT + for(x = 0; x < 256; x++) + { + clut_buf[x] = ((x*4)>255?255:x*4)>>3; + clut_buf[x]|= clut_buf[x]<<10; + } + + LoadImage(clut_buf, 512, 260, 256, 1); + while(GsIsDrawing()); + + frac_sprite.tpage = 5; + frac_sprite.attribute = COLORMODE(COLORMODE_8BPP); + frac_sprite.u = 0; + frac_sprite.v = 0; + frac_sprite.cx = 512; + frac_sprite.cy = 256; + frac_sprite.x = 0; + frac_sprite.y = 0; + frac_sprite.w = 160; + frac_sprite.h = 120; + frac_sprite.r = frac_sprite.g = frac_sprite.b = NORMAL_LUMINOSITY; + frac_sprite.scalex = SCALE_ONE*2; + frac_sprite.scaley = SCALE_ONE*2; + + time_counter = 0; + mandrelbrot_int(160, 120, frac_maxI, frac_type, frac_M); + rendering_time = time_counter * (GsScreenM==VMODE_NTSC?17:20); + LoadImage(fractal_image_data, 320, 0, 80, 120); + while(GsIsDrawing()); + + while(1) + { + if(display_is_old) + { + dbuf=!dbuf; + GsSetDispEnvSimple(0, dbuf?0:256); + GsSetDrawEnvSimple(0, dbuf?256:0, 320, 240); + + GsSortCls(0,0,0); + GsSortSprite(&frac_sprite); + + GsPrintFont(0, 0, "Type: %s", frac_type_string[(frac_type&0xff)]); + GsPrintFont(0, 8, "I=%d, M=%d, S=%c", frac_maxI, frac_M, + frac_type&FRAC_NOSIMM?'N':'Y'); + GsPrintFont(0, 16, "Time: %d.%03d", rendering_time / 1000, rendering_time % 1000); + + GsDrawList(); + while(GsIsDrawing()); + + PSX_ReadPad(&padbuf, NULL); + + if((padbuf & PAD_SELECT) && !waspal) + { + frac_sprite.cy++; + if(frac_sprite.cy>260) + frac_sprite.cy = 256; + + waspal=1; + } + + if((padbuf & PAD_CROSS) && !wastype) + { + frac_type++; + if((frac_type & 0xff) >= FRAC_TF) + frac_type&=~0xff; + + wastype=1; + } + + if((padbuf & PAD_START) && !wasrender) + { + GsPrintFont(0, 224, "Rendering..."); + GsDrawList(); + while(GsIsDrawing()); + + dbuf=!dbuf; + GsSetDispEnvSimple(0, dbuf?0:256); + GsSetDrawEnvSimple(0, dbuf?256:0, 320, 240); + + time_counter = 0; + mandrelbrot_int(160, 120, frac_maxI, frac_type, frac_M); + rendering_time = time_counter * (GsScreenM==VMODE_NTSC?17:20); + LoadImage(fractal_image_data, 320, 0, 80, 120); + while(GsIsDrawing()); + + wasrender=1; + } + + if((padbuf & PAD_CIRCLE) && !wassimm) + { + frac_type ^= FRAC_NOSIMM; + wassimm=1; + } + + if((padbuf & PAD_LEFT) && !wasMm) + { + if(frac_M>2)frac_M--; + wasMm=1; + } + + if((padbuf & PAD_RIGHT) && !wasMp) + { + frac_M++; + wasMp=1; + } + + if((padbuf & PAD_UP) && !wasIm) + { + if(frac_maxI>1)frac_maxI--; + wasIm=1; + } + + if((padbuf & PAD_DOWN) && !wasIp) + { + frac_maxI++; + wasIp=1; + } + + if(!(padbuf & PAD_SELECT)) + waspal=0; + + if(!(padbuf & PAD_CROSS)) + wastype=0; + + if(!(padbuf & PAD_START)) + wasrender=0; + + if(!(padbuf & PAD_CIRCLE)) + wassimm=0; + + if(!(padbuf & PAD_LEFT)) + wasMm=0; + + if(!(padbuf & PAD_RIGHT)) + wasMp=0; + + if(!(padbuf & PAD_UP)) + wasIm=0; + + if(!(padbuf & PAD_DOWN)) + wasIp=0; + + display_is_old=0; + } + } + + return 0; +} |
