From 845ade7683de0c2479d10b96f0ee17ad9d6e2327 Mon Sep 17 00:00:00 2001 From: bgraansm Date: Thu, 24 Aug 2017 23:06:08 -0400 Subject: [PATCH] saving pulsar from school project (reformatting machine) --- a4.c | 1525 ++++++++++++++++++++++++++++++++++++++++++++++++++++ graphics.c | 845 +++++++++++++++++++++++++++++ graphics.h | 21 + makefile | 10 + readme.txt | 2 + visible.c | 426 +++++++++++++++ 6 files changed, 2829 insertions(+) create mode 100644 a4.c create mode 100644 graphics.c create mode 100644 graphics.h create mode 100644 makefile create mode 100644 readme.txt create mode 100644 visible.c diff --git a/a4.c b/a4.c new file mode 100644 index 0000000..8459b6f --- /dev/null +++ b/a4.c @@ -0,0 +1,1525 @@ + +/* Derived from scene.c in the The OpenGL Programming Guide */ +/* Keyboard and mouse rotation taken from Swiftless Tutorials #23 Part 2 */ +/* http://www.swiftless.com/tutorials/opengl/camera2.html */ + +/* Frames per second code taken from : */ +/* http://www.lighthouse3d.com/opengl/glut/index.php?fps */ + +#include +#include +#include +#include +#include + +#include "graphics.h" + +/* mob controls */ +extern void createMob(int, float, float, float, float); +extern void setMobPosition(int, float, float, float, float); +extern void getMobPosition(int, float*, float*, float*, float*, float*, float*); +extern int isMobVisible(int); +extern void hideMob(int); +extern void showMob(int); +extern void mobTrajectory(int, float, float); + + /* viewpoint control */ +extern void setViewPosition(float, float, float); +extern void getViewPosition(float *, float *, float *); +extern void getOldViewPosition(float *, float *, float *); +extern void setViewOrientation(float, float, float); +extern void getViewOrientation(float *, float *, float *); + +void startLevel(); +void endLevel(); + +typedef enum colour { + empty, + green, + blue, + red, + black, + white, + purple, + orange, + yellow +} colour; + +typedef struct enemy { + int id; + int size; + int x; + int y; + int z; + int dest_x; + int dest_z; + colour*** form; + char type; + colour col; +} enemy; + +colour map[WORLDX][WORLDZ] = {{empty}}; +colour key[11][3] = {{empty}}; +colour message[4][78] = {{empty}}; +int dropBox[3] = {0}; +int dest[2] = {0}; +enemy* enemies = NULL; +int n_enemies = 0; +int hasKey = 0; +int dropParty = 0; +int bouncing = 0; +int shot = 0; +int level = 0; +int wall_moving = 0; +int ind = 0; + +typedef struct wall_chunk { + int x; + int z; + int dir; + colour col; +} wall_chunk; + +void quit() { + endLevel(); + printf("You made it to level %d.\n", level); + exit(0); +} + +enemy* getEnemy(int x, int y, int z) { + for(int n=0; ndest_z = mob->z; + mob->dest_x = mob->x; + + if(cell == 0 && mob->x < (WORLDX -16) -mob->size) { + mob->dest_x = mob->x + 16; + } else if(cell == 1 && mob->x > 16 +mob->size) { + mob->dest_x = mob->x - 16; + } else if(cell == 2 && mob->z < (WORLDZ -16) -mob->size) { + mob->dest_z = mob->z + 16; + } else if(cell == 3 && mob->z > 16 +mob->size) { + mob->dest_z = mob->z - 16; + } +} + +enemy initEnemy(char type, int size, int x, int z, int temp, int dir) { + static int id = 1; + enemy ret; + + if((type != 'x' && type != 'o') || size < 0 || x < 0 || z < 0) { + id = 1; + } + + ret.id = id; + ret.size = size; + ret.x = x; + ret.y = (size/2)+1; + ret.z = z; + ret.type = type; + + if(type == 'o') { + ret.col = yellow; + } else if(type == 'x') { + ret.col = orange; + } + + ret.form = malloc(sizeof(colour**)*size); + for(int i=0; itype, mob->size, mob->x, mob->z, 1, 1); + int off = mob->size/2; + + for(int i=0; isize; i++) { + for(int j=0; jsize; j++) { + for(int k=0; ksize; k++) { + if(world[i+(mob->x)-off][j+(mob->y)-off][k+(mob->z)-off] == empty) { + world[i+(mob->x)-off][j+(mob->y)-off][k+(mob->z)-off] = mob->form[i][j][k]; + } + if(map[i+(mob->x)-off][k+(mob->z)-off] == empty) { + map[i+(mob->x)-off][k+(mob->z)-off] = mob->form[i][off][k]; + } + } + } + } + for(int i=0; isize; i++) { + for(int j=0; jsize; j++) { + for(int k=0; ksize; k++) { + temp.form[i][j][k] = mob->form[k][i][j]; + } + } + } + colour*** swap = mob->form; + mob->form = temp.form; + temp.form = swap; + destroyEnemy(temp); +} + +void behaveEnemy(enemy* mob, int random) { + float x, y, z, rotx, roty, rotz, yrot; + int see = 1; + getViewPosition(&x, &y, &z); + getViewOrientation(&rotx, &roty, &rotz); + + if(mob->x != mob->dest_x) { + int off = 0; + if(mob->dest_x > mob->x) { + off = 1; + } else { + off = -1; + } + for(int i=0; isize; i++) { + for(int j=0; jsize; j++) { + if(world[mob->x+((mob->size-i)*off)][mob->y][mob->z+j-1] != empty) { + randDestCell(mob, random); + return; + } + } + } + } + if(mob->z != mob->dest_z) { + int off = 0; + if(mob->dest_z > mob->z) { + off = 1; + } else { + off = -1; + } + for(int i=0; isize; i++) { + for(int j=0; jsize; j++) { + if(world[mob->x+j-1][mob->y][mob->z+((mob->size-i)*off)] != empty) { + randDestCell(mob, random); + return; + } + } + } + } + + if(mob->dest_x == mob->x && mob->dest_z == mob->z) { + randDestCell(mob, random); + } else if(mob->x < mob->dest_x) { + mob->x = mob->x+1; + } else if(mob->x > mob->dest_x) { + mob->x = mob->x-1; + } + if(mob->z < mob->dest_z) { + mob->z = mob->z+1; + } else if(mob->z > mob->dest_z) { + mob->z = mob->z-1; + } + + x = fabs(x); + z = fabs(z); + int zdir = 1; + int xdir = 1; + + if(mob->z > z) { + zdir = -1; + } + if(mob->x > x) { + xdir = -1; + } + + for(int i=0; ix-x); i++) { + for(int j=0; jy-y); j++) { + for(int k=0; kz-z); k++) { + if(world[mob->x+i*xdir][mob->y+j][mob->z+k*zdir] != empty) { + see = 0; + break; + } + } + if(!see) { + break; + } + } + if(!see) { + break; + } + } + float xrot, zrot; + float mobx, moby, mobz, mobroty, mobrotx, mobrotz; + int xoff=0, zoff=0; + int origin = 0; + float opp, adj, mult = 1.0; + + if(mob->x>x) { + xoff = -1*mob->size; + } else if(mob->xsize; + } + if(mob->z>z) { + zoff = -1*mob->size; + } else if(mob->zsize; + } + + if(x > mob->x && z < mob->z) { + origin = 90; + opp = mob->z+zoff-z; + adj = mob->x+xoff-x; + } else if(z > mob->z && x > mob->x) { + origin = 180; + opp = mob->x+xoff-x; + adj = mob->z+zoff-z; + } else if(z > mob->z && x < mob->x) { + origin = 270; + opp = mob->z+zoff-z; + adj = mob->x+xoff-x; + mult = -1.0; + } else if(z < mob->z && x < mob->x) { + origin = 360; + opp = mob->x+xoff-x; + adj = mob->z+zoff-z; + } else { + return; + } + + yrot = (float)origin-degree(atan(opp/adj))*mult; + if(origin == 90) { + yrot = 90-(yrot-90); + } + xrot = 0.0; + zrot = 0.0; + + if(see && !isMobVisible(mob->id)) { + getMobPosition(mob->id, &mobx, &moby, &mobz, &mobroty, &mobrotx, &mobrotz); + + createMob(mob->id, mob->x+xoff, mob->y, mob->z+zoff, yrot); + mobTrajectory(mob->id, xrot, zrot); + showMob(mob->id); + } + + if(roty < 90-yrot+45 && roty > 90-yrot-45) { + switch(origin) { + case 90: + mob->dest_x = mob->x-random; + mob->dest_z = mob->z+random; + break; + case 180: + mob->dest_x = mob->x-random; + mob->dest_z = mob->z-random; + break; + case 270: + mob->dest_x = mob->x+random; + mob->dest_z = mob->z-random; + break; + case 360: + mob->dest_x = mob->x+random; + mob->dest_z = mob->z+random; + break; + default: + break; + } + } +} + +void teleEnemy(enemy* mob) { + int dropOff = 0; + int newx, newz; + + while(!dropOff) { + newx = rand()%WORLDX; + newz = rand()%WORLDZ; + int occupied = 0; + + for(int x=newx; xx = newx; + mob->z = newz; +} + +GLfloat* rgb(colour col) { + static GLfloat val[4] = {0.0, 0.0, 0.0, 1.0}; + for(int i=0; i<3; i++) { + val[i] = 0.0; + } + val[3] = 1.0; + switch(col) { + case red: + val[0] = 1.0; + break; + case blue: + val[2] = 1.0; + break; + case purple: + val[2] = 1.0; + val[0] = 1.0; + break; + case yellow: + val[1] = 1.0; + val[0] = 1.0; + break; + case white: + val[0] = 1.0; + val[1] = 1.0; + val[2] = 1.0; + break; + case green: + val[1] = 1.0; + break; + case orange: + val[0] = 1.0; + val[1] = 0.3; + break; + case black: + val[0] = 0.8; + val[3] = 0.4; + case empty: + default: + break; + } + return val; +} + + /* mouse function called by GLUT when a button is pressed or released */ +void mouse(int, int, int, int); + +extern int getMapState(); + + /* initialize graphics library */ +extern void graphicsInit(int *, char **); + + /* lighting control */ +extern void setLightPosition(GLfloat, GLfloat, GLfloat); +extern GLfloat* getLightPosition(); + + /* add cube to display list so it will be drawn */ +extern int addDisplayList(int, int, int); + + /* player controls */ +extern void createPlayer(int, float, float, float, float); +extern void setPlayerPosition(int, float, float, float, float); +extern void hidePlayer(int); +extern void showPlayer(int); + + /* 2D drawing functions */ +extern void draw2Dline(int, int, int, int, int); +extern void draw2Dbox(int, int, int, int); +extern void draw2Dtriangle(int, int, int, int, int, int); +extern void set2Dcolour(float []); + + + /* flag which is set to 1 when flying behaviour is desired */ +extern int flycontrol; + /* flag used to indicate that the test world should be used */ +extern int testWorld; + /* flag to print out frames per second */ +extern int fps; + /* flag to indicate the space bar has been pressed */ +extern int space; + /* flag indicates the program is a client when set = 1 */ +extern int netClient; + /* flag indicates the program is a server when set = 1 */ +extern int netServer; + /* size of the window in pixels */ +extern int screenWidth, screenHeight; + /* flag indicates if map is to be printed */ +extern int displayMap; + + /* frustum corner coordinates, used for visibility determination */ +extern float corners[4][3]; + + /* determine which cubes are visible e.g. in view frustum */ +extern void ExtractFrustum(); +extern void tree(float, float, float, float, float, float, int); + +/********* end of extern variable declarations **************/ + +void getDest(int* x, int* z) { + int destX, destZ; + int found = 0; + while(!found) { + destX = (rand()%(WORLDX-6))+3; + destZ = (rand()%(WORLDZ-6))+3; + for(int i=destX-1; i=0 && i=0 && j 0) { + if(world[abs((int)(x+0.25))][abs((int)(y-1))][abs((int)z)] == 0) { + newy = oldy-1; + if(powerUp(col)) { + world[abs((int)(x+0.25))][abs((int)y)][abs((int)z)] = empty; + map[abs((int)(x+0.25))][abs((int)z)] = empty; + } else { + newy = oldy-1; + } + } else { + if(col == white && world[abs((int)(x+0.25))][abs((int)(y-1))][abs((int)z)] == white && hasKey) { + printf("Congratulations, you've cleared level %d!\n", level); + endLevel(); + startLevel(); + return; + } + newx = oldx; + } + } + } else if(dirx == 'w') { + col = world[abs((int)(x-0.25))][abs((int)y)][abs((int)z)]; + if(col > 0) { + if(world[abs((int)(x-0.25))][abs((int)(y-1))][abs((int)z)] == 0) { + if(powerUp(col)) { + world[abs((int)(x-0.25))][abs((int)y)][abs((int)z)] = empty; + map[abs((int)(x-0.25))][abs((int)z)] = empty; + } else { + newy = oldy-1; + } + } else { + if(col == white && world[abs((int)(x-0.25))][abs((int)(y-1))][abs((int)z)] == white && hasKey) { + printf("Congratulations, you've cleared level %d!\n", level); + endLevel(); + startLevel(); + return; + } + newx = oldx; + } + } + } + + if(dirz == 'n') { + col = world[abs((int)x)][abs((int)y)][abs((int)(z+0.25))]; + if(col > 0) { + if(world[abs((int)x)][abs((int)(y-1))][abs((int)(z+0.25))] == 0) { + if(powerUp(col)) { + world[abs((int)x)][abs((int)y)][abs((int)(z+0.25))] = empty; + map[abs((int)x)][abs((int)(z+0.25))] = empty; + } else { + newy = oldy-1; + } + } else { + if(col == white && world[abs((int)x)][abs((int)(y-1))][abs((int)(z+0.25))] == white && hasKey) { + printf("Congratulations, you've cleared level %d!\n", level); + endLevel(); + startLevel(); + return; + } + newz = oldz; + } + } + } else if(dirz == 's') { + col = world[abs((int)x)][abs((int)y)][abs((int)(z-0.25))]; + if(col > 0) { + if(world[abs((int)x)][abs((int)(y-1))][abs((int)(z-0.25))] == 0) { + if(powerUp(col)) { + world[abs((int)x)][abs((int)y)][abs((int)(z-0.25))] = empty; + map[abs((int)x)][abs((int)(z-0.25))] = empty; + } else { + newy = oldy-1; + } + } else { + if(col == white && world[abs((int)x)][abs((int)(y-1))][abs((int)(z-0.25))] == white && hasKey) { + printf("Congratulations, you've cleared level %d!\n", level); + endLevel(); + startLevel(); + return; + } + newz = oldz; + } + } + } + + if(fabs(newx) >= WORLDX) { + newx = -1.0*(WORLDX-1); + } else if(newx > 0) { + newx = 0; + } + if(fabs(newz) >= WORLDZ) { + newz = -1.0*(WORLDZ-1); + } else if(newz > 0) { + newz = 0; + } + + setViewPosition(newx, newy, newz); + + mapx = abs((int)newx); + mapy = abs((int)newz); + for(i=mapx-1; i=0 && i=0 && j screenWidth) { + smallestRes = screenWidth; + } else { + smallestRes = screenHeight; + } + mapInflation = (int)((float)smallestRes/(float)WORLDZ); + + xdis = (screenWidth-(WORLDX*mapInflation))/2; + ydis = (screenHeight-(WORLDZ*mapInflation))/2; + + for(i=0; i 0.05) { + int destX = dest[0], destZ = dest[1]; + float xRatio = 0.0, zRatio = 0.0; + int xdir = 1, zdir = 1; + if((int)fabs(x) < destX) { + xRatio = (destX-fabs(x))/10.0; + } else if((int)fabs(x) > destX) { + xRatio = (fabs(x)-destX)/10.0; + xdir = -1; + } + if((int)fabs(z) < destZ) { + zRatio = (destZ-fabs(z))/10.0; + } else if((int)fabs(z) > destZ) { + zRatio = (fabs(z)-destZ)/10.0; + zdir = -1; + } + + if(xRatio < 1 && zRatio < 1) { + bouncing = 0; + } + for(i=(int)fabs(x)-1; i<(int)fabs(x)+2; i++) { + for(j=(int)fabs(z)-1; j<(int)fabs(z)+2; j++) { + if(map[i][j] == white) { + map[i][j] = empty; + } + } + } + for(i=(int)fabs(x-(xRatio*xdir))-1; i<(int)fabs(x-(xRatio*xdir))+2; i++) { + for(j=(int)fabs(z-(zRatio*zdir))-1; j<(int)fabs(z-(zRatio*zdir))+2; j++) { + if(!map[i][j]) { + map[i][j] = white; + } + } + } + float yoff = sqrt(((xRatio*10)*(xRatio*10))+((zRatio*10)*(zRatio*10))); + setViewPosition(x-(xRatio*xdir), -1*yoff, z-(zRatio*zdir)); + getViewPosition(&x, &y, &z); + bounce_timer = end; + } + + if((float)(end - projectile_timer) / (float)CLOCKS_PER_SEC > 0.01) { + for(i=0; i<=n_enemies; i++) { + if(isMobVisible(i)) { + float mobx, moby, mobz, mobroty, mobrotx, mobrotz, difx, difz, dify; + getMobPosition(i, &mobx, &moby, &mobz, &mobroty, &mobrotx, &mobrotz); + while(mobroty >= 360.0) { + mobroty -= 360.0; + } + while(mobrotz >= 360.0) { + mobrotz -= 360.0; + } + while(mobrotx >= 360.0) { + mobrotx -= 360.0; + } + + difz = fabs(cos(radian(mobroty))); + difx = fabs(sin(radian(mobroty))); + dify = fabs(sin(radian(mobrotx))); + + if(mobrotx > 0 && mobrotx < 180) { + dify = -1.0*dify; + } + + if(mobroty > 180 && mobroty <= 270) { + difx = -1.0*difx; + } else if(mobroty > 270 && mobroty < 360) { + difz = -1.0*difz; + difx = -1.0*difx; + } else if(mobroty >= 0 && mobroty < 90) { + difz = -1.0*difz; + } + if(map[(int)round(mobx)][(int)round(mobz)] == yellow) { + map[(int)round(mobx)][(int)round(mobz)] = empty; + } + if(mobx+difx > WORLDX || mobx+difx < 0 || mobz+difz > WORLDZ || mobz+difz < 0 || moby+dify > WORLDY || moby+dify < 0) { + hideMob(i); + } else { + setMobPosition(i, mobx+difx, moby+dify, mobz+difz, mobroty); + switch(world[(int)round(mobx+difx)][(int)round(moby+dify)][(int)round(mobz+difz)]) { + case blue: + case black: + hideMob(i); + break; + case empty: + if(map[(int)round(mobx+difx)][(int)round(mobz+difz)] == empty) { + map[(int)round(mobx+difx)][(int)round(mobz+difz)] = yellow; + } else if(map[(int)round(mobx+difx)][(int)round(mobz+difz)] == white) { + if(round(mobx+difx) == round(fabs(x)) && round(mobz+difz) == round(fabs(z))) { + if((moby+dify) < fabs(y)+1.0 && (moby+dify) > fabs(y)-1.0) { + printf("You've been shot!\n"); + shot = 12; + hideMob(i); + } + } + } + break; + default: + if((int)round(mobx+difx) > 3 && (int)round(mobx+difx) < WORLDX-3 && (int)round(mobz+difz) > 3 && (int)round(mobz+difz) < WORLDZ-3 && world[(int)round(mobx+difx)][(int)round(moby+dify)][(int)round(mobz+difz)] != white) { + world[(int)round(mobx+difx)][(int)round(moby+dify)][(int)round(mobz+difz)] = empty; + map[(int)round(mobx+difx)][(int)round(mobz+difz)] = empty; + } + hideMob(i); + } + } + } + } + } + + if((float)(end - gravity_timer) / (float)CLOCKS_PER_SEC > 0.02 && !bouncing) { + if(abs((int)y)-1 >= WORLDY || world[abs((int)x)][abs((int)y)-1][abs((int)z)] == 0) { + setViewPosition(x, y+1, z); + gravity_timer = end; + } + if(y>-1.8) { + setViewPosition(x, -1.8, z); + } + } + + if((float)(end - wall_timer) / (float)CLOCKS_PER_SEC > 5.0) { + int w=0; + + for(w=0; w 0) { + chunks[num_chunks] = chunk; + num_chunks++; + } + } + } + } + wall_moving = 1; + wall_timer = end; + } + + if(wall_moving && (float)(end - inner_wall) / (float)CLOCKS_PER_SEC > 0.08) { + float xpos, ypos, zpos; + + for(i=0; iz = mob->z - mob->size; + } else { + mob->z = mob->z + mob->size; + } + mob->dest_x = mob->x; + mob->dest_z = mob->z; + } + world[(chunks[i].x+15)-ind][k][j] = chunks[i].col; + } + map[(chunks[i].x+15)-ind][j] = chunks[i].col; + } + break; + case 2: //east + for(j=chunks[i].x+1; jx = mob->x - mob->size; + } else { + mob->x = mob->x + mob->size; + } + mob->dest_x = mob->x; + mob->dest_z = mob->z; + } + world[j][k][(chunks[i].z+15)-ind] = chunks[i].col; + } + map[j][(chunks[i].z+15)-ind] = chunks[i].col; + } + break; + case 3: //south + for(j=chunks[i].z+1; jz = mob->z - mob->size; + } else { + mob->z = mob->z + mob->size; + } + mob->dest_x = mob->x; + mob->dest_z = mob->z; + } + world[(chunks[i].x-1)-ind][k][j] = chunks[i].col; + } + map[(chunks[i].x-1)-ind][j] = chunks[i].col; + } + break; + case 4: //west + for(j=chunks[i].x+1; jx = mob->x - mob->size; + } else { + mob->x = mob->x + mob->size; + } + mob->dest_x = mob->x; + mob->dest_z = mob->z; + } + world[j][k][(chunks[i].z-1)-ind] = chunks[i].col; + } + map[j][(chunks[i].z-1)-ind] = chunks[i].col; + } + break; + } + } + ind++; + if(ind == 12) { + ind = 0; + wall_moving = 0; + num_chunks = 0; + } + inner_wall = end; + } + + if((float)(end - mob_timer) / (float)CLOCKS_PER_SEC > 0.1) { + for(i=0; i 0.1 && dropParty) { + if(dropBox[2] > 1) { + dropBox[2] = dropBox[2]-1; + + if(world[dropBox[0]-3][dropBox[2]][dropBox[1]-3] == empty) { + colour col = (rand()%3)+1; + map[dropBox[0]-3][dropBox[1]-3] = col; + world[dropBox[0]-3][dropBox[2]][dropBox[1]-3] = col; + world[dropBox[0]-3][dropBox[2]+1][dropBox[1]-3] = empty; + } + if(world[dropBox[0]+3][dropBox[2]][dropBox[1]-3] == empty) { + colour col = (rand()%3)+1; + map[dropBox[0]+3][dropBox[1]-3] = col; + world[dropBox[0]+3][dropBox[2]][dropBox[1]-3] = col; + world[dropBox[0]+3][dropBox[2]+1][dropBox[1]-3] = empty; + } + if(world[dropBox[0]-3][dropBox[2]][dropBox[1]+3] == empty) { + colour col = (rand()%3)+1; + map[dropBox[0]-3][dropBox[1]+3] = col; + world[dropBox[0]-3][dropBox[2]][dropBox[1]+3] = col; + world[dropBox[0]-3][dropBox[2]+1][dropBox[1]+3] = empty; + } + if(world[dropBox[0]+3][dropBox[2]][dropBox[1]+3] == empty) { + colour col = (rand()%3)+1; + map[dropBox[0]+3][dropBox[1]+3] = col; + world[dropBox[0]+3][dropBox[2]][dropBox[1]+3] = col; + world[dropBox[0]+3][dropBox[2]+1][dropBox[1]+3] = empty; + } + } else { + dropParty = 0; + } + drop_timer = end; + } + } +} + + + /* called by GLUT when a mouse button is pressed or released */ + /* -button indicates which button was pressed or released */ + /* -state indicates a button down or button up event */ + /* -x,y are the screen coordinates when the mouse is pressed or */ + /* released */ +void mouse(int button, int state, int x, int y) { + float xpos, ypos, zpos; + float xrot, yrot, zrot; + float mobx, moby, mobz, mobroty, mobrotx, mobrotz; + + getViewPosition(&xpos, &ypos, &zpos); + getViewOrientation(&xrot, &yrot, &zrot); + getMobPosition(0, &mobx, &moby, &mobz, &mobroty, &mobrotx, &mobrotz); + + if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { + map[(int)(mobx)][(int)(mobz)] = empty; + createMob(0, fabs(xpos), fabs(ypos), fabs(zpos), yrot); + mobTrajectory(0, xrot, zrot); + showMob(0); + } else if (button == GLUT_MIDDLE_BUTTON) { + } else { + } + if (state == GLUT_UP) { + } else { + } +} + +void startLevel() { + int x=0; + int h=WORLDY; + int l=0, randX, randZ; + int i,j,k, keySet = 0; + + level++; + + for(x=0; x=z-12; i--) { + for(j=x+1; j=x-12; j--) { + map[j][i] = purple; + for(k=1; k 16 && z > 16) { + if(rand() % 3 == 0 && n_enemies < MOB_COUNT-1) { + char type = 'x'; + int size = 3; + if(rand()%2 == 0) { + type = 'o'; + } + n_enemies++; + enemies = realloc(enemies, sizeof(enemy)*n_enemies); + enemies[n_enemies-1] = initEnemy(type, size, x, z, 0, rand()); + + for(i=0; i +#include +#include +#include + +#include "graphics.h" + +extern void update(); +extern void collisionResponse(); +extern void buildDisplayList(); +extern void mouse(int, int, int, int); +extern void draw2D(); +extern void quit(); + + + /* flags used to control the appearance of the image */ +int lineDrawing = 0; // draw polygons as solid or lines +int lighting = 1; // use diffuse and specular lighting +int smoothShading = 1; // smooth or flat shading +int textures = 0; + + /* texture data */ +GLubyte Image[64][64][4]; +GLuint textureID[1]; + + /* viewpoint coordinates */ +float vpx = -50.0, vpy = -50.0, vpz = -50.0; +float oldvpx, oldvpy, oldvpz; + + /* mouse direction coordiates */ +float mvx = 0.0, mvy = 45.0, mvz = 0.0; + + /* stores current mouse position value */ +float oldx, oldy; + + /* location for the light source (the sun), the first three + values are the x,y,z coordinates */ +GLfloat lightPosition[] = {0.0, 49.0, 0.0, 0.0}; + /* location for light source that is kept at viewpoint location */ +GLfloat viewpointLight[] = {-50.0, -50.0, -50.0, 1.0}; + + /* sky cube size */ +float skySize; + + /* screen dimensions */ +int screenWidth = 1024; +int screenHeight = 768; + + /* command line flags */ +int flycontrol = 1; // allow viewpoint to move in y axis when 1 +int displayAllCubes = 0; // draw all of the cubes in the world when 1 +int testWorld = 0; // sample world for timing tests +int fps = 0; // turn on frame per second output +int netClient = 0; // network client flag, is client when = 1 +int netServer = 0; // network server flag, is server when = 1 + + /* list of cubes to display */ +int displayList[MAX_DISPLAY_LIST][3]; +int displayCount = 0; // count of cubes in displayList[][] + + /* list of mobs - number of mobs, xyz values and rotation about y */ +float mobPosition[MOB_COUNT][6]; + /* visibility of mobs, 0 not drawn, 1 drawn */ +short mobVisible[MOB_COUNT]; + + /* list of players - number of mobs, xyz values and rotation about y */ +float playerPosition[MOB_COUNT][4]; + /* visibility of players, 0 not drawn, 1 drawn */ +short playerVisible[MOB_COUNT]; + + /* flag indicating the user wants the cube in front of them removed */ +int space = 0; + /* flag indicates if map is to be printed */ +int displayMap = 1; + + /* functions draw 2D images */ +void draw2Dline(int, int, int, int, int); +void draw2Dbox(int, int, int, int); +void draw2Dtriangle(int, int, int, int, int, int); +void set2Dcolour(float []); + +/***************/ + +int isMobVisible(int mob) { + return mobVisible[mob]; +} + +int getMapState() { + return displayMap; +} + + /* player control functions */ + /* set all player location, rotation, and visibility values to zero */ +void initPlayerArray() { +int i; + for (i=0; i= PLAYER_COUNT) { + printf("ERROR: player number greater than %d\n", PLAYER_COUNT); + exit(1); + } + playerPosition[number][0] = x; + playerPosition[number][1] = y; + playerPosition[number][2] = z; + playerPosition[number][3] = playerroty; + playerVisible[number] = 1; +} + + /* move player to a new position xyz with rotation rotx,roty,rotz */ +void setPlayerPosition(int number, float x, float y, float z, float playerroty){ + if (number >= PLAYER_COUNT) { + printf("ERROR: player number greater than %d\n", PLAYER_COUNT); + exit(1); + } + playerPosition[number][0] = x; + playerPosition[number][1] = y; + playerPosition[number][2] = z; + playerPosition[number][3] = playerroty; +} + + /* turn off drawing for player number */ +void hidePlayer(int number) { + if (number >= PLAYER_COUNT) { + printf("ERROR: player number greater than %d\n", PLAYER_COUNT); + exit(1); + } + playerVisible[number] = 0; +} + + /* turn on drawing for player number */ +void showPlayer(int number) { + if (number >= PLAYER_COUNT) { + printf("ERROR: player number greater than %d\n", PLAYER_COUNT); + exit(1); + } + playerVisible[number] = 1; +} + + + + /* mob control functions */ + /* set all mob location, rotation, and visibility values to zero */ +void initMobArray() { +int i; + for (i=0; i= MOB_COUNT) { + printf("ERROR: mob number greater than %d\n", MOB_COUNT); + exit(1); + } + mobPosition[number][0] = x; + mobPosition[number][1] = y; + mobPosition[number][2] = z; + mobPosition[number][3] = mobroty; + mobVisible[number] = 1; +} + +void mobTrajectory(int number, float mobrotx, float mobrotz) { + mobPosition[number][4] = mobrotx; + mobPosition[number][5] = mobrotz; +} + + /* move mob to a new position xyz with rotation rotx,roty,rotz */ +void setMobPosition(int number, float x, float y, float z, float mobroty){ + if (number >= MOB_COUNT) { + printf("ERROR: mob number greater than %d\n", MOB_COUNT); + exit(1); + } + mobPosition[number][0] = x; + mobPosition[number][1] = y; + mobPosition[number][2] = z; + mobPosition[number][3] = mobroty; +} + +void getMobPosition(int number, float* x, float* y, float* z, float* roty, float* rotx, float* rotz) { + *x = mobPosition[number][0]; + *y = mobPosition[number][1]; + *z = mobPosition[number][2]; + *roty = mobPosition[number][3]; + *rotx = mobPosition[number][4]; + *rotz = mobPosition[number][5]; +} + + /* turn off drawing for mob number */ +void hideMob(int number) { + if (number >= MOB_COUNT) { + printf("ERROR: mob number greater than %d\n", MOB_COUNT); + exit(1); + } + mobVisible[number] = 0; +} + + /* turn on drawing for mob number */ +void showMob(int number) { + if (number >= MOB_COUNT) { + printf("ERROR: mob number greater than %d\n", MOB_COUNT); + exit(1); + } + mobVisible[number] = 1; +} + + + + + /* allows user to set position of the light */ +void setLightPosition(GLfloat x, GLfloat y, GLfloat z) { + lightPosition[0] = x; + lightPosition[1] = y; + lightPosition[2] = z; + glLightfv (GL_LIGHT0, GL_POSITION, lightPosition); +} + + /* returns current position of the light */ +GLfloat* getLightPosition() { + return(lightPosition); +} + + /* functions store and return the current location of the viewpoint */ +void getViewPosition(float *x, float *y, float *z) { + *x = vpx; + *y = vpy; + *z = vpz; +} + +void setViewPosition(float x, float y, float z) { + oldvpx = vpx; + oldvpy = vpy; + oldvpz = vpz; + vpx = x; + vpy = y; + vpz = z; +} + + /* returns the previous location of the viewpoint */ +void getOldViewPosition(float *x, float *y, float *z) { + *x = oldvpx; + *y = oldvpy; + *z = oldvpz; +} + + /* sets the current orientation of the viewpoint */ +void setViewOrientation(float xaxis, float yaxis, float zaxis) { + mvx = xaxis; + mvy = yaxis; + mvz = zaxis; +} + + /* returns the current orientation of the viewpoint */ +void getViewOrientation(float *xaxis, float *yaxis, float *zaxis) { + *xaxis = mvx; + *yaxis = mvy; + *zaxis = mvz; +} + + /* add the cube at world[x][y][z] to the display list and */ + /* increment displayCount */ +void addDisplayList(int x, int y, int z) { + displayList[displayCount][0] = x; + displayList[displayCount][1] = y; + displayList[displayCount][2] = z; + displayCount++; + if (displayCount > MAX_DISPLAY_LIST) { + printf("You have put more items in the display list then there are\n"); + printf("cubes in the world. Set displayCount = 0 at some point.\n"); + exit(1); + } +} + + + +/* Initialize material property and light source. */ +void init (void) +{ + GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; + GLfloat light_diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; + GLfloat light_specular[] = { 0.5, 0.5, 0.5, 1.0 }; + GLfloat light_full_off[] = {0.0, 0.0, 0.0, 1.0}; + GLfloat light_full_on[] = {1.0, 1.0, 1.0, 1.0}; + + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); + + /* if lighting is turned on then use ambient, diffuse and specular + lights, otherwise use ambient lighting only */ + if (lighting == 1) { + /* sun light */ + glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient); + glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse); + /* no specular reflection from sun, it is too distracting */ + glLightfv (GL_LIGHT0, GL_SPECULAR, light_full_off); + } else { + glLightfv (GL_LIGHT0, GL_AMBIENT, light_full_on); + glLightfv (GL_LIGHT0, GL_DIFFUSE, light_full_off); + glLightfv (GL_LIGHT0, GL_SPECULAR, light_full_off); + } + glLightfv (GL_LIGHT0, GL_POSITION, lightPosition); + + /* viewpoint light */ + glLightfv (GL_LIGHT1, GL_POSITION, viewpointLight); + glLightfv (GL_LIGHT1, GL_AMBIENT, light_ambient); + glLightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse); + glLightfv (GL_LIGHT1, GL_SPECULAR, light_specular); + glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5); + + + glEnable (GL_LIGHTING); + glEnable (GL_LIGHT0); + glEnable (GL_LIGHT1); + + glEnable(GL_DEPTH_TEST); + +} + + /* draw cube in world[i][j][k] */ +void drawCube(int i, int j, int k) { +GLfloat blue[] = {0.0, 0.0, 1.0, 1.0}; +GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; +GLfloat green[] = {0.0, 1.0, 0.0, 1.0}; +GLfloat yellow[] = {1.0, 1.0, 0.0, 1.0}; +GLfloat purple[] = {1.0, 0.0, 1.0, 1.0}; +GLfloat orange[] = {1.0, 0.64, 0.0, 1.0}; +GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; +GLfloat black[] = {0.0, 0.0, 0.0, 1.0}; + +GLfloat dblue[] = {0.0, 0.0, 0.5, 1.0}; +GLfloat dred[] = {0.5, 0.0, 0.0, 1.0}; +GLfloat dgreen[] = {0.0, 0.5, 0.0, 1.0}; +GLfloat dyellow[] = {0.5, 0.5, 0.0, 1.0}; +GLfloat dpurple[] = {0.5, 0.0, 0.5, 1.0}; +GLfloat dorange[] = {0.5, 0.32, 0.0, 1.0}; + + + /* select colour based on value in the world array */ + glMaterialfv(GL_FRONT, GL_SPECULAR, white); + + if (world[i][j][k] == 1) { + glMaterialfv(GL_FRONT, GL_AMBIENT, dgreen); + glMaterialfv(GL_FRONT, GL_DIFFUSE, green); + } + else if (world[i][j][k] == 2) { + glMaterialfv(GL_FRONT, GL_AMBIENT, dblue); + glMaterialfv(GL_FRONT, GL_DIFFUSE, blue); + } + else if (world[i][j][k] == 3) { + glMaterialfv(GL_FRONT, GL_AMBIENT, dred); + glMaterialfv(GL_FRONT, GL_DIFFUSE, red); + } + else if (world[i][j][k] == 4) { + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black); + } + else if (world[i][j][k] == 5) { + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, white); + } + else if (world[i][j][k] == 6) { + glMaterialfv(GL_FRONT, GL_AMBIENT, dpurple); + glMaterialfv(GL_FRONT, GL_DIFFUSE, purple); + } + else if (world[i][j][k] == 7) { + glMaterialfv(GL_FRONT, GL_AMBIENT, dorange); + glMaterialfv(GL_FRONT, GL_DIFFUSE, orange); + } + else { + glMaterialfv(GL_FRONT, GL_AMBIENT, dyellow); + glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow); + } + + glPushMatrix (); + /* offset cubes by 0.5 so the centre of the */ + /* cube falls in the centre of the world array */ + glTranslatef(i + 0.5, j + 0.5, k + 0.5); + glutSolidCube(1.0); + glPopMatrix (); +} + + + + /* called each time the world is redrawn */ +void display (void) +{ +GLfloat skyblue[] = {0.52, 0.74, 0.84, 1.0}; +GLfloat black[] = {0.0, 0.0, 0.0, 1.0}; +GLfloat red[] = {1.0, 0.0, 0.0, 1.0}; +GLfloat gray[] = {0.3, 0.3, 0.3, 1.0}; +GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; +int i, j, k; + + buildDisplayList(); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* position viewpoint based on mouse rotation and keyboard + translation */ + glLoadIdentity(); + glRotatef(mvx, 1.0, 0.0, 0.0); + glRotatef(mvy, 0.0, 1.0, 0.0); + glRotatef(mvz, 0.0, 0.0, 1.0); + /* Subtract 0.5 to raise viewpoint slightly above objects. */ + /* Gives the impression of a head on top of a body. */ + glTranslatef(vpx, vpy - 0.5, vpz); +// glTranslatef(vpx, vpy, vpz); + + + /* set viewpoint light position */ + viewpointLight[0] = -vpx; + viewpointLight[1] = -vpy; + viewpointLight[2] = -vpz; + glLightfv (GL_LIGHT1, GL_POSITION, viewpointLight); + + /* draw surfaces as either smooth or flat shaded */ + if (smoothShading == 1) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + + /* draw polygons as either solid or outlines */ + if (lineDrawing == 1) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + else + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + /* give all objects the same shininess value and specular colour */ + glMaterialf(GL_FRONT, GL_SHININESS, 90.0); + + /* set starting location of objects */ + glPushMatrix (); + + /* make a blue sky cube */ + glShadeModel(GL_SMOOTH); + /* turn off all reflection from sky so it is a solid colour */ + glMaterialfv(GL_FRONT, GL_AMBIENT, black); + glMaterialfv(GL_FRONT, GL_DIFFUSE, black); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, skyblue); + glPushMatrix (); + /* move the sky cube center to middle of world space */ + glTranslatef((float)WORLDX/2.0, (float)WORLDY/2.0, (float)WORLDZ/2.0); + //glutSolidCube(150.0); + glutSolidCube(skySize); + glPopMatrix (); + glShadeModel(GL_SMOOTH); + /* turn off emision lighting, use only for sky */ + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); + + /* draw mobs in the world */ + for(i=0; i 2) + displayMap = 0; + break; + } +} + + /* load a texture from a file */ + /* not currently used */ +void loadTexture() { +FILE *fp; +int i, j; +int red, green, blue; + + if ((fp = fopen("image.txt", "r")) == 0) { + printf("Error, failed to find the file named image.txt.\n"); + exit(0); + } + + for(i=0; i<64; i++) { + for(j=0; j<64; j++) { + fscanf(fp, "%d %d %d", &red, &green, &blue); + Image[i][j][0] = red; + Image[i][j][1] = green; + Image[i][j][2] = blue; + Image[i][j][3] = 255; + } + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glGenTextures(1,textureID); + glBindTexture(GL_TEXTURE_2D, textureID[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, + GL_UNSIGNED_BYTE, Image); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + + fclose(fp); +} + + /* responds to mouse movement when a button is pressed */ +void motion(int x, int y) { + /* update current mouse movement but don't use to change the viewpoint*/ + oldx = x; + oldy = y; +} + + /* responds to mouse movement when a button is not pressed */ +void passivemotion(int x, int y) { + mvx += (float) y - oldy; + mvy += (float) x - oldx; + oldx = x; + oldy = y; + glutPostRedisplay(); +} + + + + /* initilize graphics information and mob data structure */ +void graphicsInit(int *argc, char **argv) { +int i, fullscreen; + /* set GL window information */ + glutInit(argc, argv); + glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); + + /* parse command line args */ + fullscreen = 0; + for(i=1; i<*argc; i++) { + if (strcmp(argv[i],"-full") == 0) + fullscreen = 1; + if (strcmp(argv[i],"-drawall") == 0) + displayAllCubes = 1; + if (strcmp(argv[i],"-testworld") == 0) + testWorld = 1; + if (strcmp(argv[i],"-fps") == 0) + fps = 1; + if (strcmp(argv[i],"-client") == 0) + netClient = 1; + if (strcmp(argv[i],"-server") == 0) + netServer = 1; + if (strcmp(argv[i],"-help") == 0) { + printf("Usage: a4 [-full] [-drawall] [-testworld] [-fps] [-client] [-server]\n"); + exit(0); + } + } + + if (fullscreen == 1) { + glutGameModeString("1024x768:32@75"); + glutEnterGameMode(); + } else { + glutInitWindowSize (screenWidth, screenHeight); + glutCreateWindow (argv[0]); + } + + init(); + +/* not used at the moment */ +// loadTexture(); + + /* attach functions to GL events */ + glutReshapeFunc (reshape); + glutDisplayFunc(display); + glutKeyboardFunc (keyboard); + glutPassiveMotionFunc(passivemotion); + glutMotionFunc(motion); + glutMouseFunc(mouse); + glutIdleFunc(update); + + + /* initialize mob and player array to empty */ + initMobArray(); + initPlayerArray(); + + /* set the size of the sky */ + if (WORLDX > WORLDY) + skySize = (float) WORLDX; + else + skySize = (float) WORLDY; + if (WORLDZ > skySize) + skySize = (float) WORLDZ; + skySize *= 1.5; +} + + /* functions to draw 2d images on screen */ +void draw2Dline(int x1, int y1, int x2, int y2, int lineWidth) { + glLineWidth(lineWidth); + glBegin(GL_LINES); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); + glLineWidth(1); +} + +void draw2Dbox(int x1, int y1, int x2, int y2) { + glBegin(GL_QUADS); + glVertex2i(x1, y1); + glVertex2i(x1, y2); + glVertex2i(x2, y2); + glVertex2i(x2, y1); + glEnd(); +} + +void draw2Dtriangle(int x1, int y1, int x2, int y2, int x3, int y3) { + glBegin(GL_TRIANGLES); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glVertex2i(x3, y3); + glEnd(); +} + +void set2Dcolour(float colourv[]) { + glMaterialfv(GL_FRONT, GL_EMISSION, colourv); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colourv); +} + diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..47bdd66 --- /dev/null +++ b/graphics.h @@ -0,0 +1,21 @@ + +#ifdef __APPLE__ + #include + #include + #include +#elif __linux__ + #include + #include + #include +#endif + +/* world size and storage array */ +#define WORLDX 100 +#define WORLDY 10 +#define WORLDZ 100 +GLubyte world[WORLDX][WORLDY][WORLDZ]; + +#define MOB_COUNT 10 +#define PLAYER_COUNT 10 + +#define MAX_DISPLAY_LIST 500000 diff --git a/makefile b/makefile new file mode 100644 index 0000000..fae9d7f --- /dev/null +++ b/makefile @@ -0,0 +1,10 @@ +INCLUDES = -F/System/Library/Frameworks -framework OpenGL -framework GLUT -lm +LINUXINCLUDES = -g -Wall -F/System/Library/Frameworks -lGL -lGLU -lm -lglut + +a3: a4.c graphics.c visible.c graphics.h + gcc a4.c graphics.c visible.c -o a4 $(INCLUDES) + +linux: a4.c graphics.c visible.c graphics.h + gcc a4.c graphics.c visible.c -o a4 $(LINUXINCLUDES) +clean: + rm a4 diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..8685ae6 --- /dev/null +++ b/readme.txt @@ -0,0 +1,2 @@ +If you have trouble finding anything in the maze far any reason, such as walls always being in your way, +you can shoot a hole in the wall and walk through. Shoot the 2nd block from the bottom and climb through. diff --git a/visible.c b/visible.c new file mode 100644 index 0000000..a4684b0 --- /dev/null +++ b/visible.c @@ -0,0 +1,426 @@ + +/* Frustum culling source code from: + http://www.crownandcutlass.com/features/technicaldetails/frustum.html +*/ + +#include +#include +#include +#include + +#include "graphics.h" + +#define OCTREE_LEVEL 1 + +extern void gradphicsInit(int *, char **); +extern void setLightPosition(GLfloat, GLfloat, GLfloat); +extern GLfloat* getLightPosition(); + +extern void setViewPosition(float, float, float); +extern void getViewPosition(float *, float *, float *); +extern void getOldViewPosition(float *, float *, float *); +extern void getViewOrientation(float *, float *, float *); + +extern int addDisplayList(int, int, int); + +extern void createMob(int, float, float, float, float); +extern void setMobPosition(int, float, float, float, float); +extern void hideMob(int); +extern void showMob(int); + +extern void createPlayer(int, float, float, float, float); +extern void setPlayerPosition(int, float, float, float, float); +extern void hidePlayer(int); +extern void showPlayer(int); + + /* flag which is set to 1 when flying behaviour is desired */ +extern int flycontrol; + /* flag used to indicate that the test world should be used */ +extern int testWorld; + /* list and count of polygons to be displayed, set during culling */ +extern int displayList[MAX_DISPLAY_LIST][3]; +extern int displayCount; + /* flag to print out frames per second */ +extern int fps; + /* flag indicates the program is a client when set = 1 */ +extern int netClient; + /* flag indicates the program is a server when set = 1 */ +extern int netServer; + + /* frustum corner coordinates */ +float corners[4][3]; + +/***********************/ + +float lengthTwoPoints(float x1, float y1, float z1, float x2, float y2, float z2) { +float result; + result = sqrtf( powf((x1 - x2), 2.0) + powf((y1 - y2), 2.0) + + powf((z1 - z2), 2.0) ); + return(result); +} + +float lengthVector(float x1, float y1, float z1) { +float result; + result = sqrtf( powf(x1, 2.0) + powf(y1, 2.0) + powf(z1, 2.0) ); + return(result); +} + +void cross(float x1, float y1, float z1, float x2, float y2, float z2, + float *x, float *y, float *z) { + *x = (y1*z2) - (z1*y2); + *y = (x1*z2) - (z1*x2); + *z = (x1*y2) - (y1*x2); +} + + /* returns radians */ +void dot (float x1, float y1, float z1, float x2, float y2, float z2) { +float result; + result = (x1 * x2) + (y1 * y2) + (z1 * z2); + result /= (lengthVector(x1, y1, z1) * lengthVector(x2, y2, z2)); + result = acosf(result); +} + + /* the next two function use Cramer's rule to find the intersection */ + /* of three planes */ + /* used to find outer points of frustum */ + /* http://www.dreamincode.net/code/snippet530.htm */ +double finddet(double a1,double a2, double a3,double b1, double b2,double b3, double c1, double c2, double c3) +{ + /*expansion of a 3x3 determinant*/ + return ((a1*b2*c3)-(a1*b3*c2)-(a2*b1*c3)+(a3*b1*c2)+(a2*b3*c1)-(a3*b2*c1)); +} + +void intersect(float a1, float b1, float c1, float d1, + float a2, float b2, float c2, float d2, + float a3, float b3, float c3, float d3, + float *x, float *y, float *z) { +float det, detx, dety, detz; + + det=finddet(a1,a2,a3,b1,b2,b3,c1,c2,c3); /*Find determinants*/ + detx=finddet(d1,d2,d3,b1,b2,b3,c1,c2,c3); + dety=finddet(a1,a2,a3,d1,d2,d3,c1,c2,c3); + detz=finddet(a1,a2,a3,b1,b2,b3,d1,d2,d3); + + /*Print Answers depending on various conditions*/ + if(d1==0 && d2==0 && d3==0 && det==0) { + printf("\n Infinite Solutions\n "); + } else if(d1==0 && d2==0 && d3==0 && det!=0) { + *x = 0; + *y = 0; + *z = 0; + } else if(det!=0) { + *x = (detx/det); + *y = (dety/det); + *z = (detz/det); +//printf("x=%lf y=%lf z=%lf\n", (detx/det), (dety/det), (detz/det)); + } else if(det==0 && detx==0 && dety==0 && detz==0) + printf("\n Infinite Solutions\n "); + else + printf("No Solution\n "); +} + +/***********************/ + +/* calculate the viewing frustum and test if cubes fall inside it */ +/* code from */ +/* http://www.crownandcutlass.com/features/technicaldetails/frustum.html */ +float frustum[6][4]; +int true = 1; +int false = 0; + +void ExtractFrustum() +{ + float proj[16]; + float modl[16]; + float clip[16]; + float t; + + /* Get the current PROJECTION matrix from OpenGL */ + glGetFloatv( GL_PROJECTION_MATRIX, proj ); + + /* Get the current MODELVIEW matrix from OpenGL */ + glGetFloatv( GL_MODELVIEW_MATRIX, modl ); + + /* Combine the two matrices (multiply projection by modelview) */ + clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12]; + clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13]; + clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14]; + clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15]; + + clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12]; + clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13]; + clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14]; + clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15]; + + clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12]; + clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13]; + clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14]; + clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15]; + + clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12]; + clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13]; + clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14]; + clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15]; + + /* Extract the numbers for the RIGHT plane */ + frustum[0][0] = clip[ 3] - clip[ 0]; + frustum[0][1] = clip[ 7] - clip[ 4]; + frustum[0][2] = clip[11] - clip[ 8]; + frustum[0][3] = clip[15] - clip[12]; + + /* Normalize the result */ + t = sqrt( frustum[0][0] * frustum[0][0] + frustum[0][1] * frustum[0][1] + frustum[0][2] * frustum[0][2] ); + frustum[0][0] /= t; + frustum[0][1] /= t; + frustum[0][2] /= t; + frustum[0][3] /= t; + + /* Extract the numbers for the LEFT plane */ + frustum[1][0] = clip[ 3] + clip[ 0]; + frustum[1][1] = clip[ 7] + clip[ 4]; + frustum[1][2] = clip[11] + clip[ 8]; + frustum[1][3] = clip[15] + clip[12]; + + /* Normalize the result */ + t = sqrt( frustum[1][0] * frustum[1][0] + frustum[1][1] * frustum[1][1] + frustum[1][2] * frustum[1][2] ); + frustum[1][0] /= t; + frustum[1][1] /= t; + frustum[1][2] /= t; + frustum[1][3] /= t; + + /* Extract the BOTTOM plane */ + frustum[2][0] = clip[ 3] + clip[ 1]; + frustum[2][1] = clip[ 7] + clip[ 5]; + frustum[2][2] = clip[11] + clip[ 9]; + frustum[2][3] = clip[15] + clip[13]; + + /* Normalize the result */ + t = sqrt( frustum[2][0] * frustum[2][0] + frustum[2][1] * frustum[2][1] + frustum[2][2] * frustum[2][2] ); + frustum[2][0] /= t; + frustum[2][1] /= t; + frustum[2][2] /= t; + frustum[2][3] /= t; + + /* Extract the TOP plane */ + frustum[3][0] = clip[ 3] - clip[ 1]; + frustum[3][1] = clip[ 7] - clip[ 5]; + frustum[3][2] = clip[11] - clip[ 9]; + frustum[3][3] = clip[15] - clip[13]; + + /* Normalize the result */ + t = sqrt( frustum[3][0] * frustum[3][0] + frustum[3][1] * frustum[3][1] + frustum[3][2] * frustum[3][2] ); + frustum[3][0] /= t; + frustum[3][1] /= t; + frustum[3][2] /= t; + frustum[3][3] /= t; + + /* Extract the FAR plane */ + frustum[4][0] = clip[ 3] - clip[ 2]; + frustum[4][1] = clip[ 7] - clip[ 6]; + frustum[4][2] = clip[11] - clip[10]; + frustum[4][3] = clip[15] - clip[14]; + + /* Normalize the result */ + t = sqrt( frustum[4][0] * frustum[4][0] + frustum[4][1] * frustum[4][1] + frustum[4][2] * frustum[4][2] ); + frustum[4][0] /= t; + frustum[4][1] /= t; + frustum[4][2] /= t; + frustum[4][3] /= t; + + /* Extract the NEAR plane */ + frustum[5][0] = clip[ 3] + clip[ 2]; + frustum[5][1] = clip[ 7] + clip[ 6]; + frustum[5][2] = clip[11] + clip[10]; + frustum[5][3] = clip[15] + clip[14]; + + /* Normalize the result */ + t = sqrt( frustum[5][0] * frustum[5][0] + frustum[5][1] * frustum[5][1] + frustum[5][2] * frustum[5][2] ); + frustum[5][0] /= t; + frustum[5][1] /= t; + frustum[5][2] /= t; + frustum[5][3] /= t; +} + +int PointInFrustum( float x, float y, float z ) +{ + int p; + + for( p = 0; p < 6; p++ ) + if( frustum[p][0] * x + frustum[p][1] * y + frustum[p][2] * z + frustum[p][3] <= 0 ) + return false; + return true; +} + +int CubeInFrustum( float x, float y, float z, float size ) +{ + int p; + int c; + int c2 = 0; + + for( p = 0; p < 6; p++ ) + { + c = 0; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + c++; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + c++; + if( c == 0 ) + return 0; + if( c == 8 ) + c2++; + } + return (c2 == 6) ? 2 : 1; +} + + +int CubeInFrustum2( float x, float y, float z, float size ) +{ + int p; + +//ZZZ + for( p = 0; p < 6; p++ ) + { + if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + continue; + if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 ) + continue; + return false; + } + return true; +} + + + +/*****/ + + + +// if frustum test shows box in view +// if level == max level then draw contents of cube +// else call 8 subdivisions, increment level +// assumes all t[xyz] are larger than b[xyz] respectively + +void tree(float bx, float by, float bz, float tx, float ty, float tz, + int level) { +float length; +float newCentrex, newCentrey, newCentrez; +int i, j, k; + + /* find length of cube edge */ + length = (tx - bx) / 2.0; + if (length < 0) length *= -1; + + /* if the octree cube is in the frustum then */ + /* if the bottom octree level is reached then */ + /* if the visible cube is not empty and is not surrounded then */ + /* add to the display list */ + if (CubeInFrustum(bx + ((tx-bx)/2), by + ((ty-by)/2), bz + ((tz-bz)/2), length )) { + if (level == OCTREE_LEVEL) { + /* draw cubes */ + for(i=bx; i-1) && (j>-1) && (k>-1)) + if ( (world[i][j][k] != 0) && + (CubeInFrustum(i+0.5, j+0.5, k+0.5, 0.5)) ) { + /* check for six neighbours */ + /* if cube is not on the outer edge and is not*/ + /* surrounded by 6 neighbours then draw it */ + /* else if the cube is an outside cube then */ + /* always draw it */ + if ( (i > 0) && (i < WORLDX-1) && + (j > 0) && (j < WORLDY-1) && + (k > 0) && (k < WORLDZ-1) && + ((world[i+1][j][k] == 0) || (world[i-1][j][k] == 0) + || (world[i][j+1][k] == 0) || (world[i][j-1][k] == 0) + || (world[i][j][k+1] == 0) || (world[i][j][k-1] == 0))) + addDisplayList(i, j, k); + else if ( (i == 0) || (i == WORLDX-1) || + (j == 0) || (j == WORLDY-1) || + (k == 0) || (k == WORLDZ-1) ) + addDisplayList(i, j, k); + } + } + } else { + /* calculate centre of new cube */ + newCentrex = bx + ((tx - bx) / 2.0); + newCentrey = by + ((ty - by) / 2.0); + newCentrez = bz + ((tz - bz) / 2.0); + /* call recursive tree functions, increment level */ + level++; + tree(bx, by, bz, newCentrex, newCentrey, newCentrez, level); + tree(newCentrex, by, bz, tx, newCentrey, newCentrez, level); + tree(bx, by, newCentrez, newCentrex, newCentrey, tz, level); + tree(newCentrex, by, newCentrez, tx, newCentrey, tz, level); + tree(bx, newCentrey, bz, newCentrex, ty, newCentrez, level); + tree(newCentrex, newCentrey, bz, tx, ty, newCentrez, level); + tree(bx, newCentrey, newCentrez, newCentrex, ty, tz, level); + tree(newCentrex, newCentrey, newCentrez, tx, ty, tz, level); + } + } + +} + + + /* determines which cubes are to be drawn and puts them into */ + /* the displayList */ + /* write your cube culling code here */ +void buildDisplayList() { +float newx, newy, newz; + /* used to calculate frames per second */ +static int frame=0, time, timebase=0; + + getViewPosition(&newx, &newy, &newz); + + + /* calculate frustum for current viewpoint, store in frustum[][] */ + ExtractFrustum(); + + /* octree, used to determine if regions are visible */ + /* stores visible cubes in a display list */ + displayCount = 0; + tree(0.0, 0.0, 0.0, (float) WORLDX, (float) WORLDY, (float) WORLDZ, 0); + + + /* frame per second calculation */ + /* don't change the following routine */ + /* Code taken from : */ + /* http://www.lighthouse3d.com/opengl/glut/index.php?fps */ + if (fps == 1) { + frame++; + time=glutGet(GLUT_ELAPSED_TIME); + if (time - timebase > 1000) { + printf("FPS:%4.2f\n", frame*1000.0/(time-timebase)); + timebase = time; + frame = 0; + } + } + + /* redraw the screen at the end of the update */ + glutPostRedisplay(); +} +