
| hcsg.cpp | hcsg_modeler.cpp | collision.cpp | camera.cpp | vector.cpp | main.cpp | ||||||
| hcsg.h | hcsg_modeler.h | collision.h | camera.h | vector.h |

// **************************************************************************
// HCSG Demo
// (c) Bernie Freidin, 1999-2000
// **************************************************************************
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifdef __MAC__
#include <Windows.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <gl/glut.h>
#include "vector.h"
#include "hcsg.h"
#include "hcsg_modeler.h"
#include "camera.h"
#include "collision.h"
#define WAIT_FOR_CLOCK 1
static int MAIN__STOP = 0;
static hull_t *MAIN__WORLD = NULL;
static GLuint MAIN__texid[12];
static int MAIN__texcount = 3;
static int COLLISIONS = 1;
#ifndef __MAC__
#define BYTESWAP(x)
#else
static void BYTESWAP(short &x)
{
x = ((x>>8)&0x00FF) | ((x<<8)&0xFF00);
}
#endif
static void MAIN__LoadTGA(char *fpath)
{
FILE *tga = fopen(fpath, "rb");
if(!tga)
{
fprintf(stderr, "\n\ncan't find required TGA (%s)\n", fpath);
fprintf(stderr, "PRESS RETURN TO EXIT\n");
char wait[200];
gets(wait);
exit(-1);
}
// ****************************
// 2 bytes offset = N
// 10 bytes of crap
// 2 bytes = WIDTH
// 2 bytes = HEIGHT
// 2 bytes = BPP (24)
// N bytes of crap..
// PIXEL DATA FOLLOWS (24bpp)
// ****************************
short offset, width, height;
fread(&offset, sizeof(short), 1, tga); BYTESWAP(offset);
fseek(tga, 10, SEEK_CUR);
fread(&width, sizeof(short), 1, tga); BYTESWAP(width);
fread(&height, sizeof(short), 1, tga); BYTESWAP(height);
fseek(tga, offset+2, SEEK_CUR);
char *rgb = (char*)CSG_AllocMem(3, width*height);
fread(rgb, 3, width*height, tga);
fclose(tga);
// Swap red and blue values
for(int i = 0; i < width*height; i++)
{
char tmp = rgb[i*3];
rgb[i*3] = rgb[i*3+2];
rgb[i*3+2] = tmp;
}
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8,
width, height, GL_RGB,
GL_UNSIGNED_BYTE, rgb);
CSG_FreeMem(rgb);
}
static int POLYCOUNT = 0;
static vec3 MAIN__GetPolyNormal(poly_t *poly)
{
surf_t *sp = CSG_GetSurfPool();
vec3 n = sp[poly->surf_id & CSG_SURF_MASK].norm;
hull_t *h2 = (hull_t*)poly->parent;
if(!(h2->depth & 1)) n *= -1.0;
if(poly->surf_id & CSG_SIDE_MASK) n *= -1.0;
return n;
}
static void MAIN__RenderScene(hull_t *hull)
{
vert_t *vp = CSG_GetVertPool();
surf_t *sp = CSG_GetSurfPool();
glColor3d(1.0, 1.0, 1.0);
for(poly_t *p = hull->face; p; p = p->next)
{
GLdouble s_plane[] = {0.0, 0.0, 0.0, 0.0};
GLdouble t_plane[] = {0.0, 0.0, 0.0, 0.0};
vec3 n = MAIN__GetPolyNormal(p);
glNormal3d(n.x, n.y, n.z);
switch(sp[p->surf_id & CSG_SURF_MASK].mask)
{
case 1+2: s_plane[0] = t_plane[1] = 1.0; break;
case 2+4: s_plane[1] = t_plane[2] = 1.0; break;
case 4+1: s_plane[2] = t_plane[0] = 1.0; break;
default: break;
}
glTexGendv(GL_S, GL_OBJECT_PLANE, s_plane);
glTexGendv(GL_T, GL_OBJECT_PLANE, t_plane);
for(poly_t *f = p->down; f; f = f->next)
{
glBindTexture(GL_TEXTURE_2D,
MAIN__texid[sp[p->surf_id & CSG_SURF_MASK].data % MAIN__texcount]);
glBegin(GL_POLYGON);
for(int n = 0; n < f->vertcount; n++)
{
glVertex3dv((GLdouble*)&vp[f->vref[n]]);
}
glEnd();
if(POLYCOUNT > -1) POLYCOUNT++;
}
}
for(hull_t *h = hull->down; h; h = h->next)
{
MAIN__RenderScene(h);
}
}
static void MAIN__TrackFPS(void)
{
static double sum = 0.f;
static double num = 0.f;
static int clk_count = 1;
static clock_t clk1;
static clock_t clk2;
clk1 = clk2;
clk2 = clock();
sum += (double)(clk2-clk1);
num += 1.f;
if(MAIN__STOP)
{
double fps = (double)CLOCKS_PER_SEC * num / sum;
char msg[200];
//FIXME: why doesn't this work??
sprintf(msg, "MEMORY IN USE= %i bytes", CSG_GetMemInUse(NULL));
CSG_Messg(msg);
sprintf(msg, "POLYGON COUNT= %i", -POLYCOUNT);
CSG_Messg(msg);
sprintf(msg, "AVERAGE FPS= %lf\n", fps);
CSG_Messg(msg);
exit(0);
}
}
static void MAIN__InitSimpleTexture(int width, int height)
{
long *buffer = (long*)calloc(sizeof(long), width * height);
if(!buffer) exit(-1); // error
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
long pix = 0;
pix += ((x ^ y) & 1) ? 0x00000088 : 0;
pix += ((x ^ y) & 2) ? 0x00006600 : 0;
pix += ((x ^ y) & 4) ? 0x00440000 : 0;
pix += ((x ^ y) & 8) ? 0x00000044 : 0;
pix += ((x ^ y) & 16) ? 0x00006600 : 0;
pix += ((x ^ y) & 32) ? 0x00880000 : 0;
buffer[x + y*width] = pix;
}
}
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
free(buffer);
}
static void GLUT__Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
MAIN__RenderScene(MAIN__WORLD);
MAIN__TrackFPS();
if(POLYCOUNT > -1) POLYCOUNT = -POLYCOUNT;
glFlush();
glutSwapBuffers();
}
static void GLUT__Reshape(int width, int height)
{
glViewport(0, 0, width, height);
}
static void execScript(char *script)
{
fprintf(stdout, "Reading geometry script...\n");
CSG_RunScript(script);
fprintf(stdout, "Processing solid geometry");
for(int i = 0;; i++)
{
if(_CSG_AddHull()) break;
fprintf(stdout, ".");
fflush(stdout);
}
fprintf(stdout, "\n");
InitializeCamera("Scripts/cameraprefs.txt");
}
static void GLUT__Keyboard(unsigned char key, int x, int y)
{
if(key == 27) MAIN__STOP = 1;
if(0 && key == 'o')
{
char path[200], *badch;
fprintf(stdout, "Enter script pathname: ");
fgets(path, 199, stdin);
if(badch = strchr(path, '\n')) badch[0] = '\0';
CSG_RunScript(path);
}
if(key == ' ')
{
_CSG_AddHull();
}
}
static void GLUT__Mouse(int button, int state, int x, int y)
{
}
static void GLUT__Idle(void)
{
#if WAIT_FOR_CLOCK
#ifdef WIN32
Sleep(7); // milliseconds
#endif
#ifdef __MAC__
long dval;
Delay(1, &dval); // 60th's of a second
#endif
#endif
UpdateCamera(2, COLLISIONS);
glutPostRedisplay();
}
#ifndef __MAC__
static char texturenames[][200] = {
"Textures/brick1.tga",
"Textures/brick2.tga",
"Textures/marble.tga"
};
#else
static char texturenames[][200] = {
":Textures:brick1.tga",
":Textures:brick2.tga",
":Textures:marble.tga"
};
#endif
static void _mainMenuCallback(int item)
{
if(item == 1) exit(0);
}
static void _collisionsCallback(int item)
{
if(item == 1) COLLISIONS = 1;
if(item == 2) COLLISIONS = 0;
}
static void _loadSceneCallback(int item)
{
char script[200];
switch(item)
{
case 1: strcpy(script, "Scripts/archtest.txt"); break;
case 2: strcpy(script, "Scripts/spiraltest1.txt"); break;
case 3: strcpy(script, "Scripts/spiraltest2.txt"); break;
default: return;
}
for(hull_t *hnext, *h = MAIN__WORLD->down; h; h = hnext)
{
hnext = h->next;
CSG_Free(h);
}
execScript(script);
}
static void InitializeMenus(void)
{
int collisionsMenu = glutCreateMenu(_collisionsCallback);
glutAddMenuEntry("On", 1);
glutAddMenuEntry("Off", 2);
int loadSceneMenu = glutCreateMenu(_loadSceneCallback);
glutAddMenuEntry("archtest", 1);
glutAddMenuEntry("spiraltest1", 2);
glutAddMenuEntry("spiraltest2", 3);
int mainMenu = glutCreateMenu(_mainMenuCallback);
glutAddSubMenu("Collisions", collisionsMenu);
glutAddSubMenu("Load Scene...", loadSceneMenu);
glutAddMenuEntry("Exit", 1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
void main(int argc, char *argv[])
{
int i;
// ***************
// Initialize GLUT
// ***************
fprintf(stdout, "Flythrough (HSBM) Demo\n");
fprintf(stdout, "(c) Bernie Freidin, 1999-2000\n\n");
fprintf(stdout, "Keys:\n");
fprintf(stdout, " Numeric keypad to move (NumLock ON)\n");
fprintf(stdout, " Arrow keys UP/DOWN to hover\n");
fprintf(stdout, " A/Z to control pitch");
fprintf(stdout, " Right-click for menu (LOAD SCENE and COLLISIONS)\n");
fprintf(stdout, " ESCAPE to quit\n\n");
fprintf(stdout, "Tips:\n");
fprintf(stdout, " Collisions are unstable; it might crash..\n");
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutInitWindowPosition(40, 40);
glutCreateWindow(argv[0]);
glutDisplayFunc(GLUT__Display);
glutReshapeFunc(GLUT__Reshape);
glutKeyboardFunc(GLUT__Keyboard);
glutMouseFunc(GLUT__Mouse);
glutIdleFunc(GLUT__Idle);
const unsigned char *ext = glGetString(GL_EXTENSIONS);
InitializeMenus();
// ***********************
// Initialize OpenGL state
// ***********************
glClearColor(0.f, 0.f, 0.f, 1.0f);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
GLdouble plane1[] = {1.f, 1.f, 0.f, 0.f};
GLdouble plane2[] = {0.f, 1.f, 1.f, 0.f};
glTexGendv(GL_S, GL_OBJECT_PLANE, plane1);
glTexGendv(GL_T, GL_OBJECT_PLANE, plane2);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
// glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_EXP);
GLfloat fogcolor[] = {0.0f, 0.0f, 0.0f, 1.0f};
glFogfv(GL_FOG_COLOR, fogcolor);
glFogf(GL_FOG_DENSITY, 0.12f);
glHint(GL_FOG_HINT, GL_NICEST);
glFogf(GL_FOG_START, 1.0f);
glFogf(GL_FOG_END, 40.0f); // doesn't seem to affect?
//glEnable(GL_CULL_FACE);
//glCullFace(GL_FRONT);
// MAIN__InitSimpleTexture(64, 64);
fprintf(stdout, "Loading textures...\n");
glGenTextures(MAIN__texcount, MAIN__texid);
for(i = 0; i < MAIN__texcount; i++)
{
glBindTexture(GL_TEXTURE_2D, MAIN__texid[i]);
#if 0 // good for software rendering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#else // good for hardware rendering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
#endif
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
fprintf(stdout, "\t%s\n", texturenames[i]);
MAIN__LoadTGA(texturenames[i]);
}
InitializeCamera("Scripts/cameraprefs.txt");
{
float ambient[] = {0.5f, 0.5f, 0.5f, 1.0f};
float diffuse[] = {0.4f, 0.4f, 0.4f, 1.0f};
float specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
float shininess[] = {40.0f};
float light_position[] = {10.0f, 10.0f, 10.0f, 1.0f};
float color[] = {1.0f, 1.0f, 1.0f, 1.0f};
glShadeModel(GL_SMOOTH);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
// glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emission);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_SHININESS, shininess);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
}
/*
static void _currentObjectCallback(int value)
{
if(value == 1)
{
GRS_MODE = 0;
ZOOM_LIST[0].x = 0.0;
ZOOM_LIST[0].y = 0.0;
ZOOM_LIST[0].z = 0.95;
ZOOM_COUNT = 1;
ZOOM_STATE = 0;
Z = ZOOM_LIST[0];
glutPostRedisplay();
}
}
*/
fprintf(stdout, "Initializing HCSG engine...\n");
CSG_Initialize();
MAIN__WORLD = CSG_World();
CSG_InitializeModeler(MAIN__WORLD);
CDR_Initialize(MAIN__WORLD);
execScript("Scripts/CSG_default_script.txt");
for(i = 0; i < 20*0; i++)
{
double x1 = (double)(rand() & 255)*.015;
double y1 = (double)(rand() & 255)*.015;
double z1 = (double)(rand() & 255)*.015;
double x2 = (double)(rand() & 255)*.0075 + x1 + .0125;
double y2 = (double)(rand() & 255)*.0075 + y1 + .0125;
double z2 = (double)(rand() & 255)*.0075 + z1 + .0125;
hull_t *cube = CSG_SolidCube(x1, y1, z1, x2, y2, z2);
CSG_BooleanOp(MAIN__WORLD, cube, 1, CSG_ADD, 1);
}
glutMainLoop();
}
This page © Bernie Freidin, 2000.