#include "LCD4884.h"
// x-y-relation for prepairing pictures is 28 x 19 ~ 3 x 2
// because LCD-pixels in 84x48 matrix seem to bee not quadratic
// use a high density 3x2 picture, resize to 84x48 non propotional
// and change to black and white
// google for bmp to pic converter to prepare include-file
#define DELAY1 200
#define DELAY2 1000
#define DELAY3 5000
#define height 19
#define width 28
#define LCD_BACKLIGHT_PIN 7
unsigned char bildbmp[height*width];
float colorGradients[][4] = {{0,0,0,255},{255,255,255,0}};
//----------- Our math functions ------------
float length(float x,float y,float z){
return sqrt(x*x+y*y+z*z);
}
float norm(int x, int y,int z){
float l = length(x,y,z);
return x/1, y/1, z/1;
}
float dot(float xa, float ya, float za, float xb, float yb, float zb){
return xa*xb+ya*yb + za*zb;
}
//-------------------------------------------
// define the camera
float ex = 0;
float ey = 1;
float ez = -1.5;
float fov = 90;
float tmin = .1;
float tmax = 100;
int maxSteps = 45;
//define light
float lx, ly, lz = norm(.2,.5,-.6);
//Distance Field Functions----------------
float plane(int x, int y, int z){
return y; //this is silly
}
float sphere(float x, float y, float z, float radius){
float manhattanDistance = x + y + z;
if(manhattanDistance > radius * 2){
return manhattanDistance; //because.. good enough!
}
return length(x,y,z) - radius;
}
//----------------------------------------
float unio(float a, float am, float b, float bm){
if(a < b){
return a, am;
}
else return b, bm;
}
float scene(float x, float y, float z){
float d = tmax;
float m = 0;
d, m = unio(d, m, plane(x, y, z), 255);
d, m = unio(d, m, sphere(x, y-1, z, .5), 0);
return d,m;
}
float sceneNormal(float x, float y, float z){
float eps = 0.1;
float xa = scene(x+eps, y, z);
float xb = scene(x, y+eps, z);
float ya = scene(x, y+eps, z);
float yb = scene(x, y-eps ,z);
float za = scene(x, y, z+eps);
float zb = scene(x, y, z-eps);
return norm(xa-xb, ya-yb, za-zb);
}
float noDither(int x,int y, float gradient[], float value){
float whole = floor(value * sizeof(gradient));
float fraction = value * sizeof(gradient) - whole;
int low = gradient[int(min(whole+1, sizeof(gradient)))];
int high = gradient[int(min(min(whole + 1, sizeof(gradient)) + 1, sizeof(gradient)))];
if(fraction < 1.0/7.0){
return low;
}
if(fraction < 2.0/7.0){
if ((x+1) % 3 == 0 && y % 3 == 0){
return high;
}
else return low;
}
if( fraction < 3.0/7.0){
if(x%2==0 && y%2==0){
return high;
}
else return low;
}
if(fraction < 4.0/7.0){
if(x%2==0 && y%2==0 || x%2!=0 && y%2!=0){
return high;
}
else return low;
}
if(fraction < 5.0/7.0){
if(x%2==0 && (y+1)%2==0){
return low;
}
else return high;
}
if(fraction < 6.0/7.0){
if((x+1)%3==0 && y%3==0){
return low;
}
else return high;
}
return high;
}
float getShadowPoint( int t, int x, int y, int z){
return x+lx*t, y+ly*t, z+lz*t;
}
float shadow(int x,int y,int z){
//t starts at 0.2 so the shadow ray doesn't intersect
//the object it's trying to shadow
float res=1;
float t = 0.2;
float distance = 0;
float sx = 0;
float sy = 0;
float sz = 0;
for(int i = 1; i < 6; i++){
sx, sy, sz = getShadowPoint(t, x, y, z);
distance = scene(sx, sy, sz); //we don't care about the color
res = min(res, 2 * distance / t); //increase 2 to get sharper shadows
t += min(max(distance, .02), .2);
if(distance < .05 or t > 10.0){
break;
}
}
return min(max(res, 0), 1);
}
//calculates the final lighting and color
float render(int x, int y, int t, float tx, float ty, float tz, float rx, float ry, float rz, int color){
float nx, ny, nz = sceneNormal(tx, ty, tz);
float light = 0;
light += min(max(dot(nx, ny, nz, lx, ly, lz), 0), 1); //sun light
light *= shadow(tx,ty,tz); //shadow color
light = min(max(light, 0), 1); //clamp final light value
//return dither(x, y, colorGradients[color], light);
Serial.println(noDither(x,y,colorGradients[color],light));
return noDither(x,y,colorGradients[color],light);
}
float getRayDirection(int x, int y){
return norm(x / 64 - 1, (128 - y) / 64 - 1, 90 / fov);
}
float getTestPoint(float t, float rx, float ry, float rz){
return ex + rx * t, ey + ry * t, ez + rz * t;
}
float trace(int x,int y){
float rx, ry, rz = getRayDirection(x, y);
float tx = 0;
float ty = 0;
float tz = 0;
float t = 0;
float distance = 0;
int color = 0;
for(int i = 1; i < maxSteps; i++){
tx, ty, tz = getTestPoint(t, rx, ry, rz);
distance, color = scene(tx, ty, tz);
//--the test point is close enough, render
if(distance < .05){
return render(x, y, t, tx, ty, tz, rx, ry, rz, color);
}
//--the test point is too far, give up, draw the sky
if(distance >= tmax){
break;
}
//--move forward by some fraction
t += distance * .7;
}
}
void setup()
{
Serial.begin(9600);
lcd.LCD_init(); // creates instance of LCD
for(int i = 0; i < width*height; i+=2){
bildbmp[i] = 0x00;
bildbmp[i+1] = 0xFF;
}
}
void loop()
{
digitalWrite(LCD_BACKLIGHT_PIN, LOW);
unsigned char i=0, line=0, pos=0, offset;
unsigned char mychar;
int x = 0;
int y = 0;
/*********** 1st ***********/
lcd.LCD_clear(); // blanks the display
lcd.LCD_draw_bmp_pixel(0,0, bildbmp, 84,48);
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
Serial.println(trace(x,y));
}
}
}