summaryrefslogtreecommitdiff
path: root/examples/mandel
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /examples/mandel
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'examples/mandel')
-rw-r--r--examples/mandel/Makefile7
-rw-r--r--examples/mandel/mandel.c347
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;
+}