#include "pch.h"
const char* c_szRadarLODs[] = {
"Radar mode: All",
"Radar mode: Default",
"Radar mode: Target",
"Radar mode: None"
};
/*
"Radar mode: Ships",
"Radar mode: Stations",
"Radar mode: Treasure",
"Radar mode: Asteroids",
};
*/
static const char* c_pszEmpty = "";
const float rangeClipLabels = 1000.0f;
const int c_iNotUseful = 0;
const int c_iUsefulPart = 1;
const int c_iUsefulTech = 2;
//////////////////////////////////////////////////////////////////////////////
//
// Peripheral Radar Image
//
//////////////////////////////////////////////////////////////////////////////
const int c_maskOrder = 0x01;
const int c_maskTarget = c_maskOrder << c_cmdCurrent;
const int c_maskAccepted = c_maskOrder << c_cmdAccepted;
const int c_maskQueued = c_maskOrder << c_cmdQueued;
const int c_maskEnemy = 0x08;
const int c_maskThreat = 0x10;
const int c_maskFlash = 0x20;
const int c_maskMe = 0x80;
const int c_maskSubject = 0x100;
const int c_maskFlag = 0x200;
const int c_maskArtifact = 0x400;
const int c_maskHighlight = 0x800;
class RadarImageImpl : public RadarImage {
//////////////////////////////////////////////////////////////////////////////
//
// Types
//
//////////////////////////////////////////////////////////////////////////////
class TextData
{
public:
const char* m_pszName;
int m_range;
float m_shield;
float m_hull;
float m_fill;
Command m_cmd;
CommandID m_cid;
Point m_position;
Point m_direction;
Color m_color;
TextData(const char* pszName,
int range,
float shield,
float hull,
float fill,
Command cmd,
CommandID cid,
const Point& position,
const Point& direction,
const Color& color)
:
m_pszName(pszName),
m_range(range),
m_shield(shield),
m_hull(hull),
m_fill (fill),
m_cmd(cmd),
m_cid(cid),
m_position(position),
m_direction(direction),
m_color(color)
{
}
TextData(const TextData& data)
:
m_pszName(data.m_pszName),
m_range(data.m_range),
m_shield(data.m_shield),
m_hull(data.m_hull),
m_fill(data.m_fill),
m_cmd(data.m_cmd),
m_cid(data.m_cid),
m_position(data.m_position),
m_direction(data.m_direction),
m_color(data.m_color)
{
}
};
typedef TList<TextData> TextDataList;
//////////////////////////////////////////////////////////////////////////////
//
// Members
//
//////////////////////////////////////////////////////////////////////////////
TextDataList m_listTextData;
TRef<Surface> m_psurfaceLastFired;
TRef<Surface> m_psurfaceTargeted;
TRef<Surface> m_psurfaceLocked;
TRef<Surface> m_psurfacePartialLock;
TRef<Surface> m_psurfaceEnemy;
TRef<Surface> m_psurfaceMe;
TRef<Surface> m_psurfaceSubject;
TRef<Surface> m_psurfaceFlag;
TRef<Surface> m_psurfaceArtifact;
TRef<Surface> m_psurfaceTechIcon;
TRef<Surface> m_psurfaceAccepted[c_cidMax];
TRef<Surface> m_psurfaceQueued[c_cidMax];
RadarLOD m_radarLOD;
TVector<VertexL> m_vertices;
TVector<WORD> m_indices;
float m_fRoundRadarRadius;
static Color s_colorNeutral;
//////////////////////////////////////////////////////////////////////////////
//
// Evaluate gets called when the view size changes
//
//////////////////////////////////////////////////////////////////////////////
void Evaluate (void)
{
Color color (0.5f, 0.5f, 0.5f, 0.25f);
Rect rectImage = GetViewRect()->GetValue();
{
Point pointCenter = rectImage.Center();
rectImage.Offset(-pointCenter);
rectImage.Expand(-c_flBorderSide);
}
// establish the vertex and index array for the round radar circle, and set the indices
const int cCount = 60;
const float fAngleStep = RadiansFromDegrees (360.0f / cCount);
m_vertices.SetCount (cCount);
m_indices.SetCount (cCount * 2);
for (int j = 0; j < cCount; j++)
{
m_indices.Set (j * 2, j);
m_indices.Set ((j * 2) + 1, (j + 1) % m_vertices.GetCount ());
}
{
m_fRoundRadarRadius = ((rectImage.YMax () - rectImage.YMin ()) * 0.48f);
// this recalculates the vertices of the round radar circle
for (int i = 0; i < m_vertices.GetCount (); i++)
{
float fTheta = fAngleStep * static_cast<float> (i),
fCosTheta = cosf (fTheta),
fSinTheta = sinf (fTheta);
m_vertices.Set (i, VertexL (Vector (fCosTheta * m_fRoundRadarRadius, fSinTheta * m_fRoundRadarRadius, 0.0f), color));
}
}
/*
{
m_vertices.Set (0, VertexL (Vector (rectImage.XMin(), rectImage.YMin(), 0.0f), color));
m_vertices.Set (1, VertexL (Vector (rectImage.XMin(), rectImage.YMax(), 0.0f), color));
m_vertices.Set (2, VertexL (Vector (rectImage.XMax(), rectImage.YMax(), 0.0f), color));
m_vertices.Set (3, VertexL (Vector (rectImage.XMax(), rectImage.YMin(), 0.0f), color));
}
*/
}
public:
//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
RadarImageImpl(Modeler* pmodeler, Viewport* pviewport) :
RadarImage(pviewport),
m_radarLOD(c_rlDefault)
{
m_psurfaceEnemy = pmodeler->LoadSurface(AWF_FLIGHT_ENEMY_ICON, true);
m_psurfaceMe = pmodeler->LoadSurface(AWF_FLIGHT_ME_ICON, true);
m_psurfaceTargeted = pmodeler->LoadSurface(AWF_FLIGHT_TARGETED_ICON, true);
m_psurfaceLocked = pmodeler->LoadSurface(AWF_FLIGHT_MISSILE_LOCKED_ICON, true);
m_psurfacePartialLock = pmodeler->LoadSurface(AWF_FLIGHT_PARTIAL_MISSILE_LOCK_ICON, true);
m_psurfaceSubject = pmodeler->LoadSurface(AWF_FLIGHT_SUBJECT_ICON, true);
m_psurfaceFlag = pmodeler->LoadSurface(AWF_FLIGHT_FLAG_ICON, true);
m_psurfaceArtifact = pmodeler->LoadSurface(AWF_FLIGHT_ARTIFACT_ICON, true);
m_psurfaceTechIcon = pmodeler->LoadSurface("icontechbmp", true);
for (CommandID i = c_cidAttack; (i < c_cidMax); i++)
{
if (c_cdAllCommands[i].szAccepted[0] != '\0')
m_psurfaceAccepted[i] = pmodeler->LoadSurface(c_cdAllCommands[i].szAccepted, true);
if (c_cdAllCommands[i].szQueued[0] != '\0')
m_psurfaceQueued[i] = pmodeler->LoadSurface(c_cdAllCommands[i].szQueued, true);
}
m_psurfaceLastFired = pmodeler->LoadSurface(AWF_FLIGHT_LASTFIRED_ICON, true);
}
void SetRadarLOD(RadarLOD radarLOD)
{
m_radarLOD = radarLOD;
}
RadarLOD GetRadarLOD(void) const
{
return m_radarLOD;
}
//////////////////////////////////////////////////////////////////////////////
//
// Draw a blip expanded to fit around the object
//
//////////////////////////////////////////////////////////////////////////////
void DrawExpandedBlip(Context* pcontext, float radius, Surface* psurface, const Color& color)
{
Point size = Point::Cast(psurface->GetSize());
float xsize = size.X();
float ysize = size.Y();
float xsizeMid = xsize / 2;
float ysizeMid = ysize / 2;
float delta = radius / sqrt2;
{
float m = xsizeMid / 2;
if (delta < m)
delta = m;
}
pcontext->DrawImage3D(psurface, Rect( 0, 0, xsizeMid, ysizeMid), color, true, Point(-delta, -delta));
pcontext->DrawImage3D(psurface, Rect(xsizeMid, 0, xsize, ysizeMid), color, true, Point( delta, -delta));
pcontext->DrawImage3D(psurface, Rect(xsizeMid, ysizeMid, xsize, ysize), color, true, Point( delta, delta));
pcontext->DrawImage3D(psurface, Rect( 0, ysizeMid, xsizeMid, ysize), color, true, Point(-delta, delta));
}
//////////////////////////////////////////////////////////////////////////////
//
// Draw a blip based on passed parameters
//
//////////////////////////////////////////////////////////////////////////////
void DrawBlip(Context* pcontext,
const Rect& rectImage,
const Color& colorIcon,
const Color& colorOther,
unsigned char ucRadarState,
ThingSite* pts,
Surface* psurfaceIcon,
const char* pszName,
int range,
float shield,
float hull,
float fill,
Command cmd,
CommandID cid,
int maskBrackets,
float lock,
bool bIcon,
bool bStats)
{
float radiusObject = pts->GetScreenRadius();
{
static const float maxRadius = sqrt2 * 80.0f;
if (radiusObject > maxRadius)
radiusObject = maxRadius;
}
float radiusBracket = 1.05f * radiusObject;
float distanceToEdge = pts->GetDistanceToEdge();
//Clip the brackets so that they are always entirely on screen
if (radiusBracket > distanceToEdge + c_flBorderSide)
radiusBracket = distanceToEdge + c_flBorderSide;
const Point& positionObject = pts->GetScreenPosition();
{
//Draw the brackets around the "object"
pcontext->Translate(positionObject);
if (lock != 0.0f)
{
if (lock == 1.0f)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceLocked, Color::White());
else
DrawExpandedBlip(pcontext, radiusBracket + 40.0f * (1.0f - lock), m_psurfacePartialLock, Color::White());
}
if (maskBrackets & c_maskEnemy)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceEnemy, colorOther);
if (maskBrackets & c_maskMe)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceMe, colorOther);
if (maskBrackets & c_maskSubject)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceSubject, colorOther);
if (maskBrackets & c_maskFlag)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceFlag, colorOther);
else if (maskBrackets & c_maskArtifact)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceArtifact, colorOther);
if (maskBrackets & c_maskTarget)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceTargeted, colorOther);
if (maskBrackets & c_maskThreat)
DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceLastFired, colorOther);
}
Point directionCenter;
{
directionCenter.SetX(positionObject.X());
directionCenter.SetY(GetWindow ()->GetRoundRadarMode()
? positionObject.Y()
: (positionObject.Y() - rectImage.Size().Y() / 5.0f));
float fLengthSquared = directionCenter.X() * directionCenter.X() + directionCenter.Y() * directionCenter.Y();
if (fLengthSquared < 1.0f)
{
directionCenter.SetX(0.0f);
directionCenter.SetY(-1.0f);
}
else
{
float f = float(-1.0 / sqrt(fLengthSquared));
directionCenter.SetX(directionCenter.X() * f);
directionCenter.SetY(directionCenter.Y() * f);
}
}
Point positionIcon;
if (ucRadarState != c_ucRadarOnScreenLarge)
{
positionIcon.SetX(0.0f);
positionIcon.SetY(0.0f);
}
else
{
// the radius bracket is big, and the icon should appear near
// the object instead of off it. Shrinking the radius bracket
// accomplishes this.
// XXX difficult to assess for now, Rob is inclined to leave the icon
// XXX further away to avoid obscuring ships, so we agreed that I could
// XXX check it in commented out.
// radiusBracket *= 0.5f;
//Get the vector from the object to the center of the screen
//where this direction for something close to the center of the
//screen is always straight down.
{
float f = (distanceToEdge < radiusBracket) ? distanceToEdge : radiusBracket;
positionIcon.SetX(directionCenter.X() * f);
positionIcon.SetY(directionCenter.Y() * f);
}
}
if (bIcon)
{
pcontext->Translate(positionIcon);
pcontext->SetBlendMode(BlendModeAdd);
pcontext->DrawImage3D(psurfaceIcon, colorIcon, true);
}
if ((pszName[0] != '\0') || (range > 0) || bStats)
{
Point positionLabel = positionObject + positionIcon;
if (maskBrackets & (c_maskTarget | c_maskAccepted | c_maskThreat))
m_listTextData.PushEnd(TextData(pszName, range, shield, hull, fill, cmd, cid, positionLabel, directionCenter, colorOther));
else
m_listTextData.PushFront(TextData(pszName, range, shield, hull, fill, cmd, cid, positionLabel, directionCenter, colorOther));
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Render one blip for each object in the cluster
//
//////////////////////////////////////////////////////////////////////////////
static int UsefulTreasure(IshipIGC* pship, ItreasureIGC* pt)
{
TreasureCode tc = pt->GetTreasureCode();
switch (tc)
{
case c_tcPowerup:
{
if (!pship->GetCluster())
return c_iNotUseful;
}
//no break
case c_tcCash:
case c_tcFlag:
{
return c_iUsefulPart;
}
break;
case c_tcDevelopment:
{
IdevelopmentIGC* pd = trekClient.m_pCoreIGC->GetDevelopment(pt->GetTreasureID());
assert (pd);
return pd->IsObsolete(trekClient.GetSide()->GetDevelopmentTechs())
? c_iNotUseful
: c_iUsefulPart; //It really is a tech, but use its icon instead of the special icon
}
break;
default:
{
assert (tc == c_tcPart);
IpartTypeIGC* ppt = trekClient.m_pCoreIGC->GetPartType(pt->GetTreasureID());
assert (ppt);
EquipmentType et = ppt->GetEquipmentType();
if (et == ET_Pack)
{
if (pship->GetCluster() != NULL)
{
const DataPackTypeIGC* pdata = (const DataPackTypeIGC*)(ppt->GetData());
if (pdata->packType == c_packFuel)
{
//Fuel is useful only if we have an afterburner
return (pship->GetMountedPart(ET_Afterburner, 0) != NULL)
? c_iUsefulPart
: c_iNotUseful;
}
else
{
assert (pdata->packType == c_packAmmo);
Mount m = pship->GetHullType()->GetMaxWeapons();
for (Mount i = 0; (i < m); i++)
{
IweaponIGC* pw = (IweaponIGC*)(pship->GetMountedPart(ET_Weapon, i));
if (pw && (pw->GetAmmoPerShot() != 0))
return c_iUsefulPart;
}
}
}
return c_iNotUseful;
}
else
{
if (!(ppt->GetEffectTechs() <= trekClient.GetSide()->GetDevelopmentTechs()))
return c_iUsefulTech;
if (IlauncherTypeIGC::IsLauncherType(et) && pship->GetCluster() && pship->GetHullType()->CanMount(ppt, 0))
return c_iUsefulPart;
return c_iNotUseful;
}
}
break;
}
}
void RenderBlips(Context* pcontext, const Rect& rectImage)
{
IclusterIGC* pcluster = trekClient.GetCluster();
if (pcluster == NULL)
return;
const ModelListIGC* models = pcluster->GetPickableModels();
ZAssert(models != NULL);
bool bRangeLabels = !TrekWindow::CommandCamera(GetWindow()->GetCameraMode());
assert (trekClient.GetShip()->GetCluster() || !bRangeLabels);
//
// Draw a blip for every model in the cluster
//
IshipIGC* pshipSource = trekClient.GetShip()->GetSourceShip();
const Vector& vecPositionPlayer = pshipSource->GetPosition();
float radiusSource = pshipSource->GetRadius();
ImodelIGC* pmodelOrders[c_cmdMax];
{
// For command targets not in the current sector ... show the user how to get there.
for (Command i = 0; (i <= c_cmdCurrent); i++) //Explicitly do not handle the case of planned
{
pmodelOrders[i] = trekClient.GetShip()->GetCommandTarget(i);
if (pmodelOrders[i])
{
IclusterIGC* c = pmodelOrders[i]->GetCluster();
if (pmodelOrders[i]->GetObjectType() == OT_ship)
{
pmodelOrders[i] = ((IshipIGC*)pmodelOrders[i])->GetSourceShip();
if (c == NULL)
c = trekClient.GetCluster(trekClient.GetShip(), pmodelOrders[i]);
}
if (c == NULL)
pmodelOrders[i] = NULL;
else
{
IclusterIGC* pcluster = trekClient.GetShip()->GetCluster();
if (pcluster && (c != pcluster))
{
// The target is not in the sector ... find out how to get to the target
pmodelOrders[i] = FindPath(trekClient.GetShip(), pmodelOrders[i], false);
}
}
}
}
}
const ShipListIGC* psubjects;
if (bRangeLabels)
psubjects = NULL;
else
psubjects = GetWindow()->GetConsoleImage()->GetSubjects();
IsideIGC* psideMine = trekClient.GetShip()->GetSide();
float capacity = trekClient.m_pCoreIGC->GetFloatConstant(c_fcidCapacityHe3) *
psideMine->GetGlobalAttributeSet().GetAttribute(c_gaMiningCapacity);
Time now = Time::Now();
ImodelIGC* pmodelEnemy = bRangeLabels
? FindTarget(pshipSource, c_ttShip | c_ttEnemy | c_ttNearest)
: NULL;
for (ModelLinkIGC* l = models->first();
(l != NULL); l = l->next())
{
ImodelIGC* pmodel = l->data();
if (pmodel->GetVisibleF() && pshipSource->CanSee(pmodel))
{
ObjectType type = pmodel->GetObjectType();
Surface* psurfaceIcon = (Surface*)(pmodel->GetIcon());
if (psurfaceIcon)
{
int maskBrackets = 0x00;
const char* pszName = pmodel->GetName();
Command cmd;
CommandID cidOrder = c_cidNone;
{
for (Command i = 0; (i < c_cmdMax); i++)
{
if (pmodel == pmodelOrders[i])
{
maskBrackets |= (c_maskOrder << i);
CommandID cid = trekClient.GetShip()->GetCommandID(i);
if (cid != c_cidNone)
{
cmd = i;
cidOrder = cid;
}
}
}
}
float lock = 0.0f;
if (maskBrackets & c_maskTarget)
{
ImagazineIGC* magazine = (ImagazineIGC*)(trekClient.GetShip()->GetMountedPart(ET_Magazine, 0));
if (magazine)
lock = magazine->GetLock();
}
float separation = (pmodel->GetPosition() - vecPositionPlayer).Length();
int range;
{
if ((pmodel == pshipSource) || !bRangeLabels)
range = 0;
else
range = int(separation + 0.5f);
}
separation -= radiusSource + pmodel->GetRadius();
if (type == OT_treasure)
{
if (((ItreasureIGC*)pmodel)->GetTreasureCode() == c_tcFlag)
maskBrackets |= c_maskHighlight;
}
else
{
SideID sidFlag = pmodel->GetFlag();
if (sidFlag != NA)
maskBrackets |= (sidFlag == SIDE_TEAMLOBBY) ? c_maskArtifact : c_maskFlag;
}
ThingSite* pts = pmodel->GetThingSite();
unsigned char ucRadarState = pts->GetRadarState();
if (psubjects && (type == OT_ship) && psubjects->find((IshipIGC*)pmodel))
maskBrackets |= c_maskSubject;
if (pmodel == pmodelEnemy)
maskBrackets |= c_maskEnemy;
{
const DamageBucketList* b = pmodel->GetDamageBuckets();
if (b->n() != 0)
{
assert (b->n() == 1);
DamageBucket* db = b->first()->data();
maskBrackets |= (db->flash(now))
? (c_maskThreat | c_maskFlash)
: c_maskThreat;
}
}
//
// Color for the side
//
IsideIGC* pside = pmodel->GetSide();
if (pmodel == pshipSource)
maskBrackets |= c_maskMe;
Color color = pside
? ((maskBrackets & c_maskFlash) ? Color::Red() : pside->GetColor())
: s_colorNeutral;
/*
static const int closeRange = 100;
static const int farRange = 1000;
static const float closeAlpha = 0.75f;
static const float farAlpha = 0.25f;
color.SetAlpha((range < closeRange)
? closeAlpha
: ((range > farRange)
? farAlpha
: (farAlpha +
(float(range - farRange) * (closeAlpha - farAlpha) / float(closeRange - farRange)))));
*/
bool bIcon = true;
bool bLabel = ((maskBrackets & (c_maskTarget |
c_maskAccepted |
c_maskQueued |
c_maskHighlight |
c_maskThreat |
c_maskFlag |
c_maskArtifact)) != 0);
bool bStats = bLabel;
if (bLabel)
{
if ((type == OT_treasure) &&
(UsefulTreasure(pshipSource, (ItreasureIGC*)pmodel) == c_iUsefulTech))
{
psurfaceIcon = m_psurfaceTechIcon;
}
}
else
{
if (m_radarLOD == c_rlMinimal)
{
if (pmodel != pshipSource)
{
bIcon = false;
range = 0;
}
}
else
{
switch (type)
{
case OT_ship:
{
switch (m_radarLOD)
{
case c_rlAll:
{
bLabel = bStats = true;
if ((ucRadarState == c_ucRadarOffScreen) && (pside == psideMine))
range = 0;
}
break;
case c_rlDefault:
{
if ((ucRadarState != c_ucRadarOffScreen) || (separation < rangeClipLabels))
bLabel = true;
if (pside == psideMine)
range = 0;
else
bStats = true;
}
break;
case c_rlTarget:
{
if (pside == psideMine)
{
if (pmodel != pshipSource)
{
bIcon = false;
range = 0;
}
}
else
{
if (ucRadarState != c_ucRadarOffScreen)
bStats = true;
if (separation < rangeClipLabels)
bLabel = true;
}
}
break;
}
}
break;
case OT_station:
{
if (((IstationIGC*)pmodel)->GetBaseStationType()->HasCapability(c_sabmPedestal))
{
if (separation >= rangeClipLabels)
{
bIcon = bLabel = bStats = false;
range = 0;
}
}
else
{
switch (m_radarLOD)
{
case c_rlAll:
{
bLabel = bStats = true;
}
break;
case c_rlDefault:
{
if ((separation >= rangeClipLabels) || (ucRadarState == c_ucRadarOffScreen))
range = 0;
}
break;
case c_rlTarget:
{
range = 0;
if ((pside == psideMine) && (ucRadarState == c_ucRadarOffScreen))
bIcon = false;
}
break;
}
}
}
break;
case OT_missile:
{
if (m_radarLOD != c_rlAll)
{
ImodelIGC* pmodelTarget = ((ImissileIGC*)pmodel)->GetTarget();
if ((pmodelTarget == NULL) || (pmodelTarget->GetSide() != psideMine))
{
bIcon = false;
range = 0;
}
}
}
break;
case OT_probe:
case OT_mine:
{
switch (m_radarLOD)
{
case c_rlAll:
{
if (pside == psideMine)
{
if ((ucRadarState == c_ucRadarOffScreen) && (separation >= rangeClipLabels))
range = 0;
}
else
{
if (ucRadarState != c_ucRadarOffScreen)
bLabel = true;
}
bStats = true;
}
break;
case c_rlDefault:
{
if (pside == psideMine)
{
if (separation >= rangeClipLabels)
range = 0;
}
}
break;
case c_rlTarget:
{
if ((pside == psideMine) || (separation >= rangeClipLabels))
{
bIcon = false;
range = 0;
}
}
break;
}
}
break;
case OT_treasure:
{
int iUseful = UsefulTreasure(pshipSource, (ItreasureIGC*)pmodel);
if (iUseful != c_iNotUseful)
{
bLabel = (m_radarLOD == c_rlAll);
if ((m_radarLOD == c_rlTarget) && (separation >= rangeClipLabels))
{
bIcon = false;
range = 0;
}
else if (iUseful == c_iUsefulTech)
{
psurfaceIcon = m_psurfaceTechIcon;
}
}
else if (m_radarLOD != c_rlAll)
{
bIcon = false;
range = 0;
}
}
break;
case OT_asteroid:
{
switch (m_radarLOD)
{
case c_rlAll:
{
if ((pszName[0] == '\0') || (pszName[0] == 'A'))
{
if (separation >= rangeClipLabels)
{
bIcon = false;
range = 0;
}
else if (range == 0)
bIcon = false;
}
else
bLabel = bStats = true;
}
break;
case c_rlDefault:
{
if ((pszName[0] == '\0') || (pszName[0] == 'A'))
{
if (separation >= rangeClipLabels)
{
bIcon = false;
range = 0;
}
else if (range == 0)
bIcon = false;
}
}
break;
case c_rlTarget:
{
if (separation >= rangeClipLabels)
{
bIcon = false;
range = 0;
}
else if (range == 0)
bIcon = false;
}
break;
}
}
break;
case OT_warp:
{
bLabel = (m_radarLOD <= c_rlDefault);
if ((m_radarLOD == c_rlTarget) && (separation >= rangeClipLabels))
range = 0;
}
break;
}
}
}
float shield = 2.0f;
float hull = 2.0f;
float fill = 2.0f;
if (!bLabel)
{
pszName = c_pszEmpty;
}
else if (pszName[0] == '\0')
{
pszName = GetModelName(pmodel);
}
if (bStats)
{
switch(type)
{
case OT_ship:
{
IshipIGC* pship = static_cast<IshipIGC*> (pmodel);
IshieldIGC* pshield = static_cast<IshieldIGC*> (pship->GetMountedPart(ET_Shield, 0));
shield = pshield ? pshield->GetFraction() : 2.0f;
hull = ((IdamageIGC*)pmodel)->GetFraction();
// this really only works if the server updates the client with
// the information. We would have to add a new message type
// for that to happen, so for now I'm just commenting it out and
// moving on.
/*
if (pship->GetPilotType () == c_ptMiner)
{
fill = pship->GetOre () / capacity;
if (fill > 1.0f)
fill = 1.0f;
}
*/
}
break;
case OT_station:
{
shield = ((IstationIGC*)pmodel)->GetShieldFraction();
hull = ((IdamageIGC*)pmodel)->GetFraction();
}
break;
case OT_asteroid:
{
hull = ((IdamageIGC*)pmodel)->GetFraction();
float ore = ((IasteroidIGC*)pmodel)->GetOre();
if (ore != 0.0f)
{
// this is displaying how many shiploads of ore are on the asteroid.
// more than two is shown as full.
fill = ore / (2.0f * capacity);
if (fill > 1.0f)
fill = 1.0f;
}
}
break;
case OT_mine:
{
fill = ((ImineIGC*)pmodel)->GetTimeFraction();
}
break;
case OT_probe:
{
fill = ((IprobeIGC*)pmodel)->GetTimeFraction();
hull = ((IprobeIGC*)pmodel)->GetFraction();
}
break;
}
}
//
// Draw the Blip
//
Color colorOther(color);
if ((maskBrackets & (c_maskTarget | c_maskAccepted | c_maskThreat | c_maskHighlight | c_maskFlag | c_maskArtifact)) == 0)
colorOther = (maskBrackets & c_maskQueued)
? (colorOther * 0.75f)
: (colorOther * 0.5f);
pcontext->PushState();
DrawBlip(pcontext,
rectImage,
color,
colorOther,
ucRadarState,
pts,
psurfaceIcon,
pszName,
range,
shield,
hull,
fill,
cmd,
cidOrder,
maskBrackets,
lock,
bIcon,
bStats);
pcontext->PopState();
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Draw a circle bordering the round radar
//
//////////////////////////////////////////////////////////////////////////////
void RenderRoundBorder (Context* pcontext, const Rect& rectImage)
{
pcontext->PushState ();
pcontext->SetClipping (false);
pcontext->SetBlendMode (BlendModeSourceAlpha);
pcontext->DrawLines(m_vertices, m_indices);
pcontext->PopState ();
}
//////////////////////////////////////////////////////////////////////////////
//
// Render the image
//
//////////////////////////////////////////////////////////////////////////////
void Render(Context* pcontext)
{
if (m_radarLOD != c_rlNone)
{
//
// Use flat shading
//
pcontext->SetShadeMode(ShadeModeFlat);
pcontext->SetLinearFilter(false, true);
//
// Shrink the rect size by half the size of the gauge bitmap
// and center the rect around the origin
//
Rect rectImage = GetViewRect()->GetValue();
{
Point pointCenter = rectImage.Center();
pcontext->Translate(pointCenter);
}
//
// Draw the round border if appropriate
//
if (GetWindow ()->GetRoundRadarMode ())
RenderRoundBorder (pcontext, rectImage);
//
// Draw some Blips
//
RenderBlips(pcontext, rectImage);
//
// Draw the text
//
TRef<IEngineFont> pfont = TrekResources::SmallFont();
float heightFont = float(pfont->GetHeight());
TextDataList::Iterator iter(m_listTextData);
while (!iter.End())
{
const TextData& data = iter.Value();
float lines = 0.0f;
float width = 0.0f;
if (data.m_pszName[0] != '\0')
{
float w = (float)(pfont->GetTextExtent(data.m_pszName).X());
if (w > width)
width = w;
lines += 1.0f;
}
char szRange[20];
if (data.m_range > 0)
{
_itoa(data.m_range, szRange, 10);
float w = (float)(pfont->GetTextExtent(szRange).X());
if (w > width)
width = w;
lines += 1.0f;
}
if (data.m_shield <= 1.0f)
{
lines += 0.5f;
}
if (data.m_hull <= 1.0f)
{
lines += 0.5f;
}
if (data.m_fill <= 1.0f)
{
lines += 0.5f;
}
Surface* psurfaceIcon = NULL;
float xshift;
if (data.m_cid != c_cidNone)
{
assert (data.m_cid >= 0);
assert (data.m_cid < c_cidMax);
psurfaceIcon = (data.m_cmd != c_cmdQueued) ? m_psurfaceAccepted[data.m_cid] : m_psurfaceQueued[data.m_cid];
if (psurfaceIcon)
{
Point size = Point::Cast(psurfaceIcon->GetSize());
xshift = size.X();
width += xshift;
}
}
//Find the offset to center the text at position + offset
Point offset(data.m_position.X() - 0.5f * width, data.m_position.Y() + heightFont * 0.5f * (lines - 2.0f));
//Adjust the offset by the amount required to move a point from the center to the edge
//in the specified direction
{
float w = width + 15.0f;
float h = heightFont * lines + 15.0f;
float x = data.m_direction.X();
float y = data.m_direction.Y();
if (x == 0.0f)
y = (y < 0.0f) ? -h : h;
else if (y == 0.0f)
x = (x <= 0.0f) ? -w : w;
else
{
float tX = w / float(fabs(x));
float tY = h / float(fabs(y));
float tMin = (tX < tY) ? tX : tY;
x *= tMin;
y *= tMin;
}
offset.SetX(offset.X() + x * 0.5f);
offset.SetY(offset.Y() + y * 0.5f);
if (psurfaceIcon)
{
offset.SetX(offset.X() + xshift * 0.5f);
pcontext->DrawImage3D(psurfaceIcon, data.m_color, true, offset);
offset.SetX(offset.X() + xshift * 0.5f);
}
}
if (data.m_pszName[0] != '\0')
{
pcontext->DrawString(pfont, data.m_color, offset, ZString(data.m_pszName));
offset.SetY(offset.Y() - heightFont);
}
if (data.m_range > 0)
{
pcontext->DrawString(pfont, data.m_color, offset, ZString(szRange));
offset.SetY(offset.Y() - heightFont);
}
if ((data.m_hull <= 1.0f) || (data.m_fill <= 1.0f))
{
const float c_width = 16.0f;
float xOffset = float(floor(offset.X()));
float yOffset = float(floor(offset.Y() + heightFont - 4.0f));
// draw the ore fill state if needed
if (data.m_fill <= 1.0f)
{
Rect rectFill (xOffset, yOffset, xOffset + (c_width * data.m_fill), yOffset + 2.0f);
pcontext->FillRect (rectFill, data.m_color);
// if the value isn't 1.0f, the bar has two parts, here we draw the "empty" part
if (data.m_fill < 1.0f)
{
rectFill.SetXMin(rectFill.XMax());
rectFill.SetXMax(xOffset + c_width);
pcontext->FillRect(rectFill, Color(0.333f, 0.0f, 0.0f));
}
yOffset -= 4.0f;
}
// if shield is valid, draw it and update the hull bar location
if (data.m_shield <= 1.0f)
{
Rect rectShield (xOffset, yOffset, xOffset + c_width * data.m_shield, yOffset + 2.0f);
pcontext->FillRect (rectShield, data.m_color);
// if the value isn't 1.0f, the bar has two parts, here we draw the "empty" part
if (data.m_shield < 1.0f)
{
rectShield.SetXMin(rectShield.XMax());
rectShield.SetXMax(xOffset + c_width);
pcontext->FillRect(rectShield, Color(1.0f, 0.0f, 0.0f));
}
yOffset -= 4.0f;
}
// if hull is valid, so draw it and update the hull bar location
if (data.m_hull <= 1.0f)
{
Rect rectHull (xOffset, yOffset, xOffset + c_width * data.m_hull, yOffset + 2.0f);
pcontext->FillRect(rectHull, data.m_color);
// if the value isn't 1.0f, the bar has two parts, here we draw the "empty" part
if (data.m_hull < 1.0f)
{
rectHull.SetXMin(rectHull.XMax());
rectHull.SetXMax(xOffset + c_width);
pcontext->FillRect(rectHull, Color(1.0f, 0.0f, 0.0f));
}
}
}
iter.Next();
}
m_listTextData.SetEmpty();
}
}
};
Color RadarImageImpl::s_colorNeutral(1, 1, 1);
//////////////////////////////////////////////////////////////////////////////
//
// RadarImage Constructor
//
//////////////////////////////////////////////////////////////////////////////
TRef<RadarImage> RadarImage::Create(Modeler* pmodeler, Viewport* pviewport)
{
return new RadarImageImpl(pmodeler, pviewport);
}