W3dWaypointBuffer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. ** Command & Conquer Generals(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. if( m_texture )
  91. {
  92. m_line->Set_Texture( m_texture );
  93. }
  94. ShaderClass lineShader=ShaderClass::_PresetAdditiveShader;
  95. lineShader.Set_Depth_Compare(ShaderClass::PASS_ALWAYS);
  96. m_line->Set_Shader( lineShader ); //pick the alpha blending mode you want - see shader.h for others.
  97. m_line->Set_Width( 1.5f );
  98. m_line->Set_Color( Vector3( 0.25f, 0.5f, 1.0f ) );
  99. m_line->Set_Texture_Mapping_Mode( SegLineRendererClass::TILED_TEXTURE_MAP ); //this tiles the texture across the line
  100. }
  101. //=============================================================================
  102. // W3DWaypointBuffer::~W3DWaypointBuffer
  103. //=============================================================================
  104. /** Destructor. Releases w3d assets. */
  105. //=============================================================================
  106. W3DWaypointBuffer::~W3DWaypointBuffer(void)
  107. {
  108. REF_PTR_RELEASE( m_waypointNodeRobj );
  109. }
  110. //=============================================================================
  111. // W3DWaypointBuffer::freeBibBuffers
  112. //=============================================================================
  113. /** Frees the index and vertex buffers. */
  114. //=============================================================================
  115. void W3DWaypointBuffer::freeWaypointBuffers()
  116. {
  117. }
  118. //=============================================================================
  119. // W3DWaypointBuffer::drawWaypoints
  120. //=============================================================================
  121. /** Draws the waypoints. Uses camera to cull */
  122. //=============================================================================
  123. void W3DWaypointBuffer::drawWaypoints(RenderInfoClass &rinfo)
  124. {
  125. if( TheInGameUI && TheInGameUI->isInWaypointMode() )
  126. {
  127. //Create a default light environment with no lights and only full ambient.
  128. //@todo: Fix later by copying default scene light environement from W3DScene.cpp.
  129. LightEnvironmentClass lightEnv;
  130. lightEnv.Reset(Vector3(0,0,0), Vector3(1.0f,1.0f,1.0f));
  131. lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  132. RenderInfoClass localRinfo(rinfo.Camera);
  133. localRinfo.light_environment=&lightEnv;
  134. Vector3 points[ MAX_DISPLAY_NODES + 1 ]; //Lines have nodes + 1 points.
  135. const DrawableList *selected = TheInGameUI->getAllSelectedDrawables();
  136. Drawable *draw;
  137. for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it )
  138. {
  139. draw = *it;
  140. Object *obj = draw->getObject();
  141. Int numPoints = 1;
  142. if( obj && ! obj->isKindOf( KINDOF_IGNORED_IN_GUI ))//so mobs and stuff sont make a gazillion lines
  143. {
  144. AIUpdateInterface *ai = obj->getAI();
  145. Int goalSize = ai ? ai->friend_getWaypointGoalPathSize() : 0;
  146. Int gpIdx = ai ? ai->friend_getCurrentGoalPathIndex() : 0;
  147. if( ai && gpIdx >= 0 && gpIdx < goalSize )
  148. {
  149. const Coord3D *pos = obj->getPosition();
  150. points[ 0 ].Set( Vector3( pos->x, pos->y, pos->z ) );
  151. for( int i = gpIdx; i < goalSize; i++ )
  152. {
  153. const Coord3D *waypoint = ai->friend_getGoalPathPosition( i );
  154. if( waypoint )
  155. {
  156. //Render line from previous point to current node.
  157. if( numPoints < MAX_DISPLAY_NODES + 1 )
  158. {
  159. points[ numPoints ].Set( Vector3( waypoint->x, waypoint->y, waypoint->z ) );
  160. numPoints++;
  161. }
  162. m_waypointNodeRobj->Set_Position(Vector3(waypoint->x,waypoint->y,waypoint->z));
  163. WW3D::Render(*m_waypointNodeRobj,localRinfo);
  164. }
  165. }
  166. //Now render the lines in one pass!
  167. m_line->Set_Points( numPoints, points );
  168. m_line->Render( localRinfo );
  169. }
  170. }
  171. }
  172. }
  173. else // maybe we want to draw rally points, then?
  174. if (TheInGameUI)
  175. {
  176. //Create a default light environment with no lights and only full ambient.
  177. //@todo: Fix later by copying default scene light environement from W3DScene.cpp.
  178. LightEnvironmentClass lightEnv;
  179. lightEnv.Reset(Vector3(0,0,0), Vector3(1.0f,1.0f,1.0f));
  180. lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  181. RenderInfoClass localRinfo(rinfo.Camera);
  182. localRinfo.light_environment=&lightEnv;
  183. Vector3 points[ MAX_DISPLAY_NODES + 1 ]; //Lines have nodes + 1 points.
  184. const DrawableList *selected = TheInGameUI->getAllSelectedDrawables();
  185. Drawable *draw;
  186. for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it )
  187. {
  188. draw = *it;
  189. Object *obj = draw->getObject();
  190. Int numPoints = 0;
  191. if( obj )
  192. {
  193. if ( ! obj->isLocallyControlled())
  194. continue;
  195. ExitInterface *exitInterface = obj->getObjectExitInterface();
  196. if( exitInterface )
  197. {
  198. Coord3D exitPoint;
  199. if ( ! exitInterface->getExitPosition(exitPoint))
  200. exitPoint = *obj->getPosition();
  201. points[ numPoints ].Set( Vector3( exitPoint.x, exitPoint.y, exitPoint.z ) );
  202. numPoints++;
  203. Bool boxWrap = TRUE;
  204. Coord3D naturalRallyPoint;
  205. if (exitInterface->getNaturalRallyPoint(naturalRallyPoint, FALSE))//FALSE means "without the extra offset"
  206. {
  207. if( !naturalRallyPoint.equals( exitPoint ) )
  208. {
  209. points[ numPoints ].Set( Vector3( naturalRallyPoint.x, naturalRallyPoint.y, naturalRallyPoint.z ) );
  210. numPoints++;
  211. }
  212. else
  213. {
  214. //Helipad rally point -- so don't use box wrapping.
  215. boxWrap = FALSE;
  216. }
  217. }
  218. else
  219. continue; //next drawable
  220. const Coord3D *rallyPoint = exitInterface->getRallyPoint();
  221. if( rallyPoint )
  222. {
  223. if( boxWrap )
  224. {
  225. //test to se whether the rally point flanks the side of the natural rally point
  226. //to do this we find the two corners of the geometry extents that are nearest the natural rally point
  227. // these define the natural rally point edge
  228. // an intermediate point should be inserted at the corner nearest the rally point
  229. const GeometryInfo& geom = obj->getGeometryInfo();
  230. const Coord3D *ctr = obj->getPosition();
  231. Coord3D NRPDelta;
  232. NRPDelta.x = naturalRallyPoint.x - exitPoint.x;
  233. NRPDelta.y = naturalRallyPoint.y - exitPoint.y;
  234. NRPDelta.z = 0.0f;
  235. //This is a quick idiot test to se whether the rally line needs to wrap the box at all
  236. Coord3D wayOutPoint = NRPDelta;
  237. wayOutPoint.normalize();
  238. wayOutPoint.scale( 99999.9f );
  239. Real wayOutLength = wayOutPoint.length();
  240. wayOutPoint.add(&naturalRallyPoint);
  241. //if the rallypoint is closer to the wayoutpoint than it is to the natural rally point then we definitely do not wrap
  242. Coord3D rallyToWayOutDelta = wayOutPoint;
  243. rallyToWayOutDelta.sub(rallyPoint);
  244. if ( (100.0f + rallyToWayOutDelta.length()) > wayOutLength)
  245. {
  246. //if we passed the above idiot test, now lets be sure by testing the dotproduct of the rp against the wayoutpoint
  247. wayOutPoint.normalize();// a normal shooting straight out the door
  248. //next comes the delta between the NRP and the RP
  249. Coord3D NRPToRPDelta = naturalRallyPoint;
  250. NRPToRPDelta.sub(rallyPoint);
  251. NRPToRPDelta.normalize();
  252. Real dot = NRPToRPDelta.x * wayOutPoint.x + NRPToRPDelta.y * wayOutPoint.y;
  253. if (dot > 0)
  254. {
  255. Real angle = obj->getOrientation();
  256. Real c = (Real)cos(angle);
  257. Real s = (Real)sin(angle);
  258. Coord3D NRPToCtrDelta;
  259. NRPToCtrDelta.x = naturalRallyPoint.x - ctr->x;
  260. NRPToCtrDelta.y = naturalRallyPoint.y - ctr->y;
  261. NRPToCtrDelta.x = 0.0f;
  262. Real exc = geom.getMajorRadius() * c;
  263. Real eyc = geom.getMinorRadius() * c;
  264. Real exs = geom.getMajorRadius() * s;
  265. Real eys = geom.getMinorRadius() * s;
  266. Coord2D corners[ 4 ];
  267. corners[0].x = ctr->x - exc - eys;
  268. corners[0].y = ctr->y + eyc - exs;
  269. corners[1].x = ctr->x + exc - eys;
  270. corners[1].y = ctr->y + eyc + exs;
  271. corners[2].x = ctr->x + exc + eys;
  272. corners[2].y = ctr->y - eyc + exs;
  273. corners[3].x = ctr->x - exc + eys;
  274. corners[3].y = ctr->y - eyc - exs;
  275. Coord2D *pNearElbow = NULL;//find the closest corner to the rallyPoint same end as door
  276. Coord2D *pFarElbow = NULL; //find the closest corner to the rallypoint away from door
  277. Coord2D *nearCandidate = NULL;
  278. Coord3D cornerToRPDelta, cornerToExitDelta;
  279. cornerToRPDelta.z = 0.0f;
  280. cornerToExitDelta.z = 0.0f;
  281. Real elbowDistanceNear = 99999.9f;
  282. Real elbowDistanceFar = 99999.9f;
  283. for (UnsignedInt cornerIndex = 0; cornerIndex < 4; ++ cornerIndex)
  284. {
  285. nearCandidate = &corners[cornerIndex];//for quicker array access
  286. cornerToExitDelta.x = exitPoint.x - nearCandidate->x;
  287. cornerToExitDelta.y = exitPoint.y - nearCandidate->y;
  288. cornerToExitDelta.normalize();
  289. dot = cornerToExitDelta.x * wayOutPoint.x + cornerToExitDelta.y * wayOutPoint.y;
  290. if ( dot < 0.0f )
  291. {
  292. cornerToRPDelta.x = rallyPoint->x - nearCandidate->x;
  293. cornerToRPDelta.y = rallyPoint->y - nearCandidate->y;
  294. if (cornerToRPDelta.length() < elbowDistanceNear)
  295. {
  296. elbowDistanceNear = cornerToRPDelta.length();
  297. pNearElbow = nearCandidate;
  298. }
  299. }
  300. else
  301. {
  302. cornerToRPDelta.x = rallyPoint->x - nearCandidate->x;
  303. cornerToRPDelta.y = rallyPoint->y - nearCandidate->y;
  304. if (cornerToRPDelta.length() < elbowDistanceFar)
  305. {
  306. elbowDistanceFar = cornerToRPDelta.length();
  307. pFarElbow = nearCandidate;
  308. }
  309. }
  310. }
  311. if (pNearElbow)//did we find a nearest corner?
  312. {
  313. m_waypointNodeRobj->Set_Position(Vector3(pNearElbow->x,pNearElbow->y,ctr->z));
  314. WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
  315. points[ numPoints ].Set( Vector3( pNearElbow->x, pNearElbow->y, ctr->z ) );
  316. numPoints++;
  317. //and for that matter did we find a far side coner?
  318. if (pFarElbow)//did we find a nearest corner?
  319. {
  320. // but let's test the dot of the first elbow against the rally point to find out
  321. //whethet the rally point wraps around this one, too
  322. Coord3D firstElbowDelta;
  323. firstElbowDelta.x = naturalRallyPoint.x - pNearElbow->x;
  324. firstElbowDelta.y = naturalRallyPoint.y - pNearElbow->y;
  325. firstElbowDelta.z = 0.0f;
  326. firstElbowDelta.normalize();
  327. Coord3D firstToRPDelta;
  328. firstToRPDelta.x = pNearElbow->x - rallyPoint->x;
  329. firstToRPDelta.y = pNearElbow->y - rallyPoint->y;
  330. firstToRPDelta.z = 0.0f;
  331. firstToRPDelta.normalize();
  332. dot = firstToRPDelta.x * firstElbowDelta.x + firstToRPDelta.y * firstElbowDelta.y;
  333. if (dot < 0)// we have a second elbow
  334. {
  335. m_waypointNodeRobj->Set_Position(Vector3(pFarElbow->x,pFarElbow->y,ctr->z));
  336. WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
  337. points[ numPoints ].Set( Vector3( pFarElbow->x, pFarElbow->y, ctr->z ) );
  338. numPoints++;
  339. }
  340. }
  341. }
  342. }
  343. }
  344. }
  345. // Finally draw the line out to the RallyPoint
  346. points[ numPoints ].Set( Vector3( rallyPoint->x, rallyPoint->y, rallyPoint->z ) );
  347. numPoints++;
  348. }
  349. else
  350. continue;
  351. m_waypointNodeRobj->Set_Position(Vector3(naturalRallyPoint.x,naturalRallyPoint.y,naturalRallyPoint.z));
  352. WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
  353. m_line->Set_Points( numPoints, points );
  354. m_line->Render( localRinfo );
  355. }
  356. }
  357. }
  358. }
  359. }