cadetflightimage.cpp 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738
  1. #include "pch.h"
  2. #include "sounds.h"
  3. //////////////////////////////////////////////////////////////////////////////
  4. //
  5. // Artwork
  6. //
  7. //////////////////////////////////////////////////////////////////////////////
  8. #define AWF_EXPLOSION_00 "dcexp20bmp"
  9. #define AWF_EXPLOSION_01 "dcexp22bmp"
  10. #define AWF_EXPLOSION_02 "dcexp23bmp"
  11. #define AWF_EXPLOSION_03 "dcexp24bmp"
  12. #define AWF_SHOCKWAVE "fx18bmp"
  13. #define AWF_SHIELD_FLARE "lens"
  14. #define AWF_SHIELD_FLARE_TEXTURE "dcfx09bmp"
  15. //////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Indicator Image
  18. //
  19. //////////////////////////////////////////////////////////////////////////////
  20. class IndicatorImage : public WrapImage
  21. {
  22. TRef<Surface> m_psurfaceDirection;
  23. TRef<Surface> m_psurfaceCenter;
  24. TRef<Surface> m_psurfaceLead;
  25. TRef<CadetGameContext> m_pgameContext;
  26. public:
  27. IndicatorImage(Modeler* pmodeler, Viewport* pviewport, CadetGameContext* pgameContext) :
  28. WrapImage(Image::GetEmpty(), pviewport),
  29. m_pgameContext(pgameContext)
  30. {
  31. m_psurfaceDirection = pmodeler->LoadSurface("dcdirectionbmp", true);
  32. m_psurfaceCenter = pmodeler->LoadSurface("dcdirectionnewbmp", true);
  33. m_psurfaceLead = pmodeler->LoadSurface("dcleadbmp", true);
  34. m_psurfaceDirection->SetColorKey(Color(0, 0, 0));
  35. m_psurfaceCenter ->SetColorKey(Color(0, 0, 0));
  36. m_psurfaceLead ->SetColorKey(Color(0, 0, 0));
  37. }
  38. void SetViewport(Viewport* pvalue) { SetChild(1, pvalue); }
  39. Viewport* GetViewport() { return Viewport::Cast(GetChild(1)); }
  40. Camera* GetCamera() { return GetViewport()->GetCamera(); }
  41. RectValue* GetViewRect() { return GetViewport()->GetViewRect(); }
  42. void RenderDirectionIndicator(Context* pcontext)
  43. {
  44. const Vector& myVelocity = m_pgameContext->GetShip()->GetVelocity();
  45. int speed = (int)(myVelocity.Length() + 0.5f);
  46. if (speed != 0)
  47. {
  48. Point pointNDC;
  49. if (GetCamera()->TransformDirectionToNDC(myVelocity, pointNDC)) {
  50. const Rect& rect = GetViewRect()->GetValue();
  51. Point pointImage = rect.TransformNDCToImage(pointNDC);
  52. if (rect.Inside(pointImage)) {
  53. pcontext->DrawImage(m_psurfaceDirection, true, pointImage);
  54. }
  55. }
  56. }
  57. }
  58. void RenderCenterIndicator(Context* pcontext)
  59. {
  60. pcontext->DrawImage(m_psurfaceCenter, true, GetViewRect()->GetValue().Center());
  61. }
  62. void RenderLeadIndicator(Context* pcontext)
  63. {
  64. //ImodelIGC* targetModel = m_pgameContext->GetShip()->GetCommandTarget(c_cmdCurrent);
  65. ImodelIGC* targetModel = FindClosestTarget();
  66. if (
  67. targetModel
  68. && (targetModel->GetCluster() == m_pgameContext->GetCluster())
  69. && m_pgameContext->GetShip()->CanSee(targetModel)
  70. ) {
  71. IweaponIGC* w = (IweaponIGC*)m_pgameContext->GetShip()->GetMountedPart(ET_Weapon, 0);
  72. if (w) {
  73. Vector vecLeadPosition;
  74. float t = solveForLead(m_pgameContext->GetShip(), targetModel, w, &vecLeadPosition);
  75. if (t <= w->GetLifespan()) {
  76. Point pointNDC;
  77. if (GetCamera()->TransformDirectionToNDC(vecLeadPosition, pointNDC)) {
  78. pcontext->DrawImage(
  79. m_psurfaceLead,
  80. true,
  81. GetViewport()->TransformNDCToImage(pointNDC)
  82. );
  83. }
  84. }
  85. }
  86. }
  87. }
  88. void Render(Context* pcontext)
  89. {
  90. if (m_pgameContext->GetShip())
  91. {
  92. //
  93. // Rendering attributes
  94. //
  95. pcontext->SetShadeMode(ShadeModeFlat);
  96. pcontext->SetColor(Color(1, 1, 1));
  97. pcontext->SetLinearFilter(false, true);
  98. pcontext->Clip(GetViewRect()->GetValue());
  99. //
  100. // Draw the indicators
  101. //
  102. RenderCenterIndicator(pcontext);
  103. RenderDirectionIndicator(pcontext);
  104. RenderLeadIndicator(pcontext);
  105. }
  106. }
  107. ImodelIGC* FindClosestTarget()
  108. {
  109. if (!m_pgameContext->GetCluster())
  110. return NULL;
  111. SideID sideID = m_pgameContext->GetShip()->GetSide()->GetObjectID();
  112. const ModelListIGC* models = m_pgameContext->GetCluster()->GetModels();
  113. assert (models);
  114. TRef<ImodelIGC> pmodelClosest;
  115. float lengthSquaredClosest = 1;
  116. for (ModelLinkIGC* l = models->first(); (l != NULL); l = l->next())
  117. {
  118. ImodelIGC* pmodel = l->data();
  119. if (pmodel != m_pgameContext->GetShip() &&
  120. pmodel->GetObjectType() == OT_ship &&
  121. pmodel->GetSide()->GetObjectID() != sideID)
  122. {
  123. const Vector& positionModel = pmodel->GetPosition();
  124. Point pointNDC;
  125. if (GetCamera()->TransformLocalToNDC(positionModel, pointNDC))
  126. {
  127. float lengthSquared = pointNDC.LengthSquared();
  128. if (lengthSquared < lengthSquaredClosest)
  129. {
  130. lengthSquaredClosest = lengthSquared;
  131. pmodelClosest = pmodel;
  132. }
  133. }
  134. }
  135. }
  136. return pmodelClosest;
  137. }
  138. };
  139. //////////////////////////////////////////////////////////////////////////////
  140. //
  141. // BillboardType
  142. //
  143. //////////////////////////////////////////////////////////////////////////////
  144. class BillboardType {
  145. public:
  146. TRef<AnimatedImage> m_pimage;
  147. float m_lifespan;
  148. BillboardType()
  149. {
  150. }
  151. BillboardType(Modeler* pmodeler, const char* textureName, float lifespan, int nRows, int nCols) :
  152. m_lifespan(lifespan)
  153. {
  154. TRef<Surface> psurface = pmodeler->LoadSurface(textureName, true);
  155. if (psurface) {
  156. m_pimage = new AnimatedImage(new Number(0.0f), psurface, nRows, nCols);
  157. }
  158. }
  159. BillboardType(const BillboardType& type) :
  160. m_pimage(type.m_pimage),
  161. m_lifespan(type.m_lifespan)
  162. {
  163. }
  164. void Purge(void)
  165. {
  166. m_pimage = NULL;
  167. }
  168. };
  169. //////////////////////////////////////////////////////////////////////////////
  170. //
  171. // Timed Billboard Geo
  172. //
  173. //////////////////////////////////////////////////////////////////////////////
  174. class TimedBillboardGeo : public Geo, public IGeoCallback {
  175. private:
  176. Vector m_vecPosition;
  177. float m_angle;
  178. float m_lifespan;
  179. float m_timeStart;
  180. float m_scale;
  181. TRef<Image> m_pimage;
  182. Number* GetTime() { return Number::Cast(GetChild(0)); }
  183. public:
  184. TimedBillboardGeo(
  185. Number* ptime,
  186. const Vector& vecPosition,
  187. float scale,
  188. AnimatedImage* pimageArg,
  189. float lifespan
  190. ) :
  191. Geo(ptime),
  192. m_vecPosition(vecPosition),
  193. m_timeStart(ptime->GetValue()),
  194. m_lifespan(lifespan),
  195. m_scale(scale),
  196. m_angle(random(0, 2 * pi))
  197. {
  198. m_pimage =
  199. new AnimatedImage(
  200. Divide(
  201. Subtract(ptime, ptime->MakeConstant()),
  202. new Number(lifespan)
  203. ),
  204. pimageArg
  205. );
  206. }
  207. void Evaluate()
  208. {
  209. if (GetTime()->GetValue() - m_timeStart > m_lifespan) {
  210. SetEmpty();
  211. }
  212. }
  213. void Render(Context* pcontext)
  214. {
  215. pcontext->DrawCallbackGeo(this);
  216. }
  217. void RenderCallback(Context* pcontext)
  218. {
  219. pcontext->SetBlendMode(BlendModeAdd);
  220. pcontext->SetColor(Color(1, 1, 1));
  221. pcontext->SetZWrite(false);
  222. pcontext->PreTranslate(m_vecPosition);
  223. pcontext->SetFaceCameraTransform();
  224. pcontext->PreRotate(Vector(0, 0, 1), m_angle);
  225. pcontext->PreScale(m_scale);
  226. // !!! animate alpha
  227. m_pimage->Update();
  228. pcontext->SetTexture(m_pimage->GetSurface());
  229. Geo::GetWhiteEmissiveSquare()->Render(pcontext);
  230. }
  231. ZString GetFunctionName()
  232. {
  233. return "TimedBillboardGeo";
  234. }
  235. };
  236. //////////////////////////////////////////////////////////////////////////////
  237. //
  238. // Forward Declarations
  239. //
  240. //////////////////////////////////////////////////////////////////////////////
  241. class CadetFlightImageImpl;
  242. TRef<ClusterSite> CreateClusterSite(Modeler* pmodeler, Number* ptime, Viewport* pviewport, CadetFlightImageImpl* pflightImg);
  243. TRef<ThingSite> CreateThingSite(ImodelIGC* pModel, CadetFlightImageImpl* pflightImg);
  244. class ThingSitePriv : public ThingSite
  245. {
  246. public:
  247. virtual void UpdateScreenPosition(
  248. const Point& pointScreenPosition,
  249. float fScreenRadius,
  250. float distanceToEdge,
  251. unsigned char ucRadarState
  252. ) = 0;
  253. };
  254. //////////////////////////////////////////////////////////////////////////////
  255. //
  256. // CadetFlightImageImpl
  257. //
  258. //////////////////////////////////////////////////////////////////////////////
  259. class CadetFlightImageImpl : public CadetFlightImage
  260. {
  261. private:
  262. // Context
  263. TRef<CadetGameContext> m_pcontext;
  264. TRef<IclusterIGC> m_pcluster;
  265. // camera and viewports
  266. TRef<Camera> m_pcameraPosters;
  267. TRef<Camera> m_pcamera;
  268. TRef<Viewport> m_pviewport;
  269. TRef<Viewport> m_pviewportPosters;
  270. // images
  271. TRef<GroupImage> m_pgroupTopImages;
  272. TRef<GroupImage> m_pgroupImage;
  273. TRef<GeoImage> m_pimageEnvironment;
  274. TRef<GroupGeo> m_pgroupGeo;
  275. TRef<WrapGeo> m_pwrapGeoScene;
  276. // TRef<RadarImage> m_pradarImage;
  277. // resources
  278. TMap<ZString, TRef<AnimatedImage> > m_mapAnimatedImages;
  279. BillboardType m_types[4];
  280. TRef<AnimatedImage> m_pimageFlare;
  281. TRef<Geo> m_pgeoFlares[3];
  282. TVector<TRef<AnimatedImage> > m_pimageExplosions;
  283. TRef<Image> m_pimageShockWave;
  284. public:
  285. CadetFlightImageImpl(CadetGameContext* pcontext) :
  286. m_pcontext(pcontext)
  287. {
  288. TRef<Modeler> pmodeler = GetModeler();
  289. m_types[0] = BillboardType(pmodeler, AWF_EXPLOSION_00, 1.38f, 2, 8);
  290. m_types[1] = BillboardType(pmodeler, AWF_EXPLOSION_01, 1.15f, 3, 8);
  291. m_types[2] = BillboardType(pmodeler, AWF_EXPLOSION_02, 1.80f, 4, 8);
  292. m_types[3] = BillboardType(pmodeler , AWF_EXPLOSION_03, 1.03f, 2, 8);
  293. AddExplosionImage(AWF_EXPLOSION_00, 2, 8);
  294. AddExplosionImage(AWF_EXPLOSION_01, 3, 8);
  295. AddExplosionImage(AWF_EXPLOSION_02, 4, 8);
  296. AddExplosionImage(AWF_EXPLOSION_03, 2, 8);
  297. TRef<Surface> psurfaceFlare = pmodeler->LoadSurface(AWF_SHIELD_FLARE_TEXTURE, true);
  298. ZAssert(psurfaceFlare);
  299. m_pimageFlare = new AnimatedImage(GetWindow()->GetTime(), psurfaceFlare);
  300. TRef<INameSpace> pns = pmodeler->GetNameSpace(AWF_SHIELD_FLARE);
  301. if (pns) {
  302. CastTo(m_pgeoFlares[0], pns->FindMember("lens30"));
  303. CastTo(m_pgeoFlares[1], pns->FindMember("lens60"));
  304. CastTo(m_pgeoFlares[2], pns->FindMember("lens90"));
  305. }
  306. m_pimageShockWave = pmodeler->LoadImage(AWF_SHOCKWAVE, true);
  307. //
  308. // The Camera
  309. //
  310. m_pcamera = new Camera();
  311. m_pcamera->SetPosition(Vector(0, 0, 5));
  312. m_pcamera->SetZClip(1, 10000);
  313. m_pcamera->SetFOV(RadiansFromDegrees(65));
  314. m_pviewport = new Viewport(m_pcamera, GetWindow()->GetRenderRectValue());
  315. m_pcameraPosters = new Camera();
  316. m_pcameraPosters->SetZClip(5, 20000);
  317. m_pcameraPosters->SetFOV(RadiansFromDegrees(50));
  318. m_pviewportPosters = new Viewport(m_pcameraPosters, GetWindow()->GetRenderRectValue());
  319. m_pgroupGeo = GroupGeo::Create();
  320. m_pgroupGeo->AddGeo(DebrisGeo::Create(1000));
  321. m_pwrapGeoScene = new WrapGeo(Geo::GetEmpty());
  322. m_pgroupGeo->AddGeo(m_pwrapGeoScene);
  323. m_pimageEnvironment = new GeoImage(Geo::GetEmpty(), m_pviewportPosters, false);
  324. //
  325. // Create a group
  326. //
  327. m_pgroupImage = new GroupImage();
  328. m_pgroupTopImages = new GroupImage();
  329. m_pgroupImage->AddImage(m_pgroupTopImages);
  330. m_pgroupImage->AddImage(new IndicatorImage(GetModeler(), m_pviewport, m_pcontext));
  331. // m_pgroupImage->AddImage( m_pradarImage = RadarImage::Create(GetModeler(), m_pviewport, m_pcontext));
  332. // m_pradarImage->SetRadarLOD(RadarImage::radarLOD2);
  333. m_pgroupImage->AddImage(CreateMuzzleFlareImage(GetModeler(), GetWindow()->GetTime()));
  334. m_pgroupImage->AddImage(CreateLensFlareImage(GetModeler(), m_pviewportPosters));
  335. m_pgroupImage->AddImage( new GeoImage(m_pgroupGeo, m_pviewport, true));
  336. m_pgroupImage->AddImage(StarImage::Create(m_pviewportPosters, 500));
  337. m_pgroupImage->AddImage(m_pimageEnvironment);
  338. SetImage(m_pgroupImage);
  339. ThingGeo::SetShowTrails(false);
  340. }
  341. TRef<IshipIGC> GetShip()
  342. {
  343. return m_pcontext->GetShip();
  344. }
  345. TRef<IclusterIGC> GetCluster()
  346. {
  347. return m_pcluster;
  348. }
  349. void SetCluster(IclusterIGC* pcluster)
  350. {
  351. m_pcluster = pcluster;
  352. m_pwrapGeoScene->SetGeo(pcluster->GetClusterSite()->GetGroupScene());
  353. }
  354. void SetCameraPosition(const Vector& vec)
  355. {
  356. m_pcamera->SetPosition(vec);
  357. }
  358. void SetCameraOrientation(const Orientation& orientation)
  359. {
  360. m_pcamera->SetOrientation(orientation);
  361. m_pcameraPosters->SetOrientation(orientation);
  362. }
  363. void AddImage(Image* pimage)
  364. {
  365. m_pgroupTopImages->AddImage(pimage);
  366. }
  367. void RemoveImage(Image* pimage)
  368. {
  369. m_pgroupTopImages->RemoveImage(pimage);
  370. }
  371. void AddGeo(Geo* pgeo)
  372. {
  373. m_pgroupGeo->AddGeo(pgeo);
  374. }
  375. void RemoveGeo(Geo* pgeo)
  376. {
  377. m_pgroupGeo->RemoveGeo(pgeo);
  378. }
  379. //////////////////////////////////////////////////
  380. // Callbacks for ClusterSite and ThingSite
  381. void AddExplosionImage(const ZString& str, int nRows = 0, int nCols = 0)
  382. {
  383. TRef<Surface> psurface = GetModeler()->LoadSurface(str, true);
  384. ZAssert(psurface);
  385. if (psurface)
  386. {
  387. m_pimageExplosions.PushEnd(new AnimatedImage(new Number(0.0f), psurface, nRows, nCols));
  388. GetModeler()->UnloadNameSpace(str);
  389. }
  390. }
  391. TRef<AnimatedImage> LoadAnimatedImage(Number* ptime, const ZString& str)
  392. {
  393. TRef<AnimatedImage> pimage;
  394. if (m_mapAnimatedImages.Find(str, pimage)) {
  395. return new AnimatedImage(ptime, pimage);
  396. } else {
  397. TRef<Surface> psurface = GetModeler()->LoadSurface(str, true);
  398. if (psurface == NULL) {
  399. return NULL;
  400. }
  401. pimage = new AnimatedImage(ptime, psurface);
  402. m_mapAnimatedImages.Set(str, pimage);
  403. return pimage;
  404. }
  405. }
  406. TVector<TRef<AnimatedImage> > GetExplosionImages()
  407. {
  408. return m_pimageExplosions;
  409. }
  410. TRef<Image> GetShockWaveImage()
  411. {
  412. return m_pimageShockWave;
  413. }
  414. TRef<AnimatedImage> GetFlareImage()
  415. {
  416. return m_pimageFlare;
  417. }
  418. void SetPosterGeo(Geo* pgeo)
  419. {
  420. m_pimageEnvironment->SetGeo(pgeo);
  421. }
  422. BillboardType* GetBillboardType(int iType)
  423. {
  424. return &m_types[iType];
  425. }
  426. void AddMuzzleFlare(const Vector& vecEmissionPoint, float duration)
  427. {
  428. }
  429. TRef<Geo> GetGeoFlares(int iFlare)
  430. {
  431. return m_pgeoFlares[iFlare];
  432. }
  433. void Render(Context* pcontext)
  434. {
  435. //Update();
  436. WrapImage::Render(pcontext);
  437. }
  438. void Update()
  439. {
  440. if (!m_pcontext->GetCluster())
  441. return;
  442. const ModelListIGC* models = m_pcontext->GetCluster()->GetModels();
  443. assert (models);
  444. for (ModelLinkIGC* l = models->first(); (l != NULL); l = l->next())
  445. {
  446. ImodelIGC* pmodel = l->data();
  447. if (pmodel->GetObjectType() == OT_ship)
  448. {
  449. IshipIGC* pship = (IshipIGC*)pmodel;
  450. if (pship->GetStateM() & miningMaskIGC)
  451. pship->GetThingSite()->ActivateBolt();
  452. else
  453. pship->GetThingSite()->DeactivateBolt();
  454. }
  455. }
  456. /*
  457. const ModelListIGC* models = m_pcontext->GetCluster()->GetPickableModels();
  458. assert (models);
  459. Rect rectImage(0,0,640,480);
  460. double angleToPixels = double(rectImage.Size().X()) / double(m_pcamera->GetFOV());
  461. Point pointCenter = rectImage.Center();
  462. rectImage.Offset(-pointCenter);
  463. static const float c_flBorderSide = 10.0f;
  464. rectImage.Expand(-c_flBorderSide);
  465. const Vector& positionCamera = m_pcamera->GetPosition();
  466. for (ModelLinkIGC* l = models->first(); (l != NULL); l = l->next())
  467. {
  468. ImodelIGC* pmodel = l->data();
  469. if (((pmodel != m_pcontext->GetShip()) || pmodel->GetVisibleF()))
  470. {
  471. ObjectType type = pmodel->GetObjectType();
  472. ThingSitePriv* psite; CastTo(psite, pmodel->GetThingSite());
  473. ThingGeo* pthing = psite->GetThingGeo();
  474. unsigned char renderMask = c_ucRenderAll;
  475. //
  476. // Update screen positions for ships
  477. //
  478. {
  479. float fScreenRadius;
  480. float distanceToEdge;
  481. Point pointScreenPosition;
  482. unsigned char ucRadarState;
  483. const Vector& positionModel = pmodel->GetPosition();
  484. {
  485. Point pointNDC;
  486. if (m_pcamera->TransformLocalToNDC(positionModel, pointNDC))
  487. {
  488. //
  489. // Blip is in front of ship
  490. //
  491. pointScreenPosition = pointNDC * (rectImage.XSize() * 0.5f);
  492. ucRadarState = rectImage.Inside(pointScreenPosition) ? c_ucRadarOnScreenLarge : c_ucRadarOffScreen;
  493. }
  494. else
  495. ucRadarState = c_ucRadarOffScreen;
  496. }
  497. if (ucRadarState == c_ucRadarOffScreen)
  498. {
  499. fScreenRadius = 14.0f;
  500. distanceToEdge = 0.0f;
  501. //
  502. // Direction from eye to object
  503. //
  504. Vector vecDirection = m_pcamera->TransformLocalToEye(positionModel);
  505. vecDirection.SetNormalize();
  506. //
  507. // Get the components
  508. //
  509. float x = vecDirection.X();
  510. float y = vecDirection.Y();
  511. if (x == 0.0f)
  512. {
  513. y = (y <= 0.0f) ? rectImage.YMin() : rectImage.YMax();
  514. }
  515. else if (y == 0.0f)
  516. {
  517. x = (x <= 0.0f) ? rectImage.XMin() : rectImage.XMax();
  518. }
  519. else
  520. {
  521. float tX = ((x > 0.0f) ? rectImage.XMax() : rectImage.XMin()) / x;
  522. float tY = ((y > 0.0f) ? rectImage.YMax() : rectImage.YMin()) / y;
  523. float tMin = (tX < tY) ? tX : tY;
  524. x *= tMin;
  525. y *= tMin;
  526. }
  527. pointScreenPosition.SetX(x);
  528. pointScreenPosition.SetY(y);
  529. }
  530. else
  531. {
  532. double sinAlpha = psite->GetRadius() / (positionModel - positionCamera).Length();
  533. fScreenRadius = (sinAlpha < 1.0)
  534. ? float(angleToPixels * asin(sinAlpha)) //hack ... 480/(50*pi/180) * 2asin(r/d)
  535. : 640.0f;
  536. distanceToEdge = (pointScreenPosition.X() >= 0.0f)
  537. ? (rectImage.XMax() - pointScreenPosition.X())
  538. : (pointScreenPosition.X() - rectImage.XMin());
  539. {
  540. float d = (pointScreenPosition.Y() >= 0.0f)
  541. ? (rectImage.YMax() - pointScreenPosition.Y())
  542. : (pointScreenPosition.Y() - rectImage.YMin());
  543. if (d < distanceToEdge)
  544. distanceToEdge = d;
  545. }
  546. if (fScreenRadius < 14.0f)
  547. {
  548. if ((pmodel != m_pcontext->GetShip()) &&
  549. ((fScreenRadius < 1.0f) ||
  550. CommandCamera(m_cm)))
  551. {
  552. ucRadarState = c_ucRadarOnScreenSmall;
  553. renderMask = c_ucRenderTrail;
  554. }
  555. fScreenRadius = 14.0f;
  556. }
  557. }
  558. psite->UpdateScreenPosition(
  559. pointScreenPosition,
  560. fScreenRadius,
  561. distanceToEdge,
  562. ucRadarState
  563. );
  564. }
  565. if (type == OT_ship)
  566. {
  567. IshipIGC* pship; CastTo(pship, pmodel);
  568. IafterburnerIGC* afterburner = (IafterburnerIGC*)(pship->GetMountedPart(ET_Afterburner, 0));
  569. float power = afterburner ? afterburner->GetPower() : 0.0f;
  570. ThingGeo* pthing = psite->GetThingGeo();
  571. if (power != 0.0f) {
  572. pthing->SetAfterburnerThrust(pship->GetOrientation().GetForward() * (-power));
  573. } else {
  574. pthing->SetAfterburnerThrust(Vector::GetZero());
  575. }
  576. pthing->SetThrust(0.5f * (pship->GetControls().jsValues[3] + 1));
  577. if (pship->GetStateM() & miningMaskIGC) {
  578. psite->ActivateBolt();
  579. } else {
  580. psite->DeactivateBolt();
  581. }
  582. }
  583. //Is the model visible?
  584. if (pmodel != m_pcontext->GetShip())
  585. {
  586. bool visibleF = true;
  587. if (!(visibleF && m_pcontext->GetShip()->CanSee(pmodel)))
  588. {
  589. visibleF = false;
  590. }
  591. pmodel->SetVisibleF(visibleF);
  592. pmodel->SetRender(visibleF ? renderMask : c_ucRenderNone);
  593. }
  594. }
  595. }
  596. */
  597. }
  598. //////////////////////////////////////////////////
  599. // IIgcSite
  600. TRef<ThingSite> CreateThingSite(ImodelIGC* pModel)
  601. {
  602. return ::CreateThingSite(pModel, this);
  603. }
  604. TRef<ClusterSite> CreateClusterSite(IclusterIGC* pCluster)
  605. {
  606. return ::CreateClusterSite(GetModeler(),
  607. GetWindow()->GetTime(),
  608. m_pviewportPosters, this);
  609. }
  610. void PlaySoundEffect(SoundID soundID, ImodelIGC* model = NULL)
  611. {
  612. if ((model == NULL) || (model == m_pcontext->GetShip()))
  613. Sound::PlaySoundEffect(soundID);
  614. }
  615. void DamageStationEvent(IstationIGC* pStation,
  616. ImodelIGC* pLauncher,
  617. float flAmount,
  618. float flLeakage)
  619. {
  620. if ((NULL != pStation->GetCluster()) &&
  621. (pStation->GetCluster() == GetCluster()))
  622. {
  623. if (pStation->GetShieldFraction() < 0.0f)
  624. PlaySoundEffect(otherHullHitSound);
  625. else
  626. PlaySoundEffect(otherShieldHitSound);
  627. }
  628. }
  629. void KillStationEvent(IstationIGC* pStation,
  630. ImodelIGC* pLauncher,
  631. float flAmount,
  632. float flLeakage)
  633. {
  634. pStation->GetCluster()->GetClusterSite()->AddExplosion(pStation);
  635. pStation->Terminate();
  636. }
  637. void DamageShipEvent(Time now, IshipIGC* pship, ImodelIGC* plauncher, float amount, float leakage, const Vector& p1, const Vector& p2)
  638. {
  639. if (pship == GetShip())
  640. {
  641. if (plauncher)
  642. {
  643. if (leakage > 0.0f)
  644. Sound::PlaySoundEffect(myHullHitSound);
  645. else
  646. Sound::PlaySoundEffect(myShieldHitSound);
  647. }
  648. }
  649. else if ((pship->GetCluster() == GetShip()->GetCluster()) && plauncher)
  650. {
  651. if (leakage > 0.0f)
  652. Sound::PlaySoundEffect(otherHullHitSound);
  653. else
  654. Sound::PlaySoundEffect(otherShieldHitSound);
  655. }
  656. }
  657. void KillShipEvent(Time now, IshipIGC* pShip, ImodelIGC* launcher, float amount, const Vector& p1, const Vector& p2)
  658. {
  659. pShip->GetCluster()->GetClusterSite()->AddExplosion(pShip);
  660. if (pShip == m_pcontext->GetShip())
  661. {
  662. m_pcontext->SetShip(NULL); // this will terminate the ship
  663. m_pcontext->SwitchToScene(CreateLoadoutScene(m_pcontext));
  664. }
  665. else
  666. {
  667. pShip->Terminate();
  668. }
  669. }
  670. void FireMissile(IshipIGC* pShip,
  671. ImagazineIGC* pMagazine,
  672. Time timeFired,
  673. ImodelIGC* pTarget,
  674. float flLock)
  675. {
  676. PlaySoundEffect(jumpSound);
  677. IclusterIGC* pCluster = pShip->GetCluster();
  678. assert (pCluster);
  679. const Vector& myVelocity = pShip->GetVelocity();
  680. const Orientation& myOrientation = pShip->GetOrientation();
  681. static const Vector offset(0, 0, -1.0f);
  682. Vector myPosition = pShip->GetPosition() +
  683. offset * myOrientation;
  684. DataMissileIGC dataMissile;
  685. dataMissile.pmissiletype = pMagazine->GetMissileType();
  686. dataMissile.forward = myOrientation.GetForward();
  687. //Permute the "forward" direction slightly by a random amount
  688. {
  689. float d = dataMissile.pmissiletype->GetDispersion();
  690. if (d != 0.0f)
  691. {
  692. float r = random(0.0f, d);
  693. float a = random(0.0f, 2.0f * pi);
  694. dataMissile.forward += (r * cos(a)) * myOrientation.GetRight();
  695. dataMissile.forward += (r * sin(a)) * myOrientation.GetUp();
  696. dataMissile.forward.SetNormalize();
  697. }
  698. }
  699. Time lastUpdate = pShip->GetLastUpdate();
  700. dataMissile.position = myPosition + myVelocity * (timeFired - lastUpdate);
  701. dataMissile.velocity = dataMissile.pmissiletype->GetInitialSpeed() * dataMissile.forward + myVelocity;
  702. dataMissile.pLauncher = pShip;
  703. dataMissile.pTarget = pTarget;
  704. dataMissile.pCluster = pCluster;
  705. dataMissile.lock = flLock;
  706. dataMissile.missileID = m_pcontext->GetMissionIGC()->GenerateNewMissileID();
  707. if (m_pcontext->GetCadetPlay()->GetCadetMode() != cmSinglePlayer)
  708. m_pcontext->GetCadetPlay()->SendFireMissileMessage(&dataMissile);
  709. ImissileIGC* m = (ImissileIGC*)(m_pcontext->GetMissionIGC()->CreateObject(timeFired,
  710. OT_missile,
  711. &dataMissile,
  712. sizeof(dataMissile)));
  713. assert (m != NULL);
  714. m->Release();
  715. short amount = pMagazine->GetAmount() - 1;
  716. if (0 == amount)
  717. {
  718. //
  719. // Nothing left ... nuke it (which may also cause it to be
  720. // released & deleted).
  721. //
  722. pMagazine->Terminate();
  723. }
  724. else
  725. {
  726. assert (amount > 0);
  727. pMagazine->SetAmount(amount);
  728. }
  729. }
  730. void TerminateModelEvent(ImodelIGC* pModel)
  731. {
  732. ObjectType type = pModel->GetObjectType();
  733. if (type == OT_ship)
  734. g_drones.DeleteShip((IshipIGC *)pModel);
  735. }
  736. void KillAsteroidEvent(IasteroidIGC* pasteroid, bool explodeF)
  737. {
  738. }
  739. void KillProbeEvent(IprobeIGC* pprobe)
  740. {
  741. }
  742. void KillMineEvent(ImineIGC* pmine)
  743. {
  744. }
  745. void KillMunitionEvent(ImunitionIGC* pmunition)
  746. {
  747. }
  748. bool DockWithStationEvent(IshipIGC* ship, IstationIGC* station)
  749. {
  750. return false;
  751. }
  752. void HitWarpEvent(IshipIGC* ship, IwarpIGC* warp)
  753. {
  754. }
  755. void HitTreasureEvent(Time now, IshipIGC* ship, ItreasureIGC* treasure)
  756. {
  757. }
  758. };
  759. TRef<CadetFlightImage> CadetFlightImage::Create(CadetGameContext* pcontext)
  760. {
  761. return new CadetFlightImageImpl(pcontext);
  762. }
  763. //////////////////////////////////////////////////////////////////////////////
  764. //
  765. // ClusterSiteImpl
  766. //
  767. //////////////////////////////////////////////////////////////////////////////
  768. class ClusterSiteImpl : public ClusterSite
  769. {
  770. public:
  771. ClusterSiteImpl(Modeler* pmodeler, Number* ptime, Viewport* pviewport, CadetFlightImageImpl* pflightImg) :
  772. m_pflightImg(pflightImg)
  773. {
  774. m_pGroupScene = GroupGeo::Create();
  775. m_pposterImage = CreatePosterImage(pviewport);
  776. m_pparticleGeo = CreateParticleGeo(pmodeler, ptime);
  777. m_pGroupScene->AddGeo(m_pparticleGeo);
  778. m_pbitsGeo = CreateBitsGeo(pmodeler, ptime);
  779. m_pGroupScene->AddGeo(m_pbitsGeo);
  780. memset(&m_sectordata, 0, sizeof(m_sectordata));
  781. }
  782. void Terminate(void)
  783. {
  784. //Clear out anything left in the scanners array
  785. //(it wasn't cleared because the player's side was set to NULL
  786. //before all objects were removed from the array).
  787. {
  788. ScannerLinkIGC* l;
  789. while (l = m_scanners.first()) //intentional assignment
  790. {
  791. l->data()->Release();
  792. delete l;
  793. }
  794. }
  795. m_pGroupScene = NULL;
  796. m_pposterImage = NULL;
  797. }
  798. void AddExplosion(
  799. const Vector& vecPosition,
  800. const Vector& vecUp,
  801. const Vector& vecForward,
  802. const Vector& vecVelocity,
  803. float scale,
  804. const Color& color,
  805. int count
  806. ) {
  807. //
  808. // Play a sound if the player can hear it
  809. //
  810. if (m_pflightImg->GetCluster() &&
  811. (m_pflightImg->GetCluster()->GetClusterSite() == this))
  812. {
  813. if (scale > 100.0f)
  814. Sound::PlaySoundEffect(explodeStationSound, vecPosition, vecVelocity);
  815. else if (scale > 10.0f)
  816. Sound::PlaySoundEffect(explodeShipSound, vecPosition, vecVelocity);
  817. else
  818. Sound::PlaySoundEffect(otherHullHitSound, vecPosition, vecVelocity);
  819. }
  820. //
  821. // Create an explosion geo
  822. //
  823. m_pGroupScene->AddGeo(
  824. CreateExplosion(
  825. GetWindow()->GetTime(),
  826. vecPosition,
  827. vecUp,
  828. vecForward,
  829. vecVelocity,
  830. scale,
  831. Color::White(),
  832. 10,
  833. m_pflightImg->GetExplosionImages(),
  834. m_pflightImg->GetShockWaveImage()
  835. )
  836. );
  837. }
  838. void AddExplosion(
  839. ImodelIGC* pmodel
  840. ) {
  841. const Orientation& orient = pmodel->GetOrientation();
  842. AddExplosion(
  843. pmodel->GetPosition(),
  844. orient.GetUp(),
  845. orient.GetForward(),
  846. pmodel->GetVelocity(),
  847. 2 * pmodel->GetThingSite()->GetRadius(),
  848. Color::White(),
  849. 10
  850. );
  851. }
  852. void AddExplosion(
  853. const Vector& vecPosition,
  854. float scale
  855. ) {
  856. AddExplosion(
  857. vecPosition,
  858. Vector(0, 1, 0),
  859. Vector(0, 1, -1),
  860. Vector(0, 0, 0),
  861. scale,
  862. Color::White(),
  863. 10
  864. );
  865. }
  866. void AddThingSite(ThingSite* pThingSite)
  867. {
  868. ThingGeo* pthing = pThingSite->GetThingGeo();
  869. if (pthing) {
  870. pthing->SetParticleGeo(m_pparticleGeo);
  871. pthing->SetBitsGeo(m_pbitsGeo);
  872. }
  873. m_pGroupScene->AddGeo(pThingSite->GetGeo());
  874. }
  875. void DeleteThingSite(ThingSite* pThingSite)
  876. {
  877. m_pGroupScene->RemoveGeo(pThingSite->GetThingGeo());
  878. }
  879. HRESULT AddPoster(const char* textureName, const Vector& vec, float radius)
  880. {
  881. TRef<Image> pimage = GetWindow()->GetModeler()->LoadImage(textureName, true);
  882. if (pimage) {
  883. m_pposterImage->AddPoster(pimage, vec, radius);
  884. return S_OK;
  885. }
  886. return E_FAIL;
  887. }
  888. HRESULT AddPosterGeo(const char* pszName)
  889. {
  890. TRef<INameSpace> pns = GetWindow()->GetModeler()->GetNameSpace(pszName);
  891. if (pns) {
  892. TRef<Geo> pgeo = Geo::Cast(pns->FindMember("object"));
  893. if (pgeo) {
  894. m_pflightImg->SetPosterGeo(pgeo);
  895. }
  896. }
  897. return E_FAIL;
  898. }
  899. GroupGeo* GetGroupScene(void)
  900. {
  901. return m_pGroupScene;
  902. }
  903. PosterImage* GetPosterImage()
  904. {
  905. return m_pposterImage;
  906. }
  907. SectorData* GetSectorData(SideID sid)
  908. {
  909. return &m_sectordata;
  910. }
  911. virtual void AddScanner(SideID sid, IscannerIGC* scannerNew)
  912. {
  913. /* assert (sid >= 0);
  914. assert (sid < c_cSidesMax);
  915. assert (scannerNew);
  916. if (sid == trekClient.GetSideID())
  917. AddIbaseIGC((BaseListIGC*)&(m_scanners), scannerNew);*/
  918. }
  919. virtual void DeleteScanner(SideID sid, IscannerIGC* scannerOld)
  920. {
  921. /* assert (sid >= 0);
  922. assert (sid < c_cSidesMax);
  923. assert (scannerOld);
  924. if (sid == trekClient.GetSideID())
  925. DeleteIbaseIGC((BaseListIGC*)&(m_scanners), scannerOld);*/
  926. }
  927. virtual const ScannerListIGC* GetScanners(SideID sid) const
  928. {
  929. /* assert (sid >= 0);
  930. assert (sid < c_cSidesMax);
  931. return &(m_scanners);*/
  932. return NULL;
  933. }
  934. private:
  935. TRef<CadetFlightImageImpl> m_pflightImg;
  936. TRef<GroupGeo> m_pGroupScene;
  937. TRef<PosterImage> m_pposterImage;
  938. TRef<ParticleGeo> m_pparticleGeo;
  939. TRef<BitsGeo> m_pbitsGeo;
  940. SectorData m_sectordata;
  941. ScannerListIGC m_scanners;
  942. };
  943. TRef<ClusterSite> CreateClusterSite(Modeler* pmodeler, Number* ptime, Viewport* pviewport, CadetFlightImageImpl* pflightImg)
  944. {
  945. return new ClusterSiteImpl(pmodeler, ptime, pviewport, pflightImg);
  946. }
  947. //////////////////////////////////////////////////////////////////////////////
  948. //
  949. // ThingSiteImpl
  950. //
  951. //////////////////////////////////////////////////////////////////////////////
  952. class ThingSiteImpl : public ThingSitePriv
  953. {
  954. public:
  955. ThingSiteImpl(ImodelIGC* pmodel, CadetFlightImageImpl* pflightImg)
  956. :
  957. m_sm(c_smNone),
  958. m_bSideVisibility(false),
  959. m_pdamagebuckets(NULL),
  960. //m_radius(1),
  961. m_pmodel(pmodel),
  962. m_pflightImg(pflightImg)
  963. {
  964. assert (pmodel);
  965. //Don't bother to AddRef pmodel -- it lifespan always exceeds that of the thingsite.
  966. }
  967. ~ThingSiteImpl(void)
  968. {
  969. assert (!m_pdamagebuckets);
  970. }
  971. void Purge(void)
  972. {
  973. if (m_pthing) {
  974. assert (!m_pdecal);
  975. m_pthing->SetEmpty();
  976. m_pthing = NULL;
  977. }
  978. else if (m_pdecal) {
  979. m_pdecal->SetEmpty();
  980. m_pdecal = NULL;
  981. }
  982. }
  983. void Terminate(void)
  984. {
  985. if (m_pthing) {
  986. assert (!m_pdecal);
  987. m_pthing->SetEmpty();
  988. m_pthing = NULL;
  989. }
  990. else if (m_pdecal) {
  991. m_pdecal->SetEmpty();
  992. m_pdecal = NULL;
  993. }
  994. if (m_pbolt) {
  995. m_pbolt->SetEmpty();
  996. m_pbolt = NULL;
  997. }
  998. if (m_pdamagebuckets)
  999. {
  1000. DamageBucketsLink* l = m_pdamagebuckets->GetLink();
  1001. assert (&(l->data()) == m_pdamagebuckets);
  1002. delete l;
  1003. //Deleting the bucket clears the backpointer from
  1004. //the thingsite to the bucket.
  1005. assert (m_pdamagebuckets == NULL);
  1006. }
  1007. }
  1008. Vector GetChildOffset(const ZString& strFrame)
  1009. {
  1010. assert (m_pthing);
  1011. m_pthing->Update();
  1012. Vector vec(0, 0, 0);
  1013. m_pthing->GetChildOffset(strFrame, vec);
  1014. return vec;
  1015. }
  1016. void AddExplosion(Time time, const Vector& vecPosition, float scale)
  1017. {
  1018. TRef<Number> ptime = GetWindow()->GetTime();
  1019. BillboardType* ptype = m_pflightImg->GetBillboardType(3);
  1020. assert (m_pthing);
  1021. m_pthing->AddGeo(new TimedBillboardGeo(ptime, vecPosition, scale, ptype->m_pimage, ptype->m_lifespan));
  1022. }
  1023. void AddHullHit(const Vector& vecPosition, const Vector& vecNormal)
  1024. {
  1025. assert (m_pthing);
  1026. m_pthing->AddHullHit(vecPosition, vecNormal);
  1027. }
  1028. void SetAfterburnerThrust(const Vector& thrust, float power)
  1029. {
  1030. if (m_pthing)
  1031. {
  1032. m_pthing->SetAfterburnerThrust(thrust, power);
  1033. }
  1034. else
  1035. {
  1036. assert (m_pdecal);
  1037. }
  1038. }
  1039. void AddMuzzleFlare(const Vector& vecEmissionPoint, float duration)
  1040. {
  1041. if (this == m_pflightImg->GetShip()->GetThingSite())
  1042. m_pflightImg->AddMuzzleFlare(vecEmissionPoint, duration);
  1043. }
  1044. void AddThingSite(ThingSite* pThingSite)
  1045. {
  1046. assert (m_pthing);
  1047. m_pthing->AddGeo(pThingSite->GetThingGeo());
  1048. }
  1049. void DeleteThingSite(ThingSite* pThingSite)
  1050. {
  1051. assert (m_pthing);
  1052. assert (pThingSite->GetThingGeo());
  1053. m_pthing->RemoveGeo(pThingSite->GetThingGeo());
  1054. }
  1055. void AddFlare(Time timeArg, const Vector& vecPosition, int id,
  1056. const Vector* ellipseEquation)
  1057. {
  1058. assert (m_pthing);
  1059. TRef<Number> ptimeArg = GetWindow()->GetTime();
  1060. TRef<Number> ptime = Subtract(ptimeArg, ptimeArg->MakeConstant());
  1061. m_pthing->AddFlare(
  1062. new TextureGeo(
  1063. m_pflightImg->GetGeoFlares(id),
  1064. new AnimatedImage(
  1065. ptime,
  1066. m_pflightImg->GetFlareImage()
  1067. )
  1068. ),
  1069. ptime,
  1070. -vecPosition, //NYI we can avoid the - by changing the Geo
  1071. ellipseEquation
  1072. );
  1073. }
  1074. void SetVisible(unsigned char render)
  1075. {
  1076. if (m_pthing)
  1077. {
  1078. bool vship = render == c_ucRenderAll;
  1079. m_pthing->SetVisible(render >= c_ucRenderTrail);
  1080. m_pthing->SetVisibleShip(vship);
  1081. if (m_pbolt)
  1082. {
  1083. if (vship)
  1084. m_pmodel->GetCluster()->GetClusterSite()->GetGroupScene()->AddGeo(m_pbolt);
  1085. else
  1086. m_pmodel->GetCluster()->GetClusterSite()->GetGroupScene()->RemoveGeo(m_pbolt);
  1087. }
  1088. }
  1089. }
  1090. ThingGeo* GetThingGeo()
  1091. {
  1092. return m_pthing;
  1093. }
  1094. Geo* GetGeo()
  1095. {
  1096. if (m_pdecal) {
  1097. return m_pdecal;
  1098. } else {
  1099. assert (m_pthing);
  1100. return m_pthing;
  1101. }
  1102. }
  1103. void SetPosition(const Vector& position)
  1104. {
  1105. if (m_pthing) {
  1106. m_pthing->SetPosition(position);
  1107. } else if (m_pdecal) {
  1108. m_pdecal->SetPosition(position);
  1109. }
  1110. }
  1111. float GetRadius(void)
  1112. {
  1113. if (m_pthing)
  1114. {
  1115. return m_pthing->GetRadius();
  1116. }
  1117. else if (m_pdecal)
  1118. {
  1119. return sqrt2;
  1120. }
  1121. else
  1122. return 0.0f;
  1123. }
  1124. void SetRadius(float r)
  1125. {
  1126. m_radius = r;
  1127. if (m_pdecal) {
  1128. if (m_pdecal->GetForward().IsZero()) {
  1129. m_pdecal->SetScale(r / sqrt2);
  1130. } else {
  1131. m_pdecal->SetForward(m_pdecal->GetForward().Normalize() * m_radius);
  1132. }
  1133. } else {
  1134. assert (m_pthing);
  1135. m_pthing->Update();
  1136. m_pthing->SetRadius(r);
  1137. }
  1138. }
  1139. void SetBlendColor(const Color& color)
  1140. {
  1141. if (m_pdecal) {
  1142. // !!! color always == black
  1143. // m_pdecal->SetColor(color);
  1144. } else {
  1145. assert (m_pthing);
  1146. m_pthing->SetBlendColor(color);
  1147. }
  1148. }
  1149. void SetOrientation(const Orientation& orientation)
  1150. {
  1151. if (m_pthing) {
  1152. m_pthing->SetOrientation(orientation);
  1153. } else if (m_pdecal) {
  1154. if (!m_pdecal->GetForward().IsZero()) {
  1155. m_pdecal->SetForward(orientation.GetForward() * m_radius);
  1156. }
  1157. }
  1158. }
  1159. void Spin(float r)
  1160. {
  1161. if (m_pdecal) {
  1162. assert (!m_pthing);
  1163. m_pdecal->SetAngle(m_pdecal->GetAngle() + r);
  1164. }
  1165. }
  1166. void SetTexture(const char* pszTextureName)
  1167. {
  1168. assert (m_pthing);
  1169. m_pthing->SetTexture(GetWindow()->GetModeler()->LoadImage(pszTextureName, false));
  1170. }
  1171. void SetAnimation(float transitionStart, float transitionStop, float transitionFPS,
  1172. float loopingStart, float loopingStop, float loopingFPS,
  1173. IEventSink* peventSink)
  1174. {
  1175. assert (m_pthing);
  1176. m_pthing->PutAnimation(transitionStart, transitionStop, transitionFPS,
  1177. loopingStart, loopingStop, loopingFPS,
  1178. peventSink);
  1179. }
  1180. HRESULT LoadDecal(const char* textureName, bool bDirectional, float width)
  1181. {
  1182. ZAssert(m_pthing == NULL && m_pdecal == NULL);
  1183. Number* ptime = GetWindow()->GetTime();
  1184. TRef<AnimatedImage> pimage =
  1185. m_pflightImg->LoadAnimatedImage(
  1186. Divide(
  1187. Subtract(ptime, ptime->MakeConstant()),
  1188. new Number(2) // number of seconds to animate through images
  1189. ),
  1190. ZString(textureName) + "bmp"
  1191. );
  1192. if (pimage) {
  1193. m_pdecal =
  1194. new DecalGeo(
  1195. pimage,
  1196. Color::White(),
  1197. Vector::GetZero(),
  1198. Vector::GetZero(),
  1199. Vector::GetZero(),
  1200. width,
  1201. 0
  1202. );
  1203. if (bDirectional) {
  1204. m_pdecal->SetForward(Vector(0, 0, -1));
  1205. }
  1206. return S_OK;
  1207. }
  1208. return E_FAIL;
  1209. }
  1210. HRESULT LoadModel(
  1211. int options,
  1212. const char* modelName,
  1213. const char* textureName,
  1214. float originalRadius,
  1215. bool bUseCache
  1216. ) {
  1217. ZAssert(m_pthing == NULL && m_pdecal == NULL);
  1218. m_pthing =
  1219. ThingGeo::Create(
  1220. GetWindow()->GetModeler(),
  1221. GetWindow()->GetTime()
  1222. );
  1223. //
  1224. // , always use cache
  1225. // multiple things will be driving the same frame pointer
  1226. bUseCache = true;
  1227. if (modelName) {
  1228. if (textureName && ((!iswalpha(textureName[0])) || (strcmp(modelName, textureName) == 0))) {
  1229. textureName = NULL;
  1230. }
  1231. TRef<Image> pimageTexture;
  1232. if (textureName) {
  1233. pimageTexture = GetWindow()->GetModeler()->LoadImage(textureName, false);
  1234. }
  1235. TRef<INameSpace> pns = GetWindow()->GetModeler()->GetNameSpace(modelName);
  1236. if (pns != NULL) {
  1237. //
  1238. // found an mdl version
  1239. //
  1240. m_pthing->LoadMDL(options, pns, pimageTexture, originalRadius);
  1241. return S_OK;
  1242. }
  1243. //
  1244. // Didn't find an MDL file try to load an XFile
  1245. return m_pthing->LoadXFile(options, modelName, pimageTexture, originalRadius);
  1246. }
  1247. return E_FAIL;
  1248. }
  1249. void SetTrailColor(const Color& color)
  1250. {
  1251. if (m_pthing)
  1252. m_pthing->SetTrailColor(color);
  1253. else
  1254. {
  1255. assert (m_pdecal);
  1256. }
  1257. }
  1258. HRESULT LoadAleph(const char* textureName)
  1259. {
  1260. ZAssert(m_pthing == NULL && m_pdecal == NULL);
  1261. m_pthing =
  1262. ThingGeo::Create(
  1263. GetWindow()->GetModeler(),
  1264. GetWindow()->GetTime()
  1265. );
  1266. TRef<Image> pimageAleph =
  1267. GetWindow()->GetModeler()->LoadImage(ZString(textureName) + "bmp", false);
  1268. if (pimageAleph) {
  1269. HRESULT hr =
  1270. m_pthing->Load(
  1271. 0,
  1272. CreateAlephGeo(
  1273. GetWindow()->GetModeler(),
  1274. GetWindow()->GetTime()
  1275. ),
  1276. pimageAleph,
  1277. 0.0f
  1278. );
  1279. m_pthing->Update();
  1280. return hr;
  1281. }
  1282. return E_FAIL;
  1283. }
  1284. void UpdateScreenPosition(
  1285. const Point& pointScreenPosition,
  1286. float fScreenRadius,
  1287. float distanceToEdge,
  1288. unsigned char ucRadarState
  1289. ) {
  1290. m_pointScreenPosition = pointScreenPosition;
  1291. m_fScreenRadius = fScreenRadius;
  1292. m_distanceToEdge = distanceToEdge;
  1293. m_ucRadarState = ucRadarState;
  1294. }
  1295. Point GetScreenPosition()
  1296. {
  1297. return m_pointScreenPosition;
  1298. }
  1299. float GetDistanceToEdge()
  1300. {
  1301. return m_distanceToEdge;
  1302. }
  1303. float GetScreenRadius()
  1304. {
  1305. return m_fScreenRadius;
  1306. }
  1307. unsigned char GetRadarState()
  1308. {
  1309. return m_ucRadarState;
  1310. }
  1311. SelectionMask GetSelectionMask(void)
  1312. {
  1313. return m_sm;
  1314. }
  1315. void SetSelectionMask(SelectionMask sm)
  1316. {
  1317. m_sm = sm;
  1318. }
  1319. void SetCluster(ImodelIGC* pmodel, IclusterIGC* pcluster)
  1320. {
  1321. /* ModelAttributes ma = pmodel->GetAttributes();
  1322. m_bSideVisibility = (ma & c_mtSeenBySide) != 0;
  1323. m_bIsShip = (pmodel->GetObjectType() == OT_ship);
  1324. {
  1325. ModelClass mc = pmodel->GetModelClass();
  1326. if (mc != c_mcUnknown)
  1327. {
  1328. assert (pmodel->GetSide());
  1329. m_sideVisibility.psCounter(pcluster
  1330. ? (&(pcluster->GetClusterSite()->GetSectorData(NA)->nModels[mc][pmodel->GetSide()->GetObjectID()]))
  1331. : NULL);
  1332. }
  1333. }
  1334. if (pcluster)
  1335. {
  1336. if ((ma & c_mtPredictable) && trekClient.m_fm.IsConnected())
  1337. m_sideVisibility.fVisible(true);
  1338. else
  1339. UpdateSideVisibility(pmodel, pcluster);
  1340. }*/
  1341. }
  1342. void UpdateSideVisibility(ImodelIGC* pmodel, IclusterIGC* pcluster)
  1343. {
  1344. /*
  1345. //We can only update it if we have one & if the client is actually on a side.
  1346. if (m_bSideVisibility && trekClient.GetSide())
  1347. {
  1348. //Update the visibility of hidden or non-static objects
  1349. //(visibile static objects stay visible)
  1350. if (!(m_sideVisibility.fVisible() && (pmodel->GetAttributes() & c_mtPredictable)))
  1351. {
  1352. //We, trivially, see anything on our side. beyond that ...
  1353. //does the ship that saw the object last still see it
  1354. //(if such a ship exists)
  1355. if ((trekClient.GetSide() == pmodel->GetSide()) ||
  1356. (m_sideVisibility.pLastSpotter() &&
  1357. m_sideVisibility.pLastSpotter()->InScannerRange(pmodel)))
  1358. {
  1359. //yes
  1360. if (!m_sideVisibility.fVisible())
  1361. {
  1362. if (m_bIsShip)
  1363. Sound::PlaySoundEffect(newShipSound);
  1364. m_sideVisibility.fVisible(true);
  1365. }
  1366. }
  1367. else
  1368. {
  1369. //do it the hard way
  1370. m_sideVisibility.fVisible(false);
  1371. for (ScannerLinkIGC* l = pcluster->GetClusterSite()->GetScanners(0)->first();
  1372. (l != NULL);
  1373. l = l->next())
  1374. {
  1375. IscannerIGC* s = l->data();
  1376. assert (s->GetCluster() == pcluster);
  1377. if (s->InScannerRange(pmodel))
  1378. {
  1379. //Ship s's side does not see the ship but this ship does
  1380. if (m_bIsShip)
  1381. Sound::PlaySoundEffect(newShipSound);
  1382. m_sideVisibility.fVisible(true);
  1383. m_sideVisibility.pLastSpotter(s);
  1384. break;
  1385. }
  1386. }
  1387. }
  1388. }
  1389. }*/
  1390. }
  1391. bool GetSideVisibility(IsideIGC* side)
  1392. {
  1393. /* assert (side);
  1394. return m_sideVisibility.fVisible();*/
  1395. return true;
  1396. }
  1397. void SetSideVisibility(IsideIGC* side, bool fVisible)
  1398. {
  1399. /* if (m_bSideVisibility && (side == trekClient.GetSide()))
  1400. m_sideVisibility.fVisible(fVisible);*/
  1401. }
  1402. DamageBuckets* GetDamageBuckets(void) const
  1403. {
  1404. // return m_pdamagebuckets;
  1405. return NULL;
  1406. }
  1407. void SetDamageBuckets(DamageBuckets* pdb)
  1408. {
  1409. // m_pdamagebuckets = pdb;
  1410. }
  1411. virtual void ActivateBolt(void)
  1412. {
  1413. if ((!m_pbolt) && m_pmodel->GetVisibleF())
  1414. {
  1415. float r = 0.5f * m_pmodel->GetRadius();
  1416. Vector f = m_pmodel->GetOrientation().GetForward();
  1417. const Vector& p1 = m_pmodel->GetPosition() + f * r; //Hack till we get an emit point
  1418. Vector p2 = p1 + (100.0f + r) * f;
  1419. m_pvvBoltP1 = new VectorValue(p1);
  1420. m_pvvBoltP2 = new VectorValue(p2);
  1421. m_pbolt = CreateBoltGeo(m_pvvBoltP1, m_pvvBoltP2, 0.125f);
  1422. m_pmodel->GetCluster()->GetClusterSite()->GetGroupScene()->AddGeo(m_pbolt);
  1423. }
  1424. }
  1425. virtual void DeactivateBolt(void)
  1426. {
  1427. if (m_pbolt)
  1428. {
  1429. m_pbolt->SetEmpty();
  1430. m_pbolt = NULL;
  1431. }
  1432. }
  1433. private:
  1434. TRef<CadetFlightImageImpl> m_pflightImg;
  1435. SideVisibility m_sideVisibility;
  1436. TRef<Geo> m_pbolt;
  1437. TRef<ThingGeo> m_pthing;
  1438. TRef<DecalGeo> m_pdecal;
  1439. ImodelIGC* m_pmodel;
  1440. Point m_pointScreenPosition;
  1441. VectorValue* m_pvvBoltP1;
  1442. VectorValue* m_pvvBoltP2;
  1443. float m_fScreenRadius;
  1444. DamageBuckets* m_pdamagebuckets;
  1445. float m_radius;
  1446. float m_distanceToEdge;
  1447. SelectionMask m_sm;
  1448. bool m_bSideVisibility;
  1449. unsigned char m_ucRadarState;
  1450. bool m_bIsShip;
  1451. };
  1452. TRef<ThingSite> CreateThingSite(ImodelIGC* pModel, CadetFlightImageImpl* pflightImg)
  1453. {
  1454. return new ThingSiteImpl(pModel, pflightImg);
  1455. }