/* Copyright (C) Justin Frankel ** 3D cube demo, for 3d math intro, or something. ** really lame. */ #include #include #include #include #include /* Decrease size of .EXE */ void __crt0_load_environment_file(char *_app_name) { return; } void __crt0_setup_arguments(void) { return; } char **__crt0_glob_function(char *_arg) { return 0; } /* Projection Ratio. Higher == zoomed in more, lower == greater FOV */ #define PROJECT_RATIO 128.0 /* Z Distance of cube */ #define Z_DISTANCE 256.0 /* Half the size of cube */ #define CUBE_SIZE 80.0 int ScreenWidth = 320, ScreenHeight = 200; int CenterX = 160, CenterY = 100; /* Actual VGA memory */ char *GraphMem; /* Allocated virtual framebuffer */ char *vGraphMem; typedef struct { float x, y, z; float xformed_x, xformed_y, xformed_z; } Point; typedef struct { Point *p1; Point *p2; } Line; typedef struct { int numpoints; int numlines; Point *points; Line *lines; } Object; /* Generates a rotation matrix. Rotates around Y, X, then Z */ void MatrixGenerate(float *m, float xDeg, float yDeg, float zDeg) { float a[4],b[4],c[4],d,e; yDeg *= (M_PI/180.0); xDeg *= (M_PI/180.0); zDeg *= (M_PI/180.0); /* Y Rotation */ a[0] = cos(yDeg); a[1] = sin(yDeg); a[2] = cos(yDeg+(M_PI/2)); a[3] = sin(yDeg+(M_PI/2)); /* X Rotation */ b[0] = cos(xDeg); b[1] = sin(xDeg); b[2] = cos(xDeg+(M_PI/2)); b[3] = sin(xDeg+(M_PI/2)); /* Z Rotation */ c[0] = cos(zDeg); c[1] = sin(zDeg); c[2] = cos(zDeg+(M_PI/2)); c[3] = sin(zDeg+(M_PI/2)); d = (b[2]*c[2]); e = (b[2]*c[3]); *m++ = (a[0]*c[0]) + (a[1]*d); *m++ = (a[0]*c[1]) + (a[1]*e); *m++ = (a[1]*b[3]); *m++ = (b[0]*c[2]); *m++ = (b[0]*c[3]); *m++ = b[1]; *m++ = (a[2]*c[0]) + (a[3]*d); *m++ = (a[2]*c[1]) + (a[3]*e); *m++ = (a[3]*b[3]); } /* Applies a rotation Matrix */ void MatrixApply(float *m, float x, float y, float z, float *outx, float *outy, float *outz) { *outx = (x*m[0]) + (y*m[3]) + (z*m[6]); *outy = (x*m[1]) + (y*m[4]) + (z*m[7]); *outz = (x*m[2]) + (y*m[5]) + (z*m[8]); } /* General purpose line routine... WARNING: DOES NOT CLIP */ void PutLine(char *fb, short int x1, short int y1, short int x2, short int y2, unsigned char c) { long int dx, dy, d, Eincr, NEincr, yincr; long int *slb; long int offs; dy = y2-y1; if (dy < 0) dy = -dy; dx = x2-x1; if (dx < 0) dx = -dx; if (dy <= dx) { if (x2 < x1) { x1 ^= x2; x2 ^= x1; x1 ^= x2; y1 ^= y2; y2 ^= y1; y1 ^= y2; } if (y2 > y1) yincr = 1; else yincr = -1; d = dy + dy - dx; Eincr = dy + dy; NEincr = d - dx; offs = y1 * ScreenWidth; fb[x1 + offs] = c; for (x1++; x1 < x2; x1++) { if (d < 0) d += Eincr; else { d += NEincr; y1 += yincr; offs += yincr > 0 ? ScreenWidth : -ScreenWidth; } fb[x1 + offs] = c; } } else { if (y2 < y1) { x1 ^= x2; x2 ^= x1; x1 ^= x2; y1 ^= y2; y2 ^= y1; y1 ^= y2; } if (x2 > x1) yincr = 1; else yincr = -1; d = dx + dx - dy; Eincr = dx + dx; NEincr = d - dy; offs = y1 * ScreenWidth; fb[x1 + offs] = c; for (y1++; y1 < y2; y1++) { offs += ScreenWidth; if (d < 0) d += Eincr; else { d += NEincr; x1 += yincr; } fb[x1 + offs] = c; } } } /* Projects points, and calls PutLine */ void Put3DLine(Line *l, char c) { int x1i, x2i, y1i, y2i; float scalefact; scalefact = PROJECT_RATIO / l->p1->xformed_z; x1i = CenterX + (int) ((l->p1->xformed_x) * scalefact); y1i = CenterY - (int) ((l->p1->xformed_y) * scalefact); scalefact = PROJECT_RATIO / l->p2->xformed_z; x2i = CenterX + (int) ((l->p2->xformed_x) * scalefact); y2i = CenterY - (int) ((l->p2->xformed_y) * scalefact); PutLine(vGraphMem,x1i,y1i,x2i,y2i,c); } /* Utility functions for making cube */ void SetPoint(Point *p, float x, float y, float z) { p->x = x; p->y = y; p->z = z; } void SetLine(Line *l, Point *p1, Point *p2) { l->p1 = p1; l->p2 = p2; } /* Makes a cube */ void Makecube(float radius, Object *obj) { obj->numpoints = 8; obj->numlines = 12; obj->points = (Point *) malloc(sizeof(Point) * 8); obj->lines = (Line *) malloc(sizeof(Line) * 8); /* Front face */ SetPoint(obj->points, radius, radius, radius); SetPoint(obj->points+1, radius, -radius, radius); SetPoint(obj->points+2, -radius, -radius, radius); SetPoint(obj->points+3, -radius, radius, radius); SetLine(obj->lines, obj->points, obj->points + 1); SetLine(obj->lines+1, obj->points+1, obj->points + 2); SetLine(obj->lines+2, obj->points+2, obj->points + 3); SetLine(obj->lines+3, obj->points, obj->points + 3); /* Back face */ SetPoint(obj->points+4, radius, radius, -radius); SetPoint(obj->points+5, radius, -radius, -radius); SetPoint(obj->points+6, -radius, -radius, -radius); SetPoint(obj->points+7, -radius, radius, -radius); SetLine(obj->lines+4, obj->points+4, obj->points + 5); SetLine(obj->lines+5, obj->points+5, obj->points + 6); SetLine(obj->lines+6, obj->points+6, obj->points + 7); SetLine(obj->lines+7, obj->points+4, obj->points + 7); /* Connect faces */ SetLine(obj->lines+8, obj->points, obj->points+4); SetLine(obj->lines+9, obj->points+1, obj->points+5); SetLine(obj->lines+10, obj->points+2, obj->points+6); SetLine(obj->lines+11, obj->points+3, obj->points+7); } /* Rotates all points, then displays all lines */ void displayObject(Object *obj, float xr, float yr, float zr, float zdist) { float Matrix[9]; int x; MatrixGenerate(Matrix,xr,yr,zr); for (x = 0; x < obj->numpoints; x++) { MatrixApply(Matrix, obj->points[x].x,obj->points[x].y,obj->points[x].z, &obj->points[x].xformed_x, &obj->points[x].xformed_y, &obj->points[x].xformed_z); obj->points[x].xformed_z += zdist; } for (x = 0; x < obj->numlines; x ++) Put3DLine(obj->lines + x, 15); } /* Utility function to set video mode. Calls int86() with int 10 */ void setmode(int mode) { union REGS r; r.d.eax = mode; int86(0x10,&r,&r); } void main() { Object cube; /* Our cube */ float xr, yr, zr; /* Our rotation angles */ Makecube(CUBE_SIZE,&cube); /* Generate cube */ setmode(0x13); /* Set mode 13h, 320x200x256 */ /* Allocate our virtual framebuffer */ vGraphMem = (char *) malloc(ScreenWidth * ScreenHeight); xr = yr = zr = 0; /* Set rotation angles */ /* Setup framebuffer */ __djgpp_nearptr_enable(); GraphMem = (char *) __djgpp_conventional_base + 0xA0000; while (!kbhit()) { memset(vGraphMem, 0, ScreenWidth * ScreenHeight); // Clear framebuffer displayObject(&cube,xr,yr,zr, Z_DISTANCE); // Render object to framebuffer while (inportb(0x3DA)&8); // Wait for vsync start while (!(inportb(0x3DA)&8)); // Wait for vsync end memcpy(GraphMem, vGraphMem, ScreenWidth * ScreenHeight); // Copy to screen xr++; yr++; zr++; // Adjust rotation angles } setmode(0x3); // Restore textmode }