Files
fs2open.github.com/code/lab/lab.cpp
T
Fabian Woltermann 770fce8de5 Bitset flags -- take 2 (#775)
This introduces a new mechanism for handling bit flags. Instead of using an int (or two, or three) to write bits into, this uses the std::bitset in a wrapper class that accepts an enum class as input. This means that certain classes of errors we've had a few of in the engine, where a coder used the wrong set of flags or checked them against the wrong variable (SF_STEALTH vs SIF_STEALTH, for example) can now be detected at a compiler level rather than not at all.
2016-08-12 16:13:50 -07:00

2726 lines
80 KiB
C++

/*
* lab.cpp
* created by WMCoolmon
*
* You may not sell or otherwise commercially exploit the source or things you
* create based on the source.
*
*/
#include "cmdline/cmdline.h"
#include "freespace.h"
#include "gamesequence/gamesequence.h"
#include "graphics/gropengldraw.h"
#include "graphics/gropengllight.h"
#include "graphics/gropenglshader.h"
#include "graphics/shadows.h"
#include "hud/hudshield.h"
#include "io/key.h"
#include "io/timer.h"
#include "lab/wmcgui.h"
#include "lighting/lighting.h"
#include "mission/missionparse.h"
#include "missionui/missionscreencommon.h"
#include "model/model.h"
#include "object/objectsnd.h"
#include "playerman/managepilot.h"
#include "render/3d.h"
#include "ship/ship.h"
#include "species_defs/species_defs.h"
#include "weapon/beam.h"
#include "weapon/weapon.h"
// flags
#define LAB_FLAG_NORMAL (0) // default
#define LAB_FLAG_NO_ROTATION (1<<0) // don't rotate models
#define LAB_FLAG_SHOW_INSIGNIA (1<<1) // show ships with insignia applied
#define LAB_FLAG_SHOW_DEBRIS (1<<2) // render debris instead of normal LOD
#define LAB_FLAG_SUBMODEL_ROTATE (1<<3) // do rotation for any rotating ship subobjects
#define LAB_FLAG_LIGHTNING_ARCS (1<<4) // show damage lightning
#define LAB_FLAG_UNUSED (1<<5) // feel free to change that to something you need - Valathil
#define LAB_FLAG_SHOW_WEAPONS (1<<6) // determines if external weapons models are displayed
#define LAB_FLAG_INITIAL_ROTATION (1<<7) // initial rotation setting
#define LAB_FLAG_DESTROYED_SUBSYSTEMS (1<<8) // render model as if all subsystems are destroyed
// modes
#define LAB_MODE_NONE 0 // not showing anything
#define LAB_MODE_SHIP 1 // dealing with ships
#define LAB_MODE_WEAPON 2 // dealing with weapons
// variables
static GUIScreen *Lab_screen = NULL;
static Window *Lab_toolbar = NULL;
static Window *Lab_class_window = NULL;
static Window *Lab_class_toolbar = NULL;
static Window *Lab_flags_window = NULL;
static Window *Lab_render_options_window = NULL;
static Window *Lab_material_override_window = NULL;
static Window *Lab_variables_window = NULL;
static Window *Lab_description_window = NULL;
static Text *Lab_description_text = NULL;
static TreeItem **Lab_species_nodes = NULL;
static bool Lab_in_mission = false;
static int Lab_screen_save_bitmap = -1;
static shader Lab_shader;
static int Lab_insignia_bitmap = -1;
static int Lab_insignia_index = -1;
static ubyte Lab_mode = LAB_MODE_NONE;
static int Lab_selected_index = -1;
static int Lab_last_selected_ship = -1;
static int Lab_selected_object = -1;
static int Lab_last_selected_weapon = -1;
static int Lab_model_num = -1;
static int Lab_weaponmodel_num[MAX_SHIP_WEAPONS];
static int Lab_model_LOD = 0;
static int Lab_model_flags = MR_AUTOCENTER | MR_NO_FOGGING;
static int Lab_model_debug_flags = 0;
static char Lab_model_filename[MAX_FILENAME_LEN];
static char Lab_weaponmodel_filename[MAX_SHIP_WEAPONS][MAX_FILENAME_LEN];
static int Lab_bitmap_id = -1;
static char Lab_bitmap_filename[MAX_FILENAME_LEN];
static float Lab_viewer_zoom = 1.2f;
static vec3d Lab_viewer_pos = ZERO_VECTOR;
static matrix Lab_viewer_orient = IDENTITY_MATRIX;
static float Lab_viewer_rotation = 0.0f;
static int Lab_viewer_flags = LAB_MODE_NONE;
static ship_subsys *Lab_ship_subsys = NULL;
static SCP_vector<model_subsystem> Lab_ship_model_subsys;
static int Lab_detail_texture_save = 0;
static int anim_timer_start = 0;
// damage lightning stuff
static vec3d Lab_arc_pts[MAX_SHIP_ARCS][2];
static int Lab_arc_timestamp[MAX_SHIP_ARCS];
static ubyte Lab_arc_type[MAX_SHIP_ARCS];
static int Lab_arc_next_time = -1;
static bool Lab_arc_disrupted = false;
static float Lab_thrust_len = 1.0f;
static bool Lab_thrust_afterburn = false;
// Trackball_mode:
// 1 == rotate (left-mouse)
// 2 == pan (shift-left-mouse)
// 3 == zoom (right-mouse)
static int Trackball_mode = 1;
static int Trackball_active = 0;
SCP_string Lab_team_color = "<none>";
// functions
void labviewer_change_ship_lod(Tree *caller);
void labviewer_change_ship(Tree *caller);
void labviewer_make_desc_window(Button *caller);
void labviewer_close_weap_window(GUIObject *caller);
void labviewer_update_flags_window();
// ---------------------- General/Utility Functions ----------------------------
void labviewer_setup_subsys_rotation()
{
if (Lab_ship_subsys != NULL) {
delete[] Lab_ship_subsys;
Lab_ship_subsys = NULL;
}
Lab_ship_model_subsys.clear();
// whole lot of of get-outs
if (Lab_mode != LAB_MODE_SHIP) {
return;
}
if (Lab_selected_index < 0) {
return;
}
if (Lab_selected_index >= static_cast<int>(Ship_info.size())) {
Int3();
return;
}
if (Ship_info[Lab_selected_index].n_subsystems <= 0) {
return;
}
uint n_subsystems = Ship_info[Lab_selected_index].n_subsystems;
Lab_ship_subsys = new ship_subsys[n_subsystems];
for (uint i = 0; i < n_subsystems; i++)
Lab_ship_subsys[i].clear();
Lab_ship_model_subsys.reserve(n_subsystems);
for (uint idx = 0; idx < n_subsystems; idx++) {
Lab_ship_model_subsys.push_back( Ship_info[Lab_selected_index].subsystems[idx] );
}
}
void labviewer_change_bitmap(int ship_index = -1, int weapon_index = -1)
{
if ( (ship_index < 0) && (weapon_index < 0) ) {
if (Lab_bitmap_id >= 0) {
bm_release(Lab_bitmap_id);
if (Lab_last_selected_weapon >= 0) {
Weapon_info[Lab_last_selected_weapon].laser_bitmap.first_frame = -1;
}
Lab_bitmap_id = -1;
Lab_last_selected_weapon = -1;
}
return;
}
if ( !Lab_in_mission ) {
if (ship_index >= 0) {
// TODO: Ship stuff!!
} else if (weapon_index >= 0) {
// release old bitmap if required
if ( (Lab_last_selected_weapon >= 0) && (Lab_last_selected_weapon != weapon_index)) {
Weapon_info[Lab_last_selected_weapon].laser_bitmap.first_frame = -1;
if (Lab_bitmap_id >= 0) {
bm_release(Lab_bitmap_id);
}
}
// load up the weapon bitmaps
extern void weapon_load_bitmaps(int);
weapon_load_bitmaps(weapon_index);
Lab_bitmap_id = Weapon_info[weapon_index].laser_bitmap.first_frame;
}
}
if (Lab_bitmap_id >= 0) {
bm_get_filename(Lab_bitmap_id, Lab_bitmap_filename);
} else {
memset( Lab_bitmap_filename, 0, sizeof(Lab_bitmap_filename) );
}
labviewer_update_flags_window();
}
void labviewer_change_model(char *model_fname, int lod = 0, int sel_index = -1)
{
bool change_model = true;
int j,l;
ship_info *sip = NULL;
anim_timer_start = timer_get_milliseconds();
if ( (model_fname != NULL) && (Lab_mode == LAB_MODE_SHIP) ) {
if ( (Lab_selected_index >= 0) && (Lab_selected_index == sel_index) ) {
change_model = false;
}
}
Lab_selected_index = sel_index;
if (change_model) {
bool valid_ship = ( (Lab_mode == LAB_MODE_SHIP) && (sel_index >= 0) );
if (Lab_model_num != -1) {
model_page_out_textures(Lab_model_num, true);
model_unload(Lab_model_num);
Lab_model_num = -1;
for (j = 0; j < MAX_SHIP_WEAPONS; j++) {
if (Lab_weaponmodel_num[j] >= 0) {
model_page_out_textures(Lab_weaponmodel_num[j], true);
model_unload(Lab_weaponmodel_num[j]);
Lab_weaponmodel_num[j] = -1;
}
}
if (Lab_last_selected_ship >= 0) {
ship_page_out_textures(Lab_last_selected_ship, true);
}
}
labviewer_setup_subsys_rotation();
Lab_viewer_zoom = 1.2f;
if (valid_ship) {
memcpy( &Lab_viewer_pos, &Ship_info[sel_index].closeup_pos, sizeof(vec3d) );
} else {
Lab_viewer_pos.xyz.x = Lab_viewer_pos.xyz.y = 0.0f;
}
// only load a new model if we are supposed to (so that we can use this function to reset states)
if (model_fname != NULL) {
model_subsystem *subsystems = NULL;
if ( !Lab_ship_model_subsys.empty() ) {
subsystems = &Lab_ship_model_subsys[0];
}
Lab_model_num = model_load(model_fname, (valid_ship) ? Ship_info[sel_index].n_subsystems : 0, subsystems, 0);
if (Lab_model_num >= 0) {
strcpy_s(Lab_model_filename, model_fname);
} else {
memset( Lab_model_filename, 0, sizeof(Lab_model_filename) );
}
if (valid_ship) {
if (Lab_model_num >= 0) {
model_page_in_textures(Lab_model_num, sel_index);
}
for (int idx = 0; idx < Ship_info[sel_index].n_subsystems; idx++) {
model_set_instance_info(&Lab_ship_subsys[idx].submodel_info_1, Lab_ship_model_subsys[idx].turn_rate, 0.5f);
}
}
// do the same for weapon models if necessary
if (Lab_mode == LAB_MODE_SHIP) {
sip = &Ship_info[Lab_selected_index];
l = 0;
for (j = 0; j < sip->num_primary_banks; j++) {
weapon_info *wip = &Weapon_info[sip->primary_bank_weapons[j]];
if (!sip->draw_primary_models[j])
continue;
Lab_weaponmodel_num[l] = -1;
if ( strlen(wip->external_model_name) ){
Lab_weaponmodel_num[l] = model_load(wip->external_model_name, 0, NULL);
}
if (Lab_weaponmodel_num[l] >= 0) {
strcpy_s(Lab_weaponmodel_filename[l], wip->external_model_name);
} else {
memset( Lab_weaponmodel_filename[l], 0, sizeof(Lab_weaponmodel_filename[l]) );
}
l++;
}
for (j = 0; j < sip->num_secondary_banks; j++) {
weapon_info *wip = &Weapon_info[sip->secondary_bank_weapons[j]];
if (!sip->draw_secondary_models[j])
continue;
Lab_weaponmodel_num[l] = -1;
if ( strlen(wip->external_model_name) ){
Lab_weaponmodel_num[l] = model_load(wip->external_model_name, 0, NULL);
}
if (Lab_weaponmodel_num[l] >= 0) {
strcpy_s(Lab_weaponmodel_filename[l], wip->external_model_name);
} else {
memset( Lab_weaponmodel_filename[l], 0, sizeof(Lab_weaponmodel_filename[l]) );
}
l++;
}
}
} else {
// clear out the model filename
memset( Lab_model_filename, 0, sizeof(Lab_model_filename) );
if (Lab_weaponmodel_num[0] >= 0) {
for (j = 0; j < MAX_SHIP_WEAPONS; j++) {
memset( Lab_weaponmodel_filename[j], 0, sizeof(Lab_weaponmodel_filename[j]) );
}
}
}
}
if (lod == 99) {
Lab_model_LOD = 0;
Lab_viewer_flags |= LAB_FLAG_SHOW_DEBRIS;
} else {
Lab_model_LOD = lod;
Lab_viewer_flags &= ~LAB_FLAG_SHOW_DEBRIS;
}
if (model_fname == NULL) {
Lab_last_selected_ship = -1;
}
labviewer_update_flags_window();
}
void labviewer_add_model_arcs()
{
int i;
float mradius = 0.0f;
const float MAX_ARC_LENGTH_PERCENTAGE = 0.25f;
if (Lab_mode != LAB_MODE_SHIP) {
return;
}
// Kill off old sparks
for (i = 0; i < MAX_SHIP_ARCS; i++) {
if ( timestamp_valid(Lab_arc_timestamp[i]) && timestamp_elapsed(Lab_arc_timestamp[i]) ) {
Lab_arc_timestamp[i] = timestamp(-1);
}
}
if ( !timestamp_valid(Lab_arc_next_time) ) {
// start the next fireball up in the next 10 seconds or so...
int freq;
if (Lab_arc_disrupted) {
freq = 150;
} else {
// 1% hull left
freq = 550;
}
// set the next arc time
Lab_arc_next_time = timestamp_rand(freq * 2, freq * 4);
}
mradius = model_get_radius(Lab_model_num);
if ( timestamp_elapsed(Lab_arc_next_time) ) {
Lab_arc_next_time = timestamp(-1); // invalid, so it gets restarted next frame
int n, n_arcs = ((rand() >> 5) % 3) + 1; // Create 1-3 sparks
vec3d v1, v2, v3, v4;
if ( Cmdline_old_collision_sys ) {
submodel_get_two_random_points(Lab_model_num, -1, &v1, &v2);
submodel_get_two_random_points(Lab_model_num, -1, &v3, &v4);
} else {
submodel_get_two_random_points_better(Lab_model_num, -1, &v1, &v2);
submodel_get_two_random_points_better(Lab_model_num, -1, &v3, &v4);
}
// For large ships, cap the length to be 25% of max radius
if (mradius > 200.0f) {
float max_dist = mradius * MAX_ARC_LENGTH_PERCENTAGE;
vec3d tmp;
float d;
// Cap arc 2->1
vm_vec_sub( &tmp, &v1, &v2 );
d = vm_vec_mag_quick( &tmp );
if ( d > max_dist ) {
vm_vec_scale_add( &v1, &v2, &tmp, max_dist / d );
}
// Cap arc 2->3
vm_vec_sub( &tmp, &v3, &v2 );
d = vm_vec_mag_quick( &tmp );
if ( d > max_dist ) {
vm_vec_scale_add( &v3, &v2, &tmp, max_dist / d );
}
// Cap arc 2->4
vm_vec_sub( &tmp, &v4, &v2 );
d = vm_vec_mag_quick( &tmp );
if ( d > max_dist ) {
vm_vec_scale_add( &v4, &v2, &tmp, max_dist / d );
}
}
n = 0;
float factor = 1.0f + 0.0025f * mradius;
int a = fl2i(factor * 100.0f);
int b = fl2i(factor * 1000.0f);
int lifetime = (myrand() % ((b) - (a) + 1)) + (a);
// Create the arc effects
for (i = 0; i < MAX_SHIP_ARCS; i++) {
if ( !timestamp_valid(Lab_arc_timestamp[i]) ) {
Lab_arc_timestamp[i] = timestamp(lifetime); // live up to a second
switch (n) {
case 0:
Lab_arc_pts[i][0] = v1;
Lab_arc_pts[i][1] = v2;
break;
case 1:
Lab_arc_pts[i][0] = v2;
Lab_arc_pts[i][1] = v3;
break;
case 2:
Lab_arc_pts[i][0] = v2;
Lab_arc_pts[i][1] = v4;
break;
default:
Int3();
}
// determine what kind of arc to create
if (Lab_arc_disrupted) {
Lab_arc_type[i] = MARC_TYPE_EMP;
} else {
Lab_arc_type[i] = MARC_TYPE_NORMAL;
}
if ( ++n == n_arcs ) {
// Don't need to create anymore
break;
}
}
}
}
// maybe move arc points around
for (i = 0; i < MAX_SHIP_ARCS; i++) {
if ( timestamp_valid(Lab_arc_timestamp[i]) ) {
if ( !timestamp_elapsed(Lab_arc_timestamp[i]) ) {
// Maybe move a vertex.... 20% of the time maybe?
int mr = myrand();
if ( mr < (RAND_MAX / 5) ) {
vec3d v1, v2;
if ( Cmdline_old_collision_sys ) {
submodel_get_two_random_points(Lab_model_num, -1, &v1, &v2);
} else {
submodel_get_two_random_points_better(Lab_model_num, -1, &v1, &v2);
}
vec3d static_one;
if (mr % 2) {
static_one = Lab_arc_pts[i][0];
} else {
static_one = Lab_arc_pts[i][1];
}
// For large ships, cap the length to be 25% of max radius
if (mradius > 200.0f) {
float max_dist = mradius * MAX_ARC_LENGTH_PERCENTAGE;
vec3d tmp;
float d;
// Cap arc 2->1
vm_vec_sub( &tmp, &v1, &static_one );
d = vm_vec_mag_quick( &tmp );
if (d > max_dist) {
vm_vec_scale_add( &v1, &static_one, &tmp, max_dist / d );
}
}
Lab_arc_pts[i][mr % 2] = v1;
}
}
}
}
for (i = 0; i < MAX_SHIP_ARCS; i++) {
if ( timestamp_valid(Lab_arc_timestamp[i]) ) {
model_add_arc(Lab_model_num, -1, &Lab_arc_pts[i][0], &Lab_arc_pts[i][1], Lab_arc_type[i]);
// maybe add lighting for the arc
if (Detail.lighting > 2) {
// Move arc endpoints into world coordinates
vec3d tmp1, tmp2;
vm_vec_unrotate(&tmp1, &Lab_arc_pts[i][0], &Lab_viewer_orient);
vm_vec_unrotate(&tmp2, &Lab_arc_pts[i][1], &Lab_viewer_orient);
light_add_point( &tmp1, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
light_add_point( &tmp2, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
}
}
}
}
void labviewer_add_model_thrusters(model_render_params *render_info, ship_info *sip)
{
static float thruster_frame = 0.0f;
static float thruster_glow_frame = 0.0f;
static int thruster_bitmap = -1;
static int thruster_glow_bitmap = -1;
static float thruster_glow_noise = 1.0f;
float rate;
int framenum;
int secondary_glow_bitmap = -1;
int tertiary_glow_bitmap = -1;
static int thruster_distortion_bitmap = -1;
generic_anim *flame_anim = NULL, *glow_anim = NULL;
species_info *species = &Species_info[0];
weapon_info *wip = NULL;
mst_info mst;
if (Lab_mode == LAB_MODE_SHIP) {
Assert( sip != NULL );
species = &Species_info[sip->species];
}
if (Lab_mode == LAB_MODE_WEAPON) {
wip = &Weapon_info[Lab_selected_index];
}
// init thruster graphics (species stuff)
extern void ship_init_thrusters();
ship_init_thrusters();
if ( Lab_thrust_afterburn && (Lab_mode != LAB_MODE_WEAPON) ) {
flame_anim = &sip->thruster_flame_info.afterburn; // select afterburner flame
glow_anim = &sip->thruster_glow_info.afterburn; // select afterburner glow
secondary_glow_bitmap = sip->thruster_secondary_glow_info.afterburn.bitmap_id;
tertiary_glow_bitmap = sip->thruster_tertiary_glow_info.afterburn.bitmap_id;
thruster_distortion_bitmap = sip->thruster_distortion_info.afterburn.bitmap_id;
rate = 1.5f; // go at 1.5x faster when afterburners on
} else {
flame_anim = &species->thruster_info.flames.normal; // select normal flame
glow_anim = &species->thruster_info.glow.normal; // select normal glow
if (Lab_mode == LAB_MODE_WEAPON) {
if (wip->thruster_flame.first_frame >= 0)
flame_anim = &wip->thruster_flame;
if (wip->thruster_glow.first_frame >= 0)
glow_anim = &wip->thruster_glow;
}
if (Lab_mode == LAB_MODE_SHIP) {
flame_anim = &sip->thruster_flame_info.normal; // select normal flame
glow_anim = &sip->thruster_glow_info.normal; // select normal glow
secondary_glow_bitmap = sip->thruster_secondary_glow_info.normal.bitmap_id;
tertiary_glow_bitmap = sip->thruster_tertiary_glow_info.normal.bitmap_id;
thruster_distortion_bitmap = sip->thruster_distortion_info.normal.bitmap_id;
}
// If thrust at 0, go at half as fast, full thrust; full framerate
// so set rate from 0.5 to 1.0, depending on thrust from 0 to 1
// rate = 0.5f + objp->phys_info.forward_thrust / 2.0f;
rate = 0.67f * (1.0f + Lab_thrust_len);
}
Assert( flFrametime > 0.0f );
if (flame_anim->first_frame >= 0) {
thruster_frame += flFrametime * rate;
framenum = bm_get_anim_frame(flame_anim->first_frame, thruster_frame, flame_anim->total_time, true);
// Get the bitmap for this frame
thruster_bitmap = flame_anim->first_frame + framenum;
} else {
thruster_frame = 0.0f;
thruster_bitmap = -1;
}
// Do it for glow bitmaps
if (glow_anim->first_frame >= 0) {
thruster_glow_frame += flFrametime * rate;
framenum = bm_get_anim_frame(glow_anim->first_frame, thruster_glow_frame, glow_anim->total_time, true);
// Get the bitmap for this frame
thruster_glow_bitmap = glow_anim->first_frame; // + framenum;
thruster_glow_noise = Noise[framenum];
} else {
thruster_glow_frame = 0.0f;
thruster_glow_bitmap = -1;
thruster_glow_noise = 1.0f;
}
// ok, we've worked out the bitmaps, so now we need to set up the thrust info
mst.length.xyz.z = Lab_thrust_len;
mst.length.xyz.x = 0.0f;
mst.length.xyz.y = 0.0f;
// Add noise to thruster geometry.
if ( Lab_mode == LAB_MODE_SHIP ) {
if (!(sip->flags[Ship::Info_Flags::No_thruster_geo_noise])) {
mst.length.xyz.z *= (1.0f + frand()/5.0f - 0.1f);
mst.length.xyz.y *= (1.0f + frand()/5.0f - 0.1f);
mst.length.xyz.x *= (1.0f + frand()/5.0f - 0.1f);
}
} else {
mst.length.xyz.z *= (1.0f + frand()/5.0f - 0.1f);
mst.length.xyz.y *= (1.0f + frand()/5.0f - 0.1f);
mst.length.xyz.x *= (1.0f + frand()/5.0f - 0.1f);
}
CLAMP(mst.length.xyz.z, -1.0f, 1.0f);
CLAMP(mst.length.xyz.y, -1.0f, 1.0f);
CLAMP(mst.length.xyz.x, -1.0f, 1.0f);
mst.primary_bitmap = thruster_bitmap;
mst.primary_glow_bitmap =thruster_glow_bitmap;
mst.secondary_glow_bitmap = secondary_glow_bitmap;
mst.tertiary_glow_bitmap = tertiary_glow_bitmap;
mst.distortion_bitmap = thruster_distortion_bitmap;
mst.use_ab = Lab_thrust_afterburn;
mst.rotvel = vmd_zero_vector;
if (Lab_mode == LAB_MODE_SHIP) {
mst.glow_noise = thruster_glow_noise * sip->thruster_glow_noise_mult;
mst.glow_rad_factor = sip->thruster01_glow_rad_factor;
mst.secondary_glow_rad_factor = sip->thruster02_glow_rad_factor;
mst.tertiary_glow_rad_factor = sip->thruster03_glow_rad_factor;
mst.glow_length_factor = sip->thruster02_glow_len_factor;
mst.distortion_length_factor = sip->thruster_dist_len_factor;
mst.distortion_rad_factor = sip->thruster_dist_rad_factor;
mst.draw_distortion = sip->draw_distortion;
}
if (Lab_mode == LAB_MODE_WEAPON) {
mst.glow_noise = thruster_glow_noise;
mst.glow_rad_factor = wip->thruster_glow_factor;
}
// set, and go...
render_info->set_thruster_info(mst);
}
void light_set_all_relevent();
void labviewer_render_model(float frametime)
{
int i, j;
float rev_rate;
angles rot_angles, view_angles;
ship_info *sip = NULL;
if ( (Lab_mode == LAB_MODE_SHIP) && (Lab_selected_index >= 0) ) {
sip = &Ship_info[Lab_selected_index];
}
model_render_params render_info;
model_clear_instance(Lab_model_num);
// get correct revolution rate
rev_rate = REVOLUTION_RATE;
if (sip != NULL) {
if (sip->is_big_ship()) {
rev_rate *= 1.7f;
} else if (sip->is_huge_ship()) {
rev_rate *= 3.0f;
}
if (sip->uses_team_colors && !Teamcolor_override) {
render_info.set_team_color(Lab_team_color, "none", 0, 0);
}
}
// rotate/pan/zoom the model as much as required for this frame
if (Trackball_active) {
int dx, dy;
matrix mat1, mat2;
mouse_get_delta(&dx, &dy);
if (dx || dy) {
// rotation mode
if (Trackball_mode == 1) {
vm_trackball(-dx, -dy, &mat1);
vm_matrix_x_matrix(&mat2, &mat1, &Lab_viewer_orient);
Lab_viewer_orient = mat2;
}
// pan mode
else if (Trackball_mode == 2) {
double scale_x = dx * (double)model_get_radius(Lab_model_num) * 0.005;
double scale_y = dy * (double)model_get_radius(Lab_model_num) * 0.005;
Lab_viewer_pos.xyz.x -= (float)scale_x;
Lab_viewer_pos.xyz.y += (float)scale_y;
}
// zoom mode
else if ( dy && (Trackball_mode == 3) ) {
float scale_y = dy * 0.01f;
Lab_viewer_zoom += scale_y;
}
}
}
// otherwise do orient/rotation calculation, if we are supposed to
else if ( !(Lab_viewer_flags & LAB_FLAG_NO_ROTATION) ) {
Lab_viewer_rotation += PI2 * frametime / rev_rate;
while (Lab_viewer_rotation > PI2)
Lab_viewer_rotation -= PI2;
// setup stuff needed to render the ship
view_angles.p = -0.6f;
view_angles.b = 0.0f;
view_angles.h = 0.0f;
vm_angles_2_matrix(&Lab_viewer_orient, &view_angles);
rot_angles.p = 0.0f;
rot_angles.b = 0.0f;
rot_angles.h = Lab_viewer_rotation;
vm_rotate_matrix_by_angles(&Lab_viewer_orient, &rot_angles);
}
// render the ship
g3_start_frame(1);
if (sip != NULL) {
Lab_viewer_pos.xyz.z = sip->closeup_pos.xyz.z;
float my_zoom = sip->closeup_zoom * Lab_viewer_zoom;
// clamp it down so that we don't get too close or too far away
CLAMP(my_zoom, 0.08f, 1.8f);
g3_set_view_matrix(&Lab_viewer_pos, &vmd_identity_matrix, my_zoom);
} else {
// find the largest radius
polymodel *pm = model_get(Lab_model_num);
float largest_radius = 0.0f;
Assert( pm != NULL );
for (i = 0; i < pm->n_models; i++) {
if ( !pm->submodel[i].is_thruster ) {
if (pm->submodel[i].rad > largest_radius) {
largest_radius = pm->submodel[i].rad;
}
}
}
Lab_viewer_pos.xyz.z = -(largest_radius * 2.0f);
CLAMP(Lab_viewer_zoom, 0.08f, 1.8f);
g3_set_view_matrix(&Lab_viewer_pos, &vmd_identity_matrix, Lab_viewer_zoom);
}
// lighting for techroom
light_reset();
vec3d light_dir = vmd_zero_vector;
light_dir.xyz.y = 1.0f;
light_dir.xyz.x = 0.0000001f;
light_add_directional(&light_dir, 0.65f, 1.0f, 1.0f, 1.0f,-1);
int mx, my;
mouse_get_pos( &mx, &my );
light_dir.xyz.y = 0.0000001f;
light_dir.xyz.x = sinf(my/150.0f);
light_dir.xyz.z = cosf(my/150.0f);
vm_vec_normalize(&light_dir);
vm_vec_scale(&light_dir, mx*10.1f);
light_add_point(&light_dir,1,mx*10.2f+0.1f, 0.5f, 1.0f, 1.0f, 1.0f,-1);
light_rotate_all();
// lighting for techroom
render_info.set_color(255, 255, 255);
render_info.set_detail_level_lock(Lab_model_LOD);
int flagggs = Lab_model_flags;
// only render the insignia when the flag is set
if (Lab_viewer_flags & LAB_FLAG_SHOW_INSIGNIA) {
render_info.set_insignia_bitmap(Lab_insignia_bitmap);
}
// render special if we are showing debris
if (Lab_viewer_flags & LAB_FLAG_SHOW_DEBRIS) {
polymodel *pm = model_get(Lab_model_num);
gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, 1.0f, Max_draw_distance);
gr_set_view_matrix(&Eye_position, &Eye_matrix);
for (i = 0; i < pm->num_debris_objects; i++) {
vec3d world_point = ZERO_VECTOR;
model_find_world_point(&world_point, &pm->submodel[pm->debris_objects[i]].offset, Lab_model_num, -1, &Lab_viewer_orient, &vmd_zero_vector);
Shadow_override = true;
render_info.set_flags(Lab_model_flags);
submodel_render_immediate(&render_info, Lab_model_num, pm->debris_objects[i], &Lab_viewer_orient, &world_point);
Shadow_override = false;
}
}
// render normally otherwise
else {
// show damage arcs if wanted
if ( (sip != NULL) && (Lab_viewer_flags & LAB_FLAG_LIGHTNING_ARCS) ) {
labviewer_add_model_arcs();
}
// ship/weapon thrusters
if (Lab_model_flags & MR_SHOW_THRUSTERS) {
labviewer_add_model_thrusters(&render_info, sip);
}
// do initial rotation
if (sip != NULL) {
if (Lab_viewer_flags & LAB_FLAG_INITIAL_ROTATION) {
for (i = 0; i < sip->n_subsystems; i++) {
if (Lab_ship_model_subsys[i].type == SUBSYSTEM_TURRET) {
for (j = 0; j < Lab_ship_model_subsys[i].n_triggers; j++) {
// special case for turrets
Lab_ship_subsys[i].submodel_info_2.angs.p = Lab_ship_model_subsys[i].triggers[j].angle.xyz.x;
Lab_ship_subsys[i].submodel_info_1.angs.h = Lab_ship_model_subsys[i].triggers[j].angle.xyz.y;
}
if ( Lab_ship_model_subsys[i].subobj_num >= 0 ) {
model_set_instance(Lab_model_num, Lab_ship_model_subsys[i].subobj_num, &Lab_ship_subsys[i].submodel_info_1 );
}
if ( (Lab_ship_model_subsys[i].subobj_num != Lab_ship_model_subsys[i].turret_gun_sobj) && (Lab_ship_model_subsys[i].turret_gun_sobj >= 0) ) {
model_set_instance(Lab_model_num, Lab_ship_model_subsys[i].turret_gun_sobj, &Lab_ship_subsys[i].submodel_info_2 );
}
}
}
}
}
// rotate submodels if wanted
if ( (sip != NULL) && (Lab_viewer_flags & LAB_FLAG_SUBMODEL_ROTATE) ) {
for (i = 0; i < sip->n_subsystems; i++) {
if ( !(Lab_ship_model_subsys[i].flags & MSS_FLAG_ROTATES) ) {
continue;
}
model_set_instance(Lab_model_num, Lab_ship_model_subsys[i].subobj_num, &Lab_ship_subsys[i].submodel_info_1 );
// if we got this far, we can rotate - so choose which method to use
if (Lab_ship_model_subsys[i].flags & MSS_FLAG_STEPPED_ROTATE) {
submodel_stepped_rotate(&Lab_ship_model_subsys[i], &Lab_ship_subsys[i].submodel_info_1);
} else {
submodel_rotate(&Lab_ship_model_subsys[i], &Lab_ship_subsys[i].submodel_info_1 );
}
}
}
if( !( flagggs & MR_NO_LIGHTING ) && Cmdline_shadow_quality ) {
polymodel *pm = model_get(Lab_model_num);
shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -Lab_viewer_pos.xyz.z + pm->rad, -Lab_viewer_pos.xyz.z + pm->rad + 200.0f, -Lab_viewer_pos.xyz.z + pm->rad + 2000.0f, -Lab_viewer_pos.xyz.z + pm->rad + 10000.0f);
render_info.set_flags(MR_NO_TEXTURING | MR_NO_LIGHTING | MR_AUTOCENTER);
model_render_immediate(&render_info, Lab_model_num, &Lab_viewer_orient, &vmd_zero_vector);
//render weapon models if selected
if ( Lab_mode == LAB_MODE_SHIP && ( Lab_viewer_flags & LAB_FLAG_SHOW_WEAPONS ) ) {
int k,l;
g3_start_instance_matrix(&vmd_zero_vector, &Lab_viewer_orient, true);
l = 0;
// no thrusters for attached missiles
int render_flags = MR_NO_TEXTURING | MR_NO_LIGHTING;
//primary weapons
for (j = 0; j < sip->num_primary_banks; j++) {
if (!sip->draw_primary_models[j])
continue;
if (Lab_weaponmodel_num[l] >= 0) {
w_bank *bank = &model_get(Lab_model_num)->gun_banks[j];
for(k = 0; k < bank->num_slots; k++) {
render_info.set_flags(render_flags);
model_render_immediate(&render_info, Lab_weaponmodel_num[l], &vmd_identity_matrix, &bank->pnt[k]);
}
}
l++;
}
//secondary weapons
vec3d secondary_weapon_pos;
w_bank* bank;
for (j = 0; j < sip->num_secondary_banks; j++) {
if (!sip->draw_secondary_models[j])
continue;
if (Lab_weaponmodel_num[l] >= 0) {
bank = &(model_get(Lab_model_num))->missile_banks[j];
if (Weapon_info[sip->secondary_bank_weapons[j]].wi_flags2 & WIF2_EXTERNAL_WEAPON_LNCH) {
for(k = 0; k < bank->num_slots; k++) {
render_info.set_flags(render_flags);
model_render_immediate(&render_info, Lab_weaponmodel_num[l], &vmd_identity_matrix, &bank->pnt[k]);
}
} else {
for(k = 0; k < bank->num_slots; k++)
{
secondary_weapon_pos = bank->pnt[k];
render_info.set_flags(render_flags);
model_render_immediate(&render_info, Lab_weaponmodel_num[l], &vmd_identity_matrix, &secondary_weapon_pos);
}
}
}
l++;
}
g3_done_instance(true);
}
shadows_end_render();
}
gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, 1.0f, Max_draw_distance);
gr_set_view_matrix(&Eye_position, &Eye_matrix);
gr_opengl_deferred_lighting_begin();
// render_info.set_animated_effect(
// ANIMATED_SHADER_LOADOUTSELECT_FS1,
// MIN((timer_get_milliseconds()-anim_timer_start)/1500.0f, 2.0f)
// );
if (sip != NULL) {
if (Lab_viewer_flags & LAB_FLAG_DESTROYED_SUBSYSTEMS) {
model_show_damaged(Lab_model_num, 1);
}
}
//render weapon models if selected
if (Lab_mode == LAB_MODE_SHIP && (Lab_viewer_flags & LAB_FLAG_SHOW_WEAPONS)) {
int k,l;
g3_start_instance_matrix(&vmd_zero_vector, &Lab_viewer_orient, true);
l = 0;
// no thrusters for attached missiles
int render_flags = flagggs;
render_flags &= ~MR_SHOW_THRUSTERS;
//primary weapons
for (j = 0; j < sip->num_primary_banks; j++) {
if (!sip->draw_primary_models[j])
continue;
if (Lab_weaponmodel_num[l] >= 0) {
w_bank *bank = &model_get(Lab_model_num)->gun_banks[j];
for(k = 0; k < bank->num_slots; k++) {
render_info.set_flags(render_flags);
model_render_immediate(&render_info, Lab_weaponmodel_num[l], &vmd_identity_matrix, &bank->pnt[k]);
}
}
l++;
}
//secondary weapons
vec3d secondary_weapon_pos;
w_bank* bank;
for (j = 0; j < sip->num_secondary_banks; j++) {
if (!sip->draw_secondary_models[j])
continue;
if (Lab_weaponmodel_num[l] >= 0) {
bank = &(model_get(Lab_model_num))->missile_banks[j];
if (Weapon_info[sip->secondary_bank_weapons[j]].wi_flags2 & WIF2_EXTERNAL_WEAPON_LNCH) {
for(k = 0; k < bank->num_slots; k++) {
render_info.set_flags(render_flags);
model_render_immediate(&render_info, Lab_weaponmodel_num[l], &vmd_identity_matrix, &bank->pnt[k]);
}
} else {
for(k = 0; k < bank->num_slots; k++)
{
secondary_weapon_pos = bank->pnt[k];
render_info.set_flags(render_flags);
model_render_immediate(&render_info, Lab_weaponmodel_num[l], &vmd_identity_matrix, &secondary_weapon_pos);
}
}
}
l++;
}
g3_done_instance(true);
}
render_info.set_debug_flags(Lab_model_debug_flags);
render_info.set_flags(flagggs);
render_info.set_object_number(Lab_selected_object);
model_render_immediate(&render_info, Lab_model_num, &Lab_viewer_orient, &vmd_zero_vector, MODEL_RENDER_OPAQUE);
gr_opengl_deferred_lighting_end();
gr_opengl_deferred_lighting_finish();
bool gpo_save = Glowpoint_override;
Glowpoint_override = true;
model_render_immediate(&render_info, Lab_model_num, &Lab_viewer_orient, &vmd_zero_vector, MODEL_RENDER_TRANS);
Glowpoint_override = gpo_save;
}
batch_render_all();
gr_copy_effect_texture();
batch_render_distortion_map_bitmaps();
gr_end_view_matrix();
gr_end_proj_matrix();
g3_end_frame();
}
void labviewer_render_bitmap(float frametime)
{
static float current_frame = 0.0f;
static float current_glow_frame = 0.0f;
int framenum = 0;
// if not valid then bail
if ( (Lab_selected_index < 0) || (Lab_mode != LAB_MODE_WEAPON) || (Lab_bitmap_id < 0) ) {
return;
}
weapon_info *wip = &Weapon_info[Lab_selected_index];
if (wip->laser_bitmap.first_frame < 0) {
return;
}
float rev_rate = REVOLUTION_RATE;
angles rot_angles, view_angles;
if (Trackball_active) {
int dx, dy;
matrix mat1, mat2;
mouse_get_delta(&dx, &dy);
if (dx || dy) {
// rotation mode
if (Trackball_mode == 1) {
vm_trackball(-dx, -dy, &mat1);
vm_matrix_x_matrix(&mat2, &mat1, &Lab_viewer_orient);
Lab_viewer_orient = mat2;
}
// pan mode
else if (Trackball_mode == 2) {
double scale_x = dx * (double)wip->laser_length * 0.005;
double scale_y = dy * (double)wip->laser_length * 0.005;
Lab_viewer_pos.xyz.x -= (float)scale_x;
Lab_viewer_pos.xyz.y += (float)scale_y;
}
// zoom mode
else if ( dy && (Trackball_mode == 3) ) {
float scale_y = dy / 100.0f;
Lab_viewer_zoom += scale_y;
}
}
}
// otherwise do orient/rotation calculation, if we are supposed to
else if ( !(Lab_viewer_flags & LAB_FLAG_NO_ROTATION) ) {
Lab_viewer_rotation += PI2 * frametime / rev_rate;
while (Lab_viewer_rotation > PI2) {
Lab_viewer_rotation -= PI2;
}
// setup stuff needed to render the ship
view_angles.p = -0.6f;
view_angles.b = 0.0f;
view_angles.h = 0.0f;
vm_angles_2_matrix(&Lab_viewer_orient, &view_angles);
rot_angles.p = 0.0f;
rot_angles.b = 0.0f;
rot_angles.h = Lab_viewer_rotation;
vm_rotate_matrix_by_angles(&Lab_viewer_orient, &rot_angles);
}
g3_start_frame(1);
Lab_viewer_pos.xyz.z = -(wip->laser_length * 2.0f);
CLAMP(Lab_viewer_zoom, 0.08f, 1.8f);
g3_set_view_matrix(&Lab_viewer_pos, &vmd_identity_matrix, Lab_viewer_zoom * 1.3f);
gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, 1.0f, Max_draw_distance);
gr_set_view_matrix(&Eye_position, &Eye_matrix);
// draw the primary laser bitmap
gr_set_color_fast(&wip->laser_color_1);
if (wip->laser_bitmap.num_frames > 1) {
current_frame += frametime;
framenum = bm_get_anim_frame(wip->laser_bitmap.first_frame, current_frame, wip->laser_bitmap.total_time, true);
}
vec3d headp;
vm_vec_scale_add(&headp, &vmd_zero_vector, &Lab_viewer_orient.vec.fvec, wip->laser_length);
gr_set_bitmap(wip->laser_bitmap.first_frame + framenum, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f);
if(wip->laser_length > 0.0001f)
g3_draw_laser(&headp, wip->laser_head_radius, &vmd_zero_vector, wip->laser_tail_radius, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT);
// now draw the laser glow bitmap, if there is one, and if we are supposed to
if ( !(Lab_model_flags & MR_NO_GLOWMAPS) && (wip->laser_glow_bitmap.first_frame >= 0) ) {
vec3d headp2, tailp;
color c;
float weapon_glow_scale_f = 2.3f;
float weapon_glow_scale_r = 2.3f;
float weapon_glow_scale_l = 1.5f;
float weapon_glow_alpha = 0.85f;
// get the laser color
if ( (wip->laser_color_2.red == 0) && (wip->laser_color_2.green == 0) && (wip->laser_color_2.blue == 0) ) {
c = wip->laser_color_1;
} else {
// lifetime pct
float pct = 1.0f;
// otherwise interpolate between the colors
gr_init_color( &c, (int)((float)wip->laser_color_1.red + (((float)wip->laser_color_2.red - (float)wip->laser_color_1.red) * pct)),
(int)((float)wip->laser_color_1.green + (((float)wip->laser_color_2.green - (float)wip->laser_color_1.green) * pct)),
(int)((float)wip->laser_color_1.blue + (((float)wip->laser_color_2.blue - (float)wip->laser_color_1.blue) * pct)) );
}
vm_vec_scale_add(&headp2, &vmd_zero_vector, &Lab_viewer_orient.vec.fvec, wip->laser_length * weapon_glow_scale_l);
vm_vec_scale_add(&tailp, &vmd_zero_vector, &Lab_viewer_orient.vec.fvec, wip->laser_length * (1 - weapon_glow_scale_l) );
framenum = 0;
if (wip->laser_glow_bitmap.num_frames > 1) {
current_glow_frame += frametime;
// Sanity checks
if (current_glow_frame < 0.0f) {
current_glow_frame = 0.0f;
} else if (current_glow_frame > 100.0f) {
current_glow_frame = 0.0f;
}
while (current_glow_frame > wip->laser_glow_bitmap.total_time) {
current_glow_frame -= wip->laser_glow_bitmap.total_time;
}
framenum = fl2i( (current_glow_frame * wip->laser_glow_bitmap.num_frames) / wip->laser_glow_bitmap.total_time );
CLAMP(framenum, 0, wip->laser_glow_bitmap.num_frames-1);
}
gr_set_bitmap(wip->laser_glow_bitmap.first_frame + framenum, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, weapon_glow_alpha);
if(wip->laser_length > 0.0001f)
g3_draw_laser_rgb(&headp2, wip->laser_head_radius * weapon_glow_scale_f, &tailp, wip->laser_tail_radius * weapon_glow_scale_r, c.red, c.green, c.blue, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_FLAG_RGB | TMAP_HTL_3D_UNLIT);
}
// clean up and move on ...
gr_end_view_matrix();
gr_end_proj_matrix();
g3_end_frame();
}
void labviewer_do_render(float frametime)
{
int w, h;
if ( (Lab_model_num < 0) && (Lab_bitmap_id < 0) ) {
gr_get_string_size(&w, &h, "Viewer off");
gr_set_color_fast(&Color_white);
gr_string(gr_screen.center_offset_x + gr_screen.center_w - w, gr_screen.center_offset_y + gr_screen.center_h - h, "Viewer off", GR_RESIZE_NONE);
return;
}
// render our particular thing
if (Lab_model_num >= 0) {
gr_scene_texture_begin();
labviewer_render_model(frametime);
gr_scene_texture_end();
// print out the current pof filename, to help with... something
if ( strlen(Lab_model_filename) ) {
gr_get_string_size(&w, &h, Lab_model_filename);
gr_set_color_fast(&Color_white);
gr_string(gr_screen.center_offset_x + gr_screen.center_w - w, gr_screen.center_offset_y + gr_screen.center_h - h, Lab_model_filename, GR_RESIZE_NONE);
}
} else if (Lab_bitmap_id >= 0) {
gr_scene_texture_begin();
labviewer_render_bitmap(frametime);
gr_scene_texture_end();
// print out the current bitmap filename, to help with... something
if ( strlen(Lab_bitmap_filename) ) {
gr_get_string_size(&w, &h, Lab_bitmap_filename);
gr_set_color_fast(&Color_white);
gr_string(gr_screen.center_offset_x + gr_screen.center_w - w, gr_screen.center_offset_y + gr_screen.center_h - h, Lab_bitmap_filename, GR_RESIZE_NONE);
}
}
// print FPS at bottom left, might be helpful
extern void game_get_framerate();
extern float frametotal;
extern float Framerate;
game_get_framerate();
gr_set_color_fast(&Color_white);
if (frametotal != 0.0f) {
gr_printf_no_resize(gr_screen.center_offset_x + 2, gr_screen.center_offset_y + gr_screen.center_h - gr_get_font_height(), "FPS: %i", fl2i(Framerate + 0.5f));
} else {
gr_string(gr_screen.center_offset_x + 10, gr_screen.center_offset_y + gr_screen.center_h - gr_get_font_height(), "FPS: ?", GR_RESIZE_NONE);
}
//Print FXAA preset
if (Cmdline_fxaa && !PostProcessing_override)
gr_printf_no_resize(gr_screen.center_offset_x + 2, gr_screen.center_offset_y + gr_screen.center_h - (gr_get_font_height() * 2) - 3, "FXAA Preset: %i", Cmdline_fxaa_preset);
//Print bloom intensity
if (Cmdline_bloom_intensity && !PostProcessing_override)
gr_printf_no_resize(gr_screen.center_offset_x + 2, gr_screen.center_offset_y + gr_screen.center_h - (gr_get_font_height() * 3) - 3, "Bloom intensity: %i", Cmdline_bloom_intensity);
//Print current Team Color setting, if any
if (Lab_team_color != "<none>")
gr_printf_no_resize(gr_screen.center_offset_x + 2, gr_screen.center_offset_y + gr_screen.center_h - (gr_get_font_height() * 4) - 3, "Use T and Y to cycle through available Team Color settings. Current: %s", Lab_team_color.c_str());
//Display helpful text
if (!PostProcessing_override)
gr_printf_no_resize(gr_screen.center_offset_x + 70, gr_screen.center_offset_y + gr_screen.center_h - gr_get_font_height(), "Use number keys to switch between FXAA presets. B and N can be used to adjust bloom.");
}
void labviewer_exit(Button *caller)
{
if(Lab_selected_object != -1) {
obj_delete(Lab_selected_object);
}
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
}
// ---------------------------- Class Window ----------------------------------
void labviewer_close_class_window(GUIObject *caller)
{
if (Lab_class_toolbar) {
Lab_class_toolbar->DeleteChildren();
}
Lab_class_window = NULL;
Lab_mode = LAB_MODE_NONE;
// reset any existing model/bitmap that is showing
labviewer_change_model(NULL);
labviewer_change_bitmap();
}
void labviewer_set_class_window(int mode)
{
if (Lab_class_window == NULL) {
Lab_class_window = (Window*)Lab_screen->Add(new Window("Class Window", gr_screen.center_offset_x + 50, gr_screen.center_offset_y + 50));
Lab_class_window->SetCloseFunction(labviewer_close_class_window);
}
if (Lab_class_toolbar == NULL) {
Lab_class_toolbar = (Window*)Lab_screen->Add(new Window("Class Toolbar", gr_screen.center_offset_x + 0, gr_screen.center_offset_y + Lab_toolbar->GetHeight(), -1, -1, WS_NOTITLEBAR | WS_NONMOVEABLE));
}
// clear out all existing children
Lab_class_window->ClearContent();
Lab_class_toolbar->ClearContent();
// set our new title
if (mode == LAB_MODE_SHIP) {
Lab_class_window->SetCaption("Ship Classes");
} else if (mode == LAB_MODE_WEAPON) {
Lab_class_window->SetCaption("Weapon Classes");
}
// reset any existing model/bitmap that is showing
labviewer_change_model(NULL);
labviewer_change_bitmap();
}
// ------------------------------ Flags Window --------------------------------
typedef struct lab_flag {
Checkbox *cb;
int flag;
bool second;
} lab_flag;
static SCP_vector<lab_flag> Lab_flags;
void labviewer_flags_clear()
{
if (Lab_flags_window != NULL) {
Lab_flags_window->DeleteChildren();
}
Lab_flags.clear();
}
void labviewer_flags_add(int *X, int *Y, char *flag_name, int flag, bool flags2 = false)
{
int x = 0, y = 0;
Assert( (Lab_flags_window != NULL) && (flag_name != NULL) );
lab_flag new_flag;
if (X) {
x = *X;
}
if (Y) {
y = *Y;
}
new_flag.cb = (Checkbox*) Lab_flags_window->AddChild(new Checkbox(flag_name, x, y));
new_flag.flag = flag;
new_flag.second = flags2;
Lab_flags.push_back( new_flag );
if (X) {
*X += new_flag.cb->GetWidth() + 2;
}
if (Y) {
*Y += new_flag.cb->GetHeight() + 1;
}
}
void labviewer_populate_flags_window()
{
if (Lab_mode == LAB_MODE_NONE) {
return;
}
if (Lab_flags_window == NULL) {
return;
}
// clear out anything that already exists
labviewer_flags_clear();
// ship flags ...
if (Lab_mode == LAB_MODE_SHIP) {
//Needs reimplementation
}
// weapon flags ...
else if (Lab_mode == LAB_MODE_WEAPON) {
//Needs reimplementation
}
}
void labviewer_update_flags_window()
{
if ( (Lab_selected_index < 0) || (Lab_mode == LAB_MODE_NONE) ) {
return;
}
// no flags? then don't bother
if (Lab_flags.empty()) {
return;
}
if (Lab_mode == LAB_MODE_SHIP) {
//Needs reimplementation
}
else if (Lab_mode == LAB_MODE_WEAPON) {
//Needs reimplementation
}
}
void labviewer_close_flags_window(GUIObject *caller)
{
Lab_flags_window = NULL;
Lab_flags.clear();
}
void labviewer_make_flags_window(Button *caller)
{
if (Lab_flags_window == NULL) {
Lab_flags_window = (Window*) Lab_screen->Add(new Window("Flags Window", gr_screen.center_offset_x + gr_screen.center_w - 205, gr_screen.center_offset_y + 200));
Lab_flags_window->SetCloseFunction(labviewer_close_flags_window);
}
// set our new title
if (Lab_mode == LAB_MODE_SHIP) {
Lab_flags_window->SetCaption("Ship Flags");
} else if (Lab_mode == LAB_MODE_WEAPON) {
Lab_flags_window->SetCaption("Weapon Flags");
}
// populate the window with our flags (controls both ships and weapons flags)
labviewer_populate_flags_window();
// update content, if we need to
labviewer_update_flags_window();
}
// ----------------------- Variables Window --------------------------------
#define VAR_POS_LEFTWIDTH 150
#define VAR_POS_RIGHTWIDTH 100
#define VAR_POS_RIGHTX 160
#define VAR_ADD_HEADER(name) { \
ntp = (Text*)Lab_variables_window->AddChild(new Text((name), (name), VAR_POS_RIGHTX/2, y + 8, VAR_POS_RIGHTWIDTH)); \
y += ntp->GetHeight() + 10; \
}
static SCP_vector<Text*> Lab_variables;
void labviewer_close_variables_window(GUIObject *caller)
{
Lab_variables_window = NULL;
Lab_variables.clear();
}
void labviewer_variables_clear()
{
if (Lab_variables_window != NULL) {
Lab_variables_window->DeleteChildren();
}
Lab_variables.clear();
}
void labviewer_variables_add(int *Y, char *var_name)
{
int y = 0;
Text *new_text;
Assert( (Lab_variables_window != NULL) && (var_name != NULL) );
if (Y) {
y = *Y;
}
// variable
Lab_variables_window->AddChild(new Text((var_name), (var_name), 0, y, VAR_POS_LEFTWIDTH));
// edit box
new_text = (Text*)Lab_variables_window->AddChild(new Text(SCP_string((var_name)) + SCP_string("Editbox"), "", VAR_POS_RIGHTX, y, VAR_POS_RIGHTWIDTH, 12, T_EDITTABLE));
if (Y) {
*Y += new_text->GetHeight() + 2;
}
Lab_variables.push_back( new_text );
}
void labviewer_populate_variables_window()
{
Text *ntp;
int y;
if (Lab_mode == LAB_MODE_NONE) {
return;
}
if (Lab_variables_window == NULL) {
return;
}
// clear out anything that already exists
labviewer_variables_clear();
y = 0;
// IMPORTANT NOTE: If you add something here, make sure you add it to labviewer_update_variables_window() as well!
// ship vFEWfe<ariables ...
if (Lab_mode == LAB_MODE_SHIP) {
labviewer_variables_add(&y, "Name");
labviewer_variables_add(&y, "Species");
labviewer_variables_add(&y, "Type");
labviewer_variables_add(&y, "Default Team Color");
// physics
VAR_ADD_HEADER("Physics");
labviewer_variables_add(&y, "Density");
labviewer_variables_add(&y, "Damp");
labviewer_variables_add(&y, "Rotdamp");
labviewer_variables_add(&y, "Max vel (x)");
labviewer_variables_add(&y, "Max vel (y)");
labviewer_variables_add(&y, "Max vel (z)");
labviewer_variables_add(&y, "Warp in speed");
labviewer_variables_add(&y, "Warp out speed");
// other
VAR_ADD_HEADER("Stats");
labviewer_variables_add(&y, "Shields");
labviewer_variables_add(&y, "Hull");
labviewer_variables_add(&y, "Subsys repair rate");
labviewer_variables_add(&y, "Hull repair rate");
labviewer_variables_add(&y, "Countermeasures");
labviewer_variables_add(&y, "HUD Icon");
VAR_ADD_HEADER("Power");
labviewer_variables_add(&y, "Power output");
labviewer_variables_add(&y, "Max oclk speed");
labviewer_variables_add(&y, "Max weapon reserve");
VAR_ADD_HEADER("Afterburner");
labviewer_variables_add(&y, "Fuel");
labviewer_variables_add(&y, "Burn rate");
labviewer_variables_add(&y, "Recharge rate");
VAR_ADD_HEADER("Explosion");
labviewer_variables_add(&y, "Inner radius");
labviewer_variables_add(&y, "Outer radius");
labviewer_variables_add(&y, "Damage");
labviewer_variables_add(&y, "Blast");
labviewer_variables_add(&y, "Propagates");
labviewer_variables_add(&y, "Shockwave speed");
labviewer_variables_add(&y, "Shockwave count");
// techroom
VAR_ADD_HEADER("Techroom");
labviewer_variables_add(&y, "Closeup zoom");
labviewer_variables_add(&y, "Closeup pos (x)");
labviewer_variables_add(&y, "Closeup pos (y)");
labviewer_variables_add(&y, "Closeup pos (z)");
}
// weapon variables ...
else if (Lab_mode == LAB_MODE_WEAPON) {
labviewer_variables_add(&y, "Name");
labviewer_variables_add(&y, "Subtype");
// physics
VAR_ADD_HEADER("Physics");
labviewer_variables_add(&y, "Mass");
labviewer_variables_add(&y, "Max speed");
labviewer_variables_add(&y, "Lifetime");
labviewer_variables_add(&y, "Range");
labviewer_variables_add(&y, "Min Range");
VAR_ADD_HEADER("Damage");
labviewer_variables_add(&y, "Fire wait");
labviewer_variables_add(&y, "Damage");
labviewer_variables_add(&y, "Armor factor");
labviewer_variables_add(&y, "Shield factor");
labviewer_variables_add(&y, "Subsys factor");
VAR_ADD_HEADER("Armor");
labviewer_variables_add(&y, "Damage type");
VAR_ADD_HEADER("Shockwave");
labviewer_variables_add(&y, "Speed");
VAR_ADD_HEADER("Missiles");
labviewer_variables_add(&y, "Turn time");
labviewer_variables_add(&y, "FOV");
labviewer_variables_add(&y, "Min locktime");
labviewer_variables_add(&y, "Pixels/sec");
labviewer_variables_add(&y, "Catchup pixels/sec");
labviewer_variables_add(&y, "Catchup pixel pen.");
labviewer_variables_add(&y, "Swarm count");
labviewer_variables_add(&y, "Swarm wait");
}
}
#define VAR_SET_VALUE(value) { \
Assert( i < Lab_variables.size() ); \
Lab_variables[i]->SetText((value)); \
i++; \
}
#define VAR_SET_VALUE_SAVE(value, max_size) { \
Assert( i < Lab_variables.size() ); \
Lab_variables[i]->SetText((value)); \
if ((max_size) < 1) { \
Assert( (max_size) == 0 ); \
Lab_variables[i]->SetSaveLoc(&(value), T_ST_ONENTER); \
} else { \
Lab_variables[i]->SetSaveLoc(&(value), T_ST_ONENTER, (max_size), 0); \
} \
i++; \
}
extern SCP_vector<SCP_string> Hud_shield_filenames;
void labviewer_update_variables_window()
{
uint i = 0;
if (Lab_mode == LAB_MODE_NONE) {
return;
}
if (Lab_variables_window == NULL) {
return;
}
if (Lab_selected_index < 0) {
return;
}
// IMPORTANT NOTE: If you add something here, make sure you add it to labviewer_populate_variables_window() as well!
// ship variables ...
if (Lab_mode == LAB_MODE_SHIP) {
Assert( Lab_selected_index < static_cast<int>(Ship_info.size()) );
ship_info *sip = &Ship_info[Lab_selected_index];
VAR_SET_VALUE(sip->name);
VAR_SET_VALUE_SAVE(sip->species, (int)(Species_info.size()-1));
VAR_SET_VALUE_SAVE(sip->class_type, (int)(Ship_types.size()-1));
VAR_SET_VALUE(sip->default_team_name);
VAR_SET_VALUE_SAVE(sip->density, 0);
VAR_SET_VALUE_SAVE(sip->damp, 0);
VAR_SET_VALUE_SAVE(sip->rotdamp, 0);
VAR_SET_VALUE_SAVE(sip->max_vel.xyz.x, 0);
VAR_SET_VALUE_SAVE(sip->max_vel.xyz.y, 0);
VAR_SET_VALUE_SAVE(sip->max_vel.xyz.z, 0);
VAR_SET_VALUE_SAVE(sip->warpin_speed, 0);
VAR_SET_VALUE_SAVE(sip->warpout_speed, 0);
VAR_SET_VALUE_SAVE(sip->max_shield_strength, 0);
VAR_SET_VALUE_SAVE(sip->max_hull_strength, 0);
VAR_SET_VALUE_SAVE(sip->subsys_repair_rate, 0);
VAR_SET_VALUE_SAVE(sip->hull_repair_rate, 0);
VAR_SET_VALUE_SAVE(sip->cmeasure_max, 0);
VAR_SET_VALUE_SAVE(sip->shield_icon_index, (int)(Hud_shield_filenames.size()-1));
VAR_SET_VALUE_SAVE(sip->power_output, 0);
VAR_SET_VALUE_SAVE(sip->max_overclocked_speed, 0);
VAR_SET_VALUE_SAVE(sip->max_weapon_reserve, 0);
// VAR_SET_VALUE_SAVE(sip->max_shield_regen_per_second, 0);
// VAR_SET_VALUE_SAVE(sip->max_weapon_regen_per_second, 0);
VAR_SET_VALUE_SAVE(sip->afterburner_fuel_capacity, 0);
VAR_SET_VALUE_SAVE(sip->afterburner_burn_rate, 0);
VAR_SET_VALUE_SAVE(sip->afterburner_recover_rate, 0);
VAR_SET_VALUE_SAVE(sip->shockwave.inner_rad, 0);
VAR_SET_VALUE_SAVE(sip->shockwave.outer_rad, 0);
VAR_SET_VALUE_SAVE(sip->shockwave.damage, 0);
VAR_SET_VALUE_SAVE(sip->shockwave.blast, 0);
VAR_SET_VALUE_SAVE(sip->explosion_propagates, 0);
VAR_SET_VALUE_SAVE(sip->shockwave.speed, 0);
VAR_SET_VALUE_SAVE(sip->shockwave_count, 0);
VAR_SET_VALUE_SAVE(sip->closeup_zoom, 0);
VAR_SET_VALUE_SAVE(sip->closeup_pos.xyz.x, 0);
VAR_SET_VALUE_SAVE(sip->closeup_pos.xyz.y, 0);
VAR_SET_VALUE_SAVE(sip->closeup_pos.xyz.z, 0);
}
// weapon variables ...
else if (Lab_mode == LAB_MODE_WEAPON) {
Assert( Lab_selected_index < Num_weapon_types );
weapon_info *wip = &Weapon_info[Lab_selected_index];
VAR_SET_VALUE(wip->name);
VAR_SET_VALUE_SAVE(wip->subtype, Num_weapon_subtypes-1);
VAR_SET_VALUE_SAVE(wip->mass, 0);
VAR_SET_VALUE_SAVE(wip->max_speed, 0);
VAR_SET_VALUE_SAVE(wip->lifetime, 0);
VAR_SET_VALUE_SAVE(wip->weapon_range, 0);
VAR_SET_VALUE_SAVE(wip->WeaponMinRange, 0);
VAR_SET_VALUE_SAVE(wip->fire_wait, 0);
VAR_SET_VALUE_SAVE(wip->damage, 0);
VAR_SET_VALUE_SAVE(wip->armor_factor, 0);
VAR_SET_VALUE_SAVE(wip->shield_factor, 0);
VAR_SET_VALUE_SAVE(wip->subsystem_factor, 0);
VAR_SET_VALUE_SAVE(wip->damage_type_idx, 0);
VAR_SET_VALUE_SAVE(wip->shockwave.speed, 0);
VAR_SET_VALUE_SAVE(wip->turn_time, 0);
VAR_SET_VALUE_SAVE(wip->fov, 0);
VAR_SET_VALUE_SAVE(wip->min_lock_time, 0);
VAR_SET_VALUE_SAVE(wip->lock_pixels_per_sec, 0);
VAR_SET_VALUE_SAVE(wip->catchup_pixels_per_sec, 0);
VAR_SET_VALUE_SAVE(wip->catchup_pixel_penalty, 0);
VAR_SET_VALUE_SAVE(wip->swarm_count, 0);
VAR_SET_VALUE_SAVE(wip->SwarmWait, 0);
}
}
void labviewer_make_variables_window(Button *caller)
{
if (Lab_variables_window != NULL) {
return;
}
Lab_variables_window = (Window*)Lab_screen->Add(new Window("Class Variables", gr_screen.center_offset_x + gr_screen.center_w - (VAR_POS_RIGHTX + VAR_POS_RIGHTWIDTH + 25), gr_screen.center_offset_y + 200));
// set our new title
if (Lab_mode == LAB_MODE_SHIP) {
Lab_variables_window->SetCaption("Ship Variables");
} else if (Lab_mode == LAB_MODE_WEAPON) {
Lab_variables_window->SetCaption("Weapon Variables");
}
// populate the window with our flags (controls both ships and weapons flags)
labviewer_populate_variables_window();
// update content, if we need to
labviewer_update_variables_window();
Lab_variables_window->SetCloseFunction(labviewer_close_variables_window);
}
// -------------------- Render Options Window ------------------------------
void labviewer_change_detail_texture(Tree *caller)
{
int slider_pos = (int)(caller->GetSelectedItem()->GetData());
Assert( (slider_pos >= 0) && (slider_pos <= MAX_DETAIL_LEVEL) );
Detail.hardware_textures = slider_pos;
}
void labviewer_close_render_options_window(GUIObject *caller)
{
Lab_render_options_window = NULL;
}
#define ADD_RENDER_FLAG(text, flag, var) { \
cbp = (Checkbox*)Lab_render_options_window->AddChild(new Checkbox((text), 2, y)); \
cbp->SetFlag(&(flag), (var)); \
y += cbp->GetHeight() + 2; \
}
#define ADD_RENDER_BOOL(text, flag) { \
cbp = (Checkbox*)Lab_render_options_window->AddChild(new Checkbox((text), 2, y)); \
cbp->SetBool(&(flag)); \
y += cbp->GetHeight() + 1; \
}
void labviewer_make_render_options_window(Button *caller)
{
Checkbox *cbp;
Tree *cmp;
TreeItem *ctip;
int y = 0;
if (Lab_render_options_window != NULL) {
return;
}
Lab_render_options_window = (Window*)Lab_screen->Add(new Window("Render Options", gr_screen.center_offset_x + gr_screen.center_w - 300, gr_screen.center_offset_y + 200));
Assert( Lab_render_options_window != NULL );
// add all of the flags that we want/need...
// viewer flags
ADD_RENDER_FLAG("Disable Model Rotation", Lab_viewer_flags, LAB_FLAG_NO_ROTATION);
ADD_RENDER_FLAG("Show Insignia", Lab_viewer_flags, LAB_FLAG_SHOW_INSIGNIA);
ADD_RENDER_FLAG("Show Damage Lightning", Lab_viewer_flags, LAB_FLAG_LIGHTNING_ARCS);
ADD_RENDER_FLAG("Rotate Subsystems", Lab_viewer_flags, LAB_FLAG_SUBMODEL_ROTATE);
if (is_minimum_GLSL_version()) {
ADD_RENDER_BOOL("Fixed Render Pipeline", GLSL_override);
if (Cmdline_postprocess) {
ADD_RENDER_BOOL("Hide Post Processing", PostProcessing_override);
ADD_RENDER_BOOL("Use FXAA", Cmdline_fxaa);
}
}
// map related flags
ADD_RENDER_BOOL("No Diffuse Map", Basemap_override);
if (Cmdline_glow) {
ADD_RENDER_FLAG("No Glow Map", Lab_model_flags, MR_NO_GLOWMAPS);
}
if (Cmdline_spec) {
ADD_RENDER_BOOL("No Specular Map", Specmap_override);
}
if (Cmdline_env) {
ADD_RENDER_BOOL("No Environment Map", Envmap_override);
}
if (Cmdline_normal) {
ADD_RENDER_BOOL("No Normal Map", Normalmap_override);
}
if (Cmdline_height) {
ADD_RENDER_BOOL("No Height Map", Heightmap_override);
}
ADD_RENDER_BOOL("No Team Colors", Teamcolor_override);
ADD_RENDER_BOOL("No Glow Points", Glowpoint_override);
// model flags
ADD_RENDER_FLAG("Wireframe", Lab_model_flags, MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_TEXTURING);
ADD_RENDER_FLAG("Transparent", Lab_model_flags, MR_ALL_XPARENT);
ADD_RENDER_FLAG("No Lighting", Lab_model_flags, MR_NO_LIGHTING);
ADD_RENDER_FLAG("No Z-Buffer", Lab_model_flags, MR_NO_ZBUFFER);
ADD_RENDER_FLAG("No Culling", Lab_model_flags, MR_NO_CULL);
ADD_RENDER_FLAG("Force Clamp", Lab_model_flags, MR_FORCE_CLAMP);
ADD_RENDER_FLAG("Show Full Detail", Lab_model_flags, MR_FULL_DETAIL);
ADD_RENDER_FLAG("Show Pivots", Lab_model_debug_flags, MR_DEBUG_PIVOTS);
ADD_RENDER_FLAG("Show Paths", Lab_model_debug_flags, MR_DEBUG_PATHS);
ADD_RENDER_FLAG("Show Bay Paths", Lab_model_debug_flags, MR_DEBUG_BAY_PATHS);
ADD_RENDER_FLAG("Show Radius", Lab_model_debug_flags, MR_DEBUG_RADIUS);
ADD_RENDER_FLAG("Show Shields", Lab_model_debug_flags, MR_DEBUG_SHIELDS);
ADD_RENDER_FLAG("Show Thrusters", Lab_model_flags, MR_SHOW_THRUSTERS);
ADD_RENDER_FLAG("Show Ship Weapons", Lab_viewer_flags, LAB_FLAG_SHOW_WEAPONS);
ADD_RENDER_FLAG("Initial Rotation", Lab_viewer_flags, LAB_FLAG_INITIAL_ROTATION);
ADD_RENDER_FLAG("Show Destroyed Subsystems", Lab_viewer_flags, LAB_FLAG_DESTROYED_SUBSYSTEMS);
// start tree
cmp = (Tree*)Lab_render_options_window->AddChild(new Tree("Detail Options Tree", 0, y + 2, NULL, Lab_render_options_window->GetWidth()));
// 3d hardware texture slider options
ctip = cmp->AddItem(NULL, "3D Hardware Textures", 0, false);
cmp->AddItem(ctip, "Minimum", 0, false, labviewer_change_detail_texture);
cmp->AddItem(ctip, "Low", 1, false, labviewer_change_detail_texture);
cmp->AddItem(ctip, "Medium", 2, false, labviewer_change_detail_texture);
cmp->AddItem(ctip, "High", 3, false, labviewer_change_detail_texture);
cmp->AddItem(ctip, "Maximum", 4, false, labviewer_change_detail_texture);
// set close function
Lab_render_options_window->SetCloseFunction(labviewer_close_render_options_window);
}
// ------------------------- Material Override Window ------------------------------
void labviewer_close_material_override_window(GUIObject *caller)
{
Lab_material_override_window = NULL;
Basemap_color_override_set = false;
Basemap_color_override[0] = 0.0f;
Basemap_color_override[1] = 0.0f;
Basemap_color_override[2] = 0.0f;
Basemap_color_override[3] = 1.0f;
Glowmap_color_override_set = false;
Glowmap_color_override[0] = 0.0f;
Glowmap_color_override[1] = 0.0f;
Glowmap_color_override[2] = 0.0f;
Specmap_color_override_set = false;
Specmap_color_override[0] = 0.0f;
Specmap_color_override[1] = 0.0f;
Specmap_color_override[2] = 0.0f;
}
void labviewer_set_material_override_diffuse_red(Slider *caller)
{
Basemap_color_override[0] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_diffuse_green(Slider *caller)
{
Basemap_color_override[1] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_diffuse_blue(Slider *caller)
{
Basemap_color_override[2] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_glow_red(Slider *caller)
{
Glowmap_color_override[0] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_glow_green(Slider *caller)
{
Glowmap_color_override[1] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_glow_blue(Slider *caller)
{
Glowmap_color_override[2] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_specular_red(Slider *caller)
{
Specmap_color_override[0] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_specular_green(Slider *caller)
{
Specmap_color_override[1] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_specular_blue(Slider *caller)
{
Specmap_color_override[2] = caller->GetSliderValue() / 255.0f;
}
void labviewer_set_material_override_specular_gloss(Slider *caller)
{
Gloss_override = caller->GetSliderValue() / 255.0f;
}
void labviewer_make_material_override_window(Button *caller)
{
Checkbox *cbp;
Slider *sldr;
int y = 0;
if (Lab_material_override_window != NULL) {
return;
}
Lab_material_override_window = (Window*)Lab_screen->Add(new Window("Material Override", gr_screen.max_w - 300, 200));
Assert(Lab_material_override_window != NULL);
// add all of the flags that we want/need...
// map related flags
cbp = (Checkbox*)Lab_material_override_window->AddChild(new Checkbox("Override Diffuse Color", 2, y));
cbp->SetBool(&Basemap_color_override_set);
y += cbp->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Red", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_diffuse_red, 275));
y += sldr->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Green", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_diffuse_green, 275));
y += sldr->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Blue", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_diffuse_blue, 275));
y += sldr->GetHeight() + 1;
if (Cmdline_glow) {
cbp = (Checkbox*)Lab_material_override_window->AddChild(new Checkbox("Override Glow Color", 2, y));
cbp->SetBool(&Glowmap_color_override_set);
y += cbp->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Red", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_glow_red, 275));
y += sldr->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Green", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_glow_green, 275));
y += sldr->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Blue", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_glow_blue, 275));
y += sldr->GetHeight() + 1;
}
if (Cmdline_spec) {
cbp = (Checkbox*)Lab_material_override_window->AddChild(new Checkbox("Override Spec Color", 2, y));
cbp->SetBool(&Specmap_color_override_set);
y += cbp->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Red", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_specular_red, 275));
y += sldr->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Green", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_specular_green, 275));
y += sldr->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Blue", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_specular_blue, 275));
y += sldr->GetHeight() + 1;
cbp = (Checkbox*)Lab_material_override_window->AddChild(new Checkbox("Override Gloss", 2, y));
cbp->SetBool(&Gloss_override_set);
y += cbp->GetHeight() + 1;
sldr = (Slider*)Lab_material_override_window->AddChild(new Slider("Gloss", 0.0f, 255.0f, 0, y + 2, labviewer_set_material_override_specular_gloss, 275));
y += sldr->GetHeight() + 1;
}
// set close function
Lab_material_override_window->SetCloseFunction(labviewer_close_material_override_window);
}
// ------------------------- Description Window ------------------------------
void labviewer_close_desc_window(GUIObject *caller)
{
Lab_description_text = NULL;
Lab_description_window = NULL;
}
void labviewer_update_desc_window()
{
if ( (Lab_description_window == NULL) || (Lab_description_text == NULL) ) {
return;
}
if (Lab_selected_index != -1) {
if (Lab_mode == LAB_MODE_SHIP) {
Lab_description_window->SetCaption(Ship_info[Lab_selected_index].name);
if (Ship_info[Lab_selected_index].tech_desc != NULL) {
Lab_description_text->SetText(Ship_info[Lab_selected_index].tech_desc);
} else {
Lab_description_text->SetText("No description available.");
}
} else if (Lab_mode == LAB_MODE_WEAPON) {
Lab_description_window->SetCaption(Weapon_info[Lab_selected_index].name);
if (Weapon_info[Lab_selected_index].tech_desc != NULL) {
Lab_description_text->SetText(Weapon_info[Lab_selected_index].tech_desc);
} else {
Lab_description_text->SetText("No description available.");
}
}
}
}
void labviewer_make_desc_window(Button *caller)
{
if (Lab_description_window != NULL) {
return;
}
Lab_description_window = (Window*)Lab_screen->Add(new Window("Description", gr_screen.center_offset_x + gr_screen.center_w - gr_screen.center_w/3 - 50,
gr_screen.center_offset_y + gr_screen.center_h - gr_screen.center_h/6 - 50, gr_screen.center_w/3,
gr_screen.center_h/6));
Lab_description_text = (Text*)Lab_description_window->AddChild(new Text("Description Text", "No ship selected.", 0, 0));
labviewer_update_desc_window();
Lab_description_window->SetCloseFunction(labviewer_close_desc_window);
}
// ------------------------ Ships Window -----------------------------------
void labviewer_make_ship_window(Button *caller)
{
GUIObject *cbp;
TreeItem *ctip, *stip;
int x, idx;
if (Lab_mode == LAB_MODE_SHIP) {
return;
}
// switch the class window to ship mode
labviewer_set_class_window(LAB_MODE_SHIP);
if ( (Lab_class_window == NULL) || (Lab_class_toolbar == NULL) ) {
Int3();
Lab_mode = LAB_MODE_SHIP;
return;
}
// populate the class toolbar
x = 0;
cbp = Lab_class_toolbar->AddChild(new Button("Class Description", x, 0, labviewer_make_desc_window));
x += cbp->GetWidth() + 10;
cbp = Lab_class_toolbar->AddChild(new Button("Class Options", x, 0, labviewer_make_flags_window));
x += cbp->GetWidth() + 10;
cbp = Lab_class_toolbar->AddChild(new Button("Class Variables", x, 0, labviewer_make_variables_window));
// populate ship class window
Tree *cmp = (Tree*)Lab_class_window->AddChild(new Tree("Ship Tree", 0, 0));
if (Lab_species_nodes != NULL) {
for (idx = 0; idx < (int)Species_info.size(); idx++) {
Lab_species_nodes[idx]->ClearAllItems();
}
delete [] Lab_species_nodes;
Lab_species_nodes = NULL;
}
Lab_species_nodes = new TreeItem*[Species_info.size()+1];
// Add species nodes
for (idx = 0; idx < (int)Species_info.size(); idx++) {
Lab_species_nodes[idx] = cmp->AddItem(NULL, Species_info[idx].species_name, 0, false);
}
// Just in case. I don't actually think this is possible though.
Lab_species_nodes[Species_info.size()] = cmp->AddItem(NULL, "Other", 0, false);
// Now add the ships
SCP_string lod_name;
char buf[33];
for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
if ( (it->species >= 0) && (it->species < (int)Species_info.size()) ) {
stip = Lab_species_nodes[it->species];
} else {
stip = Lab_species_nodes[Species_info.size()];
}
ctip = cmp->AddItem(stip, it->name, (int)std::distance(Ship_info.cbegin(), it), false, labviewer_change_ship);
if ( !Lab_in_mission ) {
for (int j = 0; j < it->num_detail_levels; j++) {
sprintf(buf, "%d", j);
lod_name = "LOD ";
lod_name += buf;
cmp->AddItem(ctip, lod_name, j, false, labviewer_change_ship_lod);
}
cmp->AddItem(ctip, "Debris", 99, false, labviewer_change_ship_lod);
}
}
// if any nodes are empty, just add a single "<none>" entry so we know that species doesn't have anything yet
// No the <= is not a mistake :)
for (idx = 0; idx < (int)Species_info.size(); idx++) {
if ( !Lab_species_nodes[idx]->HasChildren() ) {
cmp->AddItem(Lab_species_nodes[idx], "<none>", 0, false, NULL);
}
}
// if the "Other" entry doesn't contain anything then just delete it
if ( !Lab_species_nodes[Species_info.size()]->HasChildren() ) {
delete Lab_species_nodes[Species_info.size()];
}
// and... we're done!
Lab_mode = LAB_MODE_SHIP;
// populate the flags window, if it exists
// (NOTE: must be done *after* Lab_mode is set properly)
if (Lab_flags_window != NULL) {
Lab_flags_window->SetCaption("Ship Flags");
labviewer_populate_flags_window();
labviewer_update_flags_window();
}
if (Lab_description_window != NULL) {
labviewer_update_desc_window();
}
if (Lab_variables_window != NULL) {
Lab_variables_window->SetCaption("Ship Variables");
labviewer_populate_variables_window();
labviewer_update_variables_window();
}
}
void labviewer_change_ship_lod(Tree* caller)
{
int ship_index = (int)(caller->GetSelectedItem()->GetParentItem()->GetData());
Assert( ship_index >= 0 );
if (Lab_selected_object == -1)
{
// Goober5000 - The lab loads subsystems into its special lab-specific vector, but normally subsystems are loaded into the Ship_info
// entry. Note also that models are only loaded once each. If a lab model was previously loaded using the "lightweight" method,
// ship_create will not find any of the subsystems it is looking for. So we have to make sure the model is only loaded for the purposes
// of error-checking and then immediately cleared so that it can be subsequently loaded the lab way.
// reset any existing model/bitmap that is showing
labviewer_change_model(NULL);
labviewer_change_bitmap();
The_mission.ai_profile = &Ai_profiles[Default_ai_profile];
Lab_selected_object = ship_create(&vmd_identity_matrix, &vmd_zero_vector, ship_index);
// unload the model we just loaded
model_page_out_textures(Ship_info[ship_index].model_num, true);
model_unload(Ship_info[ship_index].model_num);
Ship_info[ship_index].model_num = -1;
}
else
{
obj_delete(Lab_selected_object);
Lab_selected_object = ship_create(&vmd_identity_matrix, &vmd_zero_vector, ship_index);
}
Lab_last_selected_ship = Lab_selected_index;
labviewer_change_model(Ship_info[ship_index].pof_file, caller->GetSelectedItem()->GetData(), ship_index);
if (Ship_info[ship_index].uses_team_colors) {
Lab_team_color = Ship_info[ship_index].default_team_name;
} else {
Lab_team_color = "<none>";
}
labviewer_update_desc_window();
labviewer_update_flags_window();
labviewer_update_variables_window();
for (int i = 0; i < MAX_SHIP_ARCS; i++) {
Lab_arc_timestamp[i] = -1;
Lab_arc_type[i] = MARC_TYPE_NORMAL;
Lab_arc_next_time = -1;
}
}
void labviewer_change_ship(Tree *caller)
{
// this is really only for when we are in a mission
if ( !Lab_in_mission ) {
return;
}
Lab_selected_index = (int)(caller->GetSelectedItem()->GetData());
labviewer_update_desc_window();
labviewer_update_flags_window();
labviewer_update_variables_window();
}
// --------------------------- Weapons Window --------------------------------
void labviewer_show_tech_model(Tree *caller)
{
int weap_index = (int)(caller->GetSelectedItem()->GetParentItem()->GetData());
Assert( weap_index >= 0 );
labviewer_change_model(Weapon_info[weap_index].tech_model, caller->GetSelectedItem()->GetData(), weap_index);
}
void labviewer_show_external_model(Tree *caller)
{
int weap_index = (int)(caller->GetSelectedItem()->GetParentItem()->GetData());
Assert( weap_index >= 0 );
labviewer_change_model(Weapon_info[weap_index].external_model_name, caller->GetSelectedItem()->GetData(), weap_index);
}
extern void weapon_load_bitmaps(int weapon_index);
void labviewer_change_weapon(Tree *caller)
{
int weap_index = (int)(caller->GetSelectedItem()->GetData());
Assert( weap_index >= 0 );
if ( !(Weapon_info[weap_index].wi_flags & WIF_BEAM) ) {
switch (Weapon_info[weap_index].render_type) {
case WRT_POF:
labviewer_change_bitmap();
labviewer_change_model(Weapon_info[weap_index].pofbitmap_name, 0, weap_index);
weapon_load_bitmaps(weap_index);
break;
case WRT_LASER:
labviewer_change_model(NULL);
labviewer_change_bitmap(-1, weap_index);
break;
default:
labviewer_change_model(NULL);
labviewer_change_bitmap();
break;
}
}
Lab_selected_index = weap_index;
Lab_last_selected_weapon = Lab_selected_index;
labviewer_update_desc_window();
labviewer_update_flags_window();
labviewer_update_variables_window();
}
// weapon window create function
void labviewer_make_weap_window(Button* caller)
{
GUIObject *cbp;
TreeItem *cwip, *stip;
int x;
if (Lab_mode == LAB_MODE_WEAPON) {
return;
}
// switch the class window to weapon mode
labviewer_set_class_window(LAB_MODE_WEAPON);
if ( (Lab_class_window == NULL) || (Lab_class_toolbar == NULL) ) {
Int3();
Lab_mode = LAB_MODE_WEAPON;
return;
}
// populate the weapons toolbar
x = 0;
cbp = Lab_class_toolbar->AddChild(new Button("Class Description", x, 0, labviewer_make_desc_window));
x += cbp->GetWidth() + 10;
cbp = Lab_class_toolbar->AddChild(new Button("Class Options", x, 0, labviewer_make_flags_window));
x += cbp->GetWidth() + 10;
cbp = Lab_class_toolbar->AddChild(new Button("Class Variables", x, 0, labviewer_make_variables_window));
// populate the weapons window
Tree *cmp = (Tree*)Lab_class_window->AddChild(new Tree("Weapon Tree", 0, 0));
// Unfortunately these are hardcoded
TreeItem **type_nodes = new TreeItem*[Num_weapon_subtypes];
int i;
// Add type nodes
for (i = 0; i < Num_weapon_subtypes; i++) {
type_nodes[i] = cmp->AddItem(NULL, Weapon_subtype_names[i], 0, false);
}
// Now add the weapons
for (i = 0; i < Num_weapon_types; i++) {
if (Weapon_info[i].subtype == WP_UNUSED) {
continue;
} else if (Weapon_info[i].subtype >= Num_weapon_subtypes) {
Warning(LOCATION, "Invalid weapon subtype found on weapon %s", Weapon_info[i].name);
continue;
}
if (Weapon_info[i].wi_flags & WIF_BEAM) {
stip = type_nodes[WP_BEAM];
} else {
stip = type_nodes[Weapon_info[i].subtype];
}
cwip = cmp->AddItem(stip, Weapon_info[i].name, i, false, labviewer_change_weapon);
if (Weapon_info[i].tech_model[0] != '\0') {
cmp->AddItem(cwip, "Tech Model", 0, false, labviewer_show_tech_model);
}
if (Weapon_info[i].external_model_name[0] != '\0') {
cmp->AddItem(cwip, "External Model", 0, false, labviewer_show_external_model);
}
}
// Get rid of any empty nodes
for (i = 0; i < Num_weapon_subtypes; i++) {
if ( !type_nodes[i]->HasChildren() ) {
delete type_nodes[i];
}
}
delete[] type_nodes;
Lab_mode = LAB_MODE_WEAPON;
// populate the flags window, if it exists
// (NOTE: must be done *after* Lab_mode is set properly)
if (Lab_flags_window != NULL) {
Lab_flags_window->SetCaption("Weapon Flags");
labviewer_populate_flags_window();
labviewer_update_flags_window();
}
if (Lab_description_window != NULL) {
labviewer_update_desc_window();
}
if (Lab_variables_window != NULL) {
Lab_variables_window->SetCaption("Weapon Variables");
labviewer_populate_variables_window();
labviewer_update_variables_window();
}
}
// ----------------------------- Lab functions ---------------------------------
void lab_init()
{
GUIObject *cbp;
int x,i;
weapon_pause_sounds();
if (gameseq_get_pushed_state() == GS_STATE_GAME_PLAY) {
Lab_in_mission = true;
} else {
Lab_in_mission = false;
}
if (Lab_in_mission) {
Lab_screen_save_bitmap = gr_save_screen();
gr_create_shader(&Lab_shader, 0, 0, 0, 127);
} else {
gr_set_clear_color(0, 0, 0);
}
//We start by creating the screen/toolbar
Lab_screen = GUI_system.PushScreen(new GUIScreen("Lab"));
Lab_toolbar = (Window*)Lab_screen->Add(new Window("Toolbar", gr_screen.center_offset_x, gr_screen.center_offset_y, -1, -1, WS_NOTITLEBAR | WS_NONMOVEABLE));
// start filling the main toolbar
x = 0;
cbp = Lab_toolbar->AddChild(new Button("Ships", x, 0, labviewer_make_ship_window));
x += cbp->GetWidth() + 10;
cbp = Lab_toolbar->AddChild(new Button("Weapons", x, 0, labviewer_make_weap_window));
if ( !Lab_in_mission ) {
x += cbp->GetWidth() + 10;
cbp = Lab_toolbar->AddChild(new Button("Render Options", x, 0, labviewer_make_render_options_window));
x += cbp->GetWidth() + 10;
cbp = Lab_toolbar->AddChild(new Button("Material Overrides", x, 0, labviewer_make_material_override_window));
}
x += cbp->GetWidth() + 20;
cbp = Lab_toolbar->AddChild(new Button("Exit", x, 0, labviewer_exit));
// reset some defaults, just to be sure
Lab_viewer_zoom = 1.2f;
Lab_viewer_pos.xyz.x = Lab_viewer_pos.xyz.y = 0.0f;
Lab_mode = LAB_MODE_NONE;
Lab_thrust_len = 1.0f;
Lab_thrust_afterburn = false;
Lab_arc_next_time = -1;
Lab_arc_disrupted = false;
for (i = 0; i < MAX_SHIP_WEAPONS; i++) {
Lab_weaponmodel_num[i] = -1;
}
// save detail options
Lab_detail_texture_save = Detail.hardware_textures;
if ( !Lab_in_mission ) {
// load up the list of insignia that we might use on the ships
pilot_load_squad_pic_list();
// the default insignia bitmap
Lab_insignia_index = 0;
Assert( (Lab_insignia_index < Num_pilot_squad_images) );
Lab_insignia_bitmap = bm_load_duplicate(Pilot_squad_image_names[Lab_insignia_index]);
}
// enable post-processing by default in the lab
PostProcessing_override = false;
// disable model rotation by default in the lab
Lab_viewer_flags |= LAB_FLAG_NO_ROTATION;
Lab_viewer_flags |= LAB_FLAG_INITIAL_ROTATION;
}
#include "controlconfig/controlsconfig.h"
void lab_do_frame(float frametime)
{
gr_reset_clip();
gr_clear();
if (Lab_in_mission) {
gr_restore_screen(Lab_screen_save_bitmap);
gr_set_shader(&Lab_shader);
gr_shade(0, 0, gr_screen.max_w, gr_screen.max_h, GR_RESIZE_NONE);
} else {
labviewer_do_render(frametime);
}
bool test1 = ( GUI_system.OnFrame(frametime, !(Trackball_active) ? true : false, false) == GSOF_NOTHINGPRESSED );
if (test1) {
int key = GUI_system.GetKeyPressed();
int status = GUI_system.GetStatus();
// set trackball modes
if (status & GST_MOUSE_LEFT_BUTTON) {
Trackball_active = 1;
Trackball_mode = 1; // rotate
if ( key_get_shift_status() & KEY_SHIFTED ) {
Trackball_mode = 2; // pan
}
} else if (status & GST_MOUSE_RIGHT_BUTTON) {
Trackball_active = 1;
Trackball_mode = 3; // Zoom
} else if ( !mouse_down(MOUSE_LEFT_BUTTON | MOUSE_RIGHT_BUTTON) ) {
// reset trackball modes
Trackball_active = 0;
Trackball_mode = 0;
}
//Due to switch scoping rules, this has to be declared here
SCP_map<SCP_string, team_color>::iterator color_itr = Team_Colors.find(Lab_team_color);
// handle any key presses
switch (key) {
// switch between the current insignia bitmap to render with
case KEY_DIVIDE: {
if ( !(Lab_viewer_flags & LAB_FLAG_SHOW_INSIGNIA) ) {
break;
}
Lab_insignia_index = (Lab_insignia_index+1) % Num_pilot_squad_images;
Assert( (Lab_insignia_index >= 0) && (Lab_insignia_index < Num_pilot_squad_images) );
if (Lab_insignia_bitmap >= 0) {
bm_release(Lab_insignia_bitmap);
Lab_insignia_bitmap = -1;
}
Lab_insignia_bitmap = bm_load_duplicate(Pilot_squad_image_names[Lab_insignia_index]);
break;
}
// change between damage lightning effects
case KEY_L:
Lab_arc_disrupted = !Lab_arc_disrupted;
Lab_arc_next_time = -1;
break;
// Adjust FXAA presets
case KEY_0:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 0;
break;
case KEY_1:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 1;
break;
case KEY_2:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 2;
break;
case KEY_3:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 3;
break;
case KEY_4:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 4;
break;
case KEY_5:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 5;
break;
case KEY_6:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 6;
break;
case KEY_7:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 7;
break;
case KEY_8:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 8;
break;
case KEY_9:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 9;
break;
//adjust bloom intensity
case KEY_B:
if (!PostProcessing_override) {
Cmdline_bloom_intensity++;
if (Cmdline_bloom_intensity > 200)
Cmdline_bloom_intensity = 200;
}
break;
case KEY_N:
if (!PostProcessing_override) {
Cmdline_bloom_intensity--;
if (Cmdline_bloom_intensity < 0)
Cmdline_bloom_intensity = 0;
}
break;
case KEY_T:
if (color_itr == Team_Colors.begin()) {
color_itr = --Team_Colors.end();
Lab_team_color = color_itr->first;
} else {
--color_itr;
Lab_team_color = color_itr->first;
}
break;
case KEY_Y:
++color_itr;
if (color_itr == Team_Colors.end())
color_itr = Team_Colors.begin();
Lab_team_color = color_itr->first;
break;
// bail...
case KEY_ESC:
labviewer_exit(NULL);
break;
default: {
// check for game-specific controls
if (Lab_mode == LAB_MODE_SHIP) {
if ( check_control(PLUS_5_PERCENT_THROTTLE, key) )
Lab_thrust_len += 0.05f;
else if ( check_control(MINUS_5_PERCENT_THROTTLE, key) )
Lab_thrust_len -= 0.05f;
CLAMP( Lab_thrust_len, 0.0f, 1.0f );
if ( check_control(AFTERBURNER, key) )
Lab_thrust_afterburn = !Lab_thrust_afterburn;
}
break;
}
}
}
gr_flip();
}
void lab_close()
{
int i;
Lab_toolbar = NULL;
Lab_class_toolbar = NULL;
Lab_class_window = NULL;
Lab_flags_window = NULL;
Lab_render_options_window = NULL;
delete Lab_screen;
Lab_screen = NULL;
if (Lab_species_nodes != NULL) {
for (i = 0; i < (int)Species_info.size(); i++) {
delete Lab_species_nodes[i];
}
delete[] Lab_species_nodes;
Lab_species_nodes = NULL;
}
if (Lab_insignia_bitmap >= 0) {
bm_release(Lab_insignia_bitmap);
Lab_insignia_bitmap = -1;
}
Lab_insignia_index = -1;
if (Lab_model_num != -1) {
model_page_out_textures(Lab_model_num, true);
model_unload(Lab_model_num);
Lab_model_num = -1;
}
for (i = 0; i < MAX_SHIP_WEAPONS; i++) {
if (Lab_weaponmodel_num[i] >= 0) {
model_page_out_textures(Lab_weaponmodel_num[i], true);
model_unload(Lab_weaponmodel_num[i]);
Lab_weaponmodel_num[i] = -1;
}
}
if (Lab_screen_save_bitmap != 1) {
gr_free_screen(Lab_screen_save_bitmap);
Lab_screen_save_bitmap = -1;
}
Lab_ship_model_subsys.clear();
if (Lab_ship_subsys != NULL) {
delete[] Lab_ship_subsys;
Lab_ship_subsys = NULL;
}
memset( Lab_model_filename, 0, sizeof(Lab_model_filename) );
Basemap_override = false;
Envmap_override = false;
Specmap_override = false;
Normalmap_override = false;
Heightmap_override = false;
Glowpoint_override = false;
PostProcessing_override = false;
// reset detail levels to default
Detail.hardware_textures = Lab_detail_texture_save;
weapon_unpause_sounds();
//audiostream_unpause_all();
game_flush();
}