// // 3D Cube by Jason Wright (C)opyright Pyrofer 2006 // // This code is free, there is no charge for it nor should anybody else charge // for the code, its distribution or derivitives of this code. // // You may use this code, modify and change and improve upon it on the following conditions, // // 1> You send me the modified source code and where possible make it public // 2> I am credited for the original work in all derivitives of this code // 3> You do not charge for this code or code derived from this code // 4> You comment the code you change! // // Basically, use this to learn! I couldnt find anything this simple when I started so I hope // that this helps others to learn. You should be able to change the LCD routines to drive almost // any graphics device. The base resolution is 128x128 for this display. Simply set the X and Y offset // to half the screen resolution for each axis. // Then adjust the Z offset to make the object fit nicely in the screen. #device PIC18F2520 #include "C:\Dev\PICC\PCW Projects\Dontronics LCD\gfxlcd.h" #include "math.h" // include complex math routines #ORG 0x1E00,0x1FFF{} // reserve rom spce to protect bootloader program #fuses HS,NOWDT,NOPROTECT // set pic fuses #use delay(clock=20000000) // set Clock speed for time calculations 20Mghz #use rs232(baud=115200, xmit=PIN_C1, rcv=PIN_C0) // set up IO for LCD #define OFFSETX 64 // offset for screen wont change unless #define OFFSETY 64 // i use different screen! so its kinda fixed #define OFFSETZ 30 void cube (void); // define the subroutines this one is the actual cube routine void clearscreen (void); // clear the LCD screen void lcdline (); // draw a line on the LCD void initlcd (void); // initialise the LCD void proginit (void); // setup other program stuff void shutdown (void); // shutdown the LCD // use const as they are in rom, saving ram const signed int aa[8]={10,-10,-10,10, 10,-10,-10,10}; // x data for shape vertex const signed int bb[8]={10,10,-10,-10, 10,10,-10,-10}; // y data for shape vertex const signed int cc[8]={-10,-10,-10,-10, 10,10,10,10}; // z data for shape vertex const int ff[12]={1,2,3,4, 5,6,7,8, 1,2,3,4}; // start vertex for lines const int gg[12]={2,3,4,1, 6,7,8,5, 5,6,7,8}; // end vertex for lines int sx,sy,ex,ey; // define global vars for calling graphics subroutines void main() // begin main program { initlcd(); // set autobaud and clearscreen proginit(); // call program inits cube(); // call main cube drawing routine delay_ms(9999); // wait for ages while we look at the pretty picture clearscreen(); // clear the screen shutdown(); // turn off LCD ready for power Down while(1); // wait forever as program is done. } void cube() // routine to draw and calc 3d cube { int newx[8]; // translated screen x co-ordinates for vertex int newy[8]; // translated screen y co-ordinates for vertex int i,loop; // temp variable for loops float xt,yt,zt,x,y,z,sinax,cosax,sinay,cosay,sinaz,cosaz,vertex; // lots of work variables float xpos=0; // position for object in 3d space, in x float ypos=0; // y float zpos=0; // and z values float rotx=0; // starting amount of x rotation float roty=0; // starting amount of y rotation float rotz=0; // starting amount of z rotation for (loop=0; loop<=100; loop++) // rotate the cube 100 times { xpos=xpos+0.0; // move the object ypos=ypos+0.0; // it would wander off screen zpos=zpos+0.0; // really quick, so leave it centered rotx=rotx+0.5; // rotate the cube on X axis roty=roty+0.5; // and on its y axis rotz=rotz+0.0; // dont bother with z or it gets confusing sinax=sin(rotx); // precalculate the sin and cos values cosax=cos(rotx); // for the rotation as this saves a sinay=sin(roty); // little time when running as we cosay=cos(roty); // call sin and cos less often sinaz=sin(rotz); // they are slow routines cosaz=cos(rotz); // and we dont want slow! for (i=0; i<8; i++) // translate 3d vertex position to 2d screen position { x=aa[i]; // get x for vertex i y=bb[i]; // get y for vertex i z=cc[i]; // get z for vertex i yt = y * cosax - z * sinax; // rotate around the x axis zt = y * sinax + z * cosax; // using the Y and Z for the rotation y = yt; z = zt; xt = x * cosay - z * sinay; // rotate around the Y axis zt = x * sinay + z * cosay; // using X and Z x = xt; z = zt; xt = X * cosaz - y * sinaz; // finaly rotate around the Z axis yt = X * sinaz + y * cosaz; // using X and Y x = xt; y = yt; x=x+xpos; // add the object position offset y=y+ypos; // for both x and y z=z+OFFSETZ-zpos; // as well as Z newx[i]=(x*64/z)+OFFSETX; // translate 3d to 2d coordinates for screen newy[i]=(y*64/z)+OFFSETY; // drawing so we can see the cube } delay_ms(20); // delay for a while to allow looking at the cube clearscreen(); // clear the screen to remove old cube for (i=0; i<12; i++) // draw the lines that make up the object { vertex=ff[i]-1; // temp = start vertex for this line sx=newx[vertex]; // set line start x to vertex[i] x position sy=newy[vertex]; // set line start y to vertex[i] y position vertex=gg[i]-1; // temp = end vertex for this line ex=newx[vertex]; // set line end x to vertex[i+1] x position ey=newy[vertex]; // set line end y to vertex[i+1] y position lcdline(); // draw the line between these 2 vertex } } } void lcdline() // subroutine for drawing line { delay_ms(18); // wait for LCD to be ready just in case putc(76); // send command for line putc(sx); // send topleft X coord putc(sy); // send topleft Y coord putc(ex); // send bottomright x coord putc(ey); // send bottomright y coord putc(0); // send high byte of colour putc(255); // send low byte of colour } void clearscreen() // subroutine to clear screen { delay_ms(20); // wait for LCD to be ready just in case putc(69); // send clearscreen command } void initlcd() // routine to initialise LCD { delay_ms(5000); // wait for LCD to power up if it was off putc(85); // send U for auto-baud delay_ms(20); // wait for LCD to be ready putc(89); // send command byte putc(3); // with Startup command High byte putc(1); // and low byte. delay_ms(5000); // wait for LCD to power up if it was shutdown clearscreen(); // clearscreen } void shutdown() // routine to shutdown the LCD for poweroff { delay_ms(20); // wait for LCD to be ready putc(89); // send command byte putc(3); // with Shutdown command High byte putc(0); // and low byte. } void proginit(void) { setup_wdt(WDT_OFF); // turn off watchdog timer, low volt reset, internal clock and spi setup_low_volt_detect(FALSE); setup_oscillator(FALSE); setup_spi(FALSE); }