MuckyFoot-UrbanChaos/fallen/Source/Camera.cpp
2017-05-20 11:14:17 +10:00

775 lines
18 KiB
C++

// Camera.cpp
// Guy Simmons, 5th December 1997.
#include "Game.h"
#include "id.h"
#include "statedef.h"
extern Camera test_view;
void set_camera_angle(Thing *c_thing,SLONG lag);
//---------------------------------------------------------------
void init_cameras(void)
{
memset(CAMERAS,0,sizeof(CAMERAS));
CAMERA_COUNT = 0;
}
//---------------------------------------------------------------
Thing *alloc_camera(UBYTE type)
{
SLONG c0;
CameraMan *new_camera;
Thing *camera_thing = NULL;
// Run through the camera array & find an unused one.
for(c0=0;c0<MAX_CAMERAS;c0++)
{
if(CAMERAS[c0].CameraType==CAMERA_NONE)
{
camera_thing = alloc_thing(CLASS_CAMERA);
if(camera_thing)
{
new_camera = TO_CAMERA(c0);
new_camera->CameraType = type;
new_camera->Thing = THING_NUMBER(camera_thing);
camera_thing->Genus.Camera = new_camera;
}
break;
}
}
return camera_thing;
}
//---------------------------------------------------------------
void free_camera(Thing *camera_thing)
{
// Set the camera type to none & free the thing.
camera_thing->Genus.Camera->CameraType = CAMERA_NONE;
free_thing(camera_thing);
}
//---------------------------------------------------------------
Thing *create_camera(UBYTE type,GameCoord *start_pos,Thing *track_thing)
{
CameraMan *t_camera;
GameCoord default_pos;
Thing *camera_thing = NULL;
camera_thing = alloc_camera(type);
if(camera_thing)
{
// Initialise the cameras relative position to the tracking thing.
t_camera = camera_thing->Genus.Camera;
t_camera->CameraDX = 0;
t_camera->CameraDY = 1024-256;
t_camera->CameraDZ = 1024+256;
t_camera->FocusThing = THING_NUMBER(track_thing);
// Set camera world position.
camera_thing->WorldPos = *start_pos;
// Set the type & add it to the map.
set_camera_type(camera_thing,type);
add_thing_to_map(camera_thing);
}
return camera_thing;
}
void set_up_camera(Thing *camera_thing,GameCoord *start_pos,Thing *track_thing)
{
GameCoord default_pos;
CameraMan *t_camera;
{
// Initialise the cameras relative position to the tracking thing.
t_camera = camera_thing->Genus.Camera;
t_camera->CameraDX = 0;
t_camera->CameraDY = 1024-256;
t_camera->CameraDZ = 1024+256;
t_camera->FocusThing = THING_NUMBER(track_thing);
// Set camera world position.
camera_thing->WorldPos = *start_pos;
// Set the type & add it to the map.
// set_camera_type(camera_thing,type);
camera_thing->StateFn = (void(*)(Thing*))process_t_camera;
add_thing_to_map(camera_thing);
}
}
//---------------------------------------------------------------
void set_camera_type(Thing *c_thing,UBYTE type)
{
// Set the camera state function.
switch(type)
{
case CAMERA_NONE:
c_thing->StateFn = NULL;
break;
case CAMERA_TRACKER:
c_thing->StateFn = (void(*)(Thing*))process_t_camera;
break;
case CAMERA_FIXED:
c_thing->StateFn = (void(*)(Thing*))process_f_camera;
break;
}
}
//---------------------------------------------------------------
void lock_camera_position(Thing *c_thing,GameCoord *lock_pos,BOOL snap)
{
CameraMan *t_camera;
backup_camera(c_thing);
t_camera = c_thing->Genus.Camera;
t_camera->CameraDX = lock_pos->X>>8;
t_camera->CameraDY = lock_pos->Y>>8;
t_camera->CameraDZ = lock_pos->Z>>8;
if(snap)
{
c_thing->WorldPos = *lock_pos;
// set_camera_angle(c_thing,0);
}
set_camera_type(c_thing,CAMERA_FIXED);
}
//---------------------------------------------------------------
void backup_camera(Thing *c_thing)
{
CameraMan *t_camera;
t_camera = c_thing->Genus.Camera;
t_camera->PrevDX=t_camera->CameraDX;
t_camera->PrevDY=t_camera->CameraDY;
t_camera->PrevDZ=t_camera->CameraDZ;
t_camera->StateFn=c_thing->StateFn;
}
void restore_old_camera(Thing *c_thing)
{
CameraMan *t_camera;
t_camera = c_thing->Genus.Camera;
t_camera->CameraDX=t_camera->PrevDX;
t_camera->CameraDY=t_camera->PrevDY;
t_camera->CameraDZ=t_camera->PrevDZ;
c_thing->StateFn=t_camera->StateFn;
}
void free_camera_position(Thing *c_thing,GameCoord *rel_pos,BOOL snap)
{
CameraMan *t_camera;
t_camera = c_thing->Genus.Camera;
backup_camera(c_thing);
// t_camera->PrevDX = rel_pos->X;
t_camera->CameraDX = rel_pos->X;
t_camera->CameraDY = rel_pos->Y;
t_camera->CameraDZ = rel_pos->Z;
if(snap)
{
}
set_camera_type(c_thing,CAMERA_TRACKER);
}
void set_game_camera(SLONG dx,SLONG dy,SLONG dz)
{
CameraMan *t_camera;
Thing *c_thing;
c_thing = TO_THING(TO_CAMERA(0)->Thing);
t_camera = c_thing->Genus.Camera;
backup_camera(c_thing);
t_camera->CameraDX = dx;
t_camera->CameraDY = dy;
t_camera->CameraDZ = dz;
}
//---------------------------------------------------------------
//
// A thing may required a special camera angle if its inside a building,
// or if it's on a firescape
//
SLONG special_camera_angle_required_for_thing(Thing *p_thing,GameCoord *new_pos)
{
SLONG wall;
SLONG storey;
SLONG building;
SLONG thing;
Thing *p_fthing;
if(p_thing->OnFace)
{
if(p_thing->OnFace>0)
{
if(prim_faces4[p_thing->OnFace].Type==FACE_TYPE_FIRE_ESCAPE)
{
SLONG building,storey,wall,face_x,face_y,face_z;
SLONG dx,dz;
wall = prim_faces4[p_thing->OnFace].ThingIndex;
if (wall<0)
{
storey = wall_list[-wall].StoreyHead;
building = storey_list[storey].BuildingHead;
thing = building_list[building].ThingIndex;
p_fthing = TO_THING(thing);
}
else
{
//
// face must be a building thing
//
return(0);
}
wall=storey_list[storey].WallHead;
dx = wall_list[wall].DX;
dz = wall_list[wall].DZ;
wall = wall_list[wall].Next;
dx -= wall_list[wall].DX;
dz -= wall_list[wall].DZ;
face_x = p_fthing->WorldPos.X;
face_y = p_fthing->WorldPos.Y;
face_z = p_fthing->WorldPos.Z;
new_pos->X =(face_x+dx)<<8;
new_pos->Y =p_thing->WorldPos.Y+(1000<<8);
new_pos->Z =(face_z-dz*4)<<8;
return(1);
}
}
}
return(0);
}
//---------------------------------------------------------------
//
// lag is now divided by 256 so lots of lag would be 64, not much lag would be 200, no lag would be 256
//
//
// tries to point the camera at the player
//
void set_camera_angle_for_pos(Thing *c_thing,SLONG lag)
{
SWORD angle_diff,angle_to;
SLONG t_dx,t_dy,t_dz;
CameraMan *t_camera;
GameCoord camera_position,
dest_position;
Thing *track_thing;
t_camera = c_thing->Genus.Camera;
track_thing = TO_THING(t_camera->FocusThing);
camera_position = c_thing->WorldPos;
calc_sub_objects_position(track_thing,track_thing->Draw.Tweened->AnimTween,0,&t_dx,&t_dy,&t_dz); //0 is pelvis
angle_to = (SWORD)Arctan (
(((camera_position.X-track_thing->WorldPos.X)>>8)-t_dx),
(((camera_position.Z-track_thing->WorldPos.Z)>>8)-t_dz)
);
angle_diff = (angle_to-test_view.CameraAngle)&2047;
if(angle_diff>1024)
angle_diff -= 2048;
// if(abs(angle_diff)<300)
// lag>>=1;
// lag=lag*abs(angle_diff)>>9;
// if(lag>200)
// lag=200;
if(track_thing->State==STATE_IDLE||USER_INTERFACE==0)
{
test_view.CameraAngle = (test_view.CameraAngle+((angle_diff*lag)>>8))&2047; //wal >>2 not 0
}
angle_to = Arctan (
(camera_position.Y>>8) - ((track_thing->WorldPos.Y>>8)+t_dy),
Hypotenuse (
((camera_position.X-track_thing->WorldPos.X)>>8)-t_dx,
((camera_position.Z-track_thing->WorldPos.Z)>>8)-t_dz
)
)-1024;
angle_diff = (angle_to-test_view.CameraTilt)&2047;
if(angle_diff>1024)
angle_diff -= 2048;
test_view.CameraTilt = (test_view.CameraTilt+((angle_diff*lag)>>8))&2047; //>>0 was >>2
}
//
// Tries to point the camera in the direction the player is going
//
void set_camera_rangle_for_player_angle(Thing *c_thing,SLONG lag)
{
SWORD angle_diff,angle_to;
SLONG t_dx,t_dy,t_dz;
CameraMan *t_camera;
GameCoord camera_position,
dest_position;
Thing *track_thing;
t_camera = c_thing->Genus.Camera;
track_thing = TO_THING(t_camera->FocusThing);
camera_position = c_thing->WorldPos;
angle_to = (-(track_thing->Draw.Tweened->Angle-512)+512+2048)&2047;
angle_diff = (angle_to-test_view.CameraAngle)&2047;
if(angle_diff>1024)
angle_diff -= 2048;
test_view.CameraRAngle = (test_view.CameraRAngle+((angle_diff*lag)>>8))&2047; //wal >>2 not 0
}
void process_t_camera(Thing *c_thing)
{
SLONG distance,
sin,cos,
tx = 0,
ty = 0,
tz = 0;
CameraMan *t_camera;
GameCoord camera_position,
dest_position;
Thing *track_thing;
SLONG t_dx,t_dy,t_dz;
SLONG dx,dy,dz;
SLONG car=0;
static first_person=0;
CBYTE str[100];
// LogText(" process camera\n");
t_camera = c_thing->Genus.Camera;
track_thing = TO_THING(t_camera->FocusThing);
camera_position = c_thing->WorldPos;
if(!track_thing->Draw.Tweened)
return;
// set_camera_rangle_for_player_angle(c_thing,80); //very lagged
calc_sub_objects_position(track_thing,track_thing->Draw.Tweened->AnimTween,0,&t_dx,&t_dy,&t_dz); //0 is pelvis
//
// bodge to stop camera bobbing when you run
//
if(abs(t_dy)<50)
t_dy=0;
if(special_camera_angle_required_for_thing(track_thing,&dest_position))
{
}
else
if ((GAME_FLAGS & GF_INDOORS) && Keys[KB_Q])
{
//
// Indoors, put the camera at a point in the room.
//
UBYTE room = ID_get_mapsquare_room(track_thing->WorldPos.X >> ELE_SHIFT, track_thing->WorldPos.Z >> ELE_SHIFT);
if (room == 0)
{
//
// The player is inside a building, but not inside a
// room!
//
dest_position = camera_position;
}
else
{
ID_get_room_camera(room, &dest_position.X, &dest_position.Y, &dest_position.Z);
camera_position = dest_position;
}
}
else
{
SLONG angle;
SLONG tilt;
if(USER_INTERFACE==1)
{
switch(track_thing->Class)
{
case CLASS_PERSON:
if(track_thing->State==STATE_IDLE)
{
angle = track_thing->Draw.Tweened->Angle;
}
else
{
// camera angle is flipped arround 512
angle = (-(test_view.CameraAngle-512)+512+2048)&2047; //track_thing->Draw.Tweened->Angle;
}
tilt = track_thing->Draw.Tweened->Tilt;
car=0;
break;
case CLASS_VEHICLE:
angle = track_thing->Genus.Furniture->RAngle;
tilt = track_thing->Draw.Mesh->Tilt;
car=1;
break;
}
}
else
{
switch(track_thing->Class)
{
case CLASS_PERSON:
angle = track_thing->Draw.Tweened->Angle;
tilt = track_thing->Draw.Tweened->Tilt;
car=0;
break;
case CLASS_VEHICLE:
angle = track_thing->Genus.Furniture->RAngle;
tilt = 0; //track_thing->Draw.Mesh->Tilt;
car=1;
break;
}
}
// angle = (-(test_view.CameraRAngle-512)+512+2048)&2047; //track_thing->Draw.Tweened->Angle;
// Rotate camera vector around Y axis.
sin = SIN(angle)>>2;
cos = COS(angle)>>2;
tx = t_camera->CameraDX;
tz = t_camera->CameraDZ;
dest_position.X = ((cos*tx) + (sin*tz))>>14;
dest_position.Z = ((-sin*tx) + (cos*tz))>>14;
// Rotate camera vector around X axis.
sin = SIN(tilt)>>2; //bagginess
cos = COS(tilt)>>2;
ty = t_camera->CameraDY;
tz = dest_position.Z;
dest_position.Y = ((cos*ty) + (sin*tz))>>14;
dest_position.Z = ((-sin*ty) + (cos*tz))>>14;
// This is the position the camera wants to be at.
dest_position.X += (track_thing->WorldPos.X>>8)+(t_dx);
dest_position.Y += (track_thing->WorldPos.Y>>8)+(t_dy);
dest_position.Z += (track_thing->WorldPos.Z>>8)+(t_dz);
}
// Now create a vector between the current position & the new position.
tx = dest_position.X-(camera_position.X>>8);
ty = dest_position.Y-(camera_position.Y>>8);
tz = dest_position.Z-(camera_position.Z>>8);
// Set the camera angle & tilt.
// Calculate the distance.
distance = Hypotenuse(Hypotenuse(tx,ty),tz);
// Normalise the vector.
// I don't think the camera will ever be close enough for distance to be 0, but saying that...
if(distance==0)
distance=1;
tx = (tx<<10)/distance;
ty = (ty<<10)/distance;
tz = (tz<<10)/distance;
// Dampen the distance. This defines how baggy the camera is, should be variable.
distance >>= (4-car*3); //was 5
dx=tx*distance;
dy=ty*distance;
dz=tz*distance;
/*
dx=(dx*TICK_RATIO)>>TICK_SHIFT;
dy=(dy*TICK_RATIO)>>TICK_SHIFT;
dz=(dz*TICK_RATIO)>>TICK_SHIFT;
*/
// Now set the cameras new position.
camera_position.X = ((camera_position.X<<10-8)+(dx))>>10-8;
camera_position.Y = ((camera_position.Y<<10-8)+(dy>>2))>>10-8;
camera_position.Z = ((camera_position.Z<<10-8)+(dz))>>10-8;
// camera_position=dest_position;
// Set the new position.
move_thing_on_map(c_thing,&camera_position);
// move_thing_on_map(c_thing,&dest_position);
set_camera_angle_for_pos(c_thing,100+car*120); //always look straight at player
// Set camera position.
test_view.CameraX = (float)(camera_position.X>>8);
test_view.CameraY = (float)(camera_position.Y>>8);
test_view.CameraZ = (float)(camera_position.Z>>8);
if (Keys[KB_V])
{
if(first_person)
{
first_person=0;
}
else
{
if(ShiftFlag)
first_person=2;
else
first_person=1;
}
}
if (first_person) //Keys[KB_V])
{
extern Engine the_engine;
//
// Use the mouse to look around.
//
SLONG dx;
SLONG dy;
SLONG yaw;
SLONG pitch;
dx = (MouseX - the_engine.HalfViewWidth);
dy = (MouseY - the_engine.HalfViewHeight);
dx<<=1;
dy<<=1;
#define MAX_CAM_PITCH (400)
#define MAX_CAM_YAW (1024)
yaw = (-dx * MAX_CAM_YAW) / the_engine.HalfViewWidth;
pitch = ( dy * MAX_CAM_PITCH) / the_engine.HalfViewHeight;
yaw += track_thing->Draw.Tweened->Angle;
pitch += track_thing->Draw.Tweened->Tilt;
yaw = 1024 - yaw; // !?
yaw &= 2047;
pitch &= 2047;
if (first_person==2)
{
static float camera_b_dist = 512.0F;
if (Keys[KB_P9]) {camera_b_dist += 40.0F;}
if (Keys[KB_P6]) {camera_b_dist -= 40.0F;}
SATURATE(camera_b_dist, 100.0F, 4000.0F);
//
// Look at the track_thing.
//
extern void MATRIX_vector(float vector[3], float yaw, float pitch);
float vector[3];
float f_yaw;
float f_pitch;
f_yaw = float(yaw) * (2.0 * PI / 2048.0F);
f_pitch = float(pitch) * (2.0 * PI / 2048.0F);
MATRIX_vector(
vector,
f_yaw,
f_pitch);
test_view.CameraX = float(track_thing->WorldPos.X>>8);
test_view.CameraY = float(track_thing->WorldPos.Y>>8);
test_view.CameraZ = float(track_thing->WorldPos.Z>>8);
test_view.CameraY += 0x80;
#define CAMERA_B_DIST (camera_b_dist)
test_view.CameraX -= vector[0] * CAMERA_B_DIST;
test_view.CameraY -= vector[1] * CAMERA_B_DIST;
test_view.CameraZ -= vector[2] * CAMERA_B_DIST;
yaw = -yaw;
pitch = pitch;
yaw &= 2047;
pitch &= 2047;
}
else
{
//
// Look through the eyes of the trackthing.
//
test_view.CameraX = float(track_thing->WorldPos.X>>8);
test_view.CameraY = float(track_thing->WorldPos.Y>>8);
test_view.CameraZ = float(track_thing->WorldPos.Z>>8);
test_view.CameraY += 0xb0;
}
test_view.CameraAngle = yaw;
test_view.CameraTilt = pitch;
}
}
//---------------------------------------------------------------
void process_f_camera(Thing *c_thing)
{
SWORD angle_diff,angle_to;
SLONG distance,
sin,cos,
tx = 0,
ty = 0,
tz = 0;
CameraMan *t_camera;
GameCoord camera_position,
dest_position;
Thing *track_thing;
SLONG t_dx,t_dy,t_dz;
t_camera = c_thing->Genus.Camera;
track_thing = TO_THING(t_camera->FocusThing);
camera_position = c_thing->WorldPos;
if(!track_thing->Draw.Tweened)
return;
calc_sub_objects_position(track_thing,track_thing->Draw.Tweened->AnimTween,0,&t_dx,&t_dy,&t_dz); //0 is pelvis
// This is the position the camera wants to be at.
dest_position.X = t_camera->CameraDX;
dest_position.Y = t_camera->CameraDY;
dest_position.Z = t_camera->CameraDZ;
// Now create a vector between the current position & the new position.
tx = dest_position.X-(camera_position.X>>8);
ty = dest_position.Y-(camera_position.Y>>8);
tz = dest_position.Z-(camera_position.Z>>8);
// Set the camera angle & tilt.
angle_to = (SWORD)Arctan (
(camera_position.X>>8)-((track_thing->WorldPos.X>>8)+t_dx),
(camera_position.Z>>8)-((track_thing->WorldPos.Z>>8)+t_dz)
);
angle_diff = (angle_to-test_view.CameraAngle)&2047;
if(angle_diff>1024)
angle_diff -= 2048;
test_view.CameraAngle = (test_view.CameraAngle+(angle_diff>>2))&2047; //wal >>2 not 0
angle_to = Arctan (
(camera_position.Y>>8) - ((track_thing->WorldPos.Y>>8)+t_dy),
Hypotenuse (
(camera_position.X>>8)-((track_thing->WorldPos.X>>8)+t_dx),
(camera_position.Z>>8)-((track_thing->WorldPos.Z>>8)+t_dz)
)
)-1024;
angle_diff = (angle_to-test_view.CameraTilt)&2047;
if(angle_diff>1024)
angle_diff -= 2048;
test_view.CameraTilt = (test_view.CameraTilt+(angle_diff>>2))&2047; //>>0 was >>2
// Calculate the distance.
distance = Hypotenuse(Hypotenuse(tx,ty),tz);
// Normalise the vector.
// I don't think the camera will ever be close enough for distance to be 0, but saying that...
if(distance==0)
distance=1;
tx = (tx<<14)/distance;
ty = (ty<<14)/distance;
tz = (tz<<14)/distance;
// Dampen the distance. This defines how baggy the camera is, should be variable.
distance >>= 4; //was 5
// Now set the cameras new position.
camera_position.X = ((camera_position.X<<14-8)+(tx*distance))>>14-8;
camera_position.Y = ((camera_position.Y<<14-8)+(ty*distance))>>14-8;
camera_position.Z = ((camera_position.Z<<14-8)+(tz*distance))>>14-8;
// Set the new position.
move_thing_on_map(c_thing,&camera_position);
// Set camera position.
test_view.CameraX = (float)(camera_position.X>>8);
test_view.CameraY = (float)(camera_position.Y>>8);
test_view.CameraZ = (float)(camera_position.Z>>8);
}
//---------------------------------------------------------------
SWORD spin_step = 0;
void spin_camera_around_subject(Thing *c_thing)
{
SLONG distance;
CameraMan *t_camera;
t_camera = c_thing->Genus.Camera;
distance = 1536;
t_camera->CameraDX = (SIN(spin_step&2047)*distance)>>16;
t_camera->CameraDY = 512;
t_camera->CameraDZ = (COS(spin_step&2047)*distance)>>16;
spin_step += 16;
process_t_camera(c_thing);
}
//---------------------------------------------------------------