#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#define __USE_GNU //for longer math constants
#include <math.h>
//#define DEBUG
#define SPLIT_SCREEN 2
#define CAMERA_SEPARATION 3
#define DEPTH_FACTOR 0.965
#define TRIANGLES 256
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a,b) (((a)>(b))?(a):(b))
//for one camera, not the whole thing.
//3 camera
//#define WIDTH 320
//#define HEIGHT 240
//1 camera
//#define WIDTH 800
//#define HEIGHT 600
//2 camera
#define WIDTH 400
#define HEIGHT 300
struct object_1 {
int type;
unsigned char x;
unsigned char y;
unsigned char z;
};
struct object_2 {
int type;
unsigned short x;
unsigned short y;
unsigned short z;
};
struct object_4 {
int type;
unsigned int x;
unsigned int y;
unsigned int z;
};
struct camera {
int x;
int y;
int z;
int xr;//rotations
int yr;
int zr;
} camera;
struct triangle {//use array or linked list?
char *id;
int x1;
int y1;
int z1;
int x2;
int y2;
int z2;
int x3;
int y3;
int z3;
// int dist;//most recent distance calculated from the camera
};
struct mainwin {
int x;
int y;
int depth;
int mousex;
int mousey;
int rmousex;
int rmousey;
int buttonpressed;
int width;
int height;
int border_width;
int xoff;
int math_error;
char *user;
XColor green;
Colormap color_map;
Display *dpy;
Window w;
GC gc;
struct triangle *triangle[TRIANGLES];
} global;
float zmagic(int z) {
float tmp=pow(DEPTH_FACTOR,(camera.z-z));
// float tmp=pow(DEPTH_FACTOR,(camera.z-z))/(camera.z-z);
// float tmp=pow(DEPTH_FACTOR,(camera.z-z)*(camera.z-z)*(camera.z-z));
//measure the distance form the camera and error out if it is too far away.
// if((camera.z - z) >= 0) return(global.math_error=1);
//return (float)1 / (float)(camera.z - z);
return tmp;
}
int to2D(int cw,int w,int z,int d) {
return (d/2) - (((w-cw) / zmagic(z)) * 16 );
}
float distance(int x1,int y1,int x2,int y2) {
return sqrt(((x2-x1)*(x2-x1))+((y2-y1)*(y2-y1)));
}
long double d2r(int d) {
while(d<0) d+=360;
return (long double)(d%360) / 180.0l * M_PIl;
}
int rotateXabout(int x1,int y1,int z1,int x2,int y2,int z2,int degrees) {
long double radians=(long double)degrees / (long double)180 * M_PIl;//M_PIl for long double
long double radius=distance(x1,z1,x2,z2);
if(radius == 0) return x2;
return x2 + radius * cosl(acosl(((long double)x2-(long double)x1)/radius)+radians);
}
int rotateZabout(int x1,int y1,int z1,int x2,int y2,int z2,int degrees) {
long double radians=(long double)degrees / (long double)180 * M_PIl;//M_PIl for long double
long double radius=distance(x1,z1,x2,z2);
if(radius == 0) return z2;
return z2 + radius * sinl(asinl(((long double)z2-(long double)z1)/radius)+radians);
}
int to2Dx(int x,int y,int z) {
int newx=rotateXabout(x,y,z,camera.x,camera.y,camera.z,camera.yr);
int newy=y;//rotateYabout(x,y,z,camera.x,camera.y,camera.z,camera.xr);
int newz=rotateZabout(x,y,z,camera.x,camera.y,camera.z,camera.yr);
return to2D(camera.x,newx,newz,global.width/SPLIT_SCREEN);
// return to2D(camera.x,x,z,global.width/SPLIT_SCREEN);
}
int to2Dy(int x,int y,int z) {
int newx=rotateXabout(x,y,z,camera.x,camera.y,camera.z,camera.yr);
int newy=y;//rotateYabout(x,y,z,camera.x,camera.y,camera.z,camera.yr);
int newz=rotateZabout(x,y,z,camera.x,camera.y,camera.z,camera.yr);
return to2D(camera.y,newy,newz,global.height);
// return to2D(camera.y,y,z,global.height);
}
void XDrawTriangle(int x1,int y1,int x2,int y2,int x3,int y3) {
int x;
XDrawLine(global.dpy,global.w,global.gc,x1,y1,x2,y2);
XDrawLine(global.dpy,global.w,global.gc,x2,y2,x3,y3);
XDrawLine(global.dpy,global.w,global.gc,x3,y3,x1,y1);
}
void XDrawFilledTriangle(int x1,int y1,int x2,int y2,int x3,int y3,int density) {
int x,y;
int b;
float m;
XDrawLine(global.dpy,global.w,global.gc,x1,y1,x2,y2);
XDrawLine(global.dpy,global.w,global.gc,x2,y2,x3,y3);
XDrawLine(global.dpy,global.w,global.gc,x3,y3,x1,y1);
m=(float)(y1-y2)/(float)(x1-x2);
b=y1-(m*x1);
for(x=min(x1,x2);x<max(x1,x2);x+=4) {
y=m*x+b;
XDrawLine(global.dpy,global.w,global.gc,x3,y3,x,y);
}
m=(float)(y2-y3)/(float)(x2-x3);
b=y2-(m*x2);
for(x=min(x2,x3);x<max(x2,x3);x+=4) {
y=m*x+b;
XDrawLine(global.dpy,global.w,global.gc,x1,y1,x,y);
}
m=(float)(y3-y1)/(float)(x3-x1);
b=y3-(m*x3);
for(x=min(x3,x1);x<max(x3,x1);x+=4) {
y=m*x+b;
XDrawLine(global.dpy,global.w,global.gc,x2,y2,x,y);
}
}
void draw3Dtriangle(int x1,int y1,int z1,int x2,int y2,int z2,int x3,int y3,int z3) {
char coords[256];
global.math_error=0;
int tx1=to2Dx(x1,y1,z1);
int ty1=to2Dy(x1,y1,z1);
//draw string...
int tx2=to2Dx(x2,y2,z2);
int ty2=to2Dy(x2,y2,z2);
int tx3=to2Dx(x3,y3,z3);
int ty3=to2Dy(x3,y3,z3);
if(!global.math_error) {
#ifdef DEBUG
snprintf(coords,sizeof(coords)-1,"(%d,%d,%d)",x1,y1,z1);
XDrawString(global.dpy,global.w,global.gc,global.xoff+tx1,ty1,coords,strlen(coords));
snprintf(coords,sizeof(coords)-1,"(%d,%d,%d)",x2,y2,z2);
XDrawString(global.dpy,global.w,global.gc,global.xoff+tx2,ty2,coords,strlen(coords));
snprintf(coords,sizeof(coords)-1,"(%d,%d,%d)",x3,y3,z3);
XDrawString(global.dpy,global.w,global.gc,global.xoff+tx3,ty3,coords,strlen(coords));
#endif
XDrawTriangle(global.xoff+tx1,ty1,global.xoff+tx2,ty2,global.xoff+tx3,ty3);
// XDrawFilledTriangle(global.xoff+tx1,ty1,global.xoff+tx2,ty2,global.xoff+tx3,ty3);
}
}
void draw3Dline(int x1,int y1,int z1,int x2,int y2,int z2) {
global.math_error=0;
int tx1=to2Dx(x1,y1,z1);
int ty1=to2Dy(x1,y1,z1);
int tx2=to2Dx(x2,y2,z2);
int ty2=to2Dy(x2,y2,z2);
if(!global.math_error) {
XDrawLine(global.dpy,global.w,global.gc,global.xoff+tx1,ty1,global.xoff+tx2,ty2);
}
global.math_error=0;
}
//is basing this all on triangles best, or should I use polygons?
//void pushTriangle(x1,y1,z1,1) {
// for(i=0;global.triangle[i];i++);
// global.triangle[i]=malloc(sizeof(struct triangle));
// global.triangle[i]->x1=x1;
//}
//void pushSquare() {
// pushTriangle();
// pushTriangle();
//}
void drawCube(int x,int y,int z,int i) {
//this is just drawing the cube.
draw3Dline(x,y,z,x,y,z+i);
draw3Dline(x,y,z,x,y+i,z);
draw3Dline(x,y,z,x+i,y,z);
draw3Dline(x+i,y+i,z+0,x+i,y+0,z+0);
draw3Dline(x+i,y+i,z+0,x+0,y+i,z+0);
draw3Dline(x+0,y+i,z+i,x+0,y+i,z+0);
draw3Dline(x+0,y+i,z+i,x+0,y+0,z+i);
draw3Dline(x+i,y+0,z+i,x+i,y+0,z+0);
draw3Dline(x+i,y+0,z+i,x+0,y+0,z+i);
draw3Dline(x+i,y+i,z+i,x+i,y+i,z+0);
draw3Dline(x+i,y+i,z+i,x+i,y+0,z+i);
draw3Dline(x+i,y+i,z+i,x+0,y+i,z+i);
}
int applyrule(int a,int b,int c,int rule) {
return (rule >> ((!!a<<2) | (!!b<<1) | (!!c)) ) % 2;
}
char field[HEIGHT+1][WIDTH+1];
void draw_screen(Display *dpy,Window w,GC gc) {
int i,j,k;
int cn=0;//camera number.
char **files;
static int offset=0;
XFontStruct *font=XLoadQueryFont(dpy,"fixed");
XCharStruct overall;
int direction,ascent,descent;
char coords[256];
int x,y,z,x1,y1,x2,y2;
XEvent e;
XClearWindow(dpy, w);
j=0;
for(i=0;i<HEIGHT;i++) {
for(j=0;j<WIDTH;j++) {
if(field[i][j]) XDrawPoint(dpy,w,gc,j,i);
}
}
XFlush(dpy);
}
int load_file(FILE *fp) {
struct triangle *to;
struct triangle t;
char *command;
static int i=0;//used to store the last triangle.
for(;global.triangle[i];i++) ;//hop to the end.
fcntl(fileno(fp),F_SETFL,O_NONBLOCK);
for(;;i++) {
if(feof(fp)) {
//printf("resetting EOF\n");
clearerr(fp);
}
if(fscanf(fp,"%ms %ms %d %d %d %d %d %d %d %d %d",&(t.id),&command,&(t.x1),&(t.y1),&(t.z1),&(t.x2),&(t.y2),&(t.z2),&(t.x3),&(t.y3),&(t.z3)) > 0) {
/*if(!strcmp(command,&quo