/*

  "Introduction to 3D Programming" Tutorial series
  Article #1 - For DemoNews 114

  Sample code for Watcom C 10.0 or above, for 32-bit DOS.

  Compile with: WCC386 -bt=dos WC_EX1
		(other command line switches can be added if you wish)

  Link with: WLINK system dos4g file WC_EX1
	     (or use pmodew if you have it and wish to use it)

*/

#include <stdlib.h>
#include <conio.h>


/* "vector" structure - holds a 3D cartesian point, and its projection. */
typedef struct vector
{
int x;
int y;
int z;
int scrx;
int scry;
} vector;

/* Box object, used for the example. */

vector Box[8] =  {
		 { 20, 40, 30, 0,0},
		 { 20, 40,-30, 0,0},
		 { 20,-40, 30, 0,0},
		 { 20,-40,-30, 0,0},
		 {-20, 40, 30, 0,0},
		 {-20, 40,-30, 0,0},
		 {-20,-40, 30, 0,0},
		 {-20,-40,-30, 0,0}
		 };

/*

Videomode and Putpixel functions for graphics display

(Yes, the putpixel is not optimized, but that's not the point of
 this example program :-)

*/

void videomode(unsigned short int mode);
#pragma aux videomode = \
	"int 10h"	\
	parm [ax]	\
	modify [ax];

void putpixel(unsigned int x, unsigned int y, char color);
#pragma aux putpixel =  	\
	"shl eax, 6"		\
	"mov ebx, eax"		\
	"shl eax, 2"		\
	"add eax, ebx"		\
	"add eax, ecx"		\
	"add eax, 0a0000h"	\
	"mov edi, eax"		\
	"mov [edi], dl"		\
	parm [ecx] [eax] [dl]	\
	modify [eax ebx edi];



/* Function Declarations for PointProject and DrawBox */

void PointProject(int distance, vector point, vector *dest, vector center);
void DrawBox(int cenx, int ceny, int cenz, char color);



/*
Main program - Draws three boxes at different 3D centers, showing how
	       the depth perception works.
*/

void main(void)
{
  videomode(0x13);

  DrawBox(-60, 0, -40, 13);  /* Purple box, Z=-40 so it's further away */
  DrawBox(  0, 0,   0, 14);  /* Yellow box, Z=0 so it's at the image plane */
  DrawBox( 60, 0,  40, 15);  /* White box,  Z=40 so it's closer to you */

  while (!kbhit());
  videomode(0x03);
}


/*

void PointProject(int distance, vector point, vector *dest, vector center)

Takes a viewing distance from the origin along the Z axis (in our examples
we've been using 256, so that's what I used in the main program), and the
3D point you want to project.  Fills in the 2D scrx and scry values of the
given vector, or a separate "after projection" vector, depending on what
you pass in *dest (I used the same vector for this example).

The center vector parameter is just added to the point you give.  Stupid
by itself, yes... but if you use the same center for the set of points in
an object (I used a box in this program), the whole object is moved (called
"translation") by the center.  Just run the example, and you'll see what I
mean. :-)

*/


void PointProject(int distance, vector point, vector *dest, vector center)
{
  dest->scrx = (256*(point.x+center.x) / (distance-(point.z+center.z))) + 160;
  dest->scry = 100 - (256*(point.y+center.y) / (distance-(point.z+center.z)));
}

/*

void DrawBox(int cenx, int ceny, int cenz, char color)

Draws the Box object with the 3D center you give.  The center points are
merged into the one "center" vector that PointProject wants.  All the points
use the same center, which "moves" the object.

*/

void DrawBox(int cenx, int ceny, int cenz, char color)
{
  int count;
  vector BoxCenter;

  BoxCenter.x = cenx;
  BoxCenter.y = ceny;
  BoxCenter.z = cenz;

  for (count=0; count<8; count++)
  {
    PointProject(256, Box[count], &Box[count], BoxCenter);
    putpixel(Box[count].scrx, Box[count].scry, color);
  }
}



