/** * Creates an executable shader. * * @param vs Vertex shader source code * @param fs Fragment shader source code * @param gs Geometry shader source code * @return Internal ID of compiled and linked shader generated by OpenGL */ GLhandleARB opengl_shader_create(const SCP_vector<SCP_string>& vs, const SCP_vector<SCP_string>& fs, const SCP_vector<SCP_string>& gs) { GLhandleARB vs_o = 0; GLhandleARB fs_o = 0; GLhandleARB gs_o = 0; GLhandleARB program = 0; if (!vs.empty()) { vs_o = opengl_shader_compile_object( vs, GL_VERTEX_SHADER_ARB ); if ( !vs_o ) { mprintf(("ERROR! Unable to create vertex shader!\n")); goto Done; } } if (!fs.empty()) { fs_o = opengl_shader_compile_object( fs, GL_FRAGMENT_SHADER_ARB ); if ( !fs_o ) { mprintf(("ERROR! Unable to create fragment shader!\n")); goto Done; } } if (!gs.empty()) { gs_o = opengl_shader_compile_object( gs, GL_GEOMETRY_SHADER_EXT ); if ( !gs_o ) { mprintf(("ERROR! Unable to create fragment shader!\n")); goto Done; } } program = opengl_shader_link_object(vs_o, fs_o, gs_o); if ( !program ) { mprintf(("ERROR! Unable to create shader program!\n")); } Done: if (vs_o) { vglDeleteObjectARB(vs_o); } if (fs_o) { vglDeleteObjectARB(fs_o); } if (gs_o) { vglDeleteObjectARB(gs_o); } return program; }
void obj_find_overlap_colliders(SCP_vector<int> *overlap_list_out, SCP_vector<int> *list, int axis, bool collide) { TRACE_SCOPE(tracing::FindOverlapColliders); size_t i, j; bool overlapped; bool first_not_added = true; SCP_vector<int> overlappers; float min; float overlap_max; overlappers.clear(); for ( i = 0; i < (*list).size(); ++i ) { overlapped = false; min = obj_get_collider_endpoint((*list)[i], axis, true); for ( j = 0; j < overlappers.size(); ) { overlap_max = obj_get_collider_endpoint(overlappers[j], axis, false); if ( min <= overlap_max ) { overlapped = true; if ( overlappers.size() == 1 && first_not_added ) { first_not_added = false; overlap_list_out->push_back(overlappers[j]); } if ( collide ) { obj_collide_pair(&Objects[(*list)[i]], &Objects[overlappers[j]]); } } else { overlappers[j] = overlappers.back(); overlappers.pop_back(); continue; } ++j; } if ( overlappers.empty() ) { first_not_added = true; } if ( overlapped ) { overlap_list_out->push_back((*list)[i]); } overlappers.push_back((*list)[i]); } overlapped = true; }
static void find_capture_device(OpenALInformation* info) { const char *user_device = os_config_read_string( "Sound", "CaptureDevice", NULL ); const char *default_device = info->default_capture_device.c_str(); // in case they are the same, we only want to test it once if ( (user_device && default_device) && !strcmp(user_device, default_device) ) { user_device = NULL; } for (auto& device : info->capture_devices) { OALdevice new_device(device.c_str()); if (user_device && !strcmp(device.c_str(), user_device)) { new_device.type = OAL_DEVICE_USER; } else if (default_device && !strcmp(device.c_str(), default_device)) { new_device.type = OAL_DEVICE_DEFAULT; } CaptureDevices.push_back( new_device ); } if ( CaptureDevices.empty() ) { return; } std::sort( CaptureDevices.begin(), CaptureDevices.end(), openal_device_sort_func ); // for each device that we have available, try and figure out which to use for (size_t idx = 0; idx < CaptureDevices.size(); idx++) { const ALCchar *device_name = CaptureDevices[idx].device_name.c_str(); ALCdevice *device = alcCaptureOpenDevice(device_name, 22050, AL_FORMAT_MONO8, 22050 * 2); if (device == NULL) { continue; } if (alcGetError(device) != ALC_NO_ERROR) { alcCaptureCloseDevice(device); continue; } // ok, we should be good with this one Capture_device = CaptureDevices[idx].device_name; alcCaptureCloseDevice(device); break; } }
/** * Parse the sounds.tbl file, and load the specified sounds. */ void gamesnd_parse_soundstbl() { parse_sound_table("sounds.tbl"); parse_modular_table("*-snd.tbm", parse_sound_table); // if we are missing any species then report if (!missingFlybySounds.empty()) { SCP_string errorString; for (size_t i = 0; i < missingFlybySounds.size(); i++) { errorString.append(missingFlybySounds[i].species_name); errorString.append("\n"); } Error(LOCATION, "The following species are missing flyby sounds in sounds.tbl:\n%s", errorString.c_str()); } missingFlybySounds.clear(); }
static void process_pending_data() { while (!pending_frame_data.empty()) { auto& frame_data = pending_frame_data.front(); bool finished; if (!do_gpu_queries) { finished = true; } else { // Determine if all queries have passed already finished = true; for (auto& trace_data : frame_data.data) { if (trace_data.gpu_query == -1) { // Event has been processed before continue; } if (gr_query_value_available(trace_data.gpu_query)) { trace_data.gpu_time = gr_get_query_value(trace_data.gpu_query); free_query_object(trace_data.gpu_query); trace_data.gpu_query = -1; } else { // If we are here then a query hasn't finished yet. Try again next time... finished = false; break; } } } if (finished) { std::thread writer_thread(std::bind(write_json_data, frame_data)); writer_thread.detach(); pending_frame_data.erase(pending_frame_data.begin()); } else { // GPU queries always finish in sequence so the later queries can't be finished yet break; } } }
void fs2netd_update_ban_list() { int rc = 0; if ( !Logged_in ) { return; } // destroy the file prior to updating cf_delete( "banlist.cfg", CF_TYPE_DATA ); do_full_packet = true; In_process = true; if (Is_standalone) { do { rc = fs2netd_update_ban_list_do(); } while (!rc); } else { rc = popup_till_condition(fs2netd_update_ban_list_do, XSTR("&Cancel", 779), XSTR("Requesting IP ban list", 1587)); } In_process = false; Local_timeout = -1; if ( !FS2NetD_ban_list.empty() ) { CFILE *banlist_cfg = cfopen("banlist.cfg", "wt", CFILE_NORMAL, CF_TYPE_DATA); if (banlist_cfg != NULL) { for (SCP_vector<SCP_string>::iterator bl = FS2NetD_ban_list.begin(); bl != FS2NetD_ban_list.end(); ++bl) { cfputs( const_cast<char*>(bl->c_str()), banlist_cfg ); } cfclose(banlist_cfg); } } FS2NetD_ban_list.clear(); }
void profile_deinit() { if (Cmdline_profile_write_file) { if (profiling_file.is_open()) { profiling_file.flush(); profiling_file.close(); } } if (Cmdline_json_profiling) { profile_dump_json_output(); while (!pending_frame_data.empty()) { process_pending_data(); } } for (auto obj : query_objects) { gr_delete_query_object(obj); } query_objects.clear(); SCP_queue<int>().swap(free_query_objects); }
static void find_capture_device() { const char *user_device = os_config_read_string( "Sound", "CaptureDevice", NULL ); const char *default_device = (const char*) alcGetString( NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER ); // in case they are the same, we only want to test it once if ( (user_device && default_device) && !strcmp(user_device, default_device) ) { user_device = NULL; } if ( alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE ) { const char *all_devices = (const char*) alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); const char *str_list = all_devices; int ext_length = 0; if ( (str_list != NULL) && ((ext_length = strlen(str_list)) > 0) ) { while (ext_length) { OALdevice new_device(str_list); if (user_device && !strcmp(str_list, user_device)) { new_device.type = OAL_DEVICE_USER; } else if (default_device && !strcmp(str_list, default_device)) { new_device.type = OAL_DEVICE_DEFAULT; } CaptureDevices.push_back( new_device ); str_list += (ext_length + 1); ext_length = strlen(str_list); } } } else { if (default_device) { OALdevice new_device(default_device); new_device.type = OAL_DEVICE_DEFAULT; CaptureDevices.push_back( new_device ); } if (user_device) { OALdevice new_device(user_device); new_device.type = OAL_DEVICE_USER; CaptureDevices.push_back( new_device ); } } if ( CaptureDevices.empty() ) { return; } std::sort( CaptureDevices.begin(), CaptureDevices.end(), openal_device_sort_func ); // for each device that we have available, try and figure out which to use for (size_t idx = 0; idx < CaptureDevices.size(); idx++) { const ALCchar *device_name = CaptureDevices[idx].device_name.c_str(); ALCdevice *device = alcCaptureOpenDevice(device_name, 22050, AL_FORMAT_MONO8, 22050 * 2); if (device == NULL) { continue; } if (alcGetError(device) != ALC_NO_ERROR) { alcCaptureCloseDevice(device); continue; } // ok, we should be good with this one Capture_device = CaptureDevices[idx].device_name; alcCaptureCloseDevice(device); break; } }
void particle_render_all() { ubyte flags; float pct_complete; float alpha; vertex pos; vec3d ts, te, temp; int rotate = 1; int framenum, cur_frame; bool render_batch = false; int tmap_flags = TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD; if ( !Particles_enabled ) return; MONITOR_INC( NumParticlesRend, Num_particles ); if ( Particles.empty() ) return; for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ++p) { particle* part = *p; // skip back-facing particles (ripped from fullneb code) // Wanderer - add support for attached particles vec3d p_pos; if (part->attached_objnum >= 0) { vm_vec_unrotate(&p_pos, &part->pos, &Objects[part->attached_objnum].orient); vm_vec_add2(&p_pos, &Objects[part->attached_objnum].pos); } else { p_pos = part->pos; } if ( vm_vec_dot_to_point(&Eye_matrix.vec.fvec, &Eye_position, &p_pos) <= 0.0f ) { continue; } // calculate the alpha to draw at alpha = get_current_alpha(&p_pos); // if it's transparent then just skip it if (alpha <= 0.0f) { continue; } // make sure "rotate" is enabled for this particle rotate = 1; // if this is a tracer style particle, calculate tracer vectors if (part->tracer_length > 0.0f) { ts = p_pos; temp = part->velocity; vm_vec_normalize_quick(&temp); vm_vec_scale_add(&te, &ts, &temp, part->tracer_length); // don't bother rotating rotate = 0; } // rotate the vertex if (rotate) { flags = g3_rotate_vertex( &pos, &p_pos ); if ( flags ) { continue; } if (!Cmdline_nohtl) g3_transfer_vertex(&pos, &p_pos); } // pct complete for the particle pct_complete = part->age / part->max_life; // figure out which frame we should be using if (part->nframes > 1) { framenum = fl2i(pct_complete * part->nframes + 0.5); CLAMP(framenum, 0, part->nframes-1); cur_frame = part->reverse ? (part->nframes - framenum - 1) : framenum; } else { cur_frame = 0; } if (part->type == PARTICLE_DEBUG) { gr_set_color( 255, 0, 0 ); g3_draw_sphere_ez( &p_pos, part->radius ); } else { framenum = part->optional_data; Assert( cur_frame < part->nframes ); // if this is a tracer style particle if (part->tracer_length > 0.0f) { batch_add_laser( framenum + cur_frame, &ts, part->radius, &te, part->radius ); } // draw as a regular bitmap else { batch_add_bitmap( framenum + cur_frame, tmap_flags, &pos, part->particle_index % 8, part->radius, alpha ); } render_batch = true; } } profile_begin("Batch Render"); if (render_batch) { batch_render_all(Particle_buffer_object); } profile_end("Batch Render"); }
static void find_playback_device(OpenALInformation* info) { const char *user_device = os_config_read_string( "Sound", "PlaybackDevice", NULL ); const char *default_device = info->default_playback_device.c_str(); // in case they are the same, we only want to test it once if ( (user_device && default_device) && !strcmp(user_device, default_device) ) { user_device = NULL; } for (auto& device : info->playback_devices) { OALdevice new_device(device.c_str()); if (user_device && !strcmp(device.c_str(), user_device)) { new_device.type = OAL_DEVICE_USER; } else if (default_device && !strcmp(device.c_str(), default_device)) { new_device.type = OAL_DEVICE_DEFAULT; } PlaybackDevices.push_back( new_device ); } if ( PlaybackDevices.empty() ) { return; } std::sort( PlaybackDevices.begin(), PlaybackDevices.end(), openal_device_sort_func ); ALCdevice *device = NULL; ALCcontext *context = NULL; // for each device that we have available, try and figure out which to use for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) { OALdevice *pdev = &PlaybackDevices[idx]; // open our specfic device device = alcOpenDevice( (const ALCchar*) pdev->device_name.c_str() ); if (device == NULL) { continue; } context = alcCreateContext(device, NULL); if (context == NULL) { alcCloseDevice(device); continue; } alcMakeContextCurrent(context); alcGetError(device); // check how many sources we can create static const int MIN_SOURCES = 48; // MAX_CHANNELS + 16 spare int si = 0; for (si = 0; si < MIN_SOURCES; si++) { ALuint source_id = 0; alGenSources(1, &source_id); if (alGetError() != AL_NO_ERROR) { break; } alDeleteSources(1, &source_id); } if (si == MIN_SOURCES) { // ok, it supports our minimum requirements pdev->usable = true; // need this for the future Playback_device = pdev->device_name; // done break; } else { // clean up for next pass alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); context = NULL; device = NULL; } } alcMakeContextCurrent(NULL); if (context) { alcDestroyContext(context); } if (device) { alcCloseDevice(device); } }
void fs2netd_spew_table_checksums(char *outfile) { char full_name[MAX_PATH_LEN]; int count; FILE *out = NULL; char description[512] = { 0 }; char filename[65] = { 0 }; size_t offset = 0; char *p = NULL; if ( Table_valid_status.empty() ) { return; } cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile); // open the outfile out = fopen(full_name, "wt"); if (out == NULL) { return; } p = Cmdline_spew_table_crcs; while (*p && (offset < sizeof(description))) { if (*p == '"') { description[offset++] = '"'; description[offset++] = '"'; } else { description[offset++] = *p; } p++; } // header fprintf(out, "filename,CRC32,description\r\n"); count = (int)Table_valid_status.size(); // do all the checksums for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) { offset = 0; p = tvs->name; while (*p && (offset < sizeof(filename))) { if (*p == '"') { filename[offset++] = '"'; filename[offset++] = '"'; } else { filename[offset++] = *p; } p++; } filename[offset] = '\0'; fprintf(out, "\"%s\",%u,\"%s\"\r\n", filename, tvs->crc32, description); } fflush(out); fclose(out); }
int fs2netd_update_valid_tables() { int rc; int hacked = 0; if ( !Logged_in ) { return -1; } // if there are no tables to check with then bail if ( Table_valid_status.empty() ) { return -1; } // if we're a standalone, show a dialog saying "validating tables" if (Game_mode & GM_STANDALONE_SERVER) { std_create_gen_dialog("Validating tables"); std_gen_set_text("Querying FS2NetD:", 1); } do_full_packet = true; In_process = true; if (Is_standalone) { do { rc = fs2netd_update_valid_tables_do(); } while (!rc); } else { rc = popup_till_condition(fs2netd_update_valid_tables_do, XSTR("&Cancel", 779), XSTR("Starting table validation", 1592)); } In_process = false; Local_timeout = -1; switch (rc) { // canceled by popup case 0: return -1; // timed out case 1: { if ( !Is_standalone ) { popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Table validation timed out!", 1593)); } return -1; } // no tables case 2: { if ( !Is_standalone ) { popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No tables are available from the server for validation!", 1594)); } return -1; } } // output the status of table validity to multi.log for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) { if (tvs->valid) { ml_printf("FS2NetD Table Check: '%s' -- Valid!", tvs->name); } else { ml_printf("FS2NetD Table Check: '%s' -- INVALID (0x%x)!", tvs->name, tvs->crc32); hacked = 1; } } // if we're a standalone, kill the validate dialog if (Game_mode & GM_STANDALONE_SERVER) { std_destroy_gen_dialog(); } return hacked; }
int fs2netd_get_valid_missions_do() { if (Local_timeout == -1) { Local_timeout = timer_get_seconds() + 30; } // get the available CRCs from the server if we need to if ( FS2NetD_file_list.empty() ) { int rc = FS2NetD_GetMissionsList(FS2NetD_file_list, do_full_packet); do_full_packet = false; // communications error if (rc < 0) { Local_timeout = -1; return 4; } // no missions if ( rc && FS2NetD_file_list.empty() ) { Local_timeout = -1; return 2; } // if timeout passes then bail on crc failure if ( timer_get_seconds() > Local_timeout ) { Local_timeout = -1; return 1; } } // we should have the CRCs, or there were no missions, so process them else { static char **file_names = NULL; static int idx = 0, count = 0; bool found = false; int file_index = 0; char valid_status = MVALID_STATUS_UNKNOWN; char full_name[MAX_FILENAME_LEN], wild_card[10]; char val_text[MAX_FILENAME_LEN+15]; uint checksum = 0; if (file_names == NULL) { // allocate filename space file_names = (char**) vm_malloc_q( sizeof(char*) * 1024 ); // 1024 files should be safe! if (file_names == NULL) { Local_timeout = -1; return 3; } memset( wild_card, 0, sizeof(wild_card) ); strcpy_s( wild_card, NOX("*") ); strcat_s( wild_card, FS_MISSION_FILE_EXT ); idx = count = cf_get_file_list(1024, file_names, CF_TYPE_MISSIONS, wild_card); } // drop idx first thing idx--; // we should be done validating, or just not have nothing to validate if (idx < 0) { for (idx = 0; idx < count; idx++) { if (file_names[idx] != NULL) { vm_free(file_names[idx]); file_names[idx] = NULL; } } vm_free(file_names); file_names = NULL; idx = count = 0; Local_timeout = -1; return 4; } // verify all filenames that we know about with their CRCs // NOTE: that this is done for one file per frame, since this is inside of a popup memset( full_name, 0, MAX_FILENAME_LEN ); strncpy( full_name, cf_add_ext(file_names[idx], FS_MISSION_FILE_EXT), sizeof(full_name) - 1 ); memset( val_text, 0, sizeof(val_text) ); snprintf( val_text, sizeof(val_text) - 1, "Validating: %s", full_name ); if (Is_standalone) { if ( std_gen_is_active() ) { std_gen_set_text(val_text, 1); } } else { popup_change_text(val_text); } cf_chksum_long(full_name, &checksum); // try and find the file file_index = multi_create_lookup_mission(full_name); found = false; if (file_index >= 0) { for (SCP_vector<file_record>::iterator fr = FS2NetD_file_list.begin(); fr != FS2NetD_file_list.end() && !found; ++fr) { if ( !stricmp(full_name, fr->name) ) { if (fr->crc32 == checksum) { found = true; valid_status = MVALID_STATUS_VALID; } else { valid_status = MVALID_STATUS_INVALID; } Multi_create_mission_list[file_index].valid_status = valid_status; } } if (found) { ml_printf("FS2NetD Mission Validation: %s => Valid!", full_name); } else { ml_printf("FS2NetD Mission Validation: %s => INVALID! -- 0x%08x", full_name, checksum); } } } return 0; }
void particle_move_all(float frametime) { MONITOR_INC( NumParticles, Num_particles ); if ( !Particles_enabled ) return; if ( Particles.empty() ) return; for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ) { particle* part = *p; if (part->age == 0.0f) { part->age = 0.00001f; } else { part->age += frametime; } bool remove_particle = false; // if its time expired, remove it if (part->age > part->max_life) { // special case, if max_life is 0 then we want it to render at least once if ( (part->age > frametime) || (part->max_life > 0.0f) ) { remove_particle = true; } } // if the particle is attached to an object which has become invalid, kill it if (part->attached_objnum >= 0) { // if the signature has changed, or it's bogus, kill it if ( (part->attached_objnum >= MAX_OBJECTS) || (part->attached_sig != Objects[part->attached_objnum].signature) ) { remove_particle = true; } } if (remove_particle) { part->signature = 0; delete part; // if we're sitting on the very last particle, popping-back will invalidate the iterator! if (p + 1 == Particles.end()) { Particles.pop_back(); break; } else { *p = Particles.back(); Particles.pop_back(); continue; } } // move as a regular particle vm_vec_scale_add2( &part->pos, &part->velocity, frametime ); // next particle ++p; } }
/* * Take the red alert status information, and adjust the red alert ships accordingly * "red alert ships" are wingmen and any ship with the red-alert-carry flag * Wingmen without red alert data still need to be handled / removed */ void red_alert_bash_wingman_status() { int j; ship_obj *so; SCP_vector<red_alert_ship_status>::iterator rasii; SCP_vector<p_object>::iterator poii; SCP_unordered_map<int, int> Wing_pobjects_deleted; SCP_unordered_map<int, int>::iterator ii; if ( !(Game_mode & GM_CAMPAIGN_MODE) ) { return; } if ( Red_alert_wingman_status.empty() ) { return; } // go through all ships in the game, and see if there is red alert status data for any so = GET_FIRST(&Ship_obj_list); for ( ; so != END_OF_LIST(&Ship_obj_list); ) { object *ship_objp = &Objects[so->objnum]; Assert(ship_objp->type == OBJ_SHIP); ship *shipp = &Ships[ship_objp->instance]; if ( !(shipp->flags[Ship::Ship_Flags::From_player_wing]) && !(shipp->flags[Ship::Ship_Flags::Red_alert_store_status]) ) { so = GET_NEXT(so); continue; } bool ship_data_restored = false; int ship_state = RED_ALERT_DESTROYED_SHIP_CLASS; for ( rasii = Red_alert_wingman_status.begin(); rasii != Red_alert_wingman_status.end(); ++rasii ) { red_alert_ship_status *ras = &(*rasii); // red-alert data matches this ship! if ( !stricmp(ras->name.c_str(), shipp->ship_name) ) { // we only want to restore ships which haven't been destroyed, or were removed by the player if ( (ras->ship_class != RED_ALERT_DESTROYED_SHIP_CLASS) && (ras->ship_class != RED_ALERT_PLAYER_DEL_SHIP_CLASS) ) { // if necessary, restore correct ship class if ( ras->ship_class != shipp->ship_info_index ) { if (ras->ship_class >= 0 && ras->ship_class < static_cast<int>(Ship_info.size())) change_ship_type(SHIP_INDEX(shipp), ras->ship_class); else mprintf(("Invalid ship class specified in red alert data for ship %s. Using mission defaults.\n", shipp->ship_name)); } // restore hull (but not shields) if (ras->hull >= 0.0f && ras->hull <= ship_objp->hull_strength) ship_objp->hull_strength = ras->hull; else mprintf(("Invalid health in red alert data for ship %s. Using mission defaults.\n", shipp->ship_name)); // restore weapons and subsys red_alert_bash_weapons(ras, &shipp->weapons); red_alert_bash_subsys_status(ras, shipp); ship_data_restored = true; } // must be destroyed or deleted else { ship_state = ras->ship_class; } // we won't have two ships with the same name, so bail break; } } // remove ship if it was destroyed, or if there's no red-alert data for it if ( !ship_data_restored ) { // we need to be a little tricky here because deletion invalidates the ship_obj ship_obj *next_so = GET_NEXT(so); red_alert_delete_ship(ship_objp->instance, ship_state); so = next_so; } else { so = GET_NEXT(so); } } // NOTE: in retail, red alert data was not loaded for ships that arrived later in the mission if (!Red_alert_applies_to_delayed_ships) return; // go through all ships yet to arrive, and see if there is red alert status data for any for ( poii = Parse_objects.begin(); poii != Parse_objects.end(); ++poii ) { p_object *pobjp = &(*poii); // objects that have already arrived would have been handled in the above loop if ( pobjp->created_object != NULL ) continue; // if we're in a wing, check whether we're in the player wing bool from_player_wing = false; if (pobjp->wingnum >= 0) { for (j = 0; j < MAX_STARTING_WINGS; j++) { if (!stricmp(Starting_wing_names[j], Wings[pobjp->wingnum].name)) { from_player_wing = true; break; } } } // same condition as in ship_obj loop if ( !from_player_wing && !(pobjp->flags[Mission::Parse_Object_Flags::SF_Red_alert_store_status]) ) { continue; } bool ship_data_restored = false; int ship_state = RED_ALERT_DESTROYED_SHIP_CLASS; for ( rasii = Red_alert_wingman_status.begin(); rasii != Red_alert_wingman_status.end(); ++rasii ) { red_alert_ship_status *ras = &(*rasii); // red-alert data matches this ship! if ( !stricmp(ras->name.c_str(), pobjp->name) ) { // we only want to restore ships which haven't been destroyed, or were removed by the player if ( (ras->ship_class != RED_ALERT_DESTROYED_SHIP_CLASS) && (ras->ship_class != RED_ALERT_PLAYER_DEL_SHIP_CLASS) ) { // if necessary, restore correct ship class if ( ras->ship_class != pobjp->ship_class ) { if (ras->ship_class >= 0 && ras->ship_class < static_cast<int>(Ship_info.size())) swap_parse_object(pobjp, ras->ship_class); else { mprintf(("Invalid ship class specified in red alert data for ship %s. Using mission defaults.\n", pobjp->name)); // We will break anyway to this should work break; } } // restore hull (but not shields) if (ras->hull >= 0.0f && ras->hull <= (pobjp->initial_hull * pobjp->ship_max_hull_strength / 100.0f)) pobjp->initial_hull = (int) (ras->hull * 100.0f / pobjp->ship_max_hull_strength); else mprintf(("Invalid health in red alert data for ship %s. Using mission defaults.\n", pobjp->name)); // restore weapons and subsys red_alert_bash_weapons(ras, pobjp); red_alert_bash_subsys_status(ras, pobjp); ship_data_restored = true; } // must be destroyed or deleted else { ship_state = ras->ship_class; } // we won't have two ships with the same name, so bail break; } } // remove ship if it was destroyed, or if there's no red-alert data for it if ( !ship_data_restored ) { red_alert_delete_ship(pobjp, ship_state); if (pobjp->wingnum >= 0) Wing_pobjects_deleted[pobjp->wingnum]++; } } // if all parse objects in a wing have been removed, decrement the count for that wing for (ii = Wing_pobjects_deleted.begin(); ii != Wing_pobjects_deleted.end(); ++ii) { wing *wingp = &Wings[ii->first]; if (wingp->num_waves > 0 && wingp->wave_count == ii->second) { wingp->current_wave++; wingp->red_alert_skipped_ships += wingp->wave_count; if (wingp->num_waves == 0) wingp->flags.set(Ship::Wing_Flags::Gone); // look through all ships yet to arrive... for (p_object *pobjp = GET_FIRST(&Ship_arrival_list); pobjp != END_OF_LIST(&Ship_arrival_list); pobjp = GET_NEXT(pobjp)) { // ...and mark the ones in this wing if (pobjp->wingnum == ii->first) { // no waves left to arrive, so mark ships accordingly if (wingp->num_waves == 0) pobjp->flags.set(Mission::Parse_Object_Flags::SF_Cannot_arrive); // we skipped one complete wave, so clear the flag so the next wave creates all ships else pobjp->flags.remove(Mission::Parse_Object_Flags::Red_alert_deleted); } } } } }
static void find_playback_device() { const char *user_device = os_config_read_string( "Sound", "PlaybackDevice", NULL ); const char *default_device = (const char*) alcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER ); // in case they are the same, we only want to test it once if ( (user_device && default_device) && !strcmp(user_device, default_device) ) { user_device = NULL; } if ( alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE ) { const char *all_devices = NULL; if ( alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATE_ALL_EXT") == AL_TRUE ) { all_devices = (const char*) alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); } else { all_devices = (const char*) alcGetString(NULL, ALC_DEVICE_SPECIFIER); } const char *str_list = all_devices; int ext_length = 0; if ( (str_list != NULL) && ((ext_length = strlen(str_list)) > 0) ) { while (ext_length) { OALdevice new_device(str_list); if (user_device && !strcmp(str_list, user_device)) { new_device.type = OAL_DEVICE_USER; } else if (default_device && !strcmp(str_list, default_device)) { new_device.type = OAL_DEVICE_DEFAULT; } PlaybackDevices.push_back( new_device ); str_list += (ext_length + 1); ext_length = strlen(str_list); } } } else { if (default_device) { OALdevice new_device(default_device); new_device.type = OAL_DEVICE_DEFAULT; PlaybackDevices.push_back( new_device ); } if (user_device) { OALdevice new_device(user_device); new_device.type = OAL_DEVICE_USER; PlaybackDevices.push_back( new_device ); } } if ( PlaybackDevices.empty() ) { return; } std::sort( PlaybackDevices.begin(), PlaybackDevices.end(), openal_device_sort_func ); ALCdevice *device = NULL; ALCcontext *context = NULL; // for each device that we have available, try and figure out which to use for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) { OALdevice *pdev = &PlaybackDevices[idx]; // open our specfic device device = alcOpenDevice( (const ALCchar*) pdev->device_name.c_str() ); if (device == NULL) { continue; } context = alcCreateContext(device, NULL); if (context == NULL) { alcCloseDevice(device); continue; } alcMakeContextCurrent(context); alcGetError(device); // check how many sources we can create static const int MIN_SOURCES = 48; // MAX_CHANNELS + 16 spare int si = 0; for (si = 0; si < MIN_SOURCES; si++) { ALuint source_id = 0; alGenSources(1, &source_id); if (alGetError() != AL_NO_ERROR) { break; } alDeleteSources(1, &source_id); } if (si == MIN_SOURCES) { // ok, it supports our minimum requirements pdev->usable = true; // need this for the future Playback_device = pdev->device_name; // done break; } else { // clean up for next pass alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); context = NULL; device = NULL; } } alcMakeContextCurrent(NULL); if (context) { alcDestroyContext(context); } if (device) { alcCloseDevice(device); } }
// initializes hardware device from perferred/default/enumerated list bool openal_init_device(SCP_string *playback, SCP_string *capture) { if ( !Playback_device.empty() ) { if (playback) { *playback = Playback_device; } if (capture) { *capture = Capture_device; } return true; } if (playback) { playback->erase(); } if (capture) { capture->erase(); } // This reuses the code for the launcher to make sure everything is consistent auto platform_info = openal_get_platform_information(); if (platform_info.version_major <= 1 && platform_info.version_minor < 1) { os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "OpenAL 1.1 or newer is required for proper operation. On Linux and Windows OpenAL Soft is recommended. If you are on Mac OS X you need to upgrade your OS."); return false; } // go through and find out what devices we actually want to use ... find_playback_device(&platform_info); find_capture_device(&platform_info); if ( Playback_device.empty() ) { return false; } #ifndef NDEBUG if ( !PlaybackDevices.empty() ) { nprintf(("OpenAL", " Available Playback Devices:\n")); for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) { nprintf(("OpenAL", " %s", PlaybackDevices[idx].device_name.c_str())); if (PlaybackDevices[idx].type == OAL_DEVICE_USER) { nprintf(("OpenAL", " *preferred*\n")); } else if (PlaybackDevices[idx].type == OAL_DEVICE_DEFAULT) { nprintf(("OpenAL", " *default*\n")); } else { nprintf(("OpenAL", "\n")); } } } if ( !CaptureDevices.empty() ) { if ( !PlaybackDevices.empty() ) { nprintf(("OpenAL", "\n")); } nprintf(("OpenAL", " Available Capture Devices:\n")); for (size_t idx = 0; idx < CaptureDevices.size(); idx++) { nprintf(("OpenAL", " %s", CaptureDevices[idx].device_name.c_str())); if (CaptureDevices[idx].type == OAL_DEVICE_USER) { nprintf(("OpenAL", " *preferred*\n")); } else if (CaptureDevices[idx].type == OAL_DEVICE_DEFAULT) { nprintf(("OpenAL", " *default*\n")); } else { nprintf(("OpenAL", "\n")); } } nprintf(("OpenAL", "\n")); } #endif // cleanup PlaybackDevices.clear(); CaptureDevices.clear(); if (playback) { *playback = Playback_device; } if (capture) { *capture = Capture_device; } return true; }
/* * Record the current state of the players wingman & ships with the "red-alert-carry" flag * Wingmen without the red-alert-carry flag are only stored if they survive * dead wingmen must still be handled in red_alert_bash_wingman_status */ void red_alert_store_wingman_status() { ship *shipp; red_alert_ship_status ras; ship_obj *so; object *ship_objp; // store the mission filename for the red alert precursor mission Red_alert_precursor_mission = Game_current_mission_filename; // Pyro3d - Clear list of stored red alert ships // Probably not the best solution, but it prevents an assertion in change_ship_type() Red_alert_wingman_status.clear(); // store status for all existing ships for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) { ship_objp = &Objects[so->objnum]; Assert(ship_objp->type == OBJ_SHIP); shipp = &Ships[ship_objp->instance]; if ( shipp->flags[Ship::Ship_Flags::Dying] ) { continue; } if ( !(shipp->flags[Ship::Ship_Flags::From_player_wing]) && !(shipp->flags[Ship::Ship_Flags::Red_alert_store_status]) ) { continue; } ras.name = shipp->ship_name; ras.hull = Objects[shipp->objnum].hull_strength; ras.ship_class = shipp->ship_info_index; red_alert_store_weapons(&ras, &shipp->weapons); red_alert_store_subsys_status(&ras, shipp); Red_alert_wingman_status.push_back( ras ); // niffiwan: trying to track down red alert bug creating HUGE pilot files Assert( (Red_alert_wingman_status.size() <= MAX_SHIPS) ); } // store exited ships that did not die for (int idx=0; idx<(int)Ships_exited.size(); idx++) { if (Ships_exited[idx].flags[Ship::Exit_Flags::Red_alert_carry]) { ras.name = Ships_exited[idx].ship_name; ras.hull = float(Ships_exited[idx].hull_strength); // if a ship has been destroyed or removed manually by the player, then mark it as such ... if ( Ships_exited[idx].flags[Ship::Exit_Flags::Destroyed]) { ras.ship_class = RED_ALERT_DESTROYED_SHIP_CLASS; } else if (Ships_exited[idx].flags[Ship::Exit_Flags::Player_deleted]) { ras.ship_class = RED_ALERT_PLAYER_DEL_SHIP_CLASS; } // ... otherwise we want to make sure and carry over the ship class else { Assert( Ships_exited[idx].ship_class >= 0 ); ras.ship_class = Ships_exited[idx].ship_class; } red_alert_store_weapons(&ras, NULL); red_alert_store_subsys_status(&ras, NULL); Red_alert_wingman_status.push_back( ras ); // niffiwan: trying to track down red alert bug creating HUGE pilot files Assert( (Red_alert_wingman_status.size() <= MAX_SHIPS) ); } } Assert( !Red_alert_wingman_status.empty() ); }
// initializes hardware device from perferred/default/enumerated list bool openal_init_device(SCP_string *playback, SCP_string *capture) { if ( !Playback_device.empty() ) { if (playback) { *playback = Playback_device; } if (capture) { *capture = Capture_device; } return true; } if (playback) { playback->erase(); } if (capture) { capture->erase(); } // initialize default setup first, for version check... ALCdevice *device = alcOpenDevice(NULL); if (device == NULL) { return false; } ALCcontext *context = alcCreateContext(device, NULL); if (context == NULL) { alcCloseDevice(device); return false; } alcMakeContextCurrent(context); // version check (for 1.0 or 1.1) ALCint AL_minor_version = 0; alcGetIntegerv(NULL, ALC_MINOR_VERSION, sizeof(ALCint), &AL_minor_version); if (AL_minor_version < 1) { #ifdef _WIN32 MessageBox(NULL, "OpenAL 1.1 or newer is required for proper operation. Please upgrade your OpenAL drivers, which\nare available at http://www.openal.org/downloads.html, and try running the game again.", NULL, MB_OK); #else printf("OpenAL 1.1 or newer is required for proper operation.\n"); printf("Please upgrade to a newer version if on OS X or switch\n"); printf("to OpenAL-Soft on Linux.\n"); #endif alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); return false; } alcGetError(device); // close default device alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); // go through and find out what devices we actually want to use ... find_playback_device(); find_capture_device(); if ( Playback_device.empty() ) { return false; } #ifndef NDEBUG if ( !PlaybackDevices.empty() ) { nprintf(("OpenAL", " Available Playback Devices:\n")); for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) { nprintf(("OpenAL", " %s", PlaybackDevices[idx].device_name.c_str())); if (PlaybackDevices[idx].type == OAL_DEVICE_USER) { nprintf(("OpenAL", " *preferred*\n")); } else if (PlaybackDevices[idx].type == OAL_DEVICE_DEFAULT) { nprintf(("OpenAL", " *default*\n")); } else { nprintf(("OpenAL", "\n")); } } } if ( !CaptureDevices.empty() ) { if ( !PlaybackDevices.empty() ) { nprintf(("OpenAL", "\n")); } nprintf(("OpenAL", " Available Capture Devices:\n")); for (size_t idx = 0; idx < CaptureDevices.size(); idx++) { nprintf(("OpenAL", " %s", CaptureDevices[idx].device_name.c_str())); if (CaptureDevices[idx].type == OAL_DEVICE_USER) { nprintf(("OpenAL", " *preferred*\n")); } else if (CaptureDevices[idx].type == OAL_DEVICE_DEFAULT) { nprintf(("OpenAL", " *default*\n")); } else { nprintf(("OpenAL", "\n")); } } nprintf(("OpenAL", "\n")); } #endif // cleanup PlaybackDevices.clear(); CaptureDevices.clear(); if (playback) { *playback = Playback_device; } if (capture) { *capture = Capture_device; } return true; }
/** * @brief Parses controlconfigdefault.tbl, and overrides the default control configuration for each valid entry in the .tbl */ void control_config_common_load_overrides() { LoadEnumsIntoMaps(); try { if (cf_exists_full("controlconfigdefaults.tbl", CF_TYPE_TABLES)) { read_file_text("controlconfigdefaults.tbl", CF_TYPE_TABLES); } else { read_file_text_from_default(defaults_get_file("controlconfigdefaults.tbl")); } reset_parse(); // start parsing // TODO: Split this out into more helps. Too many tabs! while(optional_string("#ControlConfigOverride")) { config_item *cfg_preset = new config_item[CCFG_MAX + 1]; std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset); Control_config_presets.push_back(cfg_preset); SCP_string preset_name; if (optional_string("$Name:")) { stuff_string_line(preset_name); } else { preset_name = "<unnamed preset>"; } Control_config_preset_names.push_back(preset_name); while (required_string_either("#End","$Bind Name:")) { const int iBufferLength = 64; char szTempBuffer[iBufferLength]; required_string("$Bind Name:"); stuff_string(szTempBuffer, F_NAME, iBufferLength); const size_t cCntrlAryLength = sizeof(Control_config) / sizeof(Control_config[0]); for (size_t i = 0; i < cCntrlAryLength; ++i) { config_item& r_ccConfig = cfg_preset[i]; if (!strcmp(szTempBuffer, r_ccConfig.text)) { /** * short key_default; * short joy_default; * char tab; * bool hasXSTR; * char type; */ int iTemp; if (optional_string("$Key Default:")) { if (optional_string("NONE")) { r_ccConfig.key_default = (short)-1; } else { stuff_string(szTempBuffer, F_NAME, iBufferLength); r_ccConfig.key_default = (short)mKeyNameToVal[szTempBuffer]; } } if (optional_string("$Joy Default:")) { stuff_int(&iTemp); r_ccConfig.joy_default = (short)iTemp; } if (optional_string("$Key Mod Shift:")) { stuff_int(&iTemp); r_ccConfig.key_default |= (iTemp == 1) ? KEY_SHIFTED : 0; } if (optional_string("$Key Mod Alt:")) { stuff_int(&iTemp); r_ccConfig.key_default |= (iTemp == 1) ? KEY_ALTED : 0; } if (optional_string("$Key Mod Ctrl:")) { stuff_int(&iTemp); r_ccConfig.key_default |= (iTemp == 1) ? KEY_CTRLED : 0; } if (optional_string("$Category:")) { stuff_string(szTempBuffer, F_NAME, iBufferLength); r_ccConfig.tab = (char)mCCTabNameToVal[szTempBuffer]; } if (optional_string("$Has XStr:")) { stuff_int(&iTemp); r_ccConfig.hasXSTR = (iTemp == 1); } if (optional_string("$Type:")) { stuff_string(szTempBuffer, F_NAME, iBufferLength); r_ccConfig.type = (char)mCCTypeNameToVal[szTempBuffer]; } if (optional_string("+Disable")) { r_ccConfig.disabled = true; } if (optional_string("$Disable:")) { stuff_boolean(&r_ccConfig.disabled); } // Nerf the buffer now. szTempBuffer[0] = '\0'; } else if ((i + 1) == cCntrlAryLength) { error_display(1, "Bind Name not found: %s\n", szTempBuffer); advance_to_eoln(NULL); ignore_white_space(); return; } } } required_string("#End"); } } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse 'controlconfigdefaults.tbl'! Error message = %s.\n", e.what())); return; } // Overwrite the control config with the first preset that was found if (!Control_config_presets.empty()) { std::copy(Control_config_presets[0], Control_config_presets[0] + CCFG_MAX + 1, Control_config); } }
// initializes hardware device from perferred/default/enumerated list bool openal_init_device(SCP_string *playback, SCP_string *capture) { if ( !Playback_device.empty() ) { if (playback) { *playback = Playback_device; } if (capture) { *capture = Capture_device; } return true; } if (playback) { playback->erase(); } if (capture) { capture->erase(); } // initialize default setup first, for version check... ALCdevice *device = alcOpenDevice(NULL); if (device == NULL) { return false; } ALCcontext *context = alcCreateContext(device, NULL); if (context == NULL) { alcCloseDevice(device); return false; } alcMakeContextCurrent(context); // version check (for 1.0 or 1.1) ALCint AL_minor_version = 0; alcGetIntegerv(NULL, ALC_MINOR_VERSION, sizeof(ALCint), &AL_minor_version); if (AL_minor_version < 1) { os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "OpenAL 1.1 or newer is required for proper operation. On Linux and Windows OpenAL Soft is recommended. If you are on Mac OS X you need to upgrade your OS."); alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); return false; } alcGetError(device); // close default device alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); // go through and find out what devices we actually want to use ... find_playback_device(); find_capture_device(); if ( Playback_device.empty() ) { return false; } #ifndef NDEBUG if ( !PlaybackDevices.empty() ) { nprintf(("OpenAL", " Available Playback Devices:\n")); for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) { nprintf(("OpenAL", " %s", PlaybackDevices[idx].device_name.c_str())); if (PlaybackDevices[idx].type == OAL_DEVICE_USER) { nprintf(("OpenAL", " *preferred*\n")); } else if (PlaybackDevices[idx].type == OAL_DEVICE_DEFAULT) { nprintf(("OpenAL", " *default*\n")); } else { nprintf(("OpenAL", "\n")); } } } if ( !CaptureDevices.empty() ) { if ( !PlaybackDevices.empty() ) { nprintf(("OpenAL", "\n")); } nprintf(("OpenAL", " Available Capture Devices:\n")); for (size_t idx = 0; idx < CaptureDevices.size(); idx++) { nprintf(("OpenAL", " %s", CaptureDevices[idx].device_name.c_str())); if (CaptureDevices[idx].type == OAL_DEVICE_USER) { nprintf(("OpenAL", " *preferred*\n")); } else if (CaptureDevices[idx].type == OAL_DEVICE_DEFAULT) { nprintf(("OpenAL", " *default*\n")); } else { nprintf(("OpenAL", "\n")); } } nprintf(("OpenAL", "\n")); } #endif // cleanup PlaybackDevices.clear(); CaptureDevices.clear(); if (playback) { *playback = Playback_device; } if (capture) { *capture = Capture_device; } return true; }