Omnimaga
Calculator Community => Casio Calculators => Topic started 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:
#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
-
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*
-
Very Cool!
-
*cough*84C*cough*
-
Ui, this is looking nice!
And I also go with tr1p's opinion :P
-
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
-
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.
-
I did this in LuaZM once... was very slow. How fast does yours render?
-
It took 46 seconds at 94.3MHz, but about 75 seconds at normal speed.
-
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
-
Eh, this reminds me of :
:P
-
Oh my gosh, I totally want to learn enough ARM assembly to do that on my NSpire o.o
-
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.
-
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.
#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;
}
-
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:
-
Darn that renders quite fast too!
-
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.
-
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?
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
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.
-
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! ;)
-
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.
-
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.
-
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.