예제 #1
0
/*
 * 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();
}
예제 #2
0
/*
 * 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();
}
예제 #3
0
/**
 * 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;
        }
    }
}
예제 #4
0
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;
}
예제 #5
0
// 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;
}
예제 #7
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);
		}
	}
}
예제 #9
0
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;
}