Omnimaga

Calculator Community => Casio Calculators => Topic started by: Xeda112358 on July 01, 2013, 11:34:31 am

Title: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on July 01, 2013, 11:34:31 am
This is my first working Prizm C program and it is much faster and prettier than my BASIC version. As the title implies, this draws the Mandelbrot set and currently does not do much. You have to wait for it to draw the whole thing and it isn't very fast (it takes about 1 minute 15 seconds to render), but once it is done it looks cool:
(https://lh3.googleusercontent.com/-hZe0H6FVNbs/UdGdl7LTDLI/AAAAAAAAAKw/uqJnufYIgss/w384-h216-no/Mandelbrot_Prizm.png)
Press [MENU] to exit.

I really don't suggest downloading it since all it amounts to is what you see in the still screenshot. My plan is to make an explorer and see if I can possibly make it faster, but I thought I would share with anybody that is curious. Also, the code:
Code: [Select]
#include <fxcg/display.h>
#include <fxcg/keyboard.h>
void plot(int x0, int y0, int color) {
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(y0*LCD_WIDTH_PX + x0);
   *(VRAM++) = (color&0x0000FF00)>>8;
   *(VRAM++) = (color&0x000000FF);
   return;
}
int main() {
  Bdisp_AllCr_VRAM();
  Bdisp_EnableColor(1);
  double CxMin=-2.0;
  double CyMax=1.5;
  double delta=3.0/192;
  double Zy2,Zx2,Zy,Zx,Cx,Cy;
  int x,y,iter,a,itermax=50;
  Cx=CxMin;
  for(x=0;x<384;x++)
  {
    Cy=CyMax;
    for(y=0;y<192;y++)
    {
      Zx=Cx;
      Zy=Cy;
      Zx2=Cx*Cx;
      Zy2=Cy*Cy;
      for(iter=0;iter<itermax && ((Zx2+Zy2)<=4);iter++)
      {
        Zy=2*Zx*Zy +Cy;
        Zx=Zx2-Zy2 +Cx;
        Zx2=Zx*Zx;
        Zy2=Zy*Zy;
      }
      a=iter-itermax;
      a=2048*(a%32) + 32*(a % 64) + (a % 32);
      plot(x,y+32,a);
      Cy-=delta;
    }
  Cx+=delta;
  Bdisp_PutDisp_DD();
  }

  int key;
  while(1)
  GetKey(&key);
  return 0;
}

I also have no Icon made yet x.x
Title: Re: [Prizm C] Mandelbrot Set
Post by: DJ Omnimaga on July 03, 2013, 11:23:59 pm
I like it so far. :D Do you plan to get more into PRIZM dev in the near future such as porting some games you made? :D

*cough*cgGrammer*cough*
Title: Re: [Prizm C] Mandelbrot Set
Post by: mlytle0 on July 04, 2013, 12:32:32 am
Very Cool!
Title: Re: [Prizm C] Mandelbrot Set
Post by: tr1p1ea on July 04, 2013, 01:09:58 am
*cough*84C*cough*
Title: Re: [Prizm C] Mandelbrot Set
Post by: Sorunome on July 04, 2013, 05:13:35 am
Ui, this is looking nice!
And I also go with tr1p's opinion :P
Title: Re: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on July 04, 2013, 06:38:05 am
I don't have an 84C yet, but I have been thinking about writing a language similar to Grammer for the Prizm :) I make no promises, though :P
Title: Re: [Prizm C] Mandelbrot Set
Post by: DJ Omnimaga on July 04, 2013, 09:44:40 am
84C would definitively be much slower, though (although you could do like tr1p1ea and only use half of the screen in stretched mode), since it's 15 MHz, while the PRIZM can go up to 94.3 MHz using Overclui.
Title: Re: [Prizm C] Mandelbrot Set
Post by: flyingfisch on July 28, 2013, 01:08:52 pm
I did this in LuaZM once... was very slow. How fast does yours render?
Title: Re: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on July 28, 2013, 01:16:17 pm
It took 46 seconds at 94.3MHz, but about 75 seconds at normal speed.
Title: Re: [Prizm C] Mandelbrot Set
Post by: flyingfisch on July 28, 2013, 01:18:19 pm
It took 46 seconds at 94.3MHz, but about 75 seconds at normal speed.

Not bad. My (unoptimized, messily coded, first attempt) LuaZM Mandelbrot generator took about a minute to make a very low-res set. The "pixels" were 4x4px :P

Good learning experience though.


EDIT:
http://www.cemetech.net/forum/viewtopic.php?t=8917&start=0
Title: Re: [Prizm C] Mandelbrot Set
Post by: Adriweb on July 28, 2013, 01:58:29 pm
Eh, this reminds me of :



:P
Title: Re: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on July 28, 2013, 10:36:27 pm
Oh my gosh, I totally want to learn enough ARM assembly to do that on my NSpire o.o
Title: Re: [Prizm C] Mandelbrot Set
Post by: DJ Omnimaga on July 28, 2013, 10:52:59 pm
I am curious about how fast this would be in computer Lua on a 150 MHz computer with 64 MB of RAM compared to the Lua TI gave us.
Title: Re: [Prizm C] Mandelbrot Set
Post by: ProgrammerNerd on September 22, 2013, 10:03:22 am
This topic reminded me of a program that I wrote awhile ago for the casio prizm. It takes less than a second in my program to do a mandelbrot. I actully wrote it about 6 months ago maybe more don't remeber. I did not spend too much time on it so there is much work needed to be done. I am working on improving it right now.
Here is a video

And the source code.
Code: [Select]
#include <display_syscalls.h>
#include <keyboard_syscalls.h>
#include <keyboard.hpp>
#include <color.h>
#include <display.h>//display is 384x216
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef int fixed_t;
static fixed_t divX;
static fixed_t addX;
static fixed_t divY;
static fixed_t addY;
static fixed_t stepX;
static fixed_t stepY;
#define preMan 13
static fixed_t scaleM[4] = {-2<<preMan,1<<preMan,-1<<preMan,1<<preMan};
const unsigned short* keyboard_register = (unsigned short*)0xA44B0000;
unsigned short lastkey[8];
unsigned short holdkey[8];
void keyupdate(void) {
memcpy(holdkey, lastkey, sizeof(unsigned short)*8);
memcpy(lastkey, keyboard_register, sizeof(unsigned short)*8);
}
int keydownlast(int basic_keycode){
int row, col, word, bit;
row = basic_keycode%10;
col = basic_keycode/10-1;
word = row>>1;
bit = col + 8*(row&1);
return (0 != (lastkey[word] & 1<<bit));
}
int keydownhold(int basic_keycode){
int row, col, word, bit;
row = basic_keycode%10;
col = basic_keycode/10-1;
word = row>>1;
bit = col + 8*(row&1);
return (0 != (holdkey[word] & 1<<bit));
}
inline fixed_t abs(fixed_t val){
if (val < 0)
val*=-1;
return val;
}
inline void plotMan(fixed_t x,fixed_t y,uint16_t col){
uint16_t * vramAd=(uint16_t *)0xA8000000;
x+=addX;
x=x*384/divX;
y+=addY;
y=y*216/divY;
vramAd+=(y*384)+x;
*vramAd=col;
}
inline fixed_t square(fixed_t x){
return x*x;
}
void setScale(fixed_t * scale){//format minx maxx miny maxy
divX=abs(scale[0]-scale[1]);
divY=abs(scale[2]-scale[3]);
addX=scale[0]*-1;
addY=scale[2]*-1;
stepX=divX/384;
stepY=divY/216;
}
uint16_t ManIt(fixed_t c_r,fixed_t c_i,uint16_t maxit){//manIt stands for mandelbrot iteration what did you think it stood for?
//c_r = scaled x coordinate of pixel (must be scaled to lie somewhere in the mandelbrot X scale (-2.5, 1)
//c_i = scaled y coordinate of pixel (must be scaled to lie somewhere in the mandelbrot Y scale (-1, 1)
// squre optimaztion code below orgionally from http://randomascii.wordpress.com/2011/08/13/faster-fractals-through-algebra/
//early bailout code from http://locklessinc.com/articles/mandelbrot/
//changed by me to use fixed point math
fixed_t ckr,cki;
unsigned p=0,ptot=8;
fixed_t z_r = c_r;
fixed_t z_i = c_i;
fixed_t zrsqr = (z_r * z_r)>>preMan;
fixed_t zisqr = (z_i * z_i)>>preMan;
//int zrsqr,zisqr;
do{
ckr = z_r;
cki = z_i;
ptot += ptot;
if (ptot > maxit) ptot = maxit;
for (; p < ptot;++p){
z_i =(square(z_r+z_i)>>preMan)-zrsqr-zisqr;
z_i += c_i;
z_r = zrsqr-zisqr+c_r;
zrsqr = (z_r*z_r)>>preMan;
zisqr = (z_i*z_i)>>preMan;
if ((zrsqr + zisqr) > (4<<preMan))
return p*0xFFFF/maxit;
if ((z_r == ckr) && (z_i == cki))
return 0xFFFF;
}
} while (ptot != maxit);
//plotMan(x0,y0,(uint32_t)iteration*(uint32_t)0xFFFF/(uint32_t)maxit);
//return (uint32_t)p*(uint32_t)0xFFFF/(uint32_t)maxit;
return 0xFFFF;
}
void mandel(uint16_t maxit){
fixed_t x,y;
uint16_t xx;
uint16_t * vramAd=(uint16_t *)0xA8000000;
for (y=scaleM[2];y<scaleM[3];y+=stepY){
xx=0;
for (x=scaleM[0];x<scaleM[1];x+=stepX){
if (xx > 400)
return;
*vramAd++=ManIt(x,y,maxit);
xx++;
}
vramAd+=384-xx;
}
Bdisp_PutDisp_DD();
}
void mandel4(uint16_t maxit){
static uint16_t temp[100];
fixed_t x,y;
uint16_t xx;
uint8_t yy,z;
uint16_t * vramAd=(uint16_t *)0xA8000000;
for (y=scaleM[2];y<scaleM[3];y+=stepY*4){
xx=0;
for (x=scaleM[0];x<scaleM[1];x+=stepX*4){
if (xx > 96)
return;
temp[xx]=ManIt(x,y,maxit);
xx++;
}
for (yy=0;yy<4;++yy){
for (x=0;x<96;++x){
*vramAd++=temp[x];
*vramAd++=temp[x];
*vramAd++=temp[x];
*vramAd++=temp[x];
}
}
// vramAd+=384-xx;
// vramAd+=384*15;
}
Bdisp_PutDisp_DD();
}
/*int PRGM_GetKey(void)
{
  unsigned char buffer[12];
  PRGM_GetKey_OS( buffer );
  return ( buffer[1] & 0x0F ) * 10 + ( ( buffer[2] & 0xF0 ) >> 4 );
}*/
void main(void) {
Bdisp_EnableColor(1);
Bdisp_AllClr_VRAM();
setScale(scaleM);
uint16_t z=31;
mandel(z);
uint8_t redraw=1;
//uint16_t z=28;//good values for z 28 31 36 41 42 31 is my favoirte so far
do{
keyupdate();
if (keydownlast(KEY_PRGM_F1) && keydownhold(KEY_PRGM_F1)){
z=0xFFFF;
redraw=2;
}
if (keydownlast(KEY_PRGM_F2) && keydownhold(KEY_PRGM_F2)){
z=31;
redraw=2;
}
if (keydownlast(KEY_PRGM_1) && keydownhold(KEY_PRGM_1)){
z--;
redraw=2;
}
if (keydownlast(KEY_PRGM_2) && keydownhold(KEY_PRGM_2)){
z++;
redraw=2;
}
if (keydownlast(KEY_PRGM_SHIFT) && keydownhold(KEY_PRGM_SHIFT)){
scaleM[0]+=256;
scaleM[1]-=256;
scaleM[2]+=144;
scaleM[3]-=144;
setScale(scaleM);
redraw=2;
}
if (keydownlast(KEY_PRGM_ALPHA) && keydownhold(KEY_PRGM_ALPHA)){
scaleM[0]-=256;
scaleM[1]+=256;
scaleM[2]-=144;
scaleM[3]+=144;
setScale(scaleM);
redraw=2;
}
if (keydownlast(KEY_PRGM_UP) && keydownhold(KEY_PRGM_UP)){
scaleM[2]-=144;
scaleM[3]-=144;
setScale(scaleM);
redraw=2;
}
if (keydownlast(KEY_PRGM_DOWN) && keydownhold(KEY_PRGM_DOWN))
{
scaleM[2]+=144;
scaleM[3]+=144;
setScale(scaleM);
redraw=2;
}
if (keydownlast(KEY_PRGM_LEFT) && keydownhold(KEY_PRGM_LEFT)){
scaleM[0]-=256;
scaleM[1]-=256;
setScale(scaleM);
redraw=2;
}
if (keydownlast(KEY_PRGM_RIGHT) && keydownhold(KEY_PRGM_RIGHT)){
scaleM[0]+=256;
scaleM[1]+=256;
setScale(scaleM);
redraw=2;
}
if (redraw == 1){
mandel(z);
redraw=0;
}
else if (redraw == 2){
mandel4(z);
redraw=1;
}
} while (!(keydownlast(KEY_PRGM_EXIT) && keydownhold(KEY_PRGM_EXIT)));
//MsgBoxPop();
return;
}
Title: Re: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on September 23, 2013, 02:55:18 pm
Wow, that looks wonderful! That is pretty similar to the explorer I made in Axe for the TI-84+ calcs (except that scrolling didn't make the image fuzzy). When zooming in, it would zoom in x2 by scaling up the image first and then redraw the image with better accuracy while the user wasn't doing anything.

:thumbsup:
Title: Re: [Prizm C] Mandelbrot Set
Post by: DJ Omnimaga on September 24, 2013, 12:53:31 am
Darn that renders quite fast too!
Title: Re: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on September 24, 2013, 09:37:37 am
I haven't gotten to look at the code much, but I imagine that it is the difference between using integer or fixed point math and floating point.
Title: Re: [Prizm C] Mandelbrot Set
Post by: ProgrammerNerd on September 25, 2013, 02:13:31 pm
Yes fixed point math is part of the speedup however I would like you to take note of the comments in the function called ManIt() as you can see I credited the websites http://locklessinc.com/articles/mandelbrot/ and https://randomascii.wordpress.com/2011/08/13/faster-fractals-through-algebra/
The first website contains some nice "early exit" code which speeds things up a lot.
The second website contains some code to reduce the amount of multiplications needed. There are still some optimizations that I don't take advantage of such as the fact that 1/4 of the pixels are already calculated and don't need to be redrawn again. I already fixed that but there is still lots more work to be done before the next release.
Also Xeda112358 what is up with your plot function?
Code: [Select]
void plot(int x0, int y0, int color) {
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(y0*LCD_WIDTH_PX + x0);
   *(VRAM++) = (color&0x0000FF00)>>8;
   *(VRAM++) = (color&0x000000FF);
   return;
}
Should be
Code: [Select]
inline void plot(unsigned short x0, unsigned short y0, unsigned short color) {
   unsigned short* VRAM = (unsigned short*)0xA8000000;
   VRAM += (y0*LCD_WIDTH_PX) + x0;
   *VRAM = color;
}
Not tested but should work. I access VRAM as unsigned short in my program and it draws just fine. The reason for the change is because your function seems kind of inefficient not to cause offense but just giving optimization tips.
Title: Re: [Prizm C] Mandelbrot Set
Post by: flyingfisch on September 25, 2013, 11:18:31 pm
wow, programmernerd, i love that fractal generator. If you could package it up with a menu, and maybe put a help file in with it, that would be great! ;)
Title: Re: [Prizm C] Mandelbrot Set
Post by: Xeda112358 on September 26, 2013, 07:55:34 am
And thanks for the tips, links, and optimisation! Optimisation is one of my favorite things to do for the Z80 calcs (I am primarily a Z80 assembly programmer). I think I found the routine on the Prizm Wiki, though I may have modified it more (I cannot remember). I also never tried testing for periodicity, though I am quite familiar with it (I even took a semester course in fractals and chaotic systems). I planned to write a program for the platform I am more familiar with and then port it to the Prizm to try out the optimisations.
Title: Re: [Prizm C] Mandelbrot Set
Post by: Vijfhoek on September 26, 2013, 10:35:14 am
I am curious about how fast this would be in computer Lua on a 150 MHz computer with 64 MB of RAM compared to the Lua TI gave us.

Won't be a fair comparison since x86 has a better IPS, it'd be better if someone ported "computer Lua" to the Nspire.
Title: Re: [Prizm C] Mandelbrot Set
Post by: DJ Omnimaga on October 09, 2013, 12:29:24 am
Yeah that's what I thought too. This also reminds me, a few years ago BrandonW wanted to rewrite the entire TI-83 Plus BASIC parser from scratch so it runs at reasonable speeds per 6 MHz standards, but sadly I don't know how far that went. It was before Axe programmers started to outnumber BASIC coders, IIRC.