W3dWaypointBuffer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DWaypointBuffer.cpp ////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Electronic Arts Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2002 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: Command & Conquers: Generals
  34. //
  35. // File name: W3DWaypointBuffer.cpp
  36. //
  37. // Created: Kris Morness, October 2002
  38. //
  39. // Desc: Draw buffer to handle all the waypoints in the scene. Waypoints
  40. // are rendered after terrain, after roads & bridges, and after
  41. // global fog, but before structures, objects, units, trees, etc.
  42. // This way if we have two waypoints at the bottom of a hill but
  43. // going through the hill, the line won't get cut off. However,
  44. // structures and units on top of paths will render above it. Waypoints
  45. // are only shown for selected units while in waypoint plotting mode.
  46. //
  47. //-----------------------------------------------------------------------------
  48. //-----------------------------------------------------------------------------
  49. // Includes
  50. //-----------------------------------------------------------------------------
  51. #include "W3DDevice/GameClient/W3DWaypointBuffer.h"
  52. #include <stdio.h>
  53. #include <string.h>
  54. #include <assetmgr.h>
  55. #include <texture.h>
  56. #include "Common/GlobalData.h"
  57. #include "Common/RandomValue.h"
  58. #include "Common/ThingFactory.h"
  59. #include "Common/ThingTemplate.h"
  60. #include "GameClient/Drawable.h"
  61. #include "GameClient/GameClient.h"
  62. #include "GameClient/InGameUI.h"
  63. #include "GameLogic/Object.h"
  64. #include "GameLogic/Module/AIUpdate.h"
  65. #include "W3DDevice/GameClient/TerrainTex.h"
  66. #include "W3DDevice/GameClient/HeightMap.h"
  67. #include "WW3D2/Camera.h"
  68. #include "WW3D2/DX8Wrapper.h"
  69. #include "WW3D2/DX8Renderer.h"
  70. #include "WW3D2/Mesh.h"
  71. #include "WW3D2/MeshMdl.h"
  72. #include "WW3D2/Segline.h"
  73. #define MAX_DISPLAY_NODES 512
  74. #ifdef _INTERNAL
  75. // for occasional debugging...
  76. //#pragma optimize("", off)
  77. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  78. #endif
  79. //=============================================================================
  80. // W3DWaypointBuffer::W3DWaypointBuffer
  81. //=============================================================================
  82. /** Constructor. Sets m_initialized to true if it finds the w3d models it needs
  83. for the bibs. */
  84. //=============================================================================
  85. W3DWaypointBuffer::W3DWaypointBuffer(void)
  86. {
  87. m_waypointNodeRobj = WW3DAssetManager::Get_Instance()->Create_Render_Obj( "SCMNode" );
  88. m_line = new SegmentedLineClass;
  89. m_texture = WW3DAssetManager::Get_Instance()->Get_Texture( "EXLaser.tga" );
  90. setDefaultLineStyle();
  91. }
  92. //=============================================================================
  93. // W3DWaypointBuffer::~W3DWaypointBuffer
  94. //=============================================================================
  95. /** Destructor. Releases w3d assets. */
  96. //=============================================================================
  97. W3DWaypointBuffer::~W3DWaypointBuffer(void)
  98. {
  99. REF_PTR_RELEASE( m_waypointNodeRobj );
  100. REF_PTR_RELEASE( m_texture );
  101. REF_PTR_RELEASE( m_line );
  102. }
  103. //=============================================================================
  104. // W3DWaypointBuffer::freeBibBuffers
  105. //=============================================================================
  106. /** Frees the index and vertex buffers. */
  107. //=============================================================================
  108. void W3DWaypointBuffer::freeWaypointBuffers()
  109. {
  110. }
  111. void W3DWaypointBuffer::setDefaultLineStyle( void )
  112. {
  113. if( m_texture )
  114. {
  115. m_line->Set_Texture( m_texture );
  116. }
  117. ShaderClass lineShader=ShaderClass::_PresetAdditiveShader;
  118. lineShader.Set_Depth_Compare(ShaderClass::PASS_ALWAYS);
  119. m_line->Set_Shader( lineShader ); //pick the alpha blending mode you want - see shader.h for others.
  120. m_line->Set_Width( 1.5f );
  121. m_line->Set_Color( Vector3( 0.25f, 0.5f, 1.0f ) );
  122. m_line->Set_Texture_Mapping_Mode( SegLineRendererClass::TILED_TEXTURE_MAP ); //this tiles the texture across the line
  123. }
  124. //=============================================================================
  125. // W3DWaypointBuffer::drawWaypoints
  126. //=============================================================================
  127. /** Draws the waypoints. Uses camera to cull */
  128. //=============================================================================
  129. void W3DWaypointBuffer::drawWaypoints(RenderInfoClass &rinfo)
  130. {
  131. if ( ! TheInGameUI )
  132. return;
  133. setDefaultLineStyle();
  134. if( TheInGameUI->isInWaypointMode() )
  135. {
  136. //Create a default light environment with no lights and only full ambient.
  137. //@todo: Fix later by copying default scene light environement from W3DScene.cpp.
  138. LightEnvironmentClass lightEnv;
  139. lightEnv.Reset(Vector3(0,0,0), Vector3(1.0f,1.0f,1.0f));
  140. lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  141. RenderInfoClass localRinfo(rinfo.Camera);
  142. localRinfo.light_environment=&lightEnv;
  143. Vector3 points[ MAX_DISPLAY_NODES + 1 ]; //Lines have nodes + 1 points.
  144. const DrawableList *selected = TheInGameUI->getAllSelectedDrawables();
  145. Drawable *draw;
  146. for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it )
  147. {
  148. draw = *it;
  149. Object *obj = draw->getObject();
  150. Int numPoints = 1;
  151. if( obj && ! obj->isKindOf( KINDOF_IGNORED_IN_GUI ))//so mobs and stuff sont make a gazillion lines
  152. {
  153. AIUpdateInterface *ai = obj->getAI();
  154. Int goalSize = ai ? ai->friend_getWaypointGoalPathSize() : 0;
  155. Int gpIdx = ai ? ai->friend_getCurrentGoalPathIndex() : 0;
  156. if( ai && gpIdx >= 0 && gpIdx < goalSize )
  157. {
  158. const Coord3D *pos = obj->getPosition();
  159. points[ 0 ].Set( Vector3( pos->x, pos->y, pos->z ) );
  160. for( int i = gpIdx; i < goalSize; i++ )
  161. {
  162. const Coord3D *waypoint = ai->friend_getGoalPathPosition( i );
  163. if( waypoint )
  164. {
  165. //Render line from previous point to current node.
  166. if( numPoints < MAX_DISPLAY_NODES + 1 )
  167. {
  168. points[ numPoints ].Set( Vector3( waypoint->x, waypoint->y, waypoint->z ) );
  169. numPoints++;
  170. }
  171. m_waypointNodeRobj->Set_Position(Vector3(waypoint->x,waypoint->y,waypoint->z));
  172. WW3D::Render(*m_waypointNodeRobj,localRinfo);
  173. }
  174. }
  175. //Now render the lines in one pass!
  176. m_line->Set_Points( numPoints, points );
  177. m_line->Render( localRinfo );
  178. }
  179. }
  180. }
  181. }
  182. else // maybe we want to draw rally points, then?
  183. {
  184. //Create a default light environment with no lights and only full ambient.
  185. //@todo: Fix later by copying default scene light environement from W3DScene.cpp.
  186. LightEnvironmentClass lightEnv;
  187. lightEnv.Reset(Vector3(0,0,0), Vector3(1.0f,1.0f,1.0f));
  188. lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  189. RenderInfoClass localRinfo(rinfo.Camera);
  190. localRinfo.light_environment=&lightEnv;
  191. Vector3 points[ MAX_DISPLAY_NODES + 1 ]; //Lines have nodes + 1 points.
  192. const DrawableList *selected = TheInGameUI->getAllSelectedDrawables();
  193. Drawable *draw;
  194. for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it )
  195. {
  196. draw = *it;
  197. Object *obj = draw->getObject();
  198. Int numPoints = 0;
  199. if( obj )
  200. {
  201. if ( ! obj->isLocallyControlled())
  202. continue;
  203. // WAIT! before we go browsing the drawable list for buildings that want to draw their rally points
  204. // lets test for that very special case of having a listeningoutpost selected, and some enemy drawable moused-over
  205. if ( obj->isKindOf( KINDOF_REVEALS_ENEMY_PATHS ) )
  206. {
  207. DrawableID enemyID = TheInGameUI->getMousedOverDrawableID();
  208. Drawable *enemyDraw = TheGameClient->findDrawableByID( enemyID );
  209. if ( enemyDraw )
  210. {
  211. Object *enemy = enemyDraw->getObject();
  212. if ( enemy )
  213. {
  214. if ( enemy->getRelationship( obj ) == ENEMIES )
  215. {
  216. Coord3D delta = *obj->getPosition();
  217. delta.sub( enemy->getPosition() );
  218. if ( delta.length() <= obj->getVisionRange() ) // is listening outpost close enough to do this?
  219. {
  220. //////////////////////////////////////////////////////////////////////
  221. AIUpdateInterface *ai = enemy->getAI();
  222. Int goalSize = ai ? ai->friend_getWaypointGoalPathSize() : 0;
  223. Int gpIdx = ai ? ai->friend_getCurrentGoalPathIndex() : 0;
  224. if( ai )
  225. {
  226. Bool lineExists = FALSE;
  227. const Coord3D *pos = enemy->getPosition();
  228. points[ numPoints++ ].Set( Vector3( pos->x, pos->y, pos->z ) );
  229. if ( gpIdx >= 0 && gpIdx < goalSize )// Ooh, the enemy is in waypoint mode
  230. {
  231. for( int i = gpIdx; i < goalSize; i++ )
  232. {
  233. const Coord3D *waypoint = ai->friend_getGoalPathPosition( i );
  234. if( waypoint )
  235. {
  236. //Render line from previous point to current node.
  237. if( numPoints < MAX_DISPLAY_NODES + 1 )
  238. {
  239. points[ numPoints++ ].Set( Vector3( waypoint->x, waypoint->y, waypoint->z ) );
  240. }
  241. m_waypointNodeRobj->Set_Position(Vector3(waypoint->x,waypoint->y,waypoint->z));
  242. WW3D::Render(*m_waypointNodeRobj,localRinfo);
  243. lineExists = TRUE;
  244. }
  245. }
  246. }
  247. else // then enemy may be moving to a goal position
  248. {
  249. const Coord3D *destinationPoint = ai->getGoalPosition();
  250. if ( destinationPoint->length() > 1.0f )
  251. {
  252. points[ numPoints++ ].Set( Vector3( destinationPoint->x, destinationPoint->y, destinationPoint->z ) );
  253. m_waypointNodeRobj->Set_Position(Vector3(destinationPoint->x,destinationPoint->y,destinationPoint->z));
  254. WW3D::Render(*m_waypointNodeRobj,localRinfo);
  255. lineExists = TRUE;
  256. }
  257. }
  258. if ( lineExists )
  259. {
  260. //Now render the lines in one pass!
  261. m_line->Set_Color( Vector3( 0.95f, 0.5f, 0.0f ) );
  262. m_line->Set_Width( 3.0f );
  263. m_line->Set_Points( numPoints, points );
  264. m_line->Render( localRinfo );
  265. }
  266. }
  267. //////////////////////////////////////////////////////////////////////
  268. }
  269. }
  270. }
  271. }
  272. break;// dont even bother with the rest, since this one listening outpost satisfies the single path-line limit
  273. }
  274. ExitInterface *exitInterface = obj->getObjectExitInterface();
  275. if( exitInterface )
  276. {
  277. Coord3D exitPoint;
  278. if ( ! exitInterface->getExitPosition(exitPoint))
  279. exitPoint = *obj->getPosition();
  280. points[ numPoints ].Set( Vector3( exitPoint.x, exitPoint.y, exitPoint.z ) );
  281. numPoints++;
  282. Bool boxWrap = TRUE;
  283. Coord3D naturalRallyPoint;
  284. if (exitInterface->getNaturalRallyPoint(naturalRallyPoint, FALSE))//FALSE means "without the extra offset"
  285. {
  286. if( !naturalRallyPoint.equals( exitPoint ) )
  287. {
  288. points[ numPoints ].Set( Vector3( naturalRallyPoint.x, naturalRallyPoint.y, naturalRallyPoint.z ) );
  289. numPoints++;
  290. }
  291. else
  292. {
  293. //Helipad rally point -- so don't use box wrapping.
  294. boxWrap = FALSE;
  295. }
  296. }
  297. else
  298. continue; //next drawable
  299. const Coord3D *rallyPoint = exitInterface->getRallyPoint();
  300. if( rallyPoint )
  301. {
  302. if( boxWrap )
  303. {
  304. //test to se whether the rally point flanks the side of the natural rally point
  305. //to do this we find the two corners of the geometry extents that are nearest the natural rally point
  306. // these define the natural rally point edge
  307. // an intermediate point should be inserted at the corner nearest the rally point
  308. const GeometryInfo& geom = obj->getGeometryInfo();
  309. const Coord3D *ctr = obj->getPosition();
  310. Coord3D NRPDelta;
  311. NRPDelta.x = naturalRallyPoint.x - exitPoint.x;
  312. NRPDelta.y = naturalRallyPoint.y - exitPoint.y;
  313. NRPDelta.z = 0.0f;
  314. //This is a quick idiot test to se whether the rally line needs to wrap the box at all
  315. Coord3D wayOutPoint = NRPDelta;
  316. wayOutPoint.normalize();
  317. wayOutPoint.scale( 99999.9f );
  318. Real wayOutLength = wayOutPoint.length();
  319. wayOutPoint.add(&naturalRallyPoint);
  320. //if the rallypoint is closer to the wayoutpoint than it is to the natural rally point then we definitely do not wrap
  321. Coord3D rallyToWayOutDelta = wayOutPoint;
  322. rallyToWayOutDelta.sub(rallyPoint);
  323. if ( (100.0f + rallyToWayOutDelta.length()) > wayOutLength)
  324. {
  325. //if we passed the above idiot test, now lets be sure by testing the dotproduct of the rp against the wayoutpoint
  326. wayOutPoint.normalize();// a normal shooting straight out the door
  327. //next comes the delta between the NRP and the RP
  328. Coord3D NRPToRPDelta = naturalRallyPoint;
  329. NRPToRPDelta.sub(rallyPoint);
  330. NRPToRPDelta.normalize();
  331. Real dot = NRPToRPDelta.x * wayOutPoint.x + NRPToRPDelta.y * wayOutPoint.y;
  332. if (dot > 0)
  333. {
  334. Real angle = obj->getOrientation();
  335. Real c = (Real)cos(angle);
  336. Real s = (Real)sin(angle);
  337. Coord3D NRPToCtrDelta;
  338. NRPToCtrDelta.x = naturalRallyPoint.x - ctr->x;
  339. NRPToCtrDelta.y = naturalRallyPoint.y - ctr->y;
  340. NRPToCtrDelta.x = 0.0f;
  341. Real exc = geom.getMajorRadius() * c;
  342. Real eyc = geom.getMinorRadius() * c;
  343. Real exs = geom.getMajorRadius() * s;
  344. Real eys = geom.getMinorRadius() * s;
  345. Coord2D corners[ 4 ];
  346. corners[0].x = ctr->x - exc - eys;
  347. corners[0].y = ctr->y + eyc - exs;
  348. corners[1].x = ctr->x + exc - eys;
  349. corners[1].y = ctr->y + eyc + exs;
  350. corners[2].x = ctr->x + exc + eys;
  351. corners[2].y = ctr->y - eyc + exs;
  352. corners[3].x = ctr->x - exc + eys;
  353. corners[3].y = ctr->y - eyc - exs;
  354. Coord2D *pNearElbow = NULL;//find the closest corner to the rallyPoint same end as door
  355. Coord2D *pFarElbow = NULL; //find the closest corner to the rallypoint away from door
  356. Coord2D *nearCandidate = NULL;
  357. Coord3D cornerToRPDelta, cornerToExitDelta;
  358. cornerToRPDelta.z = 0.0f;
  359. cornerToExitDelta.z = 0.0f;
  360. Real elbowDistanceNear = 99999.9f;
  361. Real elbowDistanceFar = 99999.9f;
  362. for (UnsignedInt cornerIndex = 0; cornerIndex < 4; ++ cornerIndex)
  363. {
  364. nearCandidate = &corners[cornerIndex];//for quicker array access
  365. cornerToExitDelta.x = exitPoint.x - nearCandidate->x;
  366. cornerToExitDelta.y = exitPoint.y - nearCandidate->y;
  367. cornerToExitDelta.normalize();
  368. dot = cornerToExitDelta.x * wayOutPoint.x + cornerToExitDelta.y * wayOutPoint.y;
  369. if ( dot < 0.0f )
  370. {
  371. cornerToRPDelta.x = rallyPoint->x - nearCandidate->x;
  372. cornerToRPDelta.y = rallyPoint->y - nearCandidate->y;
  373. if (cornerToRPDelta.length() < elbowDistanceNear)
  374. {
  375. elbowDistanceNear = cornerToRPDelta.length();
  376. pNearElbow = nearCandidate;
  377. }
  378. }
  379. else
  380. {
  381. cornerToRPDelta.x = rallyPoint->x - nearCandidate->x;
  382. cornerToRPDelta.y = rallyPoint->y - nearCandidate->y;
  383. if (cornerToRPDelta.length() < elbowDistanceFar)
  384. {
  385. elbowDistanceFar = cornerToRPDelta.length();
  386. pFarElbow = nearCandidate;
  387. }
  388. }
  389. }
  390. if (pNearElbow)//did we find a nearest corner?
  391. {
  392. m_waypointNodeRobj->Set_Position(Vector3(pNearElbow->x,pNearElbow->y,ctr->z));
  393. WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
  394. points[ numPoints ].Set( Vector3( pNearElbow->x, pNearElbow->y, ctr->z ) );
  395. numPoints++;
  396. //and for that matter did we find a far side coner?
  397. if (pFarElbow)//did we find a nearest corner?
  398. {
  399. // but let's test the dot of the first elbow against the rally point to find out
  400. //whethet the rally point wraps around this one, too
  401. Coord3D firstElbowDelta;
  402. firstElbowDelta.x = naturalRallyPoint.x - pNearElbow->x;
  403. firstElbowDelta.y = naturalRallyPoint.y - pNearElbow->y;
  404. firstElbowDelta.z = 0.0f;
  405. firstElbowDelta.normalize();
  406. Coord3D firstToRPDelta;
  407. firstToRPDelta.x = pNearElbow->x - rallyPoint->x;
  408. firstToRPDelta.y = pNearElbow->y - rallyPoint->y;
  409. firstToRPDelta.z = 0.0f;
  410. firstToRPDelta.normalize();
  411. dot = firstToRPDelta.x * firstElbowDelta.x + firstToRPDelta.y * firstElbowDelta.y;
  412. if (dot < 0)// we have a second elbow
  413. {
  414. m_waypointNodeRobj->Set_Position(Vector3(pFarElbow->x,pFarElbow->y,ctr->z));
  415. WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
  416. points[ numPoints ].Set( Vector3( pFarElbow->x, pFarElbow->y, ctr->z ) );
  417. numPoints++;
  418. }
  419. }
  420. }
  421. }
  422. }
  423. }
  424. // Finally draw the line out to the RallyPoint
  425. points[ numPoints ].Set( Vector3( rallyPoint->x, rallyPoint->y, rallyPoint->z ) );
  426. numPoints++;
  427. }
  428. else
  429. continue;
  430. m_waypointNodeRobj->Set_Position(Vector3(naturalRallyPoint.x,naturalRallyPoint.y,naturalRallyPoint.z));
  431. WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
  432. m_line->Set_Points( numPoints, points );
  433. m_line->Render( localRinfo );
  434. }// end if exit interface
  435. }
  436. }
  437. }
  438. }