Here's the source:
// Dark GDK - The Game Creators - www.thegamecreators.com
// the wizard has created a very simple project that uses Dark GDK
// it contains the basic code for a GDK application
// whenever using Dark GDK you must ensure you include the header file
#include "DarkGDK.h"
#include <ctime>
#define ERROR_NOTINSCREEN (-123456789)
#define GRAV ((float)(0.5))
#define BACKGROUND_COLOR (DWORD)(colorRGB(0,0,0))
#define toRadian(degree) ((degree) * (3.141592654f / 180.0f))
#define toDegree(radian) ((radian) * (180.0f / 3.141592654f))
#define colorRGB(r,g,b) ((DWORD)((((0xff)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
typedef unsigned long DWORD;
typedef unsigned int UINT;
struct VECTOR3{ // 3D Vector
float x,y,z;
DWORD color;
};
struct VECTOR2{ // 2D Vector
int x, y;
DWORD color;
};
struct MESH{ // Mesh, it holds vertex and index information, and object offset(from 0.0)
VECTOR3*v_buffer;
short*i_buffer;
UINT vCount, iCount;
float x, y, z;
};
struct MATRIX{ // 4x4 matrix(4th dimension for translation)
float
m00,m01,m02,m03,
m10,m11,m12,m13,
m20,m21,m22,m23,
m30,m31,m32,m33;
};
VECTOR2 getVectorScreen(VECTOR3&vect, VECTOR3&view, float feildofview, int screenWidth, int screenHeight); // Returns the screen qoordanets of a 3D Vector
bool isVectorOnScreen(VECTOR3&v, VECTOR3&view); // returns a true if a vector is on the screen based on Vector::view. Note: vect must already be transformed by the views matrix.
void transformVector(VECTOR3&vect, MATRIX&mat, float origx, float origy, float origz, VECTOR3&view, MATRIX&viewTrans); // will transform a vector(view and world transformations)
void matrixMultiply(MATRIX&out, MATRIX&a, MATRIX&b); // mutliplies 2 matrices together. the new matrix will do the operations the each of the other 2 would have.
void matrixRotationX(MATRIX&,float); // sets up a matrix for rotation on the x axis
void matrixRotationY(MATRIX&,float); // ^ y axis
void matrixRotationZ(MATRIX&,float); // ^ z axis
void matrixTranslation(MATRIX&,float,float,float); // sets up a matrix to move a vector
void matrixScale(MATRIX&, float, float, float); // sets up a matrix to scale a vector
void render(DWORD*pData, MESH*mesh, MATRIX&projTransform, VECTOR3&view, MATRIX& viewTransform, float fieldofview, bool filled); // draws a mesh to the bitmap pointed to byte pData
void triangle(DWORD*pData, VECTOR2 p1, VECTOR2 p2, VECTOR2 p3, bool fill); // draws a triangle to the bitmap pointed to by pData(do not use filled.)
MESH* create_cube(float x, float y, float z); // creates a mesh object filled with the vertices to make a cube
MESH* create_pyramid(float x, float y, float z, float size); // creates a mesh object filled with the vertices to make a pyramid
void moveVector(VECTOR3&v, float force, float anglex, float angley, float anglez); // moves a vector 'forces' units forward based on rotation
void qLine(DWORD*,int, int, int, int,DWORD,DWORD); // draws a line on the bitmap pointed to by pData
int round(float val){if( (val - ((int)(val))) >= .5 ) return ((int)(val) + 1); else return ((int)(val)); } // return the rounded value of the float 'val'
void putPixel(DWORD*,int,int,DWORD); // draws a dot to the bitmap pointed to by pData
DWORD transitionColor(DWORD,DWORD,float); // gets a transition color between 'c1' and 'c2' at percent 'p'(0 <= p <= 1.0)
void memset32(DWORD*,DWORD,DWORD); // same as memset. just with dwords instead of integers(so you can use 32bit RGB vlaues to clear a bitmap)
// the main entry point for the application is this function
void DarkGDK ( void )
{
// turn on sync rate and set maximum rate to 60 fps
dbSyncOn ( );
dbSyncRate ( 0 );
dbSetDisplayMode(640,480,32);
srand( time( 0 ) );
dbPrint("Enter number of objects. Within 0 < Mesh Count < 10000");
dbSync();
char*buffer = dbInput();
dbSync();
dbCLS();
int Count = dbVal(buffer);
const int mCount = Count;
delete[] buffer;
MESH*mesh[10000];
for(int x = 0; x < mCount; ++x)
{
if(x < mCount/2)
mesh[x] = create_cube(rand()%500, 0, rand()%500);
else
mesh[x] = create_pyramid(rand()%500, 0, rand()%500, 10);
}
VECTOR3 view = {0.0, 5.0, -50.0, 0};
// Mesh transformation matrix and view transformation matrix
MATRIX objRot, objScale, vtrans;
ZeroMemory(&vtrans, sizeof(MATRIX)); ZeroMemory(&objRot, sizeof(MATRIX));
// scale object to 200% it's size
matrixScale(objScale, 2.0, 2.0, 2.0 );
// extra matrices for initial values(will be multiplied into vtrans later)
MATRIX rotx, roty;
ZeroMemory(&rotx, sizeof(MATRIX)); ZeroMemory(&roty, sizeof(MATRIX));
// angle of y rotation on the meshes
float angle1 = 0.0;
// x and y rotation of the view
float viewAngleX = 0.0, viewAngleY = 0.0, viewForce = 0.0;
float yForce = 0.0;
bool hold = false;
float zDist = 400.0;
// Bitmap pointer stuff
DWORD w, h, d, size;
LPSTR data;
dbGetBitmapData(0, &w, &h, &d, &data, &size, true);
dbHideMouse();
// screen fps string
char fps[128] = {0};
// our main loop
while ( LoopGDK ( ) )
{
sprintf_s(fps, 128, "Screen FPS = %d", dbScreenFPS());
// Set the rotation matrix and increment the angle1
matrixRotationY(objRot, angle1);
angle1 = dbWrapValue(angle1+1.0);
// Mouse look
viewAngleY = dbWrapValue(viewAngleY + (dbMouseMoveX() / 4.0));
viewAngleX = dbWrapValue(viewAngleX + ((dbMouseMoveY()*-1) / 4.0));
dbPositionMouse(320,240);
// move the view
if(dbKeyState(17))
viewForce = 1;
if(dbKeyState(31))
viewForce = -1;
if(dbKeyState(30))
{
moveVector(view, 1, toRadian(viewAngleX), toRadian(viewAngleY-90), 0.0);
}
if(dbKeyState(32))
{
moveVector(view, 1, toRadian(viewAngleX), toRadian(viewAngleY+90), 0.0);
}
if(!dbKeyState(17) && !dbKeyState(31)) viewForce = 0;
// set the view transformation matrix to the mouselook angles
matrixRotationY(roty, viewAngleY);
matrixRotationX(rotx, viewAngleX);
matrixMultiply(vtrans, roty, rotx);
// calculate moved x and z based on the force
moveVector(view, viewForce, toRadian(viewAngleX), toRadian(viewAngleY), 0.0);
// gravity
view.y += yForce;
if(hold) yForce -= GRAV;
// draw the meshes
for(int m = 0; m < mCount; ++m)
{
if(m < mCount/2)
// send bitmap ptr, mesh, object matrix, camera position, camera matrix, zDist, and filled(filled always false)
render((DWORD*)data, mesh[m], objRot, view, vtrans, zDist, false);
else
render((DWORD*)data, mesh[m], objScale, view, vtrans, zDist, false);
}
// jump
if(dbSpaceKey() && hold == false){
hold = true;
yForce = 10;
}
if(view.y < 5){
hold = false; yForce = 0; view.y = 5;
}
// update the screen
dbSetBitmapData(0, w, h, d, data, size);
dbPrint(fps);
dbSync ( );
dbCLS(colorRGB(0,0,255));
memset32((DWORD*)data, dbRGB(0,0,0), size/4);
}
for(int m = 0; m < mCount; ++m){
delete[] mesh[m]->i_buffer;
delete[] mesh[m]->v_buffer;
}
// return back to windows
return;
}
// memset32 is like memset, but is used with DWORDs instead of integers
void memset32(DWORD*pData, DWORD val, DWORD size)
{
for(int x=0; x < size; ++x)
{
pData[x] = val;
}
}
// Moves a vector forward in 3D space
void moveVector(VECTOR3&v, float force, float anglex, float angley, float anglez)
{
// change in x
float m = sin(angley)*force;
v.x += m;
// change in z
m = cos(angley)*force;
v.z += m;
}
// Creates a mesh object with the information to draw a cube
MESH* create_cube(float x, float y, float z)
{
VECTOR3 v[8] = {
// front side
{-5.0, 0.0,-5.0,colorRGB(0,0,255)},
{-5.0, 10.0,-5.0,colorRGB(0,255,0)},
{ 5.0, 10.0,-5.0,colorRGB(255,0,0)},
{ 5.0, 0.0,-5.0,colorRGB(255,0,255)},
// Back Side
{-5.0, 0.0,5.0,colorRGB(0,255,255)},
{-5.0, 10.0,5.0,colorRGB(0,255,0)},
{ 5.0, 10.0,5.0,colorRGB(255,255,0)},
{ 5.0, 0.0,5.0,colorRGB(255,255,255)}
};
short i[36] = {
0,1,2, // front face
0,2,3,
4,5,1, // left face
4,1,0,
7,6,5, // back face
7,5,4,
3,2,6, // right face
3,6,7,
2,5,6, // top face
2,6,3,
4,0,3, // bottom face
4,3,7
};
MESH* mesh = new MESH;
mesh->v_buffer = new VECTOR3[8];
memcpy(mesh->v_buffer, v, sizeof(VECTOR3)*8);
mesh->i_buffer = new short[36];
memcpy(mesh->i_buffer, i, sizeof(short)*36);
mesh->vCount = 8;
mesh->iCount = 12;
mesh->x = x; mesh->y = y; mesh->z = z;
return mesh;
}
MESH* create_pyramid(float x, float y, float z, float size)
{
VECTOR3 v[5] = {
// top point
{0.0,size,0.0,colorRGB(0,0,255)},
// base
{-(size/2), 0.0, -(size/2), colorRGB(0,255,0)},
{-(size/2), 0.0, size/2, colorRGB(255,0,0)},
{size/2,0.0, size/2, colorRGB(255,0,255)},
{size/2,0.0, -(size/2), colorRGB(255,255,0)}
};
short i[18] = {
1,0,4,
2,0,1,
3,0,2,
4,0,3,
2,1,4,
2,4,3
};
MESH*mesh = new MESH;
mesh->v_buffer = new VECTOR3[5];
memcpy(mesh->v_buffer, v, sizeof(VECTOR3)*5);
mesh->i_buffer = new short[18];
memcpy(mesh->i_buffer, i, sizeof(short)*18);
mesh->vCount = 5;
mesh->iCount = 6;
mesh->x = x; mesh->y = y; mesh->z = z;
return mesh;
}
void matrixScale(MATRIX&mat, float sx, float sy, float sz)
{
memset(&mat, 0, sizeof(MATRIX));
mat.m00 = sx; mat.m11 = sy; mat.m22 = sz; mat.m33 = 1;
}
void matrixRotationX(MATRIX&mat, float angle)
{
angle = toRadian(angle);
mat.m00 = 1.0; mat.m01 = 0; mat.m02 = 0;
mat.m10 = 0; mat.m11 = cos(angle); mat.m12 = -sin(angle);
mat.m20 = 0; mat.m21 = sin(angle); mat.m22 = cos(angle);
}
void matrixRotationY(MATRIX&mat, float angle)
{
angle = toRadian(angle);
mat.m00 = cos(angle); mat.m01 = 0; mat.m02 = -sin(angle);
mat.m10 = 0; mat.m11 = 1; mat.m12 = 0;
mat.m20 = sin(angle); mat.m21 = 0; mat.m22 = cos(angle);
}
void matrixRotationZ(MATRIX&mat, float angle)
{
angle = toRadian(angle);
mat.m00 = cos(angle); mat.m01 = -sin(angle); mat.m02 = 0;
mat.m10 = sin(angle); mat.m11 = cos(angle); mat.m12 = 0;
mat.m20 = 0 ; mat.m21 = 0; mat.m22 = 1;
}
void matrixTranslation(MATRIX&mat, float x, float y, float z)
{
mat.m00 = 1; mat.m01 = 0; mat.m02 = 0; mat.m03 = x;
mat.m10 = 0; mat.m11 = 1; mat.m12 = 0; mat.m13 = y;
mat.m20 = 0; mat.m21 = 0; mat.m22 = 1; mat.m23 = z;
mat.m30 = 0; mat.m31 = 0; mat.m32 = 0; mat.m33 = 1;
}
void transformVector(VECTOR3&vect, MATRIX&mat, float origx, float origy, float origz, VECTOR3&view, MATRIX&viewTrans)
{
VECTOR3 hvect = vect;
vect.x = (hvect.x * mat.m00) + (hvect.y * mat.m01) + (hvect.z * mat.m02);
vect.y = (hvect.x * mat.m10) + (hvect.y * mat.m11) + (hvect.z * mat.m12);
vect.z = (hvect.x * mat.m20) + (hvect.y * mat.m21) + (hvect.z * mat.m22);
vect.x += origx; vect.y += origy; vect.z += origz;
VECTOR3 d; d.x = vect.x - view.x; d.y = vect.y - view.y; d.z = vect.z - view.z;
hvect = d;
d.x = (hvect.x * viewTrans.m00) + (hvect.y * viewTrans.m01) + (hvect.z * viewTrans.m02);
d.y = (hvect.x * viewTrans.m10) + (hvect.y * viewTrans.m11) + (hvect.z * viewTrans.m12);
d.z = (hvect.x * viewTrans.m20) + (hvect.y * viewTrans.m21) + (hvect.z * viewTrans.m22);
vect.x = view.x + d.x + mat.m03; vect.y = view.y + d.y + mat.m13; vect.z = view.z + d.z + mat.m23;
}
void matrixMultiply(MATRIX&out, MATRIX&a, MATRIX&b)
{
out.m00 = (a.m00*b.m00) + (a.m10 * b.m01) + (a.m20 * b.m02) + (a.m30 * b.m03); // First row. b matrix always the same
out.m01 = (a.m01*b.m00) + (a.m11 * b.m01) + (a.m21 * b.m02) + (a.m31 * b.m03); // a matrix, x is always the same
out.m02 = (a.m02*b.m00) + (a.m12 * b.m01) + (a.m22 * b.m02) + (a.m32 * b.m03); // but y changes for each colomn
out.m03 = (a.m03*b.m00) + (a.m13 * b.m01) + (a.m23 * b.m02) + (a.m33 * b.m03);
out.m10 = (a.m00*b.m10) + (a.m10 * b.m11) + (a.m20 * b.m12) + (a.m30 * b.m13); // Second Row
out.m11 = (a.m01*b.m10) + (a.m11 * b.m11) + (a.m21 * b.m12) + (a.m31 * b.m13);
out.m12 = (a.m02*b.m10) + (a.m12 * b.m11) + (a.m22 * b.m12) + (a.m32 * b.m13);
out.m13 = (a.m03*b.m10) + (a.m13 * b.m11) + (a.m23 * b.m12) + (a.m33 * b.m13);
out.m20 = (a.m00*b.m20) + (a.m10 * b.m21) + (a.m20 * b.m22) + (a.m30 * b.m33); // Third Row
out.m21 = (a.m01*b.m20) + (a.m11 * b.m21) + (a.m21 * b.m22) + (a.m31 * b.m33);
out.m22 = (a.m02*b.m20) + (a.m12 * b.m21) + (a.m22 * b.m22) + (a.m32 * b.m33);
out.m23 = (a.m03*b.m20) + (a.m13 * b.m21) + (a.m23 * b.m22) + (a.m33 * b.m33);
}
VECTOR2 getVectorScreen(VECTOR3&vect, VECTOR3&view, float zdist, int screenWidth, int screenHeight)
{
VECTOR2 pos;
if(!isVectorOnScreen(vect, view)){
pos.x = ERROR_NOTINSCREEN;
pos.y = ERROR_NOTINSCREEN;
pos.color = vect.color;
return pos;
}
VECTOR3 d;
d.x = vect.x - view.x; d.y = vect.y - view.y; d.z = vect.z - view.z;
pos.x = (d.x * (zdist / d.z)) + (screenWidth/2);
pos.y = (screenHeight/2) - (d.y * (zdist / d.z));
pos.color = vect.color;
return pos;
}
bool isVectorOnScreen(VECTOR3&v, VECTOR3&view)
{
float o = 0.0, a = 0.0, xang = 0.0, yang = 0.0, zang = 0.0;
o = v.x - view.x; a = v.z - view.z;
yang = toDegree(atan2(a, o));
o = v.z - view.z; a = v.y - view.y;
xang = toDegree(atan2(a, 0));
o = v.x - view.x; a = v.y - view.y;
zang = toDegree(atan2(a, 0));
if(yang > 32 && yang < 148)
return true;
else
return false;
}
// Draws the mesh pointed to by 'mesh' to the bitmap pointed to by 'pData'
void render(DWORD*pData, MESH*mesh, MATRIX& projTrans, VECTOR3&view, MATRIX&viewTrans, float fieldofview, bool filled)
{
int offset = 0;
VECTOR3 poly[3];
ZeroMemory(poly, sizeof(VECTOR3)*3);
VECTOR2 pt[3];
ZeroMemory(pt, sizeof(VECTOR2)*3);
// cycle threw the index buffer
for(int i = 0; i < mesh->iCount; ++i)
{
offset = i*3;
// get position, transform it, then get the screen position
for(int v = 0; v < 3; ++v)
{
poly[v] = mesh->v_buffer[mesh->i_buffer[offset+v]];
transformVector(poly[v], projTrans, mesh->x, mesh->y, mesh->z, view, viewTrans);
pt[v] = getVectorScreen(poly[v], view, fieldofview, 640, 480);
}
// draw the polygon
triangle(pData, pt[0],pt[1],pt[2], filled);
}
}
int compare(const void *v1, const void*v2)
{
if(v1 == v2) return 0;
if(v1 < v2) return -1;
if(v1 > v2) return 1;
return 0;
}
int compareInt(const void *p1, const void*p2)
{
int*x1 = (int*)(p1), *x2 = (int*)(p2);
if(*x1 == *x2) return 0;
if(*x1 > *x2 ) return 1;
if(*x1 < *x2 ) return -1;
return 0;
}
void triangle(DWORD*pData, VECTOR2 p1, VECTOR2 p2, VECTOR2 p3, bool fill)
{
if(fill)
{
// sort parameters
if(p1.x>p3.x){
p1.x=p1.x+p3.x ; p3.x=p1.x-p3.x ; p1.x=p1.x-p3.x;
p1.y=p1.y+p3.y ; p3.y=p1.y-p3.y ; p1.y=p1.y-p3.y;
}
if(p1.x>p2.x){
p1.x=p1.x+p2.x ; p2.x=p1.x-p2.x ; p1.x=p1.x-p2.x;
p1.y=p1.y+p2.y ; p2.y=p1.y-p2.y ; p1.y=p1.y-p2.y;
}
if(p2.x>p3.x){
p3.x=p3.x+p2.x ; p2.x=p3.x-p2.x ; p3.x=p3.x-p2.x;
p3.y=p3.y+p2.y ; p2.y=p3.y-p2.y ; p3.y=p3.y-p2.y;
}
int y1 = 0, y2 = 0;
// create triangle (+.01 is to avoid /0)
for(int x = p1.x; x <= p1.x+(p3.x-p1.x); ++x){
if(x<p2.x)
y1 = p1.y+(p2.y-p1.y)*((x-p1.x)/(p2.x+.01-p1.x));
else
y1 = p2.y+(p3.y-p2.y)*((x-p2.x)/(p3.x+.01-p2.x));
y2 = p1.y+(p3.y-p1.y)*((x-p1.x)/(p3.x+.01-p1.x));
// sort y for box drawing
if(y1>y2){ y1=y1+y2 ; y2=y1-y2 ; y1=y1-y2; }
for(int dy = y1; dy <= y2; ++dy)
putPixel(pData, x, dy, p1.color);
}
//
} else {
if(p1.x != ERROR_NOTINSCREEN && p1.y != ERROR_NOTINSCREEN && p2.y != ERROR_NOTINSCREEN && p2.x != ERROR_NOTINSCREEN){ qLine(pData, p1.x, p1.y,p2.x,p2.y,p1.color,p2.color);}
if(p3.x != ERROR_NOTINSCREEN && p3.y != ERROR_NOTINSCREEN && p2.y != ERROR_NOTINSCREEN && p2.x != ERROR_NOTINSCREEN){ qLine(pData, p2.x, p2.y,p3.x,p3.y,p2.color,p3.color);}
if(p1.x != ERROR_NOTINSCREEN && p1.y != ERROR_NOTINSCREEN && p3.y != ERROR_NOTINSCREEN && p3.x != ERROR_NOTINSCREEN){ qLine(pData, p3.x, p3.y, p1.x, p1.y, p3.color, p1.color);}
//if(p1.x != ERROR_NOTINSCREEN && p1.y != ERROR_NOTINSCREEN && p2.y != ERROR_NOTINSCREEN && p2.x != ERROR_NOTINSCREEN){ dbLine(p1.x, p1.y,p2.x,p2.y);}
//if(p3.x != ERROR_NOTINSCREEN && p3.y != ERROR_NOTINSCREEN && p2.y != ERROR_NOTINSCREEN && p2.x != ERROR_NOTINSCREEN){ dbLine(p2.x, p2.y,p3.x,p3.y);}
//if(p1.x != ERROR_NOTINSCREEN && p1.y != ERROR_NOTINSCREEN && p3.y != ERROR_NOTINSCREEN && p3.x != ERROR_NOTINSCREEN){ dbLine(p3.x, p3.y, p1.x, p1.y);}
}
}
DWORD transitionColor(DWORD c1, DWORD c2, float p)
{
if(c1 == c2) return c1;
p /= 100;
unsigned char r1 = dbRGBR(c1), g1 = dbRGBG(c1), b1 = dbRGBB(c1);
unsigned char r2 = dbRGBR(c2), g2 = dbRGBG(c2), b2 = dbRGBB(c2);
unsigned char nr = (unsigned char)(r1+((r2-r1)*p));
unsigned char ng = (unsigned char)(g1+((g2-g1)*p));
unsigned char nb = (unsigned char)(b1+((b2-b1)*p));
return colorRGB(nr,ng,nb);
}
void putPixel(DWORD*pData, int x, int y, DWORD color)
{
if(x < 0 || x > 640 || y < 0 || y > 480) return;
pData[x+y*640] = color;
}
void qLine(DWORD*pData, int x0, int y0, int x1, int y1, DWORD c1, DWORD c2)
{
int dx = x1-x0, dy = y1-y0;
int y = 0, x = 0, loops = 0;
float dxper = (dx/100.0), dyper = (dy/100.0);
if(abs(dx) > abs(dy))
{
float m = (float)(dy) / (float)(dx);
float b = y0 - m*x0;
if(dx < 0) { dx = -1; } else { dx = 1; }
while(x0 != x1)
{
x0 += dx; y = round( m * x0 + b );
putPixel(pData, x0, y, transitionColor(c1, c2, loops/dxper));
++loops;
}
} else if(dy != 0) {
float m = (float)(dx) / (float)(dy);
float b = x0 - m*y0;
if(dy < 0) {dy = -1;} else {dy = 1;}
while(y0 != y1)
{
y0 += dy; x = round( m * y0 + b );
putPixel(pData, x, y0, transitionColor(c1, c2, loops/dyper));;
++loops;
}
}
}
any questions feel free to ask. All functions are competely portable. exept for the trasitionColor function(i didn't define my own rgbr,g,b functions) so you can just copy and paste this code and use it on linux with SDL if you wanted to, because it just takes a pointer to a 640x480 bitmap.
New Site! Check it out \/