// ============================== IMPLEMENTATIONS ============================= void dc_do_command(SCP_string *cmd_str) { /** * Grab the first word from the cmd_str * If it is not a literal, ignore it "Invalid keyword: %s" * Search for the command... * Compare the word against valid commands * If command not found, ignore it "Invalid or unknown command: %s"\ * Process the command... * Call the function to process the command (the rest of the command line is in the parser) * Function takes care of long_help and status depending on the mode. */ SCP_string command; extern SCP_vector<debug_command*> dc_commands; // z64: I don't like this extern here, at all. Nope nope nope. if (cmd_str->empty()) { return; } dc_parse_init(*cmd_str); dc_stuff_string_white(command); // Grab the first token, presumably this is a command SCP_vector<debug_command*>::iterator it = find_if(dc_commands.begin(), dc_commands.end(), is_dcmd(command.c_str())); if (it == dc_commands.end()) { dc_printf("Command not found: '%s'\n", command.c_str()); return; } // Else, we found our command try { (*it)->func(); // Run the command! } catch (errParseString err) { dc_printf("Require string(s) not found: \n"); for (int i = 0; i < err.expected_tokens.size(); ++i) { dc_printf("%i: %s\n", err.expected_tokens[i].c_str()); } dc_printf("Found '%s' instead\n", err.found_token.c_str()); } catch (errParse err) { dc_printf("Invalid argument. Expected %s, found '%s'\n", token_str[err.expected_type], err.found_token.c_str()); } // dc_maybe_stuff_string is vulnerable to overflow. Once the errParseOverflow throw class (or w/e) gets // implemented, this last command should be put into its own try{} catch{} block. if (dc_maybe_stuff_string(command)) { dc_printf( "Ignoring the unused command line tail '%s'\n", command.c_str() ); } }
int gamesnd_get_by_iface_name(const char* name) { Assert( Snds_iface.size() <= INT_MAX ); Assert( Snds_iface.size() == Snds_iface_handle.size() ); int index = gamesnd_lookup_name(name, Snds_iface); if (index < 0) { int i = 0; for(SCP_vector<game_snd>::iterator snd = Snds_iface.begin(); snd != Snds_iface.end(); ++snd) { char *p = strrchr( snd->filename, '.' ); if(p == NULL) { if(!stricmp(snd->filename, name)) { index = i; break; } } else if(!strnicmp(snd->filename, name, p-snd->filename)) { index = i; break; } i++; } } return index; }
/* * Update any uninitialized EnhancedSoundData in Snds * with hardcoded defaults for retail. */ void gamesnd_add_retail_default_enhanced_sound_data() { int i = 0; for (SCP_vector<game_snd>::iterator it = Snds.begin(), end = Snds.end(); it != end; ++it, ++i) { if (it->enhanced_sound_data.priority== SND_ENHANCED_PRIORITY_INVALID) { if (i < NUM_RETAIL_GAMEPLAY_SOUNDS) { it->enhanced_sound_data.priority= Default_sound_priorities[i].priority; } else { it->enhanced_sound_data.priority= default_enhanced_sound_data.priority; } } if (it->enhanced_sound_data.limit < 1) { if (i < NUM_RETAIL_GAMEPLAY_SOUNDS) { it->enhanced_sound_data.limit = Default_sound_priorities[i].limit; } else { it->enhanced_sound_data.limit= default_enhanced_sound_data.limit; } } } }
void waypoint_add_list(const char *name, SCP_vector<vec3d> &vec_list) { Assert(name != NULL); if (find_matching_waypoint_list(name) != NULL) { Warning(LOCATION, "Waypoint list '%s' already exists in this mission! Not adding the new list...", name); return; } waypoint_list new_list(name); Waypoint_lists.push_back(new_list); waypoint_list *wp_list = &Waypoint_lists.back(); wp_list->get_waypoints().reserve(vec_list.size()); SCP_vector<vec3d>::iterator ii; for (ii = vec_list.begin(); ii != vec_list.end(); ++ii) { waypoint new_waypoint(&(*ii), wp_list); wp_list->get_waypoints().push_back(new_waypoint); } // so that masking in the other function works // though if you actually hit this Assert, you have other problems Assert(wp_list->get_waypoints().size() <= 0xffff); }
// marks a cutscene as viewable void cutscene_mark_viewable(char *filename) { char cut_file[MAX_FILENAME_LEN]; char file[MAX_FILENAME_LEN]; Assert(filename!=NULL); // strip off extension strcpy_s( file, filename ); char *p = strchr( file, '.' ); if ( p ) { *p = 0; } // change to lower case strlwr(file); int i = 0; for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) { // change the cutscene file name to lower case strcpy_s(cut_file, cut->filename); strlwr(cut_file); // see if the stripped filename matches the cutscene filename if ( strstr(cut_file, file) != NULL ) { cut->viewable = true; return; } i++; } }
void cutscene_close() { for(SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) if(cut->description != NULL) { vm_free(cut->description); cut->description = NULL; } }
void subtitles_do_frame_post_shaded(float frametime) { SCP_vector<subtitle>::iterator sub; for(sub = Subtitles.begin(); sub != Subtitles.end(); ++sub) { if ( sub->is_post_shaded( ) ) sub->do_frame(frametime); } }
// only call from game_shutdown()!!! void particle_close() { for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ++p) { (*p)->signature = 0; delete *p; } Particles.clear(); }
void cam_close() { //Set Current_camera to nothing Current_camera = camid(); for (auto ii = Cameras.begin(); ii != Cameras.end(); ++ii) { delete * ii; } Cameras.clear(); }
int batch_get_size() { int n_to_render = 0; SCP_vector<batch_item>::iterator bi; for (bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) { n_to_render += bi->batch.need_to_render(); } for (bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) { if ( bi->laser ) continue; n_to_render += bi->batch.need_to_render(); } return n_to_render * 3; }
/** * Unload the ingame sounds from memory */ void gamesnd_unload_gameplay_sounds() { Assert( Snds.size() <= INT_MAX ); for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) { if ( gs->id != -1 ) { snd_unload( gs->id ); gs->id = -1; } } }
void gr_opengl_recompile_all_shaders(const std::function<void(size_t, size_t)>& progress_callback) { for (auto sdr = GL_shader.begin(); sdr != GL_shader.end(); ++sdr) { if (progress_callback) progress_callback(std::distance(GL_shader.begin(), sdr), GL_shader.size()); sdr->program.reset(); opengl_compile_shader_actual(sdr->shader, sdr->flags, *sdr); } }
// function to return 0 based index of which CD a particular movie is on // returns -1 on failure. int cutscenes_get_cd_num( char *filename ) { for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) { if ( !stricmp(cut->filename, filename) ) { return (cut->cd - 1); } } return -1; }
/** * Unload the interface sounds from memory */ void gamesnd_unload_interface_sounds() { Assert( Snds_iface.size() < INT_MAX ); for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) { if ( si->id != -1 ) { snd_unload( si->id ); si->id = -1; si->id_sig = -1; } } }
/** * Load the interface sounds into memory */ void gamesnd_load_interface_sounds() { if ( !Sound_enabled ) return; Assert( Snds_iface.size() < INT_MAX ); for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) { if ( si->filename[0] != 0 && strnicmp(si->filename, NOX("none.wav"), 4) ) { si->id = snd_load(&(*si)); } } }
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; } }
// kill all active particles void particle_kill_all() { // kill all active particles Num_particles = 0; Num_particles_hwm = 0; for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ++p) { (*p)->signature = 0; delete *p; } Particles.clear(); }
void batch_load_buffer_distortion_map_bitmaps(effect_vertex* buffer, int *n_verts) { for (SCP_vector<batch_item>::iterator bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) { if ( bi->laser ) continue; if ( !bi->batch.need_to_render() ) continue; Assert( bi->texture >= 0 ); bi->batch.load_buffer(buffer, n_verts); } }
void os_poll() { // Replay the buffered events auto end = buffered_events.end(); for (auto it = buffered_events.begin(); it != end; ++it) { handle_sdl_event(*it); } buffered_events.clear(); SDL_Event event; while (SDL_PollEvent(&event)) { handle_sdl_event(event); } }
/** * Load the ingame sounds into memory */ void gamesnd_load_gameplay_sounds() { if ( !Sound_enabled ) return; Assert( Snds.size() <= INT_MAX ); for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) { if ( gs->filename[0] != 0 && strnicmp(gs->filename, NOX("none.wav"), 4) ) { if ( !gs->preload ) { // don't try to load anything that's already preloaded game_busy( NOX("** preloading gameplay sounds **") ); // Animate loading cursor... does nothing if loading screen not active. gs->id = snd_load(&(*gs)); } } } }
void cutscenes_screen_init() { int i; ui_button_info *b; Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0); Ui_window.set_mask_bmap(Cutscene_mask_name[gr_screen.res]); for (i=0; i<NUM_BUTTONS; i++) { b = &Buttons[gr_screen.res][i]; b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1); // set up callback for when a mouse first goes over a button b->button.set_highlight_action(common_play_highlight_sound); b->button.set_bmaps(b->filename); b->button.link_hotspot(b->hotspot); } // add xstrs for(i=0; i<NUM_CUTSCENE_TEXT; i++){ Ui_window.add_XSTR(&Cutscene_text[gr_screen.res][i]); } Buttons[gr_screen.res][EXIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER); Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP); Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN); List_region.create(&Ui_window, "", Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1], Cutscene_list_coords[gr_screen.res][2], Cutscene_list_coords[gr_screen.res][3], 0, 1); List_region.hide(); // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP); Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN); Background_bitmap = bm_load(Cutscene_bitmap_name[gr_screen.res]); Scroll_offset = Selected_line = 0; Description_index = -1; Cutscene_list.clear(); int u = 0; for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut, u++) { if ( (*cut).viewable ) { Cutscene_list.push_back(u); } } }
void batch_render_lasers(bool stream_buffer) { for (SCP_vector<batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) { if ( !bi->laser ) continue; if ( !bi->batch.need_to_render() ) continue; Assert( bi->texture >= 0 ); gr_set_bitmap(bi->texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f); if ( stream_buffer ) { bi->batch.render_buffer(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); } else { bi->batch.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); } } }
void batch_render_geometry_map_bitmaps(bool stream_buffer) { for (SCP_vector<batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) { if ( bi->laser ) continue; if ( !bi->batch.need_to_render() ) continue; Assert( bi->texture >= 0 ); gr_set_bitmap(bi->texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi->alpha); if ( stream_buffer ) { bi->batch.render_buffer(bi->tmap_flags); } else { bi->batch.render( bi->tmap_flags); } } }
/** * Pass a GLSL shader source to OpenGL and compile it into a usable shader object. * Prints compilation errors (if any) to the log. * Note that this will only compile shaders into objects, linking them into executables happens later * * @param shader_source GLSL sourcecode for the shader * @param shader_type OpenGL ID for the type of shader being used, like GL_FRAGMENT_SHADER_ARB, GL_VERTEX_SHADER_ARB * @return OpenGL handle for the compiled shader object */ GLhandleARB opengl_shader_compile_object(const SCP_vector<SCP_string>& shader_source, GLenum shader_type) { GLhandleARB shader_object = 0; GLint status = 0; SCP_vector<const GLcharARB*> sources; sources.reserve(shader_source.size()); for (auto it = shader_source.begin(); it != shader_source.end(); ++it) { sources.push_back(it->c_str()); } shader_object = vglCreateShaderObjectARB(shader_type); vglShaderSourceARB(shader_object, sources.size(), &sources[0], NULL); vglCompileShaderARB(shader_object); // check if the compile was successful vglGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status); opengl_shader_check_info_log(shader_object); // we failed, bail out now... if (status == 0) { // basic error check mprintf(("%s shader failed to compile:\n%s\n", (shader_type == GL_VERTEX_SHADER_ARB) ? "Vertex" : ((shader_type == GL_GEOMETRY_SHADER_EXT) ? "Geometry" : "Fragment"), GLshader_info_log)); // this really shouldn't exist, but just in case if (shader_object) { vglDeleteObjectARB(shader_object); } return 0; } // we succeeded, maybe output warnings too if (strlen(GLshader_info_log) > 5) { nprintf(("SHADER-DEBUG", "%s shader compiled with warnings:\n%s\n", (shader_type == GL_VERTEX_SHADER_ARB) ? "Vertex" : ((shader_type == GL_GEOMETRY_SHADER_EXT) ? "Geometry" : "Fragment"), GLshader_info_log)); } return shader_object; }
void dc_init(void) { extern SCP_vector<debug_command*> dc_commands; if (debug_inited) { return; } debug_inited = TRUE; // Sort debug_commands std::sort(dc_commands.begin(), dc_commands.end(), dcmd_less); // Init window settings dc_font = FONT1; row_height = (Current_font->h) * 1.5; // Row/Line height, in pixels col_width = Current_font->w; // Col/Character width, in pixels dc_scroll_x = 0; dc_scroll_y = 0; DCOLS = (gr_screen.max_w / col_width) - 1; // Subtract as needed. Windowed mode has some quirks with the resolution DROWS = (gr_screen.max_h / row_height) - 2; DBCOLS = DCOLS; DBROWS = 2 * DROWS; // Init History dc_history.clear(); dc_history.push_back(""); last_oldcommand = dc_history.begin(); // Init buffers dc_buffer.clear(); dc_buffer.push_back(""); dc_command_buf.reserve(MAX_CLI_LEN); dc_command_buf.clear(); sprintf(dc_title, "FreeSpace Open v%i.%i.%i", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD); dc_printf("Debug console started.\n" ); }
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(); }
/** * Function to search for a given game_snd with the specified name * in the passed vector * * @param name Name to search for * @param sounds Vector to seach in * */ int gamesnd_lookup_name(const char* name, const SCP_vector<game_snd>& sounds) { // if we get passed -1, don't bother trying to look it up. if (name == NULL || *name == 0 || !strcmp(name, "-1")) { return -1; } Assert( sounds.size() <= INT_MAX ); int i = 0; for(SCP_vector<game_snd>::const_iterator snd = sounds.begin(); snd != sounds.end(); ++snd) { if (!snd->name.compare(name)) { return i; } i++; } return -1; }
static void handle_includes_impl(SCP_vector<SCP_string>& include_stack, SCP_stringstream& output, int& include_counter, const SCP_string& filename, const SCP_string& original) { include_stack.emplace_back(filename); auto current_source_number = include_counter + 1; const char* INCLUDE_STRING = "#include"; SCP_stringstream input(original); int line_num = 1; for (SCP_string line; std::getline(input, line);) { auto include_start = line.find(INCLUDE_STRING); if (include_start != SCP_string::npos) { auto first_quote = line.find('"', include_start + strlen(INCLUDE_STRING)); auto second_quote = line.find('"', first_quote + 1); if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) { Error(LOCATION, "Shader %s:%d: Malformed include line. Could not find both quote charaters.", filename.c_str(), line_num); } auto file_name = line.substr(first_quote + 1, second_quote - first_quote - 1); auto existing_name = std::find_if(include_stack.begin(), include_stack.end(), [&file_name](const SCP_string& str) { return str == file_name; }); if (existing_name != include_stack.end()) { SCP_stringstream stack_string; for (auto& name : include_stack) { stack_string << "\t" << name << "\n"; } Error(LOCATION, "Shader %s:%d: Detected cyclic include! Previous includes (top level file first):\n%s", filename.c_str(), line_num, stack_string.str().c_str()); } ++include_counter; // The second parameter defines which source string we are currently working with. We keep track of how many // excludes have been in the file so far to specify this output << "#line 1 " << include_counter + 1 << "\n"; handle_includes_impl(include_stack, output, include_counter, file_name, opengl_load_shader(file_name.c_str())); // We are done with the include file so now we can return to the original file output << "#line " << line_num + 1 << " " << current_source_number << "\n"; } else { output << line << "\n"; } ++line_num; } include_stack.pop_back(); }
void credits_do_frame(float frametime) { GR_DEBUG_SCOPE("Credits do frame"); int i, k, next, percent, bm1, bm2; int bx1, by1, bw1, bh1; int bx2, by2, bw2, bh2; // Use this id to trigger the start of music playing on the credits screen if ( timestamp_elapsed(Credits_music_begin_timestamp) ) { Credits_music_begin_timestamp = 0; credits_start_music(); } k = Ui_window.process(); switch (k) { case KEY_ESC: gameseq_post_event(GS_EVENT_MAIN_MENU); key_flush(); break; case KEY_CTRLED | KEY_UP: case KEY_SHIFTED | KEY_TAB: if ( !(Player->flags & PLAYER_FLAGS_IS_MULTI) ) { credits_screen_button_pressed(CUTSCENES_BUTTON); break; } // else, react like tab key. case KEY_CTRLED | KEY_DOWN: case KEY_TAB: credits_screen_button_pressed(TECH_DATABASE_BUTTON); break; default: break; } // end switch for (i=0; i<NUM_BUTTONS; i++){ if (Buttons[i][gr_screen.res].button.pressed()){ if (credits_screen_button_pressed(i)){ return; } } } gr_reset_clip(); GR_MAYBE_CLEAR_RES(Background_bitmap); if (Background_bitmap >= 0) { gr_set_bitmap(Background_bitmap); gr_bitmap(0, 0, GR_RESIZE_MENU); } percent = (int) (100.0f - (Credits_artwork_display_time - Credits_counter) * 100.0f / Credits_artwork_fade_time); if (percent < 0){ percent = 0; } next = Credits_artwork_index + 1; if (next >= Credits_num_images){ next = 0; } if (Credits_bmps[Credits_artwork_index] < 0) { char buf[40]; if (gr_screen.res == GR_1024) { sprintf(buf, NOX("2_CrIm%.2d"), Credits_artwork_index); } else { sprintf(buf, NOX("CrIm%.2d"), Credits_artwork_index); } Credits_bmps[Credits_artwork_index] = bm_load(buf); } if (Credits_bmps[next] < 0) { char buf[40]; if (gr_screen.res == GR_1024) { sprintf(buf, NOX("2_CrIm%.2d"), next); } else { sprintf(buf, NOX("CrIm%.2d"), next); } Credits_bmps[next] = bm_load(buf); } bm1 = Credits_bmps[Credits_artwork_index]; bm2 = Credits_bmps[next]; if((bm1 != -1) && (bm2 != -1)){ GR_DEBUG_SCOPE("Render credits bitmap"); Assert(percent >= 0 && percent <= 100); // get width and height bm_get_info(bm1, &bw1, &bh1, NULL, NULL, NULL); bm_get_info(bm2, &bw2, &bh2, NULL, NULL, NULL); // determine where to draw the coords bx1 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw1)/2); by1 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh1)/2); bx2 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw2)/2); by2 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh2)/2); auto alpha = (float)percent / 100.0f; gr_set_bitmap(bm1, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f - alpha); gr_bitmap(bx1, by1, GR_RESIZE_MENU); gr_set_bitmap(bm2, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha); gr_bitmap(bx2, by2, GR_RESIZE_MENU); } Ui_window.draw(); for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){ if (Buttons[i][gr_screen.res].button.button_down()){ break; } } if (i > CREDITS_BUTTON){ Buttons[CREDITS_BUTTON][gr_screen.res].button.draw_forced(2); } gr_set_clip(Credits_text_coords[gr_screen.res][CREDITS_X_COORD], Credits_text_coords[gr_screen.res][CREDITS_Y_COORD], Credits_text_coords[gr_screen.res][CREDITS_W_COORD], Credits_text_coords[gr_screen.res][CREDITS_H_COORD], GR_RESIZE_MENU); font::set_font(font::FONT1); gr_set_color_fast(&Color_normal); int y_offset = 0; for (SCP_vector<SCP_string>::iterator iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter) { size_t currentPos = 0; size_t lineEnd; do { int height; int width; lineEnd = iter->find('\n', currentPos); auto length = lineEnd - currentPos; if (lineEnd == SCP_string::npos) { length = std::numeric_limits<size_t>::max(); } gr_get_string_size(&width, &height, iter->c_str() + currentPos, static_cast<int>(length)); // Check if the text part is actually visible if (Credit_position + y_offset + height > 0.0f) { float x = static_cast<float>((gr_screen.clip_width_unscaled - width) / 2); gr_string(x, Credit_position + y_offset, iter->c_str() + currentPos, GR_RESIZE_MENU, static_cast<int>(length)); } y_offset += height; currentPos = lineEnd + 1; } while (lineEnd < iter->length() && lineEnd != SCP_string::npos); } int temp_time; temp_time = timer_get_milliseconds(); Credits_frametime = temp_time - Credits_last_time; Credits_last_time = temp_time; timestamp_inc(i2f(Credits_frametime) / TIMESTAMP_FREQUENCY); float fl_frametime = i2fl(Credits_frametime) / 1000.f; if (keyd_pressed[KEY_LSHIFT]) { Credit_position -= fl_frametime * Credits_scroll_rate * 4.0f; } else { Credit_position -= fl_frametime * Credits_scroll_rate; } if (Credit_position < Credit_stop_pos){ Credit_position = Credit_start_pos; } Credits_counter += fl_frametime; while (Credits_counter >= Credits_artwork_display_time) { Credits_counter -= Credits_artwork_display_time; Credits_artwork_index = next; } gr_flip(); }
void credits_init() { int i; credits_screen_buttons *b; // pre-initialize Credits_num_images = DEFAULT_NUM_IMAGES; Credits_artwork_index = -1; // this is moved up here so we can override it if desired strcpy_s(Credits_music_name, "Cinema"); // parse credits early so as to set up any overrides (for music and such) Credits_parsed = false; credits_parse(); // we could conceivably have specified a number of images but not an index, // so if that's the case, set the value here if (Credits_artwork_index < 0) { Credits_artwork_index = rand() % Credits_num_images; } int credits_spooled_music_index = event_music_get_spooled_music_index(Credits_music_name); if(credits_spooled_music_index != -1){ char *credits_wavfile_name = Spooled_music[credits_spooled_music_index].filename; if(credits_wavfile_name != NULL){ credits_load_music(credits_wavfile_name); } } // Use this id to trigger the start of music playing on the briefing screen Credits_music_begin_timestamp = timestamp(Credits_music_delay); Credits_frametime = 0; Credits_last_time = timer_get_milliseconds(); if (!Credits_parsed) { Credit_text_parts.push_back(SCP_string("No credits available.\n")); } else { switch (SCP_credits_position) { case START: Credit_text_parts.insert(Credit_text_parts.begin(), fs2_open_credit_text); break; case END: Credit_text_parts.push_back(fs2_open_credit_text); break; default: Error(LOCATION, "Unimplemented credits position %d. Get a coder!", (int) SCP_credits_position); break; } } int ch; SCP_vector<SCP_string>::iterator iter; for (iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter) { for (SCP_string::iterator ii = iter->begin(); ii != iter->end(); ++ii) { ch = *ii; switch (ch) { case -4: ch = 129; break; case -28: ch = 132; break; case -10: ch = 148; break; case -23: ch = 130; break; case -30: ch = 131; break; case -25: ch = 135; break; case -21: ch = 137; break; case -24: ch = 138; break; case -17: ch = 139; break; case -18: ch = 140; break; case -60: ch = 142; break; case -55: ch = 144; break; case -12: ch = 147; break; case -14: ch = 149; break; case -5: ch = 150; break; case -7: ch = 151; break; case -42: ch = 153; break; case -36: ch = 154; break; case -31: ch = 160; break; case -19: ch = 161; break; case -13: ch = 162; break; case -6: ch = 163; break; case -32: ch = 133; break; case -22: ch = 136; break; case -20: ch = 141; break; } *ii = (char) ch; } } int temp_h; int h = 0; for (iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter) { gr_get_string_size(NULL, &temp_h, iter->c_str(), (int)iter->length()); h = h + temp_h; } Credit_start_pos = i2fl(Credits_text_coords[gr_screen.res][CREDITS_H_COORD]); Credit_stop_pos = -i2fl(h); Credit_position = Credit_start_pos; Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0); Ui_window.set_mask_bmap(Credits_bitmap_mask_fname[gr_screen.res]); common_set_interface_palette("InterfacePalette"); // set the interface palette for (i=0; i<NUM_BUTTONS; i++) { b = &Buttons[i][gr_screen.res]; b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1); // set up callback for when a mouse first goes over a button b->button.set_highlight_action(common_play_highlight_sound); b->button.set_bmaps(b->filename); b->button.link_hotspot(b->hotspot); } // add some text Ui_window.add_XSTR("Technical Database", 1055, Buttons[TECH_DATABASE_BUTTON][gr_screen.res].xt, Buttons[TECH_DATABASE_BUTTON][gr_screen.res].yt, &Buttons[TECH_DATABASE_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Mission Simulator", 1056, Buttons[SIMULATOR_BUTTON][gr_screen.res].xt, Buttons[SIMULATOR_BUTTON][gr_screen.res].yt, &Buttons[SIMULATOR_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Cutscenes", 1057, Buttons[CUTSCENES_BUTTON][gr_screen.res].xt, Buttons[CUTSCENES_BUTTON][gr_screen.res].yt, &Buttons[CUTSCENES_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Credits", 1058, Buttons[CREDITS_BUTTON][gr_screen.res].xt, Buttons[CREDITS_BUTTON][gr_screen.res].yt, &Buttons[CREDITS_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Exit", 1420, Buttons[EXIT_BUTTON][gr_screen.res].xt, Buttons[EXIT_BUTTON][gr_screen.res].yt, &Buttons[EXIT_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_PINK); if (Player->flags & PLAYER_FLAGS_IS_MULTI) { Buttons[SIMULATOR_BUTTON][gr_screen.res].button.disable(); Buttons[CUTSCENES_BUTTON][gr_screen.res].button.disable(); } Buttons[EXIT_BUTTON][gr_screen.res].button.set_hotkey(KEY_CTRLED | KEY_ENTER); Background_bitmap = bm_load(Credits_bitmap_fname[gr_screen.res]); Credits_bmps.resize(Credits_num_images); for (i=0; i<Credits_num_images; i++) { Credits_bmps[i] = -1; } }