3d cube on OLED
-
- Freetronics Staff
- Posts:853
- Joined:Tue Apr 09, 2013 11:19 pm
- Location:Melbourne, Australia
- Contact:
Re: 3d cube on OLED
Nice work! I would love to see the code. 

-
- Posts:71
- Joined:Fri Sep 21, 2012 7:22 am
Re: 3d cube on OLED
Its a bit messy, will have to organise it a bit. Hangovers from coding in Qbasic all those years ago.
Will comment it a bit more too before i post it.
It also uses the modified FTOled lib too, but i will also make note of the modifications.
Will comment it a bit more too before i post it.
It also uses the modified FTOled lib too, but i will also make note of the modifications.
-
- Posts:71
- Joined:Fri Sep 21, 2012 7:22 am
Re: 3d cube on OLED
OK cleaned up the code a lot, and implemented some Structs to make it much clearer and neater.
Code: Select all
/*
Draws a 3d rotating cube on the freetronics OLED screen.
*/
const byte pin_cs = 7;
const byte pin_dc = 2;
const byte pin_reset = 3;
#include <SPI.h>
#include <SD.h>
#include "FTOLED.h"
#include "fonts/SystemFont5x7.h"
OLED oled(pin_cs, pin_dc, pin_reset);
// Text box takes up bottom 32 characters of the display (ie 4 rows)
OLED_TextBox box(oled, 0, 0, 128, 32);
Colour PIX;
float xx,xy,xz;
float yx,yy,yz;
float zx,zy,zz;
float fact;
int Xan,Yan;
int Xoff;
int Yoff;
int Zoff;
struct Point3d
{
int x;
int y;
int z;
};
struct Point2d
{
int x;
int y;
};
int LinestoRender; // lines to render.
int OldLinestoRender; // lines to render just in case it changes. this makes sure the old lines all get erased.
struct Line3d
{
Point3d p0;
Point3d p1;
};
struct Line2d
{
Point2d p0;
Point2d p1;
};
Line3d Lines[20];
Line2d Render[20];
Line2d ORender[20];
/***********************************************************************************************************************************/
// Sets the global vars for the 3d transform. Any points sent through "process" will be transformed using these figures.
// only needs to be called if Xan or Yan are changed.
void SetVars(void)
{
float Xan2,Yan2,Zan2;
float s1,s2,s3,c1,c2,c3;
Xan2 = Xan / fact; // convert degrees to radians.
Yan2 = Yan / fact;
// Zan is assumed to be zero
s1 = sin(Yan2);
s2 = sin(Xan2);
c1 = cos(Yan2);
c2 = cos(Xan2);
xx = c1;
xy = 0;
xz = -s1;
yx = (s1 * s2);
yy = c2;
yz = (c1 * s2);
zx = (s1 * c2);
zy = -s2;
zz = (c1 * c2);
}
/***********************************************************************************************************************************/
// processes x1,y1,z1 and returns rx1,ry1 transformed by the variables set in SetVars()
// fairly heavy on floating point here.
// uses a bunch of global vars. Could be rewritten with a struct but not worth the effort.
void ProcessLine(struct Line2d *ret,struct Line3d vec)
{
float zvt1;
int xv1,yv1,zv1;
float zvt2;
int xv2,yv2,zv2;
int rx1,ry1;
int rx2,ry2;
int x1;
int y1;
int z1;
int x2;
int y2;
int z2;
int Ok;
x1=vec.p0.x;
y1=vec.p0.y;
z1=vec.p0.z;
x2=vec.p1.x;
y2=vec.p1.y;
z2=vec.p1.z;
Ok=0; // defaults to not OK
xv1 = (x1 * xx) + (y1 * xy) + (z1 * xz);
yv1 = (x1 * yx) + (y1 * yy) + (z1 * yz);
zv1 = (x1 * zx) + (y1 * zy) + (z1 * zz);
zvt1 = zv1 - Zoff;
if( zvt1 < -5){
rx1 = 256 * (xv1 / zvt1) + Xoff;
ry1 = 256 * (yv1 / zvt1) + Yoff;
Ok=1; // ok we are alright for point 1.
}
xv2 = (x2 * xx) + (y2 * xy) + (z2 * xz);
yv2 = (x2 * yx) + (y2 * yy) + (z2 * yz);
zv2 = (x2 * zx) + (y2 * zy) + (z2 * zz);
zvt2 = zv2 - Zoff;
if( zvt2 < -5){
rx2 = 256 * (xv2 / zvt2) + Xoff;
ry2 = 256 * (yv2 / zvt2) + Yoff;
} else
{
Ok=0;
}
if(Ok==1){
ret->p0.x=rx1;
ret->p0.y=ry1;
ret->p1.x=rx2;
ret->p1.y=ry2;
}
// The ifs here are checks for out of bounds. needs a bit more code here to "safe" lines that will be way out of whack, so they dont get drawn and cause screen garbage.
}
/***********************************************************************************************************************************/
void setup() {
oled.begin();
// oled.selectFont(System5x7);
box.setForegroundColour(WHITE); // in here is specific code for the display. change if you are using a different screen.
fact = 180 / 3.14159259; // conversion from degrees to radians.
Xoff = 63; // positions the center of the 3d conversion space into the center of the OLED screen. This is usally screen_x_size / 2.
Yoff = 63; // screen_y_size /2
Zoff = 500;
// line segments to draw a cube. basically p0 to p1. p1 to p2. p2 to p3 so on.
// Front Face.
Lines[0].p0.x=-50;
Lines[0].p0.y=-50;
Lines[0].p0.z=50;
Lines[0].p1.x=50;
Lines[0].p1.y=-50;
Lines[0].p1.z=50;
Lines[1].p0.x=50;
Lines[1].p0.y=-50;
Lines[1].p0.z=50;
Lines[1].p1.x=50;
Lines[1].p1.y=50;
Lines[1].p1.z=50;
Lines[2].p0.x=50;
Lines[2].p0.y=50;
Lines[2].p0.z=50;
Lines[2].p1.x=-50;
Lines[2].p1.y=50;
Lines[2].p1.z=50;
Lines[3].p0.x=-50;
Lines[3].p0.y=50;
Lines[3].p0.z=50;
Lines[3].p1.x=-50;
Lines[3].p1.y=-50;
Lines[3].p1.z=50;
//back face.
Lines[4].p0.x=-50;
Lines[4].p0.y=-50;
Lines[4].p0.z=-50;
Lines[4].p1.x=50;
Lines[4].p1.y=-50;
Lines[4].p1.z=-50;
Lines[5].p0.x=50;
Lines[5].p0.y=-50;
Lines[5].p0.z=-50;
Lines[5].p1.x=50;
Lines[5].p1.y=50;
Lines[5].p1.z=-50;
Lines[6].p0.x=50;
Lines[6].p0.y=50;
Lines[6].p0.z=-50;
Lines[6].p1.x=-50;
Lines[6].p1.y=50;
Lines[6].p1.z=-50;
Lines[7].p0.x=-50;
Lines[7].p0.y=50;
Lines[7].p0.z=-50;
Lines[7].p1.x=-50;
Lines[7].p1.y=-50;
Lines[7].p1.z=-50;
// now the 4 edge lines.
Lines[8].p0.x=-50;
Lines[8].p0.y=-50;
Lines[8].p0.z=50;
Lines[8].p1.x=-50;
Lines[8].p1.y=-50;
Lines[8].p1.z=-50;
Lines[9].p0.x=50;
Lines[9].p0.y=-50;
Lines[9].p0.z=50;
Lines[9].p1.x=50;
Lines[9].p1.y=-50;
Lines[9].p1.z=-50;
Lines[10].p0.x=-50;
Lines[10].p0.y=50;
Lines[10].p0.z=50;
Lines[10].p1.x=-50;
Lines[10].p1.y=50;
Lines[10].p1.z=-50;
Lines[11].p0.x=50;
Lines[11].p0.y=50;
Lines[11].p0.z=50;
Lines[11].p1.x=50;
Lines[11].p1.y=50;
Lines[11].p1.z=-50;
LinestoRender=12;
OldLinestoRender=LinestoRender;
}
/***********************************************************************************************************************************/
void RenderImage( void)
{
// renders all the lines after erasing the old ones.
// in here is the only code actually interfacing with the OLED. so if you use a different lib, this is where to change it.
for (int i=0; i<OldLinestoRender; i++ )
{
oled.drawLine(ORender[i].p0.x,ORender[i].p0.y,ORender[i].p1.x,ORender[i].p1.y, BLACK); // erase the old lines.
}
for (int i=0; i<LinestoRender; i++ )
{
oled.drawLine(Render[i].p0.x,Render[i].p0.y,Render[i].p1.x,Render[i].p1.y, PIX);
}
OldLinestoRender=LinestoRender;
}
/***********************************************************************************************************************************/
void loop() {
PIX=GREEN; // colours of all lines drawn will be green until changed.
Xan++;
Yan++;
Yan=Yan % 360;
Xan=Xan % 360; // prevents overflow.
SetVars(); //sets up the global vars to do the conversion.
for(int i=0; i<LinestoRender ; i++)
{
ORender[i]=Render[i]; // stores the old line segment so we can delete it later.
ProcessLine(&Render[i],Lines[i]); // converts the 3d line segments to 2d.
}
RenderImage(); // go draw it!
}
/***********************************************************************************************************************************/
-
- Posts:71
- Joined:Fri Sep 21, 2012 7:22 am
Re: 3d cube on OLED
It wont run very fast unless you modify FTOled.cpp with a few mods, i can go into detail of anyone wants it.
Re: 3d cube on OLED
Please do 

Re: 3d cube on OLED
Good stuff.
Off topic - Things - did you used to post on photonlexicon ?
Off topic - Things - did you used to post on photonlexicon ?
Re: 3d cube on OLED
Yup, I remember you 

Re: 3d cube on OLED
I hope you don't mind me grabbing your code to try on one of my designs. I'm using the Adafruit i2c oled library on a 0.96" mono oled display. To my surprise it runs faster than what I was expecting. I'll try it on a 16Mhz 328P next and then on a SPI display.
http://youtu.be/uan1urYKo_w
http://youtu.be/uan1urYKo_w