Files
fs2open.github.com/code/camera/camera.cpp
T

981 lines
21 KiB
C++

#include "camera/camera.h"
#include "math/vecmat.h"
#include "graphics/2d.h"
#include "globalincs/alphacolors.h"
#include "parse/parselo.h"
#include "physics/physics.h" //apply_physics
#include "globalincs/systemvars.h" //VM_FREECAMERA etc
#include "hud/hud.h" //hud_get_draw
#include "model/model.h" //polymodel, model_get
#include "playerman/player.h" //player_get_padlock_orient
#include "ship/ship.h" //compute_slew_matrix
#include "graphics/font.h"
#include "mod_table/mod_table.h"
//*************************IMPORTANT GLOBALS*************************
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
float Sexp_fov = 0.0f;
warp_camera Warp_camera;
//*************************OTHER STUFF*************************
//Some global vars
SCP_vector<subtitle> Subtitles;
SCP_vector<camera*> Cameras;
//Preset cameras
camid Current_camera;
camid Main_camera;
//*************************CLASS: camera*************************
//This is where the camera class beings! :D
camera::camera(char *in_name, int in_signature)
{
set_name(in_name);
sig = in_signature;
reset();
}
camera::~camera()
{
//Check if this is in use
if(Current_camera.getSignature() == this->sig)
{
Current_camera = camid();
}
}
void camera::clear()
{
strcpy_s(name, "");
sig = -1;
reset();
}
void camera::reset()
{
flags = CAM_DEFAULT_FLAGS;
object_host = object_target = object_h();
object_host_submodel = object_target_submodel = -1;
c_fov = VIEWER_ZOOM_DEFAULT;
c_pos = vmd_zero_vector;
c_ori = vmd_identity_matrix;
func_custom_position = NULL;
func_custom_orientation = NULL;
fov.clear();
fov.set(VIEWER_ZOOM_DEFAULT);
pos_x.clear();
pos_y.clear();
pos_z.clear();
for(int i = 0; i < 9; i++)
{
ori[i].clear();
ori[i].set(vmd_identity_matrix.a1d[i]);
}
}
void camera::set_name(char *in_name)
{
if(name != NULL)
strncpy(name, in_name, NAME_LENGTH-1);
}
void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
{
if(in_fov_time == 0.0f && in_fov_acceleration_time == 0.0f && in_fov_deceleration_time == 0.0f)
{
flags |= CAM_STATIONARY_FOV;
c_fov = in_fov;
return;
}
flags &= ~CAM_STATIONARY_FOV;
if(in_fov <= 0.0f)
{
fov.setVD(in_fov_time, in_fov_acceleration_time, 0.0f);
}
fov.setAVD(in_fov, in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
}
void camera::set_object_host(object *objp, int n_object_host_submodel)
{
if(objp == NULL)
object_host = object_h();
object_host = object_h(objp);
object_host_submodel = n_object_host_submodel;
}
void camera::set_object_target(object *objp, int n_object_target_submodel)
{
if(objp == NULL)
object_target = object_h();
object_target = object_h(objp);
object_target_submodel = n_object_target_submodel;
}
/**
* Custom function receives the already-modified current position value.
* It should be replaced or added to as the custom function modifier sees fit.
*/
void camera::set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *camera_pos))
{
func_custom_position = n_func_custom_position;
}
/**
* Custom function receives the already-modified current orientation value.
* It should be replaced or added to as the custom function modifier sees fit.
*/
void camera::set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *camera_ori))
{
func_custom_orientation = n_func_custom_orientation;
}
void camera::set_position(vec3d *in_position, float in_translation_time, float in_translation_acceleration_time, float in_translation_deceleration_time, float in_end_velocity)
{
if(in_translation_time == 0.0f && in_translation_acceleration_time == 0.0f && in_translation_deceleration_time == 0.0f)
{
c_pos = *in_position;
pos_x.set(c_pos.xyz.x);
pos_y.set(c_pos.xyz.y);
pos_z.set(c_pos.xyz.z);
flags |= CAM_STATIONARY_POS;
return;
}
flags &= ~CAM_STATIONARY_POS;
if(in_position == NULL)
{
pos_x.setVD(in_translation_time, in_translation_acceleration_time, in_end_velocity);
pos_y.setVD(in_translation_time, in_translation_acceleration_time, in_end_velocity);
pos_z.setVD(in_translation_time, in_translation_acceleration_time, in_end_velocity);
return;
}
pos_x.setAVD(in_position->xyz.x, in_translation_time, in_translation_acceleration_time, in_translation_deceleration_time, in_end_velocity);
pos_y.setAVD(in_position->xyz.y, in_translation_time, in_translation_acceleration_time, in_translation_deceleration_time, in_end_velocity);
pos_z.setAVD(in_position->xyz.z, in_translation_time, in_translation_acceleration_time, in_translation_deceleration_time, in_end_velocity);
}
void camera::set_translation_velocity(vec3d *in_velocity, float in_acceleration_time)
{
pos_x.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.x);
pos_y.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.y);
pos_z.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.z);
}
void camera::set_rotation(matrix *in_orientation, float in_rotation_time, float in_rotation_acceleration_time, float in_rotation_deceleration_time)
{
if(in_rotation_time == 0.0f && in_rotation_acceleration_time == 0.0f && in_rotation_deceleration_time == 0.0f)
{
c_ori = *in_orientation;
for(int i = 0; i < 9; i++)
ori[i].set(in_orientation->a1d[i]);
flags |= CAM_STATIONARY_ORI;
return;
}
flags &= ~CAM_STATIONARY_ORI;
if(in_orientation == NULL)
{
for(int i = 0; i < 9; i++)
ori[i].setVD(in_rotation_time, in_rotation_acceleration_time, 0.0f);
return;
}
for(int i = 0; i < 9; i++)
ori[i].setAVD(in_orientation->a1d[i], in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time, 0.0f);
}
void camera::set_rotation(angles *in_angles, float in_rotation_time, float in_rotation_acceleration_time, float in_rotation_deceleration_time)
{
matrix mtx = IDENTITY_MATRIX;
vm_rotate_matrix_by_angles(&mtx, in_angles);
this->set_rotation(&mtx, in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time);
}
void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float in_rotation_acceleration_time, float in_rotation_deceleration_time)
{
matrix temp_matrix = IDENTITY_MATRIX;
if(in_target != NULL)
{
vec3d position = vmd_zero_vector;
this->get_info(&position, NULL);
if(in_target->xyz.x == position.xyz.x && in_target->xyz.y == position.xyz.y && in_target->xyz.z == position.xyz.z)
{
Warning(LOCATION, "Camera tried to point to self");
return;
}
vec3d targetvec;
vm_vec_normalized_dir(&targetvec, in_target, &position);
vm_vector_2_matrix(&temp_matrix, &targetvec, NULL, NULL);
}
set_rotation(&temp_matrix, in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time);
}
void camera::set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time)
{
Error(LOCATION, "This function is disabled until further notice.");
}
void camera::do_frame(float in_frametime)
{
}
object *camera::get_object_host()
{
if(object_host.IsValid())
return object_host.objp;
else
return NULL;
}
int camera::get_object_host_submodel()
{
return object_host_submodel;
}
object *camera::get_object_target()
{
if(object_target.IsValid())
return object_target.objp;
else
return NULL;
}
int camera::get_object_target_submodel()
{
return object_target_submodel;
}
float camera::get_fov()
{
if(!(flags & CAM_STATIONARY_FOV))
{
fov.get(&c_fov, NULL);
}
return c_fov;
}
void camera::get_info(vec3d *position, matrix *orientation)
{
if(position == NULL && orientation == NULL)
return;
//POSITION
if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid())
{
c_pos = vmd_zero_vector;
vec3d pt;
pos_x.get(&pt.xyz.x, NULL);
pos_y.get(&pt.xyz.y, NULL);
pos_z.get(&pt.xyz.z, NULL);
if(object_host.IsValid())
{
object *objp = object_host.objp;
int model_num = object_get_model(objp);
polymodel *pm = NULL;
if(model_num > -1)
{
pm = model_get(model_num);
}
if(object_host_submodel < 0 || pm == NULL)
{
vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient);
vm_vec_add2(&c_pos, &object_host.objp->pos);
}
else
{
model_find_world_point( &c_pos, &pt, pm->id, object_host_submodel, &objp->orient, &objp->pos );
}
}
else
{
c_pos = pt;
}
//Do custom position stuff, if needed
if(func_custom_position != NULL)
{
func_custom_position(this, &c_pos);
}
}
if(position != NULL)
*position = c_pos;
//ORIENTATION
if(orientation != NULL)
{
if(!(flags & CAM_STATIONARY_ORI) || object_target.IsValid() || object_host.IsValid())
{
if(object_target.IsValid())
{
object *objp = object_target.objp;
int model_num = object_get_model(objp);
polymodel *pm = NULL;
vec3d target_pos = vmd_zero_vector;
//See if we can get the model
if(model_num > -1)
{
pm = model_get(model_num);
}
//If we don't have a submodel or don't have the model use object pos
//Otherwise, find the submodel pos as it is rotated
if(object_target_submodel < 0 || pm == NULL)
{
target_pos = objp->pos;
}
else
{
model_find_world_point( &target_pos, &vmd_zero_vector, pm->id, object_target_submodel, &objp->orient, &objp->pos );
}
vec3d targetvec;
vm_vec_normalized_dir(&targetvec, &target_pos, &c_pos);
vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL);
}
else if(object_host.IsValid())
{
c_ori = object_host.objp->orient;
}
else
{
c_ori = vmd_identity_matrix;
}
matrix mtxA = c_ori;
matrix mtxB = IDENTITY_MATRIX;
float pos = 0.0f;
for(int i = 0; i < 9; i++)
{
ori[i].get(&pos, NULL);
mtxB.a1d[i] = pos;
}
vm_matrix_x_matrix(&c_ori, &mtxA, &mtxB);
vm_orthogonalize_matrix(&c_ori);
}
//Do custom orientation stuff, if needed
if(func_custom_orientation != NULL)
{
func_custom_orientation(this, &c_ori);
}
*orientation = c_ori;
}
}
//*************************warp_camera*************************
warp_camera::warp_camera()
{
this->reset();
}
warp_camera::warp_camera(object *objp)
{
this->reset();
vec3d object_pos = objp->pos;
matrix tmp;
ship_get_eye(&object_pos, &tmp, objp);
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.rvec, 0.0f );
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.uvec, 0.952f );
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.fvec, -1.782f );
vec3d tmp_vel = { { { 0.0f, 5.1919f, 14.7f } } };
this->set_position( &object_pos );
this->set_rotation( &objp->orient );
this->set_velocity( &tmp_vel, true);
}
void warp_camera::reset()
{
c_pos = c_vel = c_desired_vel = vmd_zero_vector;
c_ori = vmd_identity_matrix;
c_damping = 1.0f;
c_time = 0.0f;
}
void warp_camera::set_position( vec3d *in_pos )
{
c_pos = *in_pos;
}
void warp_camera::set_rotation( matrix *in_ori )
{
c_ori = *in_ori;
}
void warp_camera::set_velocity( vec3d *in_vel, bool instantaneous )
{
c_desired_vel.xyz.x = 0.0f;
c_desired_vel.xyz.y = 0.0f;
c_desired_vel.xyz.z = 0.0f;
vm_vec_scale_add2( &c_desired_vel, &c_ori.vec.rvec, in_vel->xyz.x );
vm_vec_scale_add2( &c_desired_vel, &c_ori.vec.uvec, in_vel->xyz.y );
vm_vec_scale_add2( &c_desired_vel, &c_ori.vec.fvec, in_vel->xyz.z );
if ( instantaneous ) {
c_vel = c_desired_vel;
}
}
void warp_camera::do_frame(float in_frametime)
{
vec3d new_vel, delta_pos;
apply_physics( c_damping, c_desired_vel.xyz.x, c_vel.xyz.x, in_frametime, &new_vel.xyz.x, &delta_pos.xyz.x );
apply_physics( c_damping, c_desired_vel.xyz.y, c_vel.xyz.y, in_frametime, &new_vel.xyz.y, &delta_pos.xyz.y );
apply_physics( c_damping, c_desired_vel.xyz.z, c_vel.xyz.z, in_frametime, &new_vel.xyz.z, &delta_pos.xyz.z );
c_vel = new_vel;
vm_vec_add2( &c_pos, &delta_pos );
float ot = c_time+0.0f;
c_time += in_frametime;
if ( (ot < 0.667f) && ( c_time >= 0.667f ) ) {
vec3d tmp;
tmp.xyz.z = 4.739f; // always go this fast forward.
// pick x and y velocities so they are always on a
// circle with a 25 m radius.
float tmp_angle = frand()*PI2;
tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
this->set_velocity( &tmp, 0 );
}
if ( (ot < 3.0f ) && ( c_time >= 3.0f ) ) {
vec3d tmp = ZERO_VECTOR;
this->set_velocity( &tmp, 0 );
}
}
void warp_camera::get_info(vec3d *position, matrix *orientation)
{
if(position != NULL)
*position = c_pos;
if(orientation != NULL)
*orientation = c_ori;
}
//*************************subtitle*************************
#define MAX_SUBTITLE_LINES 64
subtitle::subtitle(int in_x_pos, int in_y_pos, char* in_text, char* in_imageanim, float in_display_time, float in_fade_time, color *in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width, int in_height, bool in_post_shaded)
{
// basic init, this always has to be done
memset( imageanim, 0, sizeof(imageanim) );
memset( &text_pos, 0, 2*sizeof(int) );
memset( &image_pos, 0, 4*sizeof(int) );
image_id = -1;
if ( ((in_text != NULL) && (strlen(in_text) <= 0)) && ((in_imageanim != NULL) && (strlen(in_imageanim) <= 0)) )
return;
char text_buf[256];
if (in_text != NULL && in_text[0] != '\0')
{
strcpy_s(text_buf, in_text);
sexp_replace_variable_names_with_values(text_buf, 256);
in_text = text_buf;
}
int num_text_lines = 0;
char *text_line_ptrs[MAX_SUBTITLE_LINES];
int text_line_lens[MAX_SUBTITLE_LINES];
//Setup text
if ( (in_text != NULL) && (in_text[0] != '\0') ) {
int split_width = (in_width > 0) ? in_width : 200;
num_text_lines = split_str(in_text, split_width, text_line_lens, text_line_ptrs, MAX_SUBTITLE_LINES);
SCP_string temp_str;
for(int i = 0; i < num_text_lines; i++)
{
temp_str.assign(text_line_ptrs[i], text_line_lens[i]);
text_lines.push_back(temp_str);
}
}
//Setup text color
if(in_text_color != NULL)
text_color = *in_text_color;
else
gr_init_alphacolor(&text_color, 255, 255, 255, 255);
text_fontnum = in_text_fontnum;
//Setup display and fade time
display_time = fl_abs(in_display_time);
fade_time = fl_abs(in_fade_time);
//Setup image
if ( (in_imageanim != NULL) && (in_imageanim[0] != '\0') )
{
image_id = bm_load(in_imageanim);
if (image_id >= 0)
strncpy(imageanim, in_imageanim, sizeof(imageanim) - 1);
}
//Setup pos
int w=0, h=0, tw=0, th=0;
if(center_x || center_y)
{
// switch font because we need to measure it
int old_fontnum;
if (text_fontnum >= 0)
{
old_fontnum = gr_get_current_fontnum();
gr_set_font(text_fontnum);
}
else
{
old_fontnum = -1;
}
//Get text size
for(int i = 0; i < num_text_lines; i++)
{
gr_get_string_size(&w, &h, text_line_ptrs[i], text_line_lens[i]);
if(w > tw)
tw = w;
th += h;
}
// restore old font
if (old_fontnum >= 0)
{
gr_set_font(old_fontnum);
}
//Get image size
if(image_id != -1)
{
bm_get_info(image_id, &w, &h);
if (in_width > 0)
w = in_width;
if (in_height > 0)
h = in_height;
tw += w;
if(h > th)
th = h;
}
//Center it?
if(center_x)
image_pos.x = (gr_screen.max_w - tw)/2;
if(center_y)
image_pos.y = (gr_screen.max_h - th)/2;
}
if(in_x_pos < 0 && !center_x)
image_pos.x += gr_screen.max_w + in_x_pos;
else if(!center_x)
image_pos.x += in_x_pos;
if(in_y_pos < 0 && !center_y)
image_pos.y += gr_screen.max_h + in_y_pos;
else if(!center_y)
image_pos.y += in_y_pos;
image_pos.w = in_width;
image_pos.h = in_height;
if(image_id != -1)
text_pos.x = image_pos.x + w; //Still set from bm_get_info call
else
text_pos.x = image_pos.x;
text_pos.y = image_pos.y;
time_displayed = 0.0f;
time_displayed_end = 2.0f*fade_time + display_time;
post_shaded = in_post_shaded;
}
void subtitle::do_frame(float frametime)
{
//Figure out how much alpha
if(time_displayed < fade_time)
{
text_color.alpha = (ubyte)fl2i(255.0f*(time_displayed/fade_time));
}
else if(time_displayed > time_displayed_end)
{
//We're finished
return;
}
else if((time_displayed - fade_time) > display_time)
{
text_color.alpha = (ubyte)fl2i(255.0f*(1-(time_displayed - fade_time - display_time)/fade_time));
}
else
{
text_color.alpha = 255;
}
gr_set_color_fast(&text_color);
// save old font and set new font
int old_fontnum;
if (text_fontnum >= 0)
{
old_fontnum = gr_get_current_fontnum();
gr_set_font(text_fontnum);
}
else
{
old_fontnum = -1;
}
int font_height = gr_get_font_height();
int x = text_pos.x;
int y = text_pos.y;
for(SCP_vector<SCP_string>::iterator line = text_lines.begin(); line != text_lines.end(); ++line)
{
gr_string(x, y, (char*)line->c_str(), false);
y += font_height;
}
// restore old font
if (old_fontnum >= 0)
{
gr_set_font(old_fontnum);
}
if(image_id >= 0)
{
gr_set_bitmap(image_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, text_color.alpha/255.0f);
// scaling?
if (image_pos.w > 0 || image_pos.h > 0)
{
int orig_w, orig_h;
vec3d scale;
bm_get_info(image_id, &orig_w, &orig_h);
scale.xyz.x = image_pos.w / (float) orig_w;
scale.xyz.y = image_pos.h / (float) orig_h;
scale.xyz.z = 1.0f;
gr_push_scale_matrix(&scale);
gr_bitmap(image_pos.x, image_pos.y, false);
gr_pop_scale_matrix();
}
// no scaling
else
{
gr_bitmap(image_pos.x, image_pos.y, false);
}
}
time_displayed += frametime;
}
subtitle::~subtitle()
{
if (image_id != -1) {
if ( bm_release(image_id) ) {
image_id = -1;
}
}
}
void subtitle::clone(const subtitle &sub)
{
text_lines = sub.text_lines;
text_fontnum = sub.text_fontnum;
// copy the structs
text_pos = sub.text_pos;
image_pos = sub.image_pos;
display_time = sub.display_time;
fade_time = sub.fade_time;
memcpy( &text_color, &sub.text_color, sizeof(color) );
if ( strlen(sub.imageanim) ) {
memcpy( imageanim, sub.imageanim, MAX_FILENAME_LEN );
// we bm_load() again here to kick the refcount up
image_id = bm_load(imageanim);
} else {
memset( imageanim, 0, MAX_FILENAME_LEN );
image_id = -1;
}
time_displayed = sub.time_displayed;
time_displayed_end = sub.time_displayed_end;
post_shaded = sub.post_shaded;
}
const subtitle &subtitle::operator=(const subtitle &sub)
{
if (this != &sub) {
if (image_id != -1) {
if ( bm_release(image_id) ) {
image_id = -1;
}
}
clone(sub);
}
return *this;
}
//*************************camid*************************
camid::camid()
{
idx = 0;
sig = -1;
}
camid::camid(int n_idx, int n_sig)
{
idx = n_idx;
sig = n_sig;
}
camera* camid::getCamera()
{
if(!isValid())
return NULL;
return Cameras[idx];
}
uint camid::getIndex()
{
return idx;
}
int camid::getSignature()
{
return sig;
}
bool camid::isValid()
{
if(idx >= Cameras.size())
return false;
if(Cameras[idx] == NULL)
return false;
if(Cameras[idx]->get_signature() != this->sig)
return false;
return true;
}
//*************************camera functions*************************
void cam_init()
{
//Rest FOV override
Sexp_fov = 0.0;
}
void cam_close()
{
//Set Current_camera to nothing
Current_camera = camid();
Cameras.clear();
}
int cam_get_next_sig()
{
static int next_sig = 0;
return next_sig++;
}
camid cam_create(char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
{
matrix ori;
vm_vector_2_matrix_norm(&ori, n_norm);
return cam_create(n_name, n_pos, &ori, n_object, n_object_host_submodel);
}
camid cam_create(char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
{
camera *cam = NULL;
camid cid;
//Get signature
int sig = cam_get_next_sig();
//Get name
char buf[NAME_LENGTH] = {'\0'};
if(n_name == NULL)
sprintf(buf, "Camera %d", cid.getSignature());
else
strncpy(buf, n_name, NAME_LENGTH-1);
//Find a free slot
cam = new camera(buf, sig);
cid = camid(Cameras.size(), sig);
Cameras.push_back(cam);
//Set attributes
if(n_pos != NULL)
cam->set_position(n_pos);
if(n_ori != NULL)
cam->set_rotation(n_ori);
if(n_object != NULL)
cam->set_object_host(n_object, n_object_host_submodel);
return cid;
}
void cam_delete(camid cid)
{
if(cid.isValid())
{
cid.getCamera()->clear();
}
}
void cam_do_frame(float frametime)
{
size_t i,size=Cameras.size();
for(i = 0; i < size; i++)
{
if(Cameras[i] != NULL)
Cameras[i]->do_frame(frametime);
}
}
camid cam_get_camera(uint idx)
{
if(idx >= Cameras.size())
return camid();
return camid(idx, Cameras[idx]->get_signature());
}
camid cam_get_current()
{
return Current_camera;
}
uint cam_get_num()
{
return Cameras.size();
}
/**
* Looks up camera by name, returns -1 on failure
*/
camid cam_lookup(char *name)
{
size_t i, size=Cameras.size();
for(i = 0; i < size; i++)
{
if(Cameras[i] != NULL && !stricmp(Cameras[i]->get_name(), name))
return camid(i, Cameras[i]->get_signature());
}
return camid();
}
static bool Camera_hud_draw_saved = false;
static int Camera_hud_draw_value = 0;
bool cam_set_camera(camid cid)
{
if(!cid.isValid())
{
return false;
}
Viewer_mode |= VM_FREECAMERA;
Current_camera = cid;
if (!Cutscene_camera_displays_hud)
{
if(!Camera_hud_draw_saved)
{
Camera_hud_draw_value = hud_get_draw();
Camera_hud_draw_saved = true;
}
hud_set_draw(0);
}
return true;
}
void cam_reset_camera()
{
Viewer_mode &= ~VM_FREECAMERA;
if (!Cutscene_camera_displays_hud)
{
hud_set_draw(Camera_hud_draw_value);
Camera_hud_draw_saved = false;
}
}
void subtitles_close()
{
Subtitles.clear();
}
void subtitles_do_frame(float frametime)
{
SCP_vector<subtitle>::iterator sub;
for(sub = Subtitles.begin(); sub != Subtitles.end(); ++sub)
{
if ( !sub->is_post_shaded( ) )
sub->do_frame(frametime);
}
}
void subtitles_do_frame_post_shaded(float frametime)
{
SCP_vector<subtitle>::iterator sub;
for(sub = Subtitles.begin(); sub != Subtitles.end(); ++sub)
{
if ( sub->is_post_shaded( ) )
sub->do_frame(frametime);
}
}