
| 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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "camera.h"
#include "collision.h"
#ifndef WIN32
#define __MAC__ //FIXME: FOR NOW: enable __MAC__ if not WIN32
#endif
#ifdef __MAC__
#include <Events.h>
#endif
#ifndef __MAC__
#define _A_ 'A' // see keyboards mapping
#define _Z_ 'Z' // see keyboards mapping
#else
enum
{
VK_NUMPAD9 = 0x5C,
VK_NUMPAD8 = 0x5B,
VK_NUMPAD7 = 0x59,
VK_NUMPAD6 = 0x58,
VK_NUMPAD5 = 0x57,
VK_NUMPAD4 = 0x56,
VK_NUMPAD3 = 0x55,
VK_NUMPAD2 = 0x54,
VK_NUMPAD1 = 0x53,
VK_NUMPAD0 = 0x52,
_Z_ = 0x06,
_A_ = 0x00,
_C_ = 0x05,
VK_SHIFT = 0x38,
VK_DOWN = 0x7D,
VK_UP = 0x7E
};
static unsigned char MAC__keymap[16];
static int GetAsyncKeyState(int key)
{
return((MAC__keymap[k>>3]>>(k&7))&1) ? 0x8000 : 0;
}
#endif
#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))
#ifndef PI
#define PI 3.1415926535897932384626433832795
#endif
struct clamp_t
{
double spring_center;
double spring_linear;
double spring_nonlinear;
double minv;
double maxv;
int minmax_clamp;
};
struct camera_t
{
double orientation[16]; // world->local
double position[3]; // worldspace
double velocity[3]; // local
double acceleration[3]; // local
double ypr[3];
double ypr_velocity[3];
double ypr_accel[3];
clamp_t clamp_position;
clamp_t clamp_velocity;
clamp_t clamp_ypr[3];
clamp_t clamp_ypr_velocity[3];
double instantaneous_accel[7]; // fwd,bck,hrz,vrt,yaw,pch,rol
};
static camera_t CAMERA;
static double Dot3(double v1[3], double v2[3])
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
static double Dot3_4(double v1[3], double v2[])
{
return v1[0]*v2[0] + v1[1]*v2[4] + v1[2]*v2[8];
}
static void Clamp(double &value, clamp_t *clamp)
{
// ***************************
// Apply clamp to scalar value
// ***************************
if(clamp->minmax_clamp)
{
value = _max(value, clamp->minv);
value = _min(value, clamp->maxv);
}
value -= clamp->spring_center;
value *= 1.f - clamp->spring_nonlinear;
if(value > 0.0) value = _max(value - clamp->spring_linear, 0.0);
if(value < 0.0) value = _min(value + clamp->spring_linear, 0.0);
value += clamp->spring_center;
}
static void Clamp3(double v[3], clamp_t *clamp)
{
// ************************
// Apply clamp to 3D vector
// ************************
double value = sqrt(Dot3(v, v));
double vsave = value;
if(fabs(value) < 1e-12) return;
Clamp(value, clamp);
vsave = value/vsave;
v[0] *= vsave;
v[1] *= vsave;
v[2] *= vsave;
}
static void ClampTo180(double &v)
{
if(v < -180.0) v += 360.0; else
if(v > +180.0) v -= 360.0;
}
static void LoadScalar(double *v)
{
// *****************************
// Load scalar value from strtok
// *****************************
char *paramstr = strtok(NULL, " =:\t");
if(!paramstr) return;
*v = atof(paramstr);
}
static void LoadClampParams(clamp_t *clamp)
{
// *********************************
// Load clamp parameters from strtok
// *********************************
char *paramstr = strtok(NULL, " =:\t"); if(!paramstr) return;
clamp->spring_center = atof(paramstr);
paramstr = strtok(NULL, " =:\t"); if(!paramstr) return;
clamp->spring_linear = atof(paramstr);
paramstr = strtok(NULL, " =:\t"); if(!paramstr) return;
clamp->spring_nonlinear = atof(paramstr);
paramstr = strtok(NULL, " =:\t"); if(!paramstr) return;
clamp->minv = atof(paramstr);
paramstr = strtok(NULL, " =:\t"); if(!paramstr) return;
clamp->maxv = atof(paramstr);
paramstr = strtok(NULL, " =:\t"); if(!paramstr) return;
clamp->minmax_clamp = atoi(paramstr);
}
static void LoadVector3D(double v[3])
{
// ****************************
// Load a 3D vector from strtok
// ****************************
for(int i = 0; i < 3; i++)
{
char *paramstr = strtok(NULL, " =:\t");
if(!paramstr) return;
v[i] = atof(paramstr);
}
}
void InitializeCamera(char *path)
{
// **************************************
// Load default camera settings from file
// **************************************
FILE *prefs = fopen(path, "r");
char str[200];
if(!prefs)
{
char wait[200];
fprintf(stdout, "Can't open \"%s\"\n", path);
fprintf(stdout, "[Press RETURN to quit]\n");
fgets(wait, 199, stdin);
exit(-1);
}
memset(&CAMERA, 0, sizeof(camera_t));
while(fgets(str, 199, prefs))
{
if(str[0] == '#') continue;
if(str[0] == '/' && str[1] == '/') continue;
char *vname = strtok(str, " =:\t");
if(!vname) continue;
if(!strcmp(vname, "SET_POSITION"))
LoadVector3D(CAMERA.position); else
if(!strcmp(vname, "CLAMP_POSITION"))
LoadClampParams(&CAMERA.clamp_position); else
if(!strcmp(vname, "CLAMP_VELOCITY"))
LoadClampParams(&CAMERA.clamp_velocity); else
if(!strcmp(vname, "CLAMP_YAW"))
LoadClampParams(&CAMERA.clamp_ypr[0]); else
if(!strcmp(vname, "CLAMP_PITCH"))
LoadClampParams(&CAMERA.clamp_ypr[1]); else
if(!strcmp(vname, "CLAMP_ROLL"))
LoadClampParams(&CAMERA.clamp_ypr[2]); else
if(!strcmp(vname, "CLAMP_YAW_VELOCITY"))
LoadClampParams(&CAMERA.clamp_ypr_velocity[0]); else
if(!strcmp(vname, "CLAMP_PITCH_VELOCITY"))
LoadClampParams(&CAMERA.clamp_ypr_velocity[1]); else
if(!strcmp(vname, "CLAMP_ROLL_VELOCITY"))
LoadClampParams(&CAMERA.clamp_ypr_velocity[2]); else
if(!strcmp(vname, "SET_FORWARD_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[0]); else
if(!strcmp(vname, "SET_BACKWARD_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[1]); else
if(!strcmp(vname, "SET_HORIZONTAL_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[2]); else
if(!strcmp(vname, "SET_VERTICAL_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[3]); else
if(!strcmp(vname, "SET_YAW_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[4]); else
if(!strcmp(vname, "SET_PITCH_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[5]); else
if(!strcmp(vname, "SET_ROLL_ACCELERATION"))
LoadScalar(&CAMERA.instantaneous_accel[6]);
}
fclose(prefs);
}
void UpdateCamera(int frames, int collisions)
{
// **********************************************
// UpdateCamera() performs the following actions:
//
// Set accelerations based on keyboard state
// Compute orientation matrix from YPR
// Compute world velocity
// Update position based on world velocity
// Update YPR based on rotational velocity
// Update local velocity
// Update rotational velocity
// Update OpenGL modelview matrix
// **********************************************
// Set accelerations based on keyboard state
#ifdef __MAC__
KeyMap km;
GetKeys(km);
memcpy(MAC__keymap, km, 16);
#endif
double yaw = 0.0;
double pch = 0.0;
double rol = 0.0;
double fwd = 0.0;
double sid = 0.0;
double upd = 0.0;
if(GetAsyncKeyState(VK_NUMPAD4) & 0x8000) yaw += CAMERA.instantaneous_accel[4];
if(GetAsyncKeyState(VK_NUMPAD6) & 0x8000) yaw -= CAMERA.instantaneous_accel[4];
if(GetAsyncKeyState(_A_) & 0x8000) pch += CAMERA.instantaneous_accel[5];
if(GetAsyncKeyState(_Z_) & 0x8000) pch -= CAMERA.instantaneous_accel[5];
if(GetAsyncKeyState(VK_NUMPAD7) & 0x8000) rol += CAMERA.instantaneous_accel[6];
if(GetAsyncKeyState(VK_NUMPAD9) & 0x8000) rol -= CAMERA.instantaneous_accel[6];
if(GetAsyncKeyState(VK_NUMPAD5) & 0x8000) fwd -= CAMERA.instantaneous_accel[0];
if(GetAsyncKeyState(VK_NUMPAD2) & 0x8000) fwd += CAMERA.instantaneous_accel[1];
if(GetAsyncKeyState(VK_NUMPAD1) & 0x8000) sid -= CAMERA.instantaneous_accel[2];
if(GetAsyncKeyState(VK_NUMPAD3) & 0x8000) sid += CAMERA.instantaneous_accel[2];
if(GetAsyncKeyState(VK_UP) & 0x8000) upd += CAMERA.instantaneous_accel[3];
if(GetAsyncKeyState(VK_DOWN) & 0x8000) upd -= CAMERA.instantaneous_accel[3];
CAMERA.acceleration[0] = sid;
CAMERA.acceleration[1] = upd;
CAMERA.acceleration[2] = fwd;
CAMERA.ypr_accel[0] = yaw;
CAMERA.ypr_accel[1] = pch;
CAMERA.ypr_accel[2] = rol;
for(int j, i = 0; i < frames; i++)
{
// Update rotational velocity
for(j = 0; j < 3; j++)
{
CAMERA.ypr_velocity[j] += CAMERA.ypr_accel[j];
ClampTo180(CAMERA.ypr_velocity[j]);
Clamp(CAMERA.ypr_velocity[j], &CAMERA.clamp_ypr_velocity[j]);
}
// Update YPR based on rotational velocity
for(j = 0; j < 3; j++)
{
CAMERA.ypr[j] += CAMERA.ypr_velocity[j];
ClampTo180(CAMERA.ypr[j]);
Clamp(CAMERA.ypr[j], &CAMERA.clamp_ypr[j]);
}
// Update local velocity
CAMERA.velocity[0] += CAMERA.acceleration[0];
CAMERA.velocity[1] += CAMERA.acceleration[1];
CAMERA.velocity[2] += CAMERA.acceleration[2];
Clamp3(CAMERA.velocity, &CAMERA.clamp_velocity);
// Compute orientation matrix from YPR
double cy = cos(CAMERA.ypr[0]*PI/180.0);
double sy = sin(CAMERA.ypr[0]*PI/180.0);
double cp = cos(CAMERA.ypr[1]*PI/180.0);
double sp = sin(CAMERA.ypr[1]*PI/180.0);
double cr = cos(CAMERA.ypr[2]*PI/180.0);
double sr = sin(CAMERA.ypr[2]*PI/180.0);
CAMERA.orientation[0] = sp*sr*sy + cr*cy;
CAMERA.orientation[4] = cp*sr;
CAMERA.orientation[8] = cy*sp*sr - cr*sy;
CAMERA.orientation[1] = cr*sp*sy - cy*sr;
CAMERA.orientation[5] = cp*cr;
CAMERA.orientation[9] = cr*cy*sp + sr*sy;
CAMERA.orientation[2] = cp*sy;
CAMERA.orientation[6] = -sp;
CAMERA.orientation[10]= cp*cy;
// Compute impulse vector
vec3 impulse;
impulse.x = Dot3(CAMERA.velocity, CAMERA.orientation+0);
impulse.y = Dot3(CAMERA.velocity, CAMERA.orientation+4);
impulse.z = Dot3(CAMERA.velocity, CAMERA.orientation+8);
vec3 position;
position.x = CAMERA.position[0];
position.y = CAMERA.position[1];
position.z = CAMERA.position[2];
// Collision-response physics
//FIXME: use vec3 for camera vectors so we don't have to convert
if(collisions)
{
CDR_Collide(position, impulse, 0.4);
}
else
{
position += impulse;
}
CAMERA.position[0] = position.x;
CAMERA.position[1] = position.y;
CAMERA.position[2] = position.z;
Clamp3(CAMERA.position, &CAMERA.clamp_position);
}
double px = Dot3_4(CAMERA.position, CAMERA.orientation+0);
double py = Dot3_4(CAMERA.position, CAMERA.orientation+1);
double pz = Dot3_4(CAMERA.position, CAMERA.orientation+2);
CAMERA.orientation[12] = -px;
CAMERA.orientation[13] = -py;
CAMERA.orientation[14] = -pz;
CAMERA.orientation[3] = 0.0;
CAMERA.orientation[7] = 0.0;
CAMERA.orientation[11] = 0.0;
CAMERA.orientation[15] = 1.0;
GLint vp[4];
glGetIntegerv(GL_VIEWPORT, vp);
double aspect = (double)vp[2] / (double)vp[3];
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, aspect, 0.01, 100.0);
//glScalef(1.f, 1.f, -1.f); // compensate for -z axis
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixd(CAMERA.orientation);
}
This page © Bernie Freidin, 2000.