To convert a 3d (x,y,z) coordinate to a 2d (x,y) screen coordinate, use the formulae below.
2dX = ((512*x) / (512+z)) + Xorigion
2dY = (-(512*y) / (512+z)) + Yorigion
By changing the 512 to a different number you can alter the perspective effect.
If you have a 2d polygon with points (vertexs) at (x0,y0),(x1,y1) and (x2,y2), and the points are in a clockwise direction when the polygon is facing towards the screen (i.e. when it's visible), then the following formula tells you if the polygon is visible and should be drawn -
z=(x1-x0)*(y2-y0)-(y1-y0)*(x2-x0);
If z is less than 0 the polygon is not visible.
There is lots of advanced source code on the net for 3D graphics, so here is a very simple, but fast, function for drawing a plain polygon.
#include <string.h> //for memset()
typedef unsigned char UCHAR;
//function defs
int glDo2DEdge(int x1,int y1,int x2,int y2);
void glHLineXclip(UCHAR col,int x1,int x2,int y);
//left & right edge arrays for clipped polygon
int glpl[MAXPOLYHEIGHT],glpr[MAXPOLYHEIGHT];//(fill in screen height)
//PRE-SET VARIABLES - set before calling poly function
//minimum and maximum allowable pixel coordinates
//for current screen mode (i.e. 0,0 & 639,479 for 640x480).
int glXMIN,glYMIN,glXMAX,glYMAX;
//pointer to screen memory
UCHAR *glPTR;
//step in bytes (for 256 color) from 1 line of screen memory to the next
int glLINESTEP;
//draw convex plain 256color polygon - point lists must be clockwise
int gl2DPoly(UCHAR col, int sides, int *vx,int *vy)
{
int top=vy[0],bottom=vy[0],left=vx[0],right=vx[0],height,y;
UCHAR *dst;
//get top and bottom, left and right points
for(y=1; y<sides; y++) {
if (vy[y]<top) top=vy[y]; if (vy[y]>bottom) bottom=vy[y];
if (vx[y]<left) left=vx[y]; if (vx[y]>right) right=vx[y];
}
//check polygon is in viewpoint at all
if (left>glXMAX || right<glXMIN || top>glYMAX || bottom<glYMIN) return(0);
height=bottom-top+1;
if (height<1) return(0);//error!
//now scan-convert all edges and store left/right edges in edge arrays
for(y=0; y<sides-1; y++) glDo2DEdge(vx[y],vy[y], vx[y+1],vy[y+1]);
glDo2DEdge(vx[sides-1],vy[sides-1], vx[0],vy[0]);
//clip top & bottom for drawing
if (top<glYMIN) top=glYMIN;
if (bottom>glYMAX) bottom=glYMAX;
//draw polygon - check if X clipping of scanlines necessary first
if (left>=glXMIN && right<=glXMAX) {
dst=glPTR+(top*glLINESTEP);
for(y=top; y<=bottom; y++) {
if (glpr[y]<glpl[y]) continue;//error
memset(dst+glpl[y], col, glpr[y]-glpl[y]+1); dst+=glLINESTEP;
}
}
else {//else do x-clipped lines
for(y=top; y<=bottom; y++) {
if (glpr[y]<glpl[y]) continue;//error
glHLineXclip(col,glpl[y],glpr[y],y);
}
}
return(0);
}
//Horizontal edge-clipped line
void glHLineXclip(UCHAR col,int x1,int x2,int y)
{
//if line in buffer - draw
if (x1<=glXMAX && x2>=glXMIN) {
//clip line
if (x1<glXMIN) x1=glXMIN;
if (x2>glXMAX) x2=glXMAX;
memset(glPTR+(y*glLINESTEP)+x1, col, x2-x1+1);
}
}
//CALCULATE EDGE X VALUES
//fixed point version - clipped to glYMIN/MAX
int glDo2DEdge(int x1,int y1, int x2,int y2)
{
int y;
int dx=x2-x1,dy=y2-y1;
int x,xstep;//screen x pos * step
int side=1;
int top,bottom;
//get top & bottom Y of line
if (y1<y2) {top=y1; bottom=y2;}
else {bottom=y1; top=y2;}
//check if on screen at all
if (top>glYMAX || bottom<glYMIN) return(1);//off screen top/bottom
//get edge side (left or right) - if horizontal, do simple
if (dy==0) {
if (x1<x2) {glpl[y1]=x1; glpr[y1]=x2;}
else {glpl[y1]=x2; glpr[y1]=x1;}
return(1);
}
//and get positive y distance
if (dy<0) {side=0; dy=-dy;}
//get xstep - fixed point
xstep=(dx<<16)/dy; x=(x1<<16)+32768;
//if no Y clipping needed, do txtr lines quickly
if (top>=glYMIN && bottom<=glYMAX) {
//loop through edge points & store
if (side==1) {//right
y=y1;
//first point
glpr[y++]=x>>16;
//rest
do {
x+=xstep;
glpr[y++]=x>>16;
}
while(y<=y2);
}
else {//left
y=y1;
//first point
glpl[y--]=x>>16;
//rest
do {
x+=xstep;
glpl[y--]=x>>16;
}
while(y>=y2);
}
return(1);//non-clipped edge done
}
//CLIPPED edge -
//get start clip distance
int clipskip=0;
if (y1<glYMIN) clipskip=glYMIN-y1;
if (y1>glYMAX) clipskip=y1-glYMAX;
//clip y2
if (y2<glYMIN) y2=glYMIN;
if (y2>glYMAX) y2=glYMAX;
//skip clipped points
x+=xstep*clipskip;
//loop through edge points & store
if (side==1) {//right
y=y1+clipskip;
//rest
do {
glpr[y++]=x>>16;
x+=xstep;
}
while(y<=y2);
}
else {//left
y=y1-clipskip;
//rest
do {
glpl[y--]=x>>16;
x+=xstep;
}
while(y>=y2);
}
return(1);
}