radarimage.cpp 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. #include "pch.h"
  2. const char* c_szRadarLODs[] = {
  3. "Radar mode: All",
  4. "Radar mode: Default",
  5. "Radar mode: Target",
  6. "Radar mode: None"
  7. };
  8. /*
  9. "Radar mode: Ships",
  10. "Radar mode: Stations",
  11. "Radar mode: Treasure",
  12. "Radar mode: Asteroids",
  13. };
  14. */
  15. static const char* c_pszEmpty = "";
  16. const float rangeClipLabels = 1000.0f;
  17. const int c_iNotUseful = 0;
  18. const int c_iUsefulPart = 1;
  19. const int c_iUsefulTech = 2;
  20. //////////////////////////////////////////////////////////////////////////////
  21. //
  22. // Peripheral Radar Image
  23. //
  24. //////////////////////////////////////////////////////////////////////////////
  25. const int c_maskOrder = 0x01;
  26. const int c_maskTarget = c_maskOrder << c_cmdCurrent;
  27. const int c_maskAccepted = c_maskOrder << c_cmdAccepted;
  28. const int c_maskQueued = c_maskOrder << c_cmdQueued;
  29. const int c_maskEnemy = 0x08;
  30. const int c_maskThreat = 0x10;
  31. const int c_maskFlash = 0x20;
  32. const int c_maskMe = 0x80;
  33. const int c_maskSubject = 0x100;
  34. const int c_maskFlag = 0x200;
  35. const int c_maskArtifact = 0x400;
  36. const int c_maskHighlight = 0x800;
  37. class RadarImageImpl : public RadarImage {
  38. //////////////////////////////////////////////////////////////////////////////
  39. //
  40. // Types
  41. //
  42. //////////////////////////////////////////////////////////////////////////////
  43. class TextData
  44. {
  45. public:
  46. const char* m_pszName;
  47. int m_range;
  48. float m_shield;
  49. float m_hull;
  50. float m_fill;
  51. Command m_cmd;
  52. CommandID m_cid;
  53. Point m_position;
  54. Point m_direction;
  55. Color m_color;
  56. TextData(const char* pszName,
  57. int range,
  58. float shield,
  59. float hull,
  60. float fill,
  61. Command cmd,
  62. CommandID cid,
  63. const Point& position,
  64. const Point& direction,
  65. const Color& color)
  66. :
  67. m_pszName(pszName),
  68. m_range(range),
  69. m_shield(shield),
  70. m_hull(hull),
  71. m_fill (fill),
  72. m_cmd(cmd),
  73. m_cid(cid),
  74. m_position(position),
  75. m_direction(direction),
  76. m_color(color)
  77. {
  78. }
  79. TextData(const TextData& data)
  80. :
  81. m_pszName(data.m_pszName),
  82. m_range(data.m_range),
  83. m_shield(data.m_shield),
  84. m_hull(data.m_hull),
  85. m_fill(data.m_fill),
  86. m_cmd(data.m_cmd),
  87. m_cid(data.m_cid),
  88. m_position(data.m_position),
  89. m_direction(data.m_direction),
  90. m_color(data.m_color)
  91. {
  92. }
  93. };
  94. typedef TList<TextData> TextDataList;
  95. //////////////////////////////////////////////////////////////////////////////
  96. //
  97. // Members
  98. //
  99. //////////////////////////////////////////////////////////////////////////////
  100. TextDataList m_listTextData;
  101. TRef<Surface> m_psurfaceLastFired;
  102. TRef<Surface> m_psurfaceTargeted;
  103. TRef<Surface> m_psurfaceLocked;
  104. TRef<Surface> m_psurfacePartialLock;
  105. TRef<Surface> m_psurfaceEnemy;
  106. TRef<Surface> m_psurfaceMe;
  107. TRef<Surface> m_psurfaceSubject;
  108. TRef<Surface> m_psurfaceFlag;
  109. TRef<Surface> m_psurfaceArtifact;
  110. TRef<Surface> m_psurfaceTechIcon;
  111. TRef<Surface> m_psurfaceAccepted[c_cidMax];
  112. TRef<Surface> m_psurfaceQueued[c_cidMax];
  113. RadarLOD m_radarLOD;
  114. TVector<VertexL> m_vertices;
  115. TVector<WORD> m_indices;
  116. float m_fRoundRadarRadius;
  117. static Color s_colorNeutral;
  118. //////////////////////////////////////////////////////////////////////////////
  119. //
  120. // Evaluate gets called when the view size changes
  121. //
  122. //////////////////////////////////////////////////////////////////////////////
  123. void Evaluate (void)
  124. {
  125. Color color (0.5f, 0.5f, 0.5f, 0.25f);
  126. Rect rectImage = GetViewRect()->GetValue();
  127. {
  128. Point pointCenter = rectImage.Center();
  129. rectImage.Offset(-pointCenter);
  130. rectImage.Expand(-c_flBorderSide);
  131. }
  132. // establish the vertex and index array for the round radar circle, and set the indices
  133. const int cCount = 60;
  134. const float fAngleStep = RadiansFromDegrees (360.0f / cCount);
  135. m_vertices.SetCount (cCount);
  136. m_indices.SetCount (cCount * 2);
  137. for (int j = 0; j < cCount; j++)
  138. {
  139. m_indices.Set (j * 2, j);
  140. m_indices.Set ((j * 2) + 1, (j + 1) % m_vertices.GetCount ());
  141. }
  142. {
  143. m_fRoundRadarRadius = ((rectImage.YMax () - rectImage.YMin ()) * 0.48f);
  144. // this recalculates the vertices of the round radar circle
  145. for (int i = 0; i < m_vertices.GetCount (); i++)
  146. {
  147. float fTheta = fAngleStep * static_cast<float> (i),
  148. fCosTheta = cosf (fTheta),
  149. fSinTheta = sinf (fTheta);
  150. m_vertices.Set (i, VertexL (Vector (fCosTheta * m_fRoundRadarRadius, fSinTheta * m_fRoundRadarRadius, 0.0f), color));
  151. }
  152. }
  153. /*
  154. {
  155. m_vertices.Set (0, VertexL (Vector (rectImage.XMin(), rectImage.YMin(), 0.0f), color));
  156. m_vertices.Set (1, VertexL (Vector (rectImage.XMin(), rectImage.YMax(), 0.0f), color));
  157. m_vertices.Set (2, VertexL (Vector (rectImage.XMax(), rectImage.YMax(), 0.0f), color));
  158. m_vertices.Set (3, VertexL (Vector (rectImage.XMax(), rectImage.YMin(), 0.0f), color));
  159. }
  160. */
  161. }
  162. public:
  163. //////////////////////////////////////////////////////////////////////////////
  164. //
  165. // Constructor
  166. //
  167. //////////////////////////////////////////////////////////////////////////////
  168. RadarImageImpl(Modeler* pmodeler, Viewport* pviewport) :
  169. RadarImage(pviewport),
  170. m_radarLOD(c_rlDefault)
  171. {
  172. m_psurfaceEnemy = pmodeler->LoadSurface(AWF_FLIGHT_ENEMY_ICON, true);
  173. m_psurfaceMe = pmodeler->LoadSurface(AWF_FLIGHT_ME_ICON, true);
  174. m_psurfaceTargeted = pmodeler->LoadSurface(AWF_FLIGHT_TARGETED_ICON, true);
  175. m_psurfaceLocked = pmodeler->LoadSurface(AWF_FLIGHT_MISSILE_LOCKED_ICON, true);
  176. m_psurfacePartialLock = pmodeler->LoadSurface(AWF_FLIGHT_PARTIAL_MISSILE_LOCK_ICON, true);
  177. m_psurfaceSubject = pmodeler->LoadSurface(AWF_FLIGHT_SUBJECT_ICON, true);
  178. m_psurfaceFlag = pmodeler->LoadSurface(AWF_FLIGHT_FLAG_ICON, true);
  179. m_psurfaceArtifact = pmodeler->LoadSurface(AWF_FLIGHT_ARTIFACT_ICON, true);
  180. m_psurfaceTechIcon = pmodeler->LoadSurface("icontechbmp", true);
  181. for (CommandID i = c_cidAttack; (i < c_cidMax); i++)
  182. {
  183. if (c_cdAllCommands[i].szAccepted[0] != '\0')
  184. m_psurfaceAccepted[i] = pmodeler->LoadSurface(c_cdAllCommands[i].szAccepted, true);
  185. if (c_cdAllCommands[i].szQueued[0] != '\0')
  186. m_psurfaceQueued[i] = pmodeler->LoadSurface(c_cdAllCommands[i].szQueued, true);
  187. }
  188. m_psurfaceLastFired = pmodeler->LoadSurface(AWF_FLIGHT_LASTFIRED_ICON, true);
  189. }
  190. void SetRadarLOD(RadarLOD radarLOD)
  191. {
  192. m_radarLOD = radarLOD;
  193. }
  194. RadarLOD GetRadarLOD(void) const
  195. {
  196. return m_radarLOD;
  197. }
  198. //////////////////////////////////////////////////////////////////////////////
  199. //
  200. // Draw a blip expanded to fit around the object
  201. //
  202. //////////////////////////////////////////////////////////////////////////////
  203. void DrawExpandedBlip(Context* pcontext, float radius, Surface* psurface, const Color& color)
  204. {
  205. Point size = Point::Cast(psurface->GetSize());
  206. float xsize = size.X();
  207. float ysize = size.Y();
  208. float xsizeMid = xsize / 2;
  209. float ysizeMid = ysize / 2;
  210. float delta = radius / sqrt2;
  211. {
  212. float m = xsizeMid / 2;
  213. if (delta < m)
  214. delta = m;
  215. }
  216. pcontext->DrawImage3D(psurface, Rect( 0, 0, xsizeMid, ysizeMid), color, true, Point(-delta, -delta));
  217. pcontext->DrawImage3D(psurface, Rect(xsizeMid, 0, xsize, ysizeMid), color, true, Point( delta, -delta));
  218. pcontext->DrawImage3D(psurface, Rect(xsizeMid, ysizeMid, xsize, ysize), color, true, Point( delta, delta));
  219. pcontext->DrawImage3D(psurface, Rect( 0, ysizeMid, xsizeMid, ysize), color, true, Point(-delta, delta));
  220. }
  221. //////////////////////////////////////////////////////////////////////////////
  222. //
  223. // Draw a blip based on passed parameters
  224. //
  225. //////////////////////////////////////////////////////////////////////////////
  226. void DrawBlip(Context* pcontext,
  227. const Rect& rectImage,
  228. const Color& colorIcon,
  229. const Color& colorOther,
  230. unsigned char ucRadarState,
  231. ThingSite* pts,
  232. Surface* psurfaceIcon,
  233. const char* pszName,
  234. int range,
  235. float shield,
  236. float hull,
  237. float fill,
  238. Command cmd,
  239. CommandID cid,
  240. int maskBrackets,
  241. float lock,
  242. bool bIcon,
  243. bool bStats)
  244. {
  245. float radiusObject = pts->GetScreenRadius();
  246. {
  247. static const float maxRadius = sqrt2 * 80.0f;
  248. if (radiusObject > maxRadius)
  249. radiusObject = maxRadius;
  250. }
  251. float radiusBracket = 1.05f * radiusObject;
  252. float distanceToEdge = pts->GetDistanceToEdge();
  253. //Clip the brackets so that they are always entirely on screen
  254. if (radiusBracket > distanceToEdge + c_flBorderSide)
  255. radiusBracket = distanceToEdge + c_flBorderSide;
  256. const Point& positionObject = pts->GetScreenPosition();
  257. {
  258. //Draw the brackets around the "object"
  259. pcontext->Translate(positionObject);
  260. if (lock != 0.0f)
  261. {
  262. if (lock == 1.0f)
  263. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceLocked, Color::White());
  264. else
  265. DrawExpandedBlip(pcontext, radiusBracket + 40.0f * (1.0f - lock), m_psurfacePartialLock, Color::White());
  266. }
  267. if (maskBrackets & c_maskEnemy)
  268. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceEnemy, colorOther);
  269. if (maskBrackets & c_maskMe)
  270. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceMe, colorOther);
  271. if (maskBrackets & c_maskSubject)
  272. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceSubject, colorOther);
  273. if (maskBrackets & c_maskFlag)
  274. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceFlag, colorOther);
  275. else if (maskBrackets & c_maskArtifact)
  276. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceArtifact, colorOther);
  277. if (maskBrackets & c_maskTarget)
  278. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceTargeted, colorOther);
  279. if (maskBrackets & c_maskThreat)
  280. DrawExpandedBlip(pcontext, radiusBracket, m_psurfaceLastFired, colorOther);
  281. }
  282. Point directionCenter;
  283. {
  284. directionCenter.SetX(positionObject.X());
  285. directionCenter.SetY(GetWindow ()->GetRoundRadarMode()
  286. ? positionObject.Y()
  287. : (positionObject.Y() - rectImage.Size().Y() / 5.0f));
  288. float fLengthSquared = directionCenter.X() * directionCenter.X() + directionCenter.Y() * directionCenter.Y();
  289. if (fLengthSquared < 1.0f)
  290. {
  291. directionCenter.SetX(0.0f);
  292. directionCenter.SetY(-1.0f);
  293. }
  294. else
  295. {
  296. float f = float(-1.0 / sqrt(fLengthSquared));
  297. directionCenter.SetX(directionCenter.X() * f);
  298. directionCenter.SetY(directionCenter.Y() * f);
  299. }
  300. }
  301. Point positionIcon;
  302. if (ucRadarState != c_ucRadarOnScreenLarge)
  303. {
  304. positionIcon.SetX(0.0f);
  305. positionIcon.SetY(0.0f);
  306. }
  307. else
  308. {
  309. // the radius bracket is big, and the icon should appear near
  310. // the object instead of off it. Shrinking the radius bracket
  311. // accomplishes this.
  312. // XXX difficult to assess for now, Rob is inclined to leave the icon
  313. // XXX further away to avoid obscuring ships, so we agreed that I could
  314. // XXX check it in commented out.
  315. // radiusBracket *= 0.5f;
  316. //Get the vector from the object to the center of the screen
  317. //where this direction for something close to the center of the
  318. //screen is always straight down.
  319. {
  320. float f = (distanceToEdge < radiusBracket) ? distanceToEdge : radiusBracket;
  321. positionIcon.SetX(directionCenter.X() * f);
  322. positionIcon.SetY(directionCenter.Y() * f);
  323. }
  324. }
  325. if (bIcon)
  326. {
  327. pcontext->Translate(positionIcon);
  328. pcontext->SetBlendMode(BlendModeAdd);
  329. pcontext->DrawImage3D(psurfaceIcon, colorIcon, true);
  330. }
  331. if ((pszName[0] != '\0') || (range > 0) || bStats)
  332. {
  333. Point positionLabel = positionObject + positionIcon;
  334. if (maskBrackets & (c_maskTarget | c_maskAccepted | c_maskThreat))
  335. m_listTextData.PushEnd(TextData(pszName, range, shield, hull, fill, cmd, cid, positionLabel, directionCenter, colorOther));
  336. else
  337. m_listTextData.PushFront(TextData(pszName, range, shield, hull, fill, cmd, cid, positionLabel, directionCenter, colorOther));
  338. }
  339. }
  340. //////////////////////////////////////////////////////////////////////////////
  341. //
  342. // Render one blip for each object in the cluster
  343. //
  344. //////////////////////////////////////////////////////////////////////////////
  345. static int UsefulTreasure(IshipIGC* pship, ItreasureIGC* pt)
  346. {
  347. TreasureCode tc = pt->GetTreasureCode();
  348. switch (tc)
  349. {
  350. case c_tcPowerup:
  351. {
  352. if (!pship->GetCluster())
  353. return c_iNotUseful;
  354. }
  355. //no break
  356. case c_tcCash:
  357. case c_tcFlag:
  358. {
  359. return c_iUsefulPart;
  360. }
  361. break;
  362. case c_tcDevelopment:
  363. {
  364. IdevelopmentIGC* pd = trekClient.m_pCoreIGC->GetDevelopment(pt->GetTreasureID());
  365. assert (pd);
  366. return pd->IsObsolete(trekClient.GetSide()->GetDevelopmentTechs())
  367. ? c_iNotUseful
  368. : c_iUsefulPart; //It really is a tech, but use its icon instead of the special icon
  369. }
  370. break;
  371. default:
  372. {
  373. assert (tc == c_tcPart);
  374. IpartTypeIGC* ppt = trekClient.m_pCoreIGC->GetPartType(pt->GetTreasureID());
  375. assert (ppt);
  376. EquipmentType et = ppt->GetEquipmentType();
  377. if (et == ET_Pack)
  378. {
  379. if (pship->GetCluster() != NULL)
  380. {
  381. const DataPackTypeIGC* pdata = (const DataPackTypeIGC*)(ppt->GetData());
  382. if (pdata->packType == c_packFuel)
  383. {
  384. //Fuel is useful only if we have an afterburner
  385. return (pship->GetMountedPart(ET_Afterburner, 0) != NULL)
  386. ? c_iUsefulPart
  387. : c_iNotUseful;
  388. }
  389. else
  390. {
  391. assert (pdata->packType == c_packAmmo);
  392. Mount m = pship->GetHullType()->GetMaxWeapons();
  393. for (Mount i = 0; (i < m); i++)
  394. {
  395. IweaponIGC* pw = (IweaponIGC*)(pship->GetMountedPart(ET_Weapon, i));
  396. if (pw && (pw->GetAmmoPerShot() != 0))
  397. return c_iUsefulPart;
  398. }
  399. }
  400. }
  401. return c_iNotUseful;
  402. }
  403. else
  404. {
  405. if (!(ppt->GetEffectTechs() <= trekClient.GetSide()->GetDevelopmentTechs()))
  406. return c_iUsefulTech;
  407. if (IlauncherTypeIGC::IsLauncherType(et) && pship->GetCluster() && pship->GetHullType()->CanMount(ppt, 0))
  408. return c_iUsefulPart;
  409. return c_iNotUseful;
  410. }
  411. }
  412. break;
  413. }
  414. }
  415. void RenderBlips(Context* pcontext, const Rect& rectImage)
  416. {
  417. IclusterIGC* pcluster = trekClient.GetCluster();
  418. if (pcluster == NULL)
  419. return;
  420. const ModelListIGC* models = pcluster->GetPickableModels();
  421. ZAssert(models != NULL);
  422. bool bRangeLabels = !TrekWindow::CommandCamera(GetWindow()->GetCameraMode());
  423. assert (trekClient.GetShip()->GetCluster() || !bRangeLabels);
  424. //
  425. // Draw a blip for every model in the cluster
  426. //
  427. IshipIGC* pshipSource = trekClient.GetShip()->GetSourceShip();
  428. const Vector& vecPositionPlayer = pshipSource->GetPosition();
  429. float radiusSource = pshipSource->GetRadius();
  430. ImodelIGC* pmodelOrders[c_cmdMax];
  431. {
  432. // For command targets not in the current sector ... show the user how to get there.
  433. for (Command i = 0; (i <= c_cmdCurrent); i++) //Explicitly do not handle the case of planned
  434. {
  435. pmodelOrders[i] = trekClient.GetShip()->GetCommandTarget(i);
  436. if (pmodelOrders[i])
  437. {
  438. IclusterIGC* c = pmodelOrders[i]->GetCluster();
  439. if (pmodelOrders[i]->GetObjectType() == OT_ship)
  440. {
  441. pmodelOrders[i] = ((IshipIGC*)pmodelOrders[i])->GetSourceShip();
  442. if (c == NULL)
  443. c = trekClient.GetCluster(trekClient.GetShip(), pmodelOrders[i]);
  444. }
  445. if (c == NULL)
  446. pmodelOrders[i] = NULL;
  447. else
  448. {
  449. IclusterIGC* pcluster = trekClient.GetShip()->GetCluster();
  450. if (pcluster && (c != pcluster))
  451. {
  452. // The target is not in the sector ... find out how to get to the target
  453. pmodelOrders[i] = FindPath(trekClient.GetShip(), pmodelOrders[i], false);
  454. }
  455. }
  456. }
  457. }
  458. }
  459. const ShipListIGC* psubjects;
  460. if (bRangeLabels)
  461. psubjects = NULL;
  462. else
  463. psubjects = GetWindow()->GetConsoleImage()->GetSubjects();
  464. IsideIGC* psideMine = trekClient.GetShip()->GetSide();
  465. float capacity = trekClient.m_pCoreIGC->GetFloatConstant(c_fcidCapacityHe3) *
  466. psideMine->GetGlobalAttributeSet().GetAttribute(c_gaMiningCapacity);
  467. Time now = Time::Now();
  468. ImodelIGC* pmodelEnemy = bRangeLabels
  469. ? FindTarget(pshipSource, c_ttShip | c_ttEnemy | c_ttNearest)
  470. : NULL;
  471. for (ModelLinkIGC* l = models->first();
  472. (l != NULL); l = l->next())
  473. {
  474. ImodelIGC* pmodel = l->data();
  475. if (pmodel->GetVisibleF() && pshipSource->CanSee(pmodel))
  476. {
  477. ObjectType type = pmodel->GetObjectType();
  478. Surface* psurfaceIcon = (Surface*)(pmodel->GetIcon());
  479. if (psurfaceIcon)
  480. {
  481. int maskBrackets = 0x00;
  482. const char* pszName = pmodel->GetName();
  483. Command cmd;
  484. CommandID cidOrder = c_cidNone;
  485. {
  486. for (Command i = 0; (i < c_cmdMax); i++)
  487. {
  488. if (pmodel == pmodelOrders[i])
  489. {
  490. maskBrackets |= (c_maskOrder << i);
  491. CommandID cid = trekClient.GetShip()->GetCommandID(i);
  492. if (cid != c_cidNone)
  493. {
  494. cmd = i;
  495. cidOrder = cid;
  496. }
  497. }
  498. }
  499. }
  500. float lock = 0.0f;
  501. if (maskBrackets & c_maskTarget)
  502. {
  503. ImagazineIGC* magazine = (ImagazineIGC*)(trekClient.GetShip()->GetMountedPart(ET_Magazine, 0));
  504. if (magazine)
  505. lock = magazine->GetLock();
  506. }
  507. float separation = (pmodel->GetPosition() - vecPositionPlayer).Length();
  508. int range;
  509. {
  510. if ((pmodel == pshipSource) || !bRangeLabels)
  511. range = 0;
  512. else
  513. range = int(separation + 0.5f);
  514. }
  515. separation -= radiusSource + pmodel->GetRadius();
  516. if (type == OT_treasure)
  517. {
  518. if (((ItreasureIGC*)pmodel)->GetTreasureCode() == c_tcFlag)
  519. maskBrackets |= c_maskHighlight;
  520. }
  521. else
  522. {
  523. SideID sidFlag = pmodel->GetFlag();
  524. if (sidFlag != NA)
  525. maskBrackets |= (sidFlag == SIDE_TEAMLOBBY) ? c_maskArtifact : c_maskFlag;
  526. }
  527. ThingSite* pts = pmodel->GetThingSite();
  528. unsigned char ucRadarState = pts->GetRadarState();
  529. if (psubjects && (type == OT_ship) && psubjects->find((IshipIGC*)pmodel))
  530. maskBrackets |= c_maskSubject;
  531. if (pmodel == pmodelEnemy)
  532. maskBrackets |= c_maskEnemy;
  533. {
  534. const DamageBucketList* b = pmodel->GetDamageBuckets();
  535. if (b->n() != 0)
  536. {
  537. assert (b->n() == 1);
  538. DamageBucket* db = b->first()->data();
  539. maskBrackets |= (db->flash(now))
  540. ? (c_maskThreat | c_maskFlash)
  541. : c_maskThreat;
  542. }
  543. }
  544. //
  545. // Color for the side
  546. //
  547. IsideIGC* pside = pmodel->GetSide();
  548. if (pmodel == pshipSource)
  549. maskBrackets |= c_maskMe;
  550. Color color = pside
  551. ? ((maskBrackets & c_maskFlash) ? Color::Red() : pside->GetColor())
  552. : s_colorNeutral;
  553. /*
  554. static const int closeRange = 100;
  555. static const int farRange = 1000;
  556. static const float closeAlpha = 0.75f;
  557. static const float farAlpha = 0.25f;
  558. color.SetAlpha((range < closeRange)
  559. ? closeAlpha
  560. : ((range > farRange)
  561. ? farAlpha
  562. : (farAlpha +
  563. (float(range - farRange) * (closeAlpha - farAlpha) / float(closeRange - farRange)))));
  564. */
  565. bool bIcon = true;
  566. bool bLabel = ((maskBrackets & (c_maskTarget |
  567. c_maskAccepted |
  568. c_maskQueued |
  569. c_maskHighlight |
  570. c_maskThreat |
  571. c_maskFlag |
  572. c_maskArtifact)) != 0);
  573. bool bStats = bLabel;
  574. if (bLabel)
  575. {
  576. if ((type == OT_treasure) &&
  577. (UsefulTreasure(pshipSource, (ItreasureIGC*)pmodel) == c_iUsefulTech))
  578. {
  579. psurfaceIcon = m_psurfaceTechIcon;
  580. }
  581. }
  582. else
  583. {
  584. if (m_radarLOD == c_rlMinimal)
  585. {
  586. if (pmodel != pshipSource)
  587. {
  588. bIcon = false;
  589. range = 0;
  590. }
  591. }
  592. else
  593. {
  594. switch (type)
  595. {
  596. case OT_ship:
  597. {
  598. switch (m_radarLOD)
  599. {
  600. case c_rlAll:
  601. {
  602. bLabel = bStats = true;
  603. if ((ucRadarState == c_ucRadarOffScreen) && (pside == psideMine))
  604. range = 0;
  605. }
  606. break;
  607. case c_rlDefault:
  608. {
  609. if ((ucRadarState != c_ucRadarOffScreen) || (separation < rangeClipLabels))
  610. bLabel = true;
  611. if (pside == psideMine)
  612. range = 0;
  613. else
  614. bStats = true;
  615. }
  616. break;
  617. case c_rlTarget:
  618. {
  619. if (pside == psideMine)
  620. {
  621. if (pmodel != pshipSource)
  622. {
  623. bIcon = false;
  624. range = 0;
  625. }
  626. }
  627. else
  628. {
  629. if (ucRadarState != c_ucRadarOffScreen)
  630. bStats = true;
  631. if (separation < rangeClipLabels)
  632. bLabel = true;
  633. }
  634. }
  635. break;
  636. }
  637. }
  638. break;
  639. case OT_station:
  640. {
  641. if (((IstationIGC*)pmodel)->GetBaseStationType()->HasCapability(c_sabmPedestal))
  642. {
  643. if (separation >= rangeClipLabels)
  644. {
  645. bIcon = bLabel = bStats = false;
  646. range = 0;
  647. }
  648. }
  649. else
  650. {
  651. switch (m_radarLOD)
  652. {
  653. case c_rlAll:
  654. {
  655. bLabel = bStats = true;
  656. }
  657. break;
  658. case c_rlDefault:
  659. {
  660. if ((separation >= rangeClipLabels) || (ucRadarState == c_ucRadarOffScreen))
  661. range = 0;
  662. }
  663. break;
  664. case c_rlTarget:
  665. {
  666. range = 0;
  667. if ((pside == psideMine) && (ucRadarState == c_ucRadarOffScreen))
  668. bIcon = false;
  669. }
  670. break;
  671. }
  672. }
  673. }
  674. break;
  675. case OT_missile:
  676. {
  677. if (m_radarLOD != c_rlAll)
  678. {
  679. ImodelIGC* pmodelTarget = ((ImissileIGC*)pmodel)->GetTarget();
  680. if ((pmodelTarget == NULL) || (pmodelTarget->GetSide() != psideMine))
  681. {
  682. bIcon = false;
  683. range = 0;
  684. }
  685. }
  686. }
  687. break;
  688. case OT_probe:
  689. case OT_mine:
  690. {
  691. switch (m_radarLOD)
  692. {
  693. case c_rlAll:
  694. {
  695. if (pside == psideMine)
  696. {
  697. if ((ucRadarState == c_ucRadarOffScreen) && (separation >= rangeClipLabels))
  698. range = 0;
  699. }
  700. else
  701. {
  702. if (ucRadarState != c_ucRadarOffScreen)
  703. bLabel = true;
  704. }
  705. bStats = true;
  706. }
  707. break;
  708. case c_rlDefault:
  709. {
  710. if (pside == psideMine)
  711. {
  712. if (separation >= rangeClipLabels)
  713. range = 0;
  714. }
  715. }
  716. break;
  717. case c_rlTarget:
  718. {
  719. if ((pside == psideMine) || (separation >= rangeClipLabels))
  720. {
  721. bIcon = false;
  722. range = 0;
  723. }
  724. }
  725. break;
  726. }
  727. }
  728. break;
  729. case OT_treasure:
  730. {
  731. int iUseful = UsefulTreasure(pshipSource, (ItreasureIGC*)pmodel);
  732. if (iUseful != c_iNotUseful)
  733. {
  734. bLabel = (m_radarLOD == c_rlAll);
  735. if ((m_radarLOD == c_rlTarget) && (separation >= rangeClipLabels))
  736. {
  737. bIcon = false;
  738. range = 0;
  739. }
  740. else if (iUseful == c_iUsefulTech)
  741. {
  742. psurfaceIcon = m_psurfaceTechIcon;
  743. }
  744. }
  745. else if (m_radarLOD != c_rlAll)
  746. {
  747. bIcon = false;
  748. range = 0;
  749. }
  750. }
  751. break;
  752. case OT_asteroid:
  753. {
  754. switch (m_radarLOD)
  755. {
  756. case c_rlAll:
  757. {
  758. if ((pszName[0] == '\0') || (pszName[0] == 'A'))
  759. {
  760. if (separation >= rangeClipLabels)
  761. {
  762. bIcon = false;
  763. range = 0;
  764. }
  765. else if (range == 0)
  766. bIcon = false;
  767. }
  768. else
  769. bLabel = bStats = true;
  770. }
  771. break;
  772. case c_rlDefault:
  773. {
  774. if ((pszName[0] == '\0') || (pszName[0] == 'A'))
  775. {
  776. if (separation >= rangeClipLabels)
  777. {
  778. bIcon = false;
  779. range = 0;
  780. }
  781. else if (range == 0)
  782. bIcon = false;
  783. }
  784. }
  785. break;
  786. case c_rlTarget:
  787. {
  788. if (separation >= rangeClipLabels)
  789. {
  790. bIcon = false;
  791. range = 0;
  792. }
  793. else if (range == 0)
  794. bIcon = false;
  795. }
  796. break;
  797. }
  798. }
  799. break;
  800. case OT_warp:
  801. {
  802. bLabel = (m_radarLOD <= c_rlDefault);
  803. if ((m_radarLOD == c_rlTarget) && (separation >= rangeClipLabels))
  804. range = 0;
  805. }
  806. break;
  807. }
  808. }
  809. }
  810. float shield = 2.0f;
  811. float hull = 2.0f;
  812. float fill = 2.0f;
  813. if (!bLabel)
  814. {
  815. pszName = c_pszEmpty;
  816. }
  817. else if (pszName[0] == '\0')
  818. {
  819. pszName = GetModelName(pmodel);
  820. }
  821. if (bStats)
  822. {
  823. switch(type)
  824. {
  825. case OT_ship:
  826. {
  827. IshipIGC* pship = static_cast<IshipIGC*> (pmodel);
  828. IshieldIGC* pshield = static_cast<IshieldIGC*> (pship->GetMountedPart(ET_Shield, 0));
  829. shield = pshield ? pshield->GetFraction() : 2.0f;
  830. hull = ((IdamageIGC*)pmodel)->GetFraction();
  831. // this really only works if the server updates the client with
  832. // the information. We would have to add a new message type
  833. // for that to happen, so for now I'm just commenting it out and
  834. // moving on.
  835. /*
  836. if (pship->GetPilotType () == c_ptMiner)
  837. {
  838. fill = pship->GetOre () / capacity;
  839. if (fill > 1.0f)
  840. fill = 1.0f;
  841. }
  842. */
  843. }
  844. break;
  845. case OT_station:
  846. {
  847. shield = ((IstationIGC*)pmodel)->GetShieldFraction();
  848. hull = ((IdamageIGC*)pmodel)->GetFraction();
  849. }
  850. break;
  851. case OT_asteroid:
  852. {
  853. hull = ((IdamageIGC*)pmodel)->GetFraction();
  854. float ore = ((IasteroidIGC*)pmodel)->GetOre();
  855. if (ore != 0.0f)
  856. {
  857. // this is displaying how many shiploads of ore are on the asteroid.
  858. // more than two is shown as full.
  859. fill = ore / (2.0f * capacity);
  860. if (fill > 1.0f)
  861. fill = 1.0f;
  862. }
  863. }
  864. break;
  865. case OT_mine:
  866. {
  867. fill = ((ImineIGC*)pmodel)->GetTimeFraction();
  868. }
  869. break;
  870. case OT_probe:
  871. {
  872. fill = ((IprobeIGC*)pmodel)->GetTimeFraction();
  873. hull = ((IprobeIGC*)pmodel)->GetFraction();
  874. }
  875. break;
  876. }
  877. }
  878. //
  879. // Draw the Blip
  880. //
  881. Color colorOther(color);
  882. if ((maskBrackets & (c_maskTarget | c_maskAccepted | c_maskThreat | c_maskHighlight | c_maskFlag | c_maskArtifact)) == 0)
  883. colorOther = (maskBrackets & c_maskQueued)
  884. ? (colorOther * 0.75f)
  885. : (colorOther * 0.5f);
  886. pcontext->PushState();
  887. DrawBlip(pcontext,
  888. rectImage,
  889. color,
  890. colorOther,
  891. ucRadarState,
  892. pts,
  893. psurfaceIcon,
  894. pszName,
  895. range,
  896. shield,
  897. hull,
  898. fill,
  899. cmd,
  900. cidOrder,
  901. maskBrackets,
  902. lock,
  903. bIcon,
  904. bStats);
  905. pcontext->PopState();
  906. }
  907. }
  908. }
  909. }
  910. //////////////////////////////////////////////////////////////////////////////
  911. //
  912. // Draw a circle bordering the round radar
  913. //
  914. //////////////////////////////////////////////////////////////////////////////
  915. void RenderRoundBorder (Context* pcontext, const Rect& rectImage)
  916. {
  917. pcontext->PushState ();
  918. pcontext->SetClipping (false);
  919. pcontext->SetBlendMode (BlendModeSourceAlpha);
  920. pcontext->DrawLines(m_vertices, m_indices);
  921. pcontext->PopState ();
  922. }
  923. //////////////////////////////////////////////////////////////////////////////
  924. //
  925. // Render the image
  926. //
  927. //////////////////////////////////////////////////////////////////////////////
  928. void Render(Context* pcontext)
  929. {
  930. if (m_radarLOD != c_rlNone)
  931. {
  932. //
  933. // Use flat shading
  934. //
  935. pcontext->SetShadeMode(ShadeModeFlat);
  936. pcontext->SetLinearFilter(false, true);
  937. //
  938. // Shrink the rect size by half the size of the gauge bitmap
  939. // and center the rect around the origin
  940. //
  941. Rect rectImage = GetViewRect()->GetValue();
  942. {
  943. Point pointCenter = rectImage.Center();
  944. pcontext->Translate(pointCenter);
  945. }
  946. //
  947. // Draw the round border if appropriate
  948. //
  949. if (GetWindow ()->GetRoundRadarMode ())
  950. RenderRoundBorder (pcontext, rectImage);
  951. //
  952. // Draw some Blips
  953. //
  954. RenderBlips(pcontext, rectImage);
  955. //
  956. // Draw the text
  957. //
  958. TRef<IEngineFont> pfont = TrekResources::SmallFont();
  959. float heightFont = float(pfont->GetHeight());
  960. TextDataList::Iterator iter(m_listTextData);
  961. while (!iter.End())
  962. {
  963. const TextData& data = iter.Value();
  964. float lines = 0.0f;
  965. float width = 0.0f;
  966. if (data.m_pszName[0] != '\0')
  967. {
  968. float w = (float)(pfont->GetTextExtent(data.m_pszName).X());
  969. if (w > width)
  970. width = w;
  971. lines += 1.0f;
  972. }
  973. char szRange[20];
  974. if (data.m_range > 0)
  975. {
  976. _itoa(data.m_range, szRange, 10);
  977. float w = (float)(pfont->GetTextExtent(szRange).X());
  978. if (w > width)
  979. width = w;
  980. lines += 1.0f;
  981. }
  982. if (data.m_shield <= 1.0f)
  983. {
  984. lines += 0.5f;
  985. }
  986. if (data.m_hull <= 1.0f)
  987. {
  988. lines += 0.5f;
  989. }
  990. if (data.m_fill <= 1.0f)
  991. {
  992. lines += 0.5f;
  993. }
  994. Surface* psurfaceIcon = NULL;
  995. float xshift;
  996. if (data.m_cid != c_cidNone)
  997. {
  998. assert (data.m_cid >= 0);
  999. assert (data.m_cid < c_cidMax);
  1000. psurfaceIcon = (data.m_cmd != c_cmdQueued) ? m_psurfaceAccepted[data.m_cid] : m_psurfaceQueued[data.m_cid];
  1001. if (psurfaceIcon)
  1002. {
  1003. Point size = Point::Cast(psurfaceIcon->GetSize());
  1004. xshift = size.X();
  1005. width += xshift;
  1006. }
  1007. }
  1008. //Find the offset to center the text at position + offset
  1009. Point offset(data.m_position.X() - 0.5f * width, data.m_position.Y() + heightFont * 0.5f * (lines - 2.0f));
  1010. //Adjust the offset by the amount required to move a point from the center to the edge
  1011. //in the specified direction
  1012. {
  1013. float w = width + 15.0f;
  1014. float h = heightFont * lines + 15.0f;
  1015. float x = data.m_direction.X();
  1016. float y = data.m_direction.Y();
  1017. if (x == 0.0f)
  1018. y = (y < 0.0f) ? -h : h;
  1019. else if (y == 0.0f)
  1020. x = (x <= 0.0f) ? -w : w;
  1021. else
  1022. {
  1023. float tX = w / float(fabs(x));
  1024. float tY = h / float(fabs(y));
  1025. float tMin = (tX < tY) ? tX : tY;
  1026. x *= tMin;
  1027. y *= tMin;
  1028. }
  1029. offset.SetX(offset.X() + x * 0.5f);
  1030. offset.SetY(offset.Y() + y * 0.5f);
  1031. if (psurfaceIcon)
  1032. {
  1033. offset.SetX(offset.X() + xshift * 0.5f);
  1034. pcontext->DrawImage3D(psurfaceIcon, data.m_color, true, offset);
  1035. offset.SetX(offset.X() + xshift * 0.5f);
  1036. }
  1037. }
  1038. if (data.m_pszName[0] != '\0')
  1039. {
  1040. pcontext->DrawString(pfont, data.m_color, offset, ZString(data.m_pszName));
  1041. offset.SetY(offset.Y() - heightFont);
  1042. }
  1043. if (data.m_range > 0)
  1044. {
  1045. pcontext->DrawString(pfont, data.m_color, offset, ZString(szRange));
  1046. offset.SetY(offset.Y() - heightFont);
  1047. }
  1048. if ((data.m_hull <= 1.0f) || (data.m_fill <= 1.0f))
  1049. {
  1050. const float c_width = 16.0f;
  1051. float xOffset = float(floor(offset.X()));
  1052. float yOffset = float(floor(offset.Y() + heightFont - 4.0f));
  1053. // draw the ore fill state if needed
  1054. if (data.m_fill <= 1.0f)
  1055. {
  1056. Rect rectFill (xOffset, yOffset, xOffset + (c_width * data.m_fill), yOffset + 2.0f);
  1057. pcontext->FillRect (rectFill, data.m_color);
  1058. // if the value isn't 1.0f, the bar has two parts, here we draw the "empty" part
  1059. if (data.m_fill < 1.0f)
  1060. {
  1061. rectFill.SetXMin(rectFill.XMax());
  1062. rectFill.SetXMax(xOffset + c_width);
  1063. pcontext->FillRect(rectFill, Color(0.333f, 0.0f, 0.0f));
  1064. }
  1065. yOffset -= 4.0f;
  1066. }
  1067. // if shield is valid, draw it and update the hull bar location
  1068. if (data.m_shield <= 1.0f)
  1069. {
  1070. Rect rectShield (xOffset, yOffset, xOffset + c_width * data.m_shield, yOffset + 2.0f);
  1071. pcontext->FillRect (rectShield, data.m_color);
  1072. // if the value isn't 1.0f, the bar has two parts, here we draw the "empty" part
  1073. if (data.m_shield < 1.0f)
  1074. {
  1075. rectShield.SetXMin(rectShield.XMax());
  1076. rectShield.SetXMax(xOffset + c_width);
  1077. pcontext->FillRect(rectShield, Color(1.0f, 0.0f, 0.0f));
  1078. }
  1079. yOffset -= 4.0f;
  1080. }
  1081. // if hull is valid, so draw it and update the hull bar location
  1082. if (data.m_hull <= 1.0f)
  1083. {
  1084. Rect rectHull (xOffset, yOffset, xOffset + c_width * data.m_hull, yOffset + 2.0f);
  1085. pcontext->FillRect(rectHull, data.m_color);
  1086. // if the value isn't 1.0f, the bar has two parts, here we draw the "empty" part
  1087. if (data.m_hull < 1.0f)
  1088. {
  1089. rectHull.SetXMin(rectHull.XMax());
  1090. rectHull.SetXMax(xOffset + c_width);
  1091. pcontext->FillRect(rectHull, Color(1.0f, 0.0f, 0.0f));
  1092. }
  1093. }
  1094. }
  1095. iter.Next();
  1096. }
  1097. m_listTextData.SetEmpty();
  1098. }
  1099. }
  1100. };
  1101. Color RadarImageImpl::s_colorNeutral(1, 1, 1);
  1102. //////////////////////////////////////////////////////////////////////////////
  1103. //
  1104. // RadarImage Constructor
  1105. //
  1106. //////////////////////////////////////////////////////////////////////////////
  1107. TRef<RadarImage> RadarImage::Create(Modeler* pmodeler, Viewport* pviewport)
  1108. {
  1109. return new RadarImageImpl(pmodeler, pviewport);
  1110. }