void CGEObjectives::Paint( void )
{
	C_GEPlayer *pPlayer = ToGEPlayer( C_BasePlayer::GetLocalPlayer() );
	if ( !pPlayer || !m_pCardTexture )
		return;

	Vector myEyePos = pPlayer->EyePosition();
	Vector myAbsPos = pPlayer->GetAbsOrigin();

	int half_w = ScreenWidth()  / 2, 
		half_h = ScreenHeight() / 2,
		card_w = XRES(20),
		card_h = XRES(20),
		buffer = XRES(5),
		off_upleft_x	= m_iInnerBound,
		off_lowleft_x	= m_iInnerBound,
		off_upright_x	= ScreenWidth() - m_iInnerBound - card_w,
		off_lowright_x	= ScreenWidth() - m_iInnerBound - card_w;

	vgui::HFont text_font = scheme()->GetIScheme( GetScheme() )->GetFont("GETargetID", true);

	for ( int i=0; i < m_vObjectives.Count(); i++ )
	{
		GEObjective *obj = m_vObjectives[i];

		Vector screen;
		Vector objAbsPos;
		// Calculate the current position based off of interpolation
		VectorLerp(obj->last_pos, obj->curr_pos, (gpGlobals->curtime - obj->update_time) / RADAR_THINK_INT, objAbsPos ); 
		// This lets us mess with the objective position without losing our "real" position
		Vector objPos = objAbsPos;
		
		int	x = 0, y = 0;
		float theta = 0;

		CBaseEntity *pEnt = obj->hEnt.Get();
		if ( pEnt )
		{
			// If we aren't dormant use our known position
			if ( !pEnt->IsDormant() )
			{
				// Try to get our NPC's position if we are really a bot
				C_GEBotPlayer *pBot = ToGEBotPlayer( pEnt );
				if ( pBot && pBot->GetNPC() )
					objPos = pBot->GetNPC()->GetAbsOrigin();
				else
					objPos = pEnt->GetAbsOrigin();
			}

			// Add our collision box which (usually) surrounds the entire entity
			float height = pEnt->CollisionProp()->OBBMaxs().z;

			// Add additional z for player specific reasons
			if ( pEnt->IsPlayer() )
				objPos.z += height + ToGEPlayer(pEnt)->GetHeadOffset();
			else
				objPos.z += max( height, 40.0f );
		}

		// Calculate parameters
		Vector toEye = objPos - myEyePos;
		float dist = toEye.Length();

		// Check out min distance parameter
		float alpha_mod = 1.0f;
		if ( obj->min_dist > 0 )
			alpha_mod = RemapValClamped( dist, obj->min_dist, obj->min_dist + 80, 0, 1.0f );

		if ( alpha_mod == 0 )
			continue;

		// Find where on the screen to draw the indicator
		// Note: we don't draw it behind us if we are really close
		bool behind = ScreenTransform( objPos, screen ) && dist > OBJ_ABS_MIN_DIST;

		if ( !behind && screen.x > -1.0 && screen.x < 1.0 )
		{
			x = half_w + screen.x*half_w - card_w/2;
			y = half_h - screen.y*half_h - card_h;

			// We are off-screen vertically, flip the card
			if ( screen.y > 1.0 )
				theta = M_PI;
		}
		else
		{
			bool onLeft = screen.x < 0;

			// Calculate a new position for our object to make it "on-screen" at the same height
			Vector forward;
			pPlayer->EyeVectors( &forward );

			Vector newPos;
			VectorMA( myEyePos, dist, forward, newPos );

			newPos.z = objPos.z;
			if ( abs(toEye.z) > 100.0f )
				newPos.z += toEye.z;
			
			//debugoverlay->AddBoxOverlay( newPos, Vector(-5), Vector(5), vec3_angle, 255, 0, 0, 200, gpGlobals->frametime );

			// Find our new screen coordinates
			ScreenTransform( newPos, screen );

			if ( screen.y > 0.97f )
			{
				// The obj is above us and off-screen
				y = m_iInnerBound;

				if ( onLeft )
				{
					x = off_upleft_x;
					theta = 0.75 * M_PI;
					off_upleft_x += card_w + buffer;
				}
				else
				{
					x = off_upright_x;
					theta = 1.25 * M_PI;
					off_upright_x -= card_w + buffer;
				}
			}
			else if ( screen.y < -0.97f )
			{
				// The obj is below us and off-screen
				y = ScreenHeight() - m_iInnerBound;

				if ( onLeft )
				{
					x = off_lowleft_x;
					theta = 0.25 * M_PI;
					off_lowleft_x += card_w + buffer;
				}
				else
				{
					x = off_lowright_x;
					theta = -0.25 * M_PI;
					off_lowright_x -= card_w + buffer;
				}
			}
			else
			{
				// The obj is "on-screen" and level with us
				if ( onLeft )
				{
					x = m_iInnerBound;
					y = half_h - screen.y*half_h;
					theta = M_HALFPI;
				}
				else
				{
					x = ScreenWidth() - m_iInnerBound - card_w;
					y = half_h - screen.y*half_h;
					theta = -M_HALFPI;
				}
			}
		}

		// Default color is white
		Color c = obj->color;
		if ( c.a() == 0 )
			c = Color( 255, 255, 255, 120 );

		// Apply alpha mod
		if ( (!behind && screen.x > -1.0 && screen.x < 1.0) )
			c[3] *= alpha_mod;

		// Bound our results
		x = clamp( x, m_iInnerBound, ScreenWidth() - m_iInnerBound - card_w );
		y = clamp( y, m_iInnerBound, ScreenHeight() - m_iInnerBound - card_h );
		
		// Draw text (if defined) before applying pulse so we don't affect it's color
		if ( obj->text[0] )
		{
			// This is where we clamp the size to 16
			int txtX, txtY;
			txtX = clamp( (x + card_w/2) - obj->txtW/2, XRES(3), ScreenWidth() - obj->txtW - XRES(3) );
			txtY = y - obj->txtH - YRES(3);

			if ( txtY < 0 )
				txtY = y + card_h + YRES(3);

			surface()->DrawSetTextColor( c );
			surface()->DrawSetTextFont( text_font );
			surface()->DrawSetTextPos( txtX, txtY );
			surface()->DrawUnicodeString( obj->text );
		}

		// Apply Pulse
		if ( obj->pulse )
		{
			float blink = SmoothCurve( obj->pulse_mod );
			c[0] = c[0] + (blink * (255-c[0]) * 0.15f);
			c[1] = c[1] + (blink * (255-c[1]) * 0.15f);
			c[2] = c[2] + (blink * (255-c[2]) * 0.15f);

			// Modulate the blink
			obj->pulse_mod += 1.2f * gpGlobals->frametime;
			if ( obj->pulse_mod > 1.0f )
				obj->pulse_mod -= 1.0f;
		}

		m_pCardTexture->DrawSelfRotated( x, y, card_w, card_h, theta, c );
	}
}