/* * Render a shield icon - basic shape is: * 1 3 * *************************** * *************************** * ** 2 4 ** * * * * 0 5 * * Defined by 6 points, must be passed in the order show above (i.e. a valid triangle strip) * */ void HudGaugeShield::renderShieldIcon(coord2d coords[6]) { int nx = 0, ny = 0, i; if ( gr_screen.rendering_to_texture != -1 ) { gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true); } else { if ( reticle_follow ) { nx = HUD_nose_x; ny = HUD_nose_y; gr_resize_screen_pos(&nx, &ny); gr_set_screen_scale(base_w, base_h); gr_unsize_screen_pos(&nx, &ny); } else { gr_set_screen_scale(base_w, base_h); } } for (i = 0; i < 6; ++i) { coords[i].x += nx; coords[i].y += ny; } //gr_shield_icon(coords); g3_render_shield_icon(coords); gr_reset_screen_scale(); }
/* * Render a shield icon - basic shape is: * 1 3 * *************************** * *************************** * ** 2 4 ** * * * * 0 5 * * Defined by 6 points, must be passed in the order show above (i.e. a valid triangle strip) * */ void HudGaugeShield::renderShieldIcon(coord2d coords[6]) { int nx = 0, ny = 0, i; if ( gr_screen.rendering_to_texture != -1 ) { gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true); // Respect the rendering display offset specified in the table nx = display_offset_x; ny = display_offset_y; // Transfer the offset position into actual texture coordinates gr_unsize_screen_pos(&nx, &ny); } else { if ( reticle_follow ) { nx = HUD_nose_x; ny = HUD_nose_y; gr_resize_screen_pos(&nx, &ny); gr_set_screen_scale(base_w, base_h); gr_unsize_screen_pos(&nx, &ny); } else { gr_set_screen_scale(base_w, base_h); } } for (i = 0; i < 6; ++i) { coords[i].x += nx; coords[i].y += ny; } //gr_shield_icon(coords); g3_render_shield_icon(coords); gr_reset_screen_scale(); }
/** * Renders everything for a head animation * Also checks for when new head ani's need to start playing */ void HudGaugeTalkingHead::render(float frametime) { if ( Head_frame.first_frame == -1 ) { return; } if(msg_id != -1 && head_anim != NULL) { if(!head_anim->done_playing) { // draw frame // hud_set_default_color(); setGaugeColor(); // clear setClip(position[0] + Anim_offsets[0], position[1] + Anim_offsets[1], Anim_size[0], Anim_size[1]); gr_clear(); resetClip(); renderBitmap(Head_frame.first_frame, position[0], position[1]); // head ani border float scale_x = i2fl(Anim_size[0]) / i2fl(head_anim->width); float scale_y = i2fl(Anim_size[1]) / i2fl(head_anim->height); gr_set_screen_scale(fl2ir(base_w / scale_x), fl2ir(base_h / scale_y)); setGaugeColor(); generic_anim_render(head_anim,frametime, fl2ir((position[0] + Anim_offsets[0] + HUD_offset_x) / scale_x), fl2ir((position[1] + Anim_offsets[1] + HUD_offset_y) / scale_y)); // draw title gr_set_screen_scale(base_w, base_h); renderString(position[0] + Header_offsets[0], position[1] + Header_offsets[1], XSTR("message", 217)); } else { for (int j = 0; j < Num_messages_playing; ++j) { if (Playing_messages[j].id == msg_id) { Playing_messages[j].play_anim = false; break; // only one head ani plays at a time } } msg_id = -1; // allow repeated messages to display a new head ani head_anim = NULL; // Nothing to see here anymore, move along } } // check playing messages to see if we have any messages with talking animations that need to be created. for (int i = 0; i < Num_messages_playing; i++ ) { if(Playing_messages[i].play_anim && Playing_messages[i].id != msg_id ) { msg_id = Playing_messages[i].id; if (Playing_messages[i].anim_data) head_anim = Playing_messages[i].anim_data; else head_anim = NULL; return; } } }
int popup_do_with_condition(popup_info *pi, int flags, int(*condition)()) { int screen_id, choice = -1, done = 0; int test; screen_id = gr_save_screen(); if ( popup_init(pi, flags) == -1 ) return -1; int old_max_w_unscaled = gr_screen.max_w_unscaled; int old_max_h_unscaled = gr_screen.max_h_unscaled; int old_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed; int old_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed; gr_reset_screen_scale(); while(!done) { int k; os_poll(); game_set_frametime(-1); game_do_state_common(gameseq_get_state()); // do stuff common to all states gr_restore_screen(screen_id); // draw one frame first Popup_window.draw(); popup_force_draw_buttons(pi); popup_draw_msg_text(pi, flags); popup_draw_button_text(pi, flags); gr_flip(); // test the condition function or process for the window if ((test = condition()) > 0) { done = 1; choice = test; } else { k = Popup_window.process(); // poll for input, handle mouse choice = popup_process_keys(pi, k, flags); if ( choice != POPUP_NOCHANGE ) { done=1; } if ( !done ) { choice = popup_check_buttons(pi); if ( choice != POPUP_NOCHANGE ) { done=1; } } } } gr_set_screen_scale(old_max_w_unscaled, old_max_h_unscaled, old_max_w_unscaled_zoomed, old_max_h_unscaled_zoomed); popup_close(pi,screen_id); return choice; }
// exit: -1 => error // 0..nchoices-1 => choice int popup_do(popup_info *pi, int flags) { int screen_id, choice = -1, done = 0; if ( popup_init(pi, flags) == -1 ){ return -1; } screen_id = gr_save_screen(); int old_max_w_unscaled = gr_screen.max_w_unscaled; int old_max_h_unscaled = gr_screen.max_h_unscaled; int old_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed; int old_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed; gr_reset_screen_scale(); while(!done) { int k; os_poll(); // if we were killed by a call to popup_kill_any_active(), kill the popup if(Popup_should_die){ choice = -1; break; } // if we're flagged as should be running the state underneath, then do so if(flags & PF_RUN_STATE){ game_do_state(gameseq_get_state()); } // otherwise just run the common functions (for networking,etc) else { game_set_frametime(-1); game_do_state_common(gameseq_get_state(),flags & PF_NO_NETWORKING); // do stuff common to all states } k = Popup_window.process(); // poll for input, handle mouse choice = popup_process_keys(pi, k, flags); if ( choice != POPUP_NOCHANGE ) { done=1; } if ( !done ) { choice = popup_check_buttons(pi); if ( choice != POPUP_NOCHANGE ) { done=1; } } // don't draw anything if(!(flags & PF_RUN_STATE)){ gr_restore_screen(screen_id); } // if this is an input popup, store the input text if(flags & PF_INPUT){ Popup_input.get_text(pi->input_text); } Popup_window.draw(); popup_force_draw_buttons(pi); popup_draw_msg_text(pi, flags); popup_draw_button_text(pi, flags); gr_flip(); } gr_set_screen_scale(old_max_w_unscaled, old_max_h_unscaled, old_max_w_unscaled_zoomed, old_max_h_unscaled_zoomed); popup_close(pi,screen_id); return choice; }
/** * @brief This function is called to blit the next frame of an anim instance to the screen. * This is normally called by the anim_render_all() function. * * @param instance Pointer to animation instance * @param frametime Time elapsed since last call, in seconds */ int anim_show_next_frame(anim_instance *instance, float frametime) { int bitmap_id, bitmap_flags=0, new_frame_num, frame_diff=0, i, n_frames=0,frame_save; float percent_through, time; vertex image_vertex; int aabitmap = 0; int bpp = 16; Assert( instance != NULL ); instance->time_elapsed += frametime; // Advance to the next frame, if we determine enough time has elapsed. if(instance->direction == ANIM_DIRECT_FORWARD) n_frames = instance->stop_at - instance->start_at + 1; else if(instance->direction == ANIM_DIRECT_REVERSE) n_frames = instance->start_at - instance->stop_at + 1; time = n_frames / i2fl(instance->parent->fps); percent_through = instance->time_elapsed / time; if(instance->direction == ANIM_DIRECT_FORWARD) new_frame_num = instance->start_at - 1 + fl2i(percent_through * n_frames + 0.5f); else new_frame_num = instance->start_at - 1 - fl2i(percent_through * n_frames + 0.5f); frame_save = instance->frame_num; // If framerate independent, use the new_frame_num... unless instance->skip_frames is // FALSE, then only advance a maximum of one frame (this is needed since some big animations // should just play slower rather than taking the hit of decompressing multiple frames and // creating an even greater slowdown if (instance->framerate_independent) { if(instance->direction == ANIM_DIRECT_FORWARD){ if ( new_frame_num > instance->last_frame_num) { if ( instance->skip_frames ) instance->frame_num = new_frame_num; else instance->frame_num++; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if( new_frame_num < instance->last_frame_num) { if ( instance->skip_frames ) instance->frame_num = new_frame_num; else instance->frame_num--; } } } else { if(instance->direction == ANIM_DIRECT_FORWARD){ if ( new_frame_num > instance->last_frame_num) { instance->frame_num++; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if ( new_frame_num < instance->last_frame_num) { instance->frame_num--; } } } if(instance->direction == ANIM_DIRECT_FORWARD){ if ( instance->frame_num < instance->start_at ) { instance->frame_num = instance->start_at; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if ( instance->frame_num > instance->start_at ) { instance->frame_num = instance->start_at; } } if ( instance->stop_now == TRUE ) { return -1; } // If past the last frame, clamp to the last frame and then set the stop_now flag in the // anim instance. The next iteration, the animation will stop. if(instance->direction == ANIM_DIRECT_FORWARD){ if (instance->frame_num >= instance->stop_at ) { if (instance->looped) { // looped animations instance->frame_num = instance->stop_at; instance->time_elapsed = 0.0f; } else if(instance->ping_pong) { // pingponged animations instance->frame_num = instance->stop_at; anim_reverse_direction(instance); } else { // one-shot animations instance->frame_num = instance->stop_at; instance->last_frame_num = instance->frame_num; instance->stop_now = TRUE; } } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if (instance->frame_num <= instance->stop_at ) { if (instance->looped) { // looped animations instance->frame_num = instance->stop_at; instance->time_elapsed = 0.0f; } else if(instance->ping_pong) { // pingponged animations instance->frame_num = instance->stop_at; anim_reverse_direction(instance); } else { // one-shot animations instance->frame_num = instance->stop_at+1; instance->last_frame_num = instance->frame_num; instance->stop_now = TRUE; } } } if(instance->direction == ANIM_DIRECT_FORWARD){ if( instance->last_frame_num >= instance->start_at ) { frame_diff = instance->frame_num - instance->last_frame_num; } else { frame_diff = 1; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if( instance->last_frame_num <= instance->start_at ) { frame_diff = instance->last_frame_num - instance->frame_num; } else { frame_diff = 1; } } Assert(frame_diff >= 0); Assert( instance->frame_num >= 0 && instance->frame_num < instance->parent->total_frames ); // if the anim is paused, ignore all the above changes and still display this frame if(instance->paused || Anim_paused){ instance->frame_num = frame_save; instance->time_elapsed -= frametime; frame_diff = 0; } if (instance->parent->flags & ANF_XPARENT){ bitmap_flags = 0; } bpp = 16; if(instance->aa_color != NULL){ bitmap_flags |= BMP_AABITMAP; aabitmap = 1; bpp = 8; } if ( frame_diff > 0 ) { instance->last_frame_num = instance->frame_num; t1 = timer_get_fixed_seconds(); for ( i = 0; i < frame_diff; i++ ) { anim_check_for_palette_change(instance); // if we're playing backwards, every frame must be a keyframe and we set the data ptr here if(instance->direction == ANIM_DIRECT_REVERSE){ if ( anim_instance_is_streamed(instance) ) { instance->file_offset = instance->parent->file_offset + instance->parent->keys[instance->frame_num-1].offset; } else { instance->data = instance->parent->data + instance->parent->keys[instance->frame_num-1].offset; } } ubyte *temp = NULL; int temp_file_offset = -1; // if we're using bitmap polys BM_SELECT_TEX_FORMAT(); if ( anim_instance_is_streamed(instance) ) { if ( instance->xlate_pal ){ temp_file_offset = unpack_frame_from_file(instance, instance->frame, instance->parent->width*instance->parent->height, instance->parent->palette_translation, aabitmap, bpp); } else { temp_file_offset = unpack_frame_from_file(instance, instance->frame, instance->parent->width*instance->parent->height, NULL, aabitmap, bpp); } } else { if ( instance->xlate_pal ){ temp = unpack_frame(instance, instance->data, instance->frame, instance->parent->width*instance->parent->height, instance->parent->palette_translation, aabitmap, bpp); } else { temp = unpack_frame(instance, instance->data, instance->frame, instance->parent->width*instance->parent->height, NULL, aabitmap, bpp); } } // always go back to screen format BM_SELECT_SCREEN_FORMAT(); // see if we had an error during decode (corrupted anim stream) if ( (temp == NULL) && (temp_file_offset < 0) ) { mprintf(("ANI: Fatal ERROR at frame %i!! Aborting playback of \"%s\"...\n", instance->frame_num, instance->parent->name)); // return -1 to end all playing of this anim instanc return -1; } if(instance->direction == ANIM_DIRECT_FORWARD){ if ( anim_instance_is_streamed(instance) ) { instance->file_offset = temp_file_offset; } else { instance->data = temp; } } } t2 = timer_get_fixed_seconds(); } else { t2=t1=0; } // this only happens when the anim is being looped, we need to reset the last_frame_num if ( (instance->time_elapsed == 0) && (instance->looped) ) { instance->last_frame_num = -1; instance->frame_num = -1; instance->data = instance->parent->data; instance->file_offset = instance->parent->file_offset; instance->loop_count++; } t1 = timer_get_fixed_seconds(); if ( frame_diff == 0 && instance->last_bitmap != -1 ) { bitmap_id = instance->last_bitmap; } else { if ( instance->last_bitmap != -1 ){ bm_release(instance->last_bitmap); } bitmap_id = bm_create(bpp, instance->parent->width, instance->parent->height, instance->frame, bitmap_flags); } if ( bitmap_id == -1 ) { // anim has finsished playing, free the instance frame data anim_release_render_instance(instance); return -1; // NOTE: there is no need to free the instance, since it was pre-allocated as // part of the anim_free_list } else { gr_set_bitmap(bitmap_id); // determine x,y to display the bitmap at if ( instance->world_pos == NULL ) { int old_max_w_unscaled = gr_screen.max_w_unscaled; int old_max_h_unscaled = gr_screen.max_h_unscaled; int old_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed; int old_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed; gr_set_screen_scale(instance->base_w, instance->base_h); gr_set_clip(0, 0, instance->base_w, instance->base_h, GR_RESIZE_MENU); if ( instance->aa_color == NULL ) { gr_bitmap(instance->x, instance->y, GR_RESIZE_MENU_NO_OFFSET); } else { gr_set_color_fast( (color*)instance->aa_color ); gr_aabitmap(instance->x, instance->y, GR_RESIZE_MENU_NO_OFFSET); } gr_set_screen_scale(old_max_w_unscaled, old_max_h_unscaled, old_max_w_unscaled_zoomed, old_max_h_unscaled_zoomed); gr_reset_clip(); } else { g3_rotate_vertex(&image_vertex,instance->world_pos); Assert(instance->radius != 0.0f); //g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D); material mat_params; material_set_unlit(&mat_params, bitmap_id, 1.0f, false, false); g3_render_rect_screen_aligned_2d(&mat_params, &image_vertex, 0, instance->radius*1.5f); } instance->last_bitmap = bitmap_id; } t2 = timer_get_fixed_seconds(); return 0; }
// hud_show_lock_indicator() will display the lock indicator for homing missiles. // lock_point_pos should be the world coordinates of the target being locked. Assuming all the // necessary locking calculations are done for this frame, this function will compute // where the indicator should be relative to the player's viewpoint and will render accordingly. void HudGaugeLock::render(float frametime) { int target_objnum, sx, sy; object *targetp; vertex lock_point; bool locked = Player_ai->current_target_is_locked ? true : false; bool reset_timers = false; if ( locked != Last_lock_status ) { // check if player lock status has changed since the last frame. reset_timers = true; Last_lock_status = locked; } if (Player_ai->target_objnum == -1) { return; } if (Player->target_is_dying) { return; } if (!Players[Player_num].lock_indicator_visible){ return; } target_objnum = Player_ai->target_objnum; Assert(target_objnum != -1); targetp = &Objects[target_objnum]; // check to see if there are any missile to fire.. we don't want to show the // lock indicator if there are missiles to fire. if ( !ship_secondary_bank_has_ammo(Player_obj->instance) ) { return; } bool in_frame = g3_in_frame() > 0; if(!in_frame) g3_start_frame(0); gr_set_screen_scale(base_w, base_h); // Get the target's current position on the screen. If he's not on there, // we're not going to draw the lock indicator even if he's in front // of our ship, so bail out. g3_rotate_vertex(&lock_point, &lock_world_pos); g3_project_vertex(&lock_point); if (lock_point.codes & PF_OVERFLOW) { gr_reset_screen_scale(); if(!in_frame) g3_end_frame(); return; } hud_set_iff_color(targetp); // nprintf(("Alan","lockx: %d, locky: %d TargetX: %d, TargetY: %d\n", Players[Player_num].lock_indicator_x, Players[Player_num].lock_indicator_y, Player->current_target_sx, Player->current_target_sy)); // We have the coordinates of the lock indicator relative to the target in our "virtual frame" // so, we calculate where it should be drawn based on the player's viewpoint. if (Player_ai->current_target_is_locked) { sx = fl2i(lock_point.screen.xyw.x); sy = fl2i(lock_point.screen.xyw.y); gr_unsize_screen_pos(&sx, &sy); // show the rotating triangles if target is locked renderLockTriangles(sx, sy, frametime); if ( reset_timers ) { Lock_gauge.time_elapsed = 0.0f; } } else { const float scaling_factor = (gr_screen.clip_center_x < gr_screen.clip_center_y) ? (gr_screen.clip_center_x / VIRTUAL_FRAME_HALF_WIDTH) : (gr_screen.clip_center_y / VIRTUAL_FRAME_HALF_HEIGHT); sx = fl2i(lock_point.screen.xyw.x) - fl2i(i2fl(Player->current_target_sx - Players[Player_num].lock_indicator_x) * scaling_factor); sy = fl2i(lock_point.screen.xyw.y) - fl2i(i2fl(Player->current_target_sy - Players[Player_num].lock_indicator_y) * scaling_factor); gr_unsize_screen_pos(&sx, &sy); if ( reset_timers ) { Lock_gauge_draw_stamp = -1; Lock_gauge_draw = 0; Lock_anim.time_elapsed = 0.0f; } } // show locked indicator Lock_gauge.sx = sx - Lock_gauge_half_w; Lock_gauge.sy = sy - Lock_gauge_half_h; if (Player_ai->current_target_is_locked) { hud_anim_render(&Lock_gauge, 0.0f, 1); } else { hud_anim_render(&Lock_gauge, frametime, 1); } gr_reset_screen_scale(); if(!in_frame) g3_end_frame(); }
/** * Displays (renders) the training message to the screen */ void HudGaugeTrainingMessages::render(float frametime) { const char *str; char buf[256]; int i, z, x, y, height, mode, count; if (Training_failure){ return; } if (timestamp_elapsed(Training_message_timestamp) || !strlen(Training_buf)){ return; } if (Training_num_lines <= 0){ return; } gr_set_screen_scale(base_w, base_h); height = gr_get_font_height(); gr_set_shader(&Training_msg_glass); gr_shade(position[0], position[1], TRAINING_MESSAGE_WINDOW_WIDTH, Training_num_lines * height + height); gr_reset_screen_scale(); gr_set_color_fast(&Color_bright_blue); mode = count = 0; for (i=0; i<Training_num_lines; i++) { // loop through all lines of message str = Training_lines[i]; z = 0; x = position[0] + (TRAINING_MESSAGE_WINDOW_WIDTH - TRAINING_LINE_WIDTH) / 2; y = position[1] + i * height + height / 2 + 1; while ((str - Training_lines[i]) < Training_line_lengths[i]) { // loop through each character of each line if ((count < MAX_TRAINING_MESSAGE_MODS) && (str == Training_message_mods[count].pos)) { buf[z] = 0; renderPrintf(x, y, buf); gr_get_string_size(&z, NULL, buf); x += z; z = 0; mode = Training_message_mods[count++].mode; switch (mode) { case TMMOD_NORMAL: gr_set_color_fast(&Color_bright_blue); break; case TMMOD_BOLD: gr_set_color_fast(&Color_white); break; } } buf[z++] = *str++; } if (z) { buf[z] = 0; renderPrintf(x, y, "%s", buf); } } }
void HudGaugeRadarStd::drawContactImage( int x, int y, int rad, int idx, int clr_idx, int size ) { // this we will move as ships.tbl option (or use for radar scaling etc etc) //int size = 24; int w, h, old_bottom, old_bottom_unscaled, old_right, old_right_unscaled; float scalef, wf, hf, xf, yf; vec3d blip_scaler; if(bm_get_info(idx, &w, &h) < 0) { // Just if something goes terribly wrong drawContactCircle(x, y, rad); return; } // just to make sure the missing casts wont screw the math wf = (float) w; hf = (float) h; xf = (float) x; yf = (float) y; // make sure we use the larger dimension for the scaling // lets go case by case to make sure there are no probs if (size == -1) scalef = 1.0f; else if ((h == w) && (size == h)) scalef = 1.0f; else if ( h > w) scalef = ((float) size) / hf; else scalef = ((float) size) / wf; Assert(scalef != 0); // animate the targeted icon - option 1 of highlighting the targets if ( rad == Radar_blip_radius_target ) { if (radar_target_id_flags & RTIF_PULSATE) { scalef *= 1.3f + (sinf(10 * f2fl(Missiontime)) * 0.3f); } if (radar_target_id_flags & RTIF_BLINK) { if (Missiontime & 8192) return; } if (radar_target_id_flags & RTIF_ENLARGE) { scalef *= 1.3f; } } // setup the scaler blip_scaler.xyz.x = scalef; blip_scaler.xyz.y = scalef; blip_scaler.xyz.z = 1.0f; old_bottom = gr_screen.clip_bottom; old_bottom_unscaled = gr_screen.clip_bottom_unscaled; gr_screen.clip_bottom = (int) (old_bottom/scalef); gr_screen.clip_bottom_unscaled = (int) (old_bottom_unscaled/scalef); old_right = gr_screen.clip_right; old_right_unscaled = gr_screen.clip_right_unscaled; gr_screen.clip_right = (int) (old_right/scalef); gr_screen.clip_right_unscaled = (int) (old_right_unscaled/scalef); // scale the drawing coordinates x = (int) ((xf / scalef) - wf/2.0f); y = (int) ((yf / scalef) - hf/2.0f); gr_push_scale_matrix(&blip_scaler); if ( idx >= 0 ) { gr_set_bitmap(idx,GR_ALPHABLEND_NONE,GR_BITBLT_MODE_NORMAL,1.0f); renderBitmap( x, y ); } if ( clr_idx >= 0 ) { gr_set_screen_scale(base_w, base_h); gr_bitmap(x, y); gr_reset_screen_scale(); } gr_pop_scale_matrix(); gr_screen.clip_bottom = old_bottom; gr_screen.clip_bottom_unscaled = old_bottom_unscaled; gr_screen.clip_right = old_right; gr_screen.clip_right_unscaled = old_right_unscaled; }