W3DView.cpp 112 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363
  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: W3DView.cpp //////////////////////////////////////////////////////////////////////////////
  24. //
  25. // W3D implementation of the game view class. This view allows us to have
  26. // a "window" into the game world that can change its width, height as
  27. // well as camera positioning controls
  28. //
  29. // Author: Colin Day, April 2001
  30. //
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////
  32. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////////////////////////
  33. #include <stdlib.h>
  34. #include <windows.h>
  35. // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
  36. #include "Common/BuildAssistant.h"
  37. #include "Common/GlobalData.h"
  38. #include "Common/Module.h"
  39. #include "Common/RandomValue.h"
  40. #include "Common/ThingTemplate.h"
  41. #include "Common/ThingSort.h"
  42. #include "Common/PerfTimer.h"
  43. #include "Common/PlayerList.h"
  44. #include "Common/Player.h"
  45. #include "GameClient/Color.h"
  46. #include "GameClient/CommandXlat.h"
  47. #include "GameClient/Drawable.h"
  48. #include "GameClient/GameClient.h"
  49. #include "GameClient/GameWindowManager.h"
  50. #include "GameClient/Image.h"
  51. #include "GameClient/InGameUI.h"
  52. #include "GameClient/Line2D.h"
  53. #include "GameClient/SelectionInfo.h"
  54. #include "GameClient/Shell.h"
  55. #include "GameClient/TerrainVisual.h"
  56. #include "GameClient/Water.h"
  57. #include "GameLogic/AI.h" ///< For AI debug (yes, I'm cheating for now)
  58. #include "GameLogic/AIPathfind.h" ///< For AI debug (yes, I'm cheating for now)
  59. #include "GameLogic/ExperienceTracker.h"
  60. #include "GameLogic/GameLogic.h"
  61. #include "GameLogic/Module/AIUpdate.h"
  62. #include "GameLogic/Module/BodyModule.h"
  63. #include "GameLogic/Module/ContainModule.h"
  64. #include "GameLogic/Module/OpenContain.h"
  65. #include "GameLogic/Object.h"
  66. #include "GameLogic/ScriptEngine.h"
  67. #include "GameLogic/TerrainLogic.h" ///< @todo This should be TerrainVisual (client side)
  68. #include "Common/AudioEventInfo.h"
  69. #include "W3DDevice/Common/W3DConvert.h"
  70. #include "W3DDevice/GameClient/HeightMap.h"
  71. #include "W3DDevice/GameClient/W3DAssetManager.h"
  72. #include "W3DDevice/GameClient/W3DDisplay.h"
  73. #include "W3DDevice/GameClient/W3DScene.h"
  74. #include "W3DDevice/GameClient/W3DView.h"
  75. #include "D3dx8math.h"
  76. #include "W3DDevice/GameClient/W3DShaderManager.h"
  77. #include "W3DDevice/GameClient/Module/W3DModelDraw.h"
  78. #include "W3DDevice/GameClient/W3DCustomScene.h"
  79. #include "WW3D2/DX8Renderer.h"
  80. #include "WW3D2/Light.h"
  81. #include "WW3D2/Camera.h"
  82. #include "WW3D2/Coltype.h"
  83. #include "WW3D2/PredLod.h"
  84. #include "WW3D2/WW3D.h"
  85. #include "W3DDevice/GameClient/camerashakesystem.h"
  86. #include "WinMain.h" /** @todo Remove this, it's only here because we
  87. are using timeGetTime, but we can remove that
  88. when we have our own timer */
  89. #ifdef _INTERNAL
  90. // for occasional debugging...
  91. //#pragma optimize("", off)
  92. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  93. #endif
  94. // 30 fps
  95. Int TheW3DFrameLengthInMsec = 1000/LOGICFRAMES_PER_SECOND; // default is 33msec/frame == 30fps. but we may change it depending on sys config.
  96. static const Int MAX_REQUEST_CACHE_SIZE = 40; // Any size larger than 10, or examine code below for changes. jkmcd.
  97. static const Real DRAWABLE_OVERSCAN = 75.0f; ///< 3D world coords of how much to overscan in the 3D screen region
  98. //=================================================================================================
  99. inline Real minf(Real a, Real b) { if (a < b) return a; else return b; }
  100. inline Real maxf(Real a, Real b) { if (a > b) return a; else return b; }
  101. //-------------------------------------------------------------------------------------------------
  102. // Normalizes angle to +- PI.
  103. //-------------------------------------------------------------------------------------------------
  104. static void normAngle(Real &angle)
  105. {
  106. if (angle < -10*PI) {
  107. angle = 0;
  108. }
  109. if (angle > 10*PI) {
  110. angle = 0;
  111. }
  112. while (angle < -PI) {
  113. angle += 2*PI;
  114. }
  115. while (angle > PI) {
  116. angle -= 2*PI;
  117. }
  118. }
  119. #define TERRAIN_SAMPLE_SIZE 40.0f
  120. static Real getHeightAroundPos(Real x, Real y)
  121. {
  122. // terrain height + desired height offset == cameraOffset * actual zoom
  123. Real terrainHeight = TheTerrainLogic->getGroundHeight(x, y);
  124. // find best approximation of max terrain height we can see
  125. Real terrainHeightMax = terrainHeight;
  126. terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x+TERRAIN_SAMPLE_SIZE, y-TERRAIN_SAMPLE_SIZE));
  127. terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x-TERRAIN_SAMPLE_SIZE, y-TERRAIN_SAMPLE_SIZE));
  128. terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x+TERRAIN_SAMPLE_SIZE, y+TERRAIN_SAMPLE_SIZE));
  129. terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x-TERRAIN_SAMPLE_SIZE, y+TERRAIN_SAMPLE_SIZE));
  130. return terrainHeightMax;
  131. }
  132. //-------------------------------------------------------------------------------------------------
  133. //-------------------------------------------------------------------------------------------------
  134. W3DView::W3DView()
  135. {
  136. m_3DCamera = NULL;
  137. m_2DCamera = NULL;
  138. m_groundLevel = 10.0;
  139. m_cameraOffset.z = TheGlobalData->m_cameraHeight;
  140. m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
  141. m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
  142. m_viewFilterMode = FM_VIEW_DEFAULT;
  143. m_viewFilter = FT_VIEW_DEFAULT;
  144. m_isWireFrameEnabled = m_nextWireFrameEnabled = FALSE;
  145. m_shakeOffset.x = 0.0f;
  146. m_shakeOffset.y = 0.0f;
  147. m_shakeIntensity = 0.0f;
  148. m_FXPitch = 1.0f;
  149. m_freezeTimeForCameraMovement = false;
  150. m_cameraHasMovedSinceRequest = true;
  151. m_locationRequests.clear();
  152. m_locationRequests.reserve(MAX_REQUEST_CACHE_SIZE + 10); // This prevents the vector from ever re-allocing
  153. //Enhancements from CNC3 WST 4/15/2003. JSC Integrated 5/20/03.
  154. m_CameraArrivedAtWaypointOnPathFlag = false; // Scripts for polling camera reached targets
  155. m_isCameraSlaved = false; // This is for 3DSMax camera playback
  156. m_useRealZoomCam = false; // true; //WST 10/18/2002
  157. m_shakerAngles.X =0.0f; // Proper camera shake generator & sources
  158. m_shakerAngles.Y =0.0f;
  159. m_shakerAngles.Z =0.0f;
  160. } // end W3DView
  161. //-------------------------------------------------------------------------------------------------
  162. //-------------------------------------------------------------------------------------------------
  163. W3DView::~W3DView()
  164. {
  165. REF_PTR_RELEASE( m_2DCamera );
  166. REF_PTR_RELEASE( m_3DCamera );
  167. } // end ~W3DView
  168. //-------------------------------------------------------------------------------------------------
  169. /** Sets the height of the viewport, while maintaining original camera perspective. */
  170. //-------------------------------------------------------------------------------------------------
  171. void W3DView::setHeight(Int height)
  172. {
  173. // extend View functionality
  174. View::setHeight(height);
  175. Vector2 vMin,vMax;
  176. m_3DCamera->Set_Aspect_Ratio((Real)getWidth()/(Real)height);
  177. m_3DCamera->Get_Viewport(vMin,vMax);
  178. vMax.Y=(Real)(m_originY+height)/(Real)TheDisplay->getHeight();
  179. m_3DCamera->Set_Viewport(vMin,vMax);
  180. }
  181. //-------------------------------------------------------------------------------------------------
  182. /** Sets the width of the viewport, while maintaining original camera perspective. */
  183. //-------------------------------------------------------------------------------------------------
  184. void W3DView::setWidth(Int width)
  185. {
  186. // extend View functionality
  187. View::setWidth(width);
  188. Vector2 vMin,vMax;
  189. m_3DCamera->Set_Aspect_Ratio((Real)width/(Real)getHeight());
  190. m_3DCamera->Get_Viewport(vMin,vMax);
  191. vMax.X=(Real)(m_originX+width)/(Real)TheDisplay->getWidth();
  192. m_3DCamera->Set_Viewport(vMin,vMax);
  193. //we want to maintain the same scale, so we'll need to adjust the fov.
  194. //default W3D fov for full-screen is 50 degrees.
  195. m_3DCamera->Set_View_Plane((Real)width/(Real)TheDisplay->getWidth()*DEG_TO_RADF(50.0f),-1);
  196. }
  197. //-------------------------------------------------------------------------------------------------
  198. /** Sets location of top-left view corner on display */
  199. //-------------------------------------------------------------------------------------------------
  200. void W3DView::setOrigin( Int x, Int y)
  201. {
  202. // extend View functionality
  203. View::setOrigin(x,y);
  204. Vector2 vMin,vMax;
  205. m_3DCamera->Get_Viewport(vMin,vMax);
  206. vMin.X=(Real)x/(Real)TheDisplay->getWidth();
  207. vMin.Y=(Real)y/(Real)TheDisplay->getHeight();
  208. m_3DCamera->Set_Viewport(vMin,vMax);
  209. // bottom-right border was also moved my this call, so force an update of extents.
  210. setWidth(m_width);
  211. setHeight(m_height);
  212. }
  213. //-------------------------------------------------------------------------------------------------
  214. /** @todo This is inefficient. We should construct the matrix directly using vectors. */
  215. //-------------------------------------------------------------------------------------------------
  216. #define MIN_CAPPED_ZOOM (0.5f) //WST 10.19.2002. JSC integrated 5/20/03.
  217. void W3DView::buildCameraTransform( Matrix3D *transform )
  218. {
  219. Vector3 sourcePos, targetPos;
  220. Real groundLevel = m_groundLevel; // 93.0f;
  221. Real zoom = getZoom();
  222. Real angle = getAngle();
  223. Real pitch = getPitch();
  224. Coord3D pos = *getPosition();
  225. // add in the camera shake, if any
  226. pos.x += m_shakeOffset.x;
  227. pos.y += m_shakeOffset.y;
  228. if (m_cameraConstraintValid)
  229. {
  230. pos.x = maxf(m_cameraConstraint.lo.x, pos.x);
  231. pos.x = minf(m_cameraConstraint.hi.x, pos.x);
  232. pos.y = maxf(m_cameraConstraint.lo.y, pos.y);
  233. pos.y = minf(m_cameraConstraint.hi.y, pos.y);
  234. }
  235. // set position of camera itself
  236. if (m_useRealZoomCam) //WST 10/10/2002 Real Zoom using FOV
  237. {
  238. sourcePos.X = m_cameraOffset.x;
  239. sourcePos.Y = m_cameraOffset.y;
  240. sourcePos.Z = m_cameraOffset.z;
  241. Real capped_zoom = zoom;
  242. if (capped_zoom > 1.0f)
  243. {
  244. capped_zoom= 1.0f;
  245. }
  246. if (capped_zoom < MIN_CAPPED_ZOOM)
  247. {
  248. capped_zoom = MIN_CAPPED_ZOOM;
  249. }
  250. m_FOV = 50.0f * PI/180.0f * capped_zoom * capped_zoom;
  251. }
  252. else
  253. {
  254. sourcePos.X = m_cameraOffset.x*zoom;
  255. sourcePos.Y = m_cameraOffset.y*zoom;
  256. sourcePos.Z = m_cameraOffset.z*zoom;
  257. }
  258. #ifdef NOT_IN_USE
  259. if (TheGlobalData->m_isOffsetCameraZ && TheTerrainLogic)
  260. {
  261. sourcePos.Z += TheTerrainLogic->getGroundHeight(pos.x, pos.y);
  262. if (m_prevSourcePosZ != SOURCEPOS_INVALID)
  263. {
  264. const Real MAX_SPZ_VARIATION = 0.05f;
  265. Real spzMin = m_prevSourcePosZ*(1.0-MAX_SPZ_VARIATION);
  266. Real spzMax Coord3D center;
  267. = m_prevSourcePosZ*(1.0+MAX_SPZ_VARIATION);
  268. if (sourcePos.Z < spzMin) sourcePos.Z = spzMin;
  269. if (sourcePos.Z > spzMax) sourcePos.Z = spzMax;
  270. }
  271. m_prevSourcePosZ = sourcePos.Z;
  272. }
  273. #endif
  274. // camera looking at origin
  275. targetPos.X = 0;
  276. targetPos.Y = 0;
  277. targetPos.Z = 0;
  278. Real factor = 1.0 - (groundLevel/sourcePos.Z );
  279. // construct a matrix to rotate around the up vector by the given angle
  280. Matrix3D angleTransform( Vector3( 0.0f, 0.0f, 1.0f ), angle );
  281. // construct a matrix to rotate around the horizontal vector by the given angle
  282. Matrix3D pitchTransform( Vector3( 1.0f, 0.0f, 0.0f ), pitch );
  283. // rotate camera position (pitch, then angle)
  284. #ifdef ALLOW_TEMPORARIES
  285. sourcePos = pitchTransform * sourcePos;
  286. sourcePos = angleTransform * sourcePos;
  287. #else
  288. pitchTransform.mulVector3(sourcePos);
  289. angleTransform.mulVector3(sourcePos);
  290. #endif
  291. sourcePos *= factor;
  292. // translate to current XY position
  293. sourcePos.X += pos.x;
  294. sourcePos.Y += pos.y;
  295. sourcePos.Z += groundLevel;
  296. targetPos.X += pos.x;
  297. targetPos.Y += pos.y;
  298. targetPos.Z += groundLevel;
  299. // do m_FXPitch adjustment.
  300. //WST Real height = sourcePos.Z - targetPos.Z;
  301. //WST height *= m_FXPitch;
  302. //WST targetPos.Z = sourcePos.Z - height;
  303. // The following code moves camera down and pitch up when player zooms in.
  304. // Use scripts to switch to useRealZoomCam
  305. if (m_useRealZoomCam)
  306. {
  307. Real pitch_adjust = 1.0f;
  308. if (!TheDisplay->isLetterBoxed())
  309. {
  310. Real capped_zoom = zoom;
  311. if (capped_zoom > 1.0f)
  312. {
  313. capped_zoom= 1.0f;
  314. }
  315. if (capped_zoom < MIN_CAPPED_ZOOM)
  316. {
  317. capped_zoom = MIN_CAPPED_ZOOM;
  318. }
  319. sourcePos.Z = sourcePos.Z * ( 0.5f + capped_zoom * 0.5f); // move camera down physically
  320. pitch_adjust = capped_zoom; // adjust camera to pitch up
  321. }
  322. m_FXPitch = 1.0f * (0.25f + pitch_adjust*0.75f);
  323. }
  324. // do fxPitch adjustment
  325. if (m_useRealZoomCam)
  326. {
  327. sourcePos.X = targetPos.X + ((sourcePos.X - targetPos.X) / m_FXPitch);
  328. sourcePos.Y = targetPos.Y + ((sourcePos.Y - targetPos.Y) / m_FXPitch);
  329. }
  330. else
  331. {
  332. if (m_FXPitch <= 1.0f)
  333. {
  334. Real height = sourcePos.Z - targetPos.Z;
  335. height *= m_FXPitch;
  336. targetPos.Z = sourcePos.Z - height;
  337. }
  338. else
  339. {
  340. sourcePos.X = targetPos.X + ((sourcePos.X - targetPos.X) / m_FXPitch);
  341. sourcePos.Y = targetPos.Y + ((sourcePos.Y - targetPos.Y) / m_FXPitch);
  342. }
  343. }
  344. //m_3DCamera->Set_View_Plane(DEG_TO_RADF(50.0f));
  345. //DEBUG_LOG(("zoom %f, SourceZ %f, posZ %f, groundLevel %f CamOffZ %f\n",
  346. // zoom, sourcePos.Z, pos.z, groundLevel,m_cameraOffset.z));
  347. // build new camera transform
  348. transform->Make_Identity();
  349. transform->Look_At( sourcePos, targetPos, 0 );
  350. //WST 11/12/2002 New camera shaker system
  351. CameraShakerSystem.Timestep(1.0f/30.0f);
  352. CameraShakerSystem.Update_Camera_Shaker(sourcePos, &m_shakerAngles);
  353. transform->Rotate_X(m_shakerAngles.X);
  354. transform->Rotate_Y(m_shakerAngles.Y);
  355. transform->Rotate_Z(m_shakerAngles.Z);
  356. //if (m_shakerAngles.X >= 0.0f)
  357. //{
  358. // DEBUG_LOG(("m_shakerAngles %f, %f, %f\n", m_shakerAngles.X, m_shakerAngles.Y, m_shakerAngles.Z));
  359. //}
  360. // (gth) check if the camera is being controlled by an animation
  361. if (m_isCameraSlaved) {
  362. // find object named m_cameraSlaveObjectName
  363. Object * obj = TheScriptEngine->getUnitNamed(m_cameraSlaveObjectName);
  364. if (obj != NULL) {
  365. // dig out the drawable
  366. Drawable * draw = obj->getDrawable();
  367. if (draw != NULL) {
  368. // dig out the first draw module with an ObjectDrawInterface
  369. for (DrawModule ** dm = draw->getDrawModules(); *dm; ++dm) {
  370. const ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
  371. if (di) {
  372. Matrix3D tm;
  373. di->clientOnly_getRenderObjBoneTransform(m_cameraSlaveObjectBoneName,&tm);
  374. // Ok, slam it into the camera!
  375. *transform = tm;
  376. //--------------------------------------------------------------------
  377. // WST 10.22.2002. Update the Listener positions used by audio system
  378. //--------------------------------------------------------------------
  379. Vector3 position = transform->Get_Translation();
  380. m_pos.x = position.X;
  381. m_pos.y = position.Y;
  382. m_pos.z = position.Z;
  383. //DEBUG_LOG(("mpos x%f, y%f, z%f\n", m_pos.x, m_pos.y, m_pos.z ));
  384. break;
  385. }
  386. }
  387. } else {
  388. m_isCameraSlaved = false;
  389. }
  390. } else {
  391. m_isCameraSlaved = false;
  392. }
  393. }
  394. }
  395. //-------------------------------------------------------------------------------------------------
  396. //-------------------------------------------------------------------------------------------------
  397. void W3DView::calcCameraConstraints()
  398. {
  399. // const Matrix3D& cameraTransform = m_3DCamera->Get_Transform();
  400. // DEBUG_LOG(("*** rebuilding cam constraints\n"));
  401. // ok, now check to ensure that we can't see outside the map region,
  402. // and twiddle the camera if needed
  403. if (TheTerrainLogic)
  404. {
  405. Region3D mapRegion;
  406. TheTerrainLogic->getExtent( &mapRegion );
  407. /*
  408. Note the following restrictions on camera constraints!
  409. -- they assume that all maps are height 'm_groundLevel' at the edges.
  410. (since you need to add some "buffer" around the edges of your map
  411. anyway, this shouldn't be an issue.)
  412. -- for angles/pitches other than zero, it may show boundaries.
  413. since we currently plan the game to be restricted to this,
  414. it shouldn't be an issue.
  415. */
  416. Real maxEdgeZ = m_groundLevel;
  417. // const Real BORDER_FUDGE = MAP_XY_FACTOR * 1.414f;
  418. Coord3D center, bottom;
  419. ICoord2D screen;
  420. //Pick at the center
  421. screen.x=0.5f*getWidth()+m_originX;
  422. screen.y=0.5f*getHeight()+m_originY;
  423. Vector3 rayStart,rayEnd;
  424. getPickRay(&screen,&rayStart,&rayEnd);
  425. center.x = Vector3::Find_X_At_Z(maxEdgeZ, rayStart, rayEnd);
  426. center.y = Vector3::Find_Y_At_Z(maxEdgeZ, rayStart, rayEnd);
  427. center.z = maxEdgeZ;
  428. screen.y = m_originY+ 0.95f*getHeight();
  429. getPickRay(&screen,&rayStart,&rayEnd);
  430. bottom.x = Vector3::Find_X_At_Z(maxEdgeZ, rayStart, rayEnd);
  431. bottom.y = Vector3::Find_Y_At_Z(maxEdgeZ, rayStart, rayEnd);
  432. bottom.z = maxEdgeZ;
  433. center.x -= bottom.x;
  434. center.y -= bottom.y;
  435. Real offset = center.length();
  436. if (TheGlobalData->m_debugAI) {
  437. offset = -1000; // push out the constraints so we can look at staging areas.
  438. }
  439. m_cameraConstraint.lo.x = mapRegion.lo.x + offset;
  440. m_cameraConstraint.hi.x = mapRegion.hi.x - offset;
  441. // this looks inverted, but is correct
  442. m_cameraConstraint.lo.y = mapRegion.lo.y + offset;
  443. m_cameraConstraint.hi.y = mapRegion.hi.y - offset;
  444. m_cameraConstraintValid = true;
  445. }
  446. }
  447. //-------------------------------------------------------------------------------------------------
  448. /** Returns a world-space ray originating at a given screen pixel position
  449. and ending at the far clip plane for current camera. Screen coordinates
  450. assumed in absolute values relative to full display resolution.*/
  451. //-------------------------------------------------------------------------------------------------
  452. void W3DView::getPickRay(const ICoord2D *screen, Vector3 *rayStart, Vector3 *rayEnd)
  453. {
  454. Real logX,logY;
  455. //W3D Screen coordinates are -1 to 1, so we need to do some conversion:
  456. PixelScreenToW3DLogicalScreen(screen->x - m_originX,screen->y - m_originY, &logX, &logY,getWidth(),getHeight());
  457. *rayStart = m_3DCamera->Get_Position(); //get camera location
  458. m_3DCamera->Un_Project(*rayEnd,Vector2(logX,logY)); //get world space point
  459. *rayEnd -= *rayStart; //vector camera to world space point
  460. rayEnd->Normalize(); //make unit vector
  461. *rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane
  462. *rayEnd += *rayStart; //get point on far clip plane along ray from camera.
  463. }
  464. //-------------------------------------------------------------------------------------------------
  465. /** set the transform matrix of m_3DCamera, based on m_pos & m_angle */
  466. //-------------------------------------------------------------------------------------------------
  467. void W3DView::setCameraTransform( void )
  468. {
  469. m_cameraHasMovedSinceRequest = true;
  470. Matrix3D cameraTransform( 1 );
  471. Real nearZ, farZ;
  472. // m_3DCamera->Get_Clip_Planes(nearZ, farZ);
  473. // Set the near to MAP_XY_FACTOR. Improves zbuffer resolution.
  474. nearZ = MAP_XY_FACTOR;
  475. farZ = 1200.0f;
  476. if (m_useRealZoomCam) //WST 10.19.2002
  477. {
  478. if (m_FXPitch<0.95f)
  479. {
  480. farZ = farZ / m_FXPitch; //Extend far Z when we pitch up for RealZoomCam
  481. }
  482. }
  483. else
  484. {
  485. if ((TheGlobalData && TheGlobalData->m_drawEntireTerrain) || (m_FXPitch<0.95f || m_zoom>1.05))
  486. { //need to extend far clip plane so entire terrain can be visible
  487. farZ *= MAP_XY_FACTOR;
  488. }
  489. }
  490. m_3DCamera->Set_Clip_Planes(nearZ, farZ);
  491. #if defined(_DEBUG) || defined(_INTERNAL)
  492. if (TheGlobalData->m_useCameraConstraints)
  493. #endif
  494. {
  495. if (!m_cameraConstraintValid)
  496. {
  497. buildCameraTransform(&cameraTransform);
  498. m_3DCamera->Set_Transform( cameraTransform );
  499. calcCameraConstraints();
  500. }
  501. DEBUG_ASSERTLOG(m_cameraConstraintValid,("*** cam constraints are not valid!!!\n"));
  502. if (m_cameraConstraintValid)
  503. {
  504. Coord3D pos = *getPosition();
  505. pos.x = maxf(m_cameraConstraint.lo.x, pos.x);
  506. pos.x = minf(m_cameraConstraint.hi.x, pos.x);
  507. pos.y = maxf(m_cameraConstraint.lo.y, pos.y);
  508. pos.y = minf(m_cameraConstraint.hi.y, pos.y);
  509. setPosition(&pos);
  510. }
  511. }
  512. #if defined(_DEBUG) || defined(_INTERNAL)
  513. m_3DCamera->Set_View_Plane( m_FOV, -1 );
  514. #endif
  515. // rebuild it (even if we just did it due to camera constraints)
  516. buildCameraTransform( &cameraTransform );
  517. m_3DCamera->Set_Transform( cameraTransform );
  518. if (TheTerrainRenderObject)
  519. {
  520. RefRenderObjListIterator *it = W3DDisplay::m_3DScene->createLightsIterator();
  521. TheTerrainRenderObject->updateCenter(m_3DCamera, it);
  522. if (it)
  523. {
  524. W3DDisplay::m_3DScene->destroyLightsIterator(it);
  525. it = NULL;
  526. }
  527. }
  528. }
  529. //-------------------------------------------------------------------------------------------------
  530. //-------------------------------------------------------------------------------------------------
  531. void W3DView::init( void )
  532. {
  533. // extend View functionality
  534. View::init();
  535. setName("W3DView");
  536. // set default camera "lookat" point
  537. Coord3D pos;
  538. pos.x = 87.0f;
  539. pos.y = 77.0f;
  540. pos.z = 0;
  541. pos.x *= MAP_XY_FACTOR;
  542. pos.y *= MAP_XY_FACTOR;
  543. setPosition(&pos);
  544. // create our 3D camera
  545. m_3DCamera = NEW_REF( CameraClass, () );
  546. setCameraTransform();
  547. // create our 2D camera for the GUI overlay
  548. m_2DCamera = NEW_REF( CameraClass, () );
  549. m_2DCamera->Set_Position( Vector3( 0, 0, 1 ) );
  550. Vector2 min = Vector2( -1, -0.75f );
  551. Vector2 max = Vector2( +1, +0.75f );
  552. m_2DCamera->Set_View_Plane( min, max );
  553. m_2DCamera->Set_Clip_Planes( 0.995f, 2.0f );
  554. m_cameraConstraintValid = false;
  555. m_scrollAmountCutoff = TheGlobalData->m_scrollAmountCutoff;
  556. } // end init
  557. //-------------------------------------------------------------------------------------------------
  558. const Coord3D& W3DView::get3DCameraPosition() const
  559. {
  560. Vector3 camera = m_3DCamera->Get_Position();
  561. static Coord3D pos;
  562. pos.set( camera.X, camera.Y, camera.Z );
  563. return pos;
  564. }
  565. //-------------------------------------------------------------------------------------------------
  566. //-------------------------------------------------------------------------------------------------
  567. void W3DView::reset( void )
  568. {
  569. View::reset();
  570. // Just in case...
  571. setTimeMultiplier(1); // Set time rate back to 1.
  572. Coord3D arbitraryPos = { 0, 0, 0 };
  573. // Just move the camera to 0, 0, 0. It'll get repositioned at the beginning of the next game
  574. // anyways.
  575. resetCamera(&arbitraryPos, 1, 0.0f, 0.0f);
  576. setViewFilter(FT_VIEW_DEFAULT);
  577. Coord2D gb = { 0,0 };
  578. setGuardBandBias( &gb );
  579. }
  580. //-------------------------------------------------------------------------------------------------
  581. /** draw worker for drawables in the view region */
  582. //-------------------------------------------------------------------------------------------------
  583. static void drawDrawable( Drawable *draw, void *userData )
  584. {
  585. draw->draw( (View *)userData );
  586. } // end drawDrawable
  587. // ------------------------------------------------------------------------------------------------
  588. //-------------------------------------------------------------------------------------------------
  589. static void drawTerrainNormal( Drawable *draw, void *userData )
  590. {
  591. UnsignedInt color = GameMakeColor( 255, 255, 0, 255 );
  592. if (TheTerrainLogic)
  593. {
  594. Coord3D pos = *draw->getPosition();
  595. Coord3D normal;
  596. pos.z = TheTerrainLogic->getGroundHeight(pos.x, pos.y, &normal);
  597. const Real NORMLEN = 20;
  598. normal.x = pos.x + normal.x * NORMLEN;
  599. normal.y = pos.y + normal.y * NORMLEN;
  600. normal.z = pos.z + normal.z * NORMLEN;
  601. ICoord2D start, end;
  602. TheTacticalView->worldToScreen(&pos, &start);
  603. TheTacticalView->worldToScreen(&normal, &end);
  604. TheDisplay->drawLine(start.x, start.y, end.x, end.y, 1.0f, color);
  605. }
  606. }
  607. #if defined(_DEBUG) || defined(_INTERNAL)
  608. // ------------------------------------------------------------------------------------------------
  609. // Draw a crude circle. Appears on top of any world geometry
  610. // ------------------------------------------------------------------------------------------------
  611. void drawDebugCircle( const Coord3D & center, Real radius, Real width, Color color )
  612. {
  613. const Real inc = PI/4.0f;
  614. Real angle = 0.0f;
  615. Coord3D pnt, lastPnt;
  616. ICoord2D start, end;
  617. Bool endValid, startValid;
  618. lastPnt.x = center.x + radius * (Real)cos(angle);
  619. lastPnt.y = center.y + radius * (Real)sin(angle);
  620. lastPnt.z = center.z;
  621. endValid = ( TheTacticalView->worldToScreenTriReturn( &lastPnt, &end ) != View::WTS_INVALID );
  622. for( angle = inc; angle <= 2.0f * PI; angle += inc )
  623. {
  624. pnt.x = center.x + radius * (Real)cos(angle);
  625. pnt.y = center.y + radius * (Real)sin(angle);
  626. pnt.z = center.z;
  627. startValid = ( TheTacticalView->worldToScreenTriReturn( &pnt, &start ) != View::WTS_INVALID );
  628. if ( startValid && endValid )
  629. TheDisplay->drawLine( start.x, start.y, end.x, end.y, width, color );
  630. lastPnt = pnt;
  631. end = start;
  632. endValid = startValid;
  633. }
  634. }
  635. void drawDrawableExtents( Drawable *draw, void *userData ); // FORWARD DECLARATION
  636. // ------------------------------------------------------------------------------------------------
  637. // ------------------------------------------------------------------------------------------------
  638. static void drawContainedDrawable( Object *obj, void *userData )
  639. {
  640. Drawable *draw = obj->getDrawable();
  641. if( draw )
  642. drawDrawableExtents( draw, userData );
  643. } // end drawContainedDrawable
  644. //-------------------------------------------------------------------------------------------------
  645. //-------------------------------------------------------------------------------------------------
  646. static void drawDrawableExtents( Drawable *draw, void *userData )
  647. {
  648. UnsignedInt color = GameMakeColor( 0, 255, 0, 255 );
  649. switch( draw->getDrawableGeometryInfo().getGeomType() )
  650. {
  651. //---------------------------------------------------------------------------------------------
  652. case GEOMETRY_BOX:
  653. {
  654. Real angle = draw->getOrientation();
  655. Real c = (Real)cos(angle);
  656. Real s = (Real)sin(angle);
  657. Real exc = draw->getDrawableGeometryInfo().getMajorRadius()*c;
  658. Real eyc = draw->getDrawableGeometryInfo().getMinorRadius()*c;
  659. Real exs = draw->getDrawableGeometryInfo().getMajorRadius()*s;
  660. Real eys = draw->getDrawableGeometryInfo().getMinorRadius()*s;
  661. Coord3D pts[4];
  662. pts[0].x = draw->getPosition()->x - exc - eys;
  663. pts[0].y = draw->getPosition()->y + eyc - exs;
  664. pts[0].z = 0;
  665. pts[1].x = draw->getPosition()->x + exc - eys;
  666. pts[1].y = draw->getPosition()->y + eyc + exs;
  667. pts[1].z = 0;
  668. pts[2].x = draw->getPosition()->x + exc + eys;
  669. pts[2].y = draw->getPosition()->y - eyc + exs;
  670. pts[2].z = 0;
  671. pts[3].x = draw->getPosition()->x - exc + eys;
  672. pts[3].y = draw->getPosition()->y - eyc - exs;
  673. pts[3].z = 0;
  674. Real z = draw->getPosition()->z;
  675. for( int i = 0; i < 2; i++ )
  676. {
  677. for (int corner = 0; corner < 4; corner++)
  678. {
  679. ICoord2D start, end;
  680. pts[corner].z = z;
  681. pts[(corner+1)&3].z = z;
  682. TheTacticalView->worldToScreen(&pts[corner], &start);
  683. TheTacticalView->worldToScreen(&pts[(corner+1)&3], &end);
  684. TheDisplay->drawLine(start.x, start.y, end.x, end.y, 1.0f, color);
  685. }
  686. z += draw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
  687. } // end for i
  688. break;
  689. } // end case box
  690. //---------------------------------------------------------------------------------------------
  691. case GEOMETRY_SPHERE: // not quite right, but close enough
  692. case GEOMETRY_CYLINDER:
  693. {
  694. Coord3D center = *draw->getPosition();
  695. const Real radius = draw->getDrawableGeometryInfo().getMajorRadius();
  696. // draw cylinder
  697. for( int i=0; i<2; i++ )
  698. {
  699. drawDebugCircle( center, radius, 1.0f, color );
  700. // next time 'round, draw the top of the cylinder
  701. center.z += draw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
  702. } // end for i
  703. // draw centerline
  704. ICoord2D start, end;
  705. center = *draw->getPosition();
  706. TheTacticalView->worldToScreen( &center, &start );
  707. center.z += draw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
  708. TheTacticalView->worldToScreen( &center, &end );
  709. TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
  710. break;
  711. } // case CYLINDER
  712. } // end switch
  713. // draw any extents for things that are contained by this
  714. Object *obj = draw->getObject();
  715. if( obj )
  716. {
  717. ContainModuleInterface *contain = obj->getContain();
  718. if( contain )
  719. contain->iterateContained( drawContainedDrawable, userData, FALSE );
  720. } // end if
  721. } // end drawDrawableExtents
  722. void drawAudioLocations( Drawable *draw, void *userData );
  723. // ------------------------------------------------------------------------------------------------
  724. // Helper for drawAudioLocations
  725. // ------------------------------------------------------------------------------------------------
  726. static void drawContainedAudioLocations( Object *obj, void *userData )
  727. {
  728. Drawable *draw = obj->getDrawable();
  729. if( draw )
  730. drawAudioLocations( draw, userData );
  731. } // end drawContainedAudio
  732. //-------------------------------------------------------------------------------------------------
  733. // Draw the location of audio objects in the world
  734. //-------------------------------------------------------------------------------------------------
  735. static void drawAudioLocations( Drawable *draw, void *userData )
  736. {
  737. // draw audio for things that are contained by this
  738. Object *obj = draw->getObject();
  739. if( obj )
  740. {
  741. ContainModuleInterface *contain = obj->getContain();
  742. if( contain )
  743. contain->iterateContained( drawContainedAudioLocations, userData, FALSE );
  744. } // end if
  745. const ThingTemplate * thingTemplate = draw->getTemplate();
  746. if ( thingTemplate == NULL || thingTemplate->getEditorSorting() != ES_AUDIO )
  747. {
  748. return; // All done
  749. }
  750. // Copied in hideously inappropriate code copying ways from DrawObject.cpp
  751. // Should definately be a global, probably read in from an INI file <gasp>
  752. static const Int poleHeight = 20;
  753. static const Int flagHeight = 10;
  754. static const Int flagWidth = 10;
  755. const Color color = GameMakeColor(0x25, 0x25, 0xEF, 0xFF);
  756. // Draw flag for audio-only objects:
  757. // *
  758. // * *
  759. // * *
  760. // * *
  761. // * *
  762. // * *
  763. // *
  764. // *
  765. // *
  766. // *
  767. // *
  768. Coord3D worldPoint;
  769. ICoord2D start, end;
  770. worldPoint = *draw->getPosition();
  771. TheTacticalView->worldToScreen( &worldPoint, &start );
  772. worldPoint.z += poleHeight;
  773. TheTacticalView->worldToScreen( &worldPoint, &end );
  774. TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
  775. worldPoint.z -= flagHeight / 2;
  776. worldPoint.x += flagWidth;
  777. TheTacticalView->worldToScreen( &worldPoint, &start );
  778. TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
  779. worldPoint.z -= flagHeight / 2;
  780. worldPoint.x -= flagWidth;
  781. TheTacticalView->worldToScreen( &worldPoint, &end );
  782. TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
  783. }
  784. //-------------------------------------------------------------------------------------------------
  785. // Draw the radii of sounds attached to any type of object.
  786. //-------------------------------------------------------------------------------------------------
  787. static void drawAudioRadii( const Drawable * drawable )
  788. {
  789. // Draw radii, if sound is playing
  790. const AudioEventRTS * ambientSound = drawable->getAmbientSound();
  791. if ( ambientSound && ambientSound->isCurrentlyPlaying() )
  792. {
  793. const AudioEventInfo * ambientInfo = ambientSound->getAudioEventInfo();
  794. if ( ambientInfo == NULL )
  795. {
  796. // I don't think that's right...
  797. OutputDebugString( ("Playing sound has NULL AudioEventInfo?\n" ) );
  798. if ( TheAudio != NULL )
  799. {
  800. ambientInfo = TheAudio->findAudioEventInfo( ambientSound->getEventName() );
  801. }
  802. }
  803. if ( ambientInfo != NULL )
  804. {
  805. // Colors match those used in WorldBuilder
  806. drawDebugCircle( *drawable->getPosition(), ambientInfo->m_minDistance, 1.0f, GameMakeColor(0x00, 0x00, 0xFF, 0xFF) );
  807. drawDebugCircle( *drawable->getPosition(), ambientInfo->m_maxDistance, 1.0f, GameMakeColor(0xFF, 0x00, 0xFF, 0xFF) );
  808. }
  809. }
  810. }
  811. #endif
  812. //-------------------------------------------------------------------------------------------------
  813. /** An opportunity to draw something after all drawables have been drawn once */
  814. //-------------------------------------------------------------------------------------------------
  815. static void drawablePostDraw( Drawable *draw, void *userData )
  816. {
  817. Real FXPitch = TheTacticalView->getFXPitch();
  818. if (draw->isDrawableEffectivelyHidden() || FXPitch < 0.0f)
  819. return;
  820. Object* obj = draw->getObject();
  821. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  822. #if defined(_DEBUG) || defined(_INTERNAL)
  823. ObjectShroudStatus ss = (!obj || !TheGlobalData->m_shroudOn) ? OBJECTSHROUD_CLEAR : obj->getShroudedStatus(localPlayerIndex);
  824. #else
  825. ObjectShroudStatus ss = (!obj) ? OBJECTSHROUD_CLEAR : obj->getShroudedStatus(localPlayerIndex);
  826. #endif
  827. if (ss > OBJECTSHROUD_PARTIAL_CLEAR)
  828. return;
  829. // draw the any "icon" UI for a drawable (health bars, veterency, etc);
  830. //*****
  831. //@TODO: Create a way to reject this call easily -- like objects that have no compatible modules.
  832. //*****
  833. //if( draw->getStatusBits() )
  834. //{
  835. draw->drawIconUI();
  836. //}
  837. #if defined(_DEBUG) || defined(_INTERNAL)
  838. // debug collision extents
  839. if( TheGlobalData->m_showCollisionExtents )
  840. drawDrawableExtents( draw, userData );
  841. if ( TheGlobalData->m_showAudioLocations )
  842. drawAudioLocations( draw, userData );
  843. #endif
  844. // debug terrain normals at object positions
  845. if( TheGlobalData->m_showTerrainNormals )
  846. drawTerrainNormal( draw, userData );
  847. TheGameClient->incrementRenderedObjectCount();
  848. } // end drawablePostDraw
  849. //-------------------------------------------------------------------------------------------------
  850. // Display AI debug visuals
  851. //-------------------------------------------------------------------------------------------------
  852. static void renderAIDebug( void )
  853. {
  854. }
  855. // ------------------------------------------------------------------------------------------------
  856. // ------------------------------------------------------------------------------------------------
  857. Bool W3DView::updateCameraMovements()
  858. {
  859. Bool didUpdate = false;
  860. if (m_doingZoomCamera)
  861. {
  862. zoomCameraOneFrame();
  863. didUpdate = true;
  864. }
  865. if (m_doingPitchCamera)
  866. {
  867. pitchCameraOneFrame();
  868. didUpdate = true;
  869. }
  870. if (m_doingRotateCamera) {
  871. m_previousLookAtPosition = *getPosition();
  872. rotateCameraOneFrame();
  873. didUpdate = true;
  874. } else if (m_doingMoveCameraOnWaypointPath) {
  875. m_previousLookAtPosition = *getPosition();
  876. moveAlongWaypointPath(TheW3DFrameLengthInMsec);
  877. didUpdate = true;
  878. }
  879. if (m_doingScriptedCameraLock)
  880. {
  881. didUpdate = true;
  882. }
  883. return didUpdate;
  884. }
  885. /** This function performs all actions which affect the camera transform or 3D objects
  886. rendered in this frame.
  887. MW: I moved this code out out W3DView::draw() so that we can get final camera and object
  888. positions before any rendering begins. This was necessary so that reflection textures
  889. (which update before the main rendering loop) could get a correct version of the scene.
  890. Without this change, the reflections were always 1 frame behind the non-reflected view.
  891. */
  892. void W3DView::updateView(void)
  893. {
  894. UPDATE();
  895. }
  896. //DECLARE_PERF_TIMER(W3DView_updateView)
  897. void W3DView::update(void)
  898. {
  899. //USE_PERF_TIMER(W3DView_updateView)
  900. Bool recalcCamera = false;
  901. Bool didScriptedMovement = false;
  902. #ifdef LOG_FRAME_TIMES
  903. __int64 curTime64,freq64;
  904. static __int64 prevTime64=0;
  905. QueryPerformanceFrequency((LARGE_INTEGER *)&freq64);
  906. QueryPerformanceCounter((LARGE_INTEGER *)&curTime64);
  907. freq64 /= 1000;
  908. Int elapsedTimeMs = (curTime64 - prevTime64)/freq64;
  909. prevTime64 = curTime64;
  910. #endif
  911. // Int elapsedTimeMs = TheW3DFrameLengthInMsec; // Assume a constant time flow. It just works out better. jba.
  912. if (TheTerrainRenderObject->doesNeedFullUpdate()) {
  913. RefRenderObjListIterator *it = W3DDisplay::m_3DScene->createLightsIterator();
  914. TheTerrainRenderObject->updateCenter(m_3DCamera, it);
  915. if (it)
  916. {
  917. W3DDisplay::m_3DScene->destroyLightsIterator(it);
  918. it = NULL;
  919. }
  920. }
  921. static Real followFactor = -1;
  922. ObjectID cameraLock = getCameraLock();
  923. if (cameraLock == INVALID_ID)
  924. {
  925. followFactor = -1;
  926. }
  927. if (cameraLock != INVALID_ID)
  928. {
  929. m_doingMoveCameraOnWaypointPath = false;
  930. m_CameraArrivedAtWaypointOnPathFlag = false;
  931. Object* cameraLockObj = TheGameLogic->findObjectByID(cameraLock);
  932. Bool loseLock = false;
  933. // check if object has been destroyed or is dead -> lose lock
  934. if (cameraLockObj == NULL)
  935. {
  936. loseLock = true;
  937. }
  938. #if 0
  939. else
  940. {
  941. AIUpdateInterface *ai = cameraLockObj->getAIUpdateInterface();
  942. if (ai && ai->isDead())
  943. loseLock = true;
  944. }
  945. #endif
  946. if (loseLock)
  947. {
  948. setCameraLock(INVALID_ID);
  949. setCameraLockDrawable(NULL);
  950. followFactor = -1;
  951. }
  952. else
  953. {
  954. if (followFactor<0) {
  955. followFactor = 0.05f;
  956. } else {
  957. followFactor += 0.05f;
  958. if (followFactor>1.0f) followFactor = 1.0f;
  959. }
  960. if (getCameraLockDrawable() != NULL)
  961. {
  962. Drawable* cameraLockDrawable = (Drawable *)getCameraLockDrawable();
  963. if (!cameraLockDrawable)
  964. {
  965. setCameraLockDrawable(NULL);
  966. }
  967. else
  968. {
  969. Coord3D pos;
  970. Real boundingSphereRadius;
  971. Matrix3D transform;
  972. // this method must ONLY be called from the client, NEVER From the logic, not even indirectly.
  973. if (cameraLockDrawable->clientOnly_getFirstRenderObjInfo(&pos, &boundingSphereRadius, &transform))
  974. {
  975. Vector3 zaxis(0,0,1);
  976. Vector3 objPos;
  977. objPos.X = pos.x;
  978. objPos.Y = pos.y;
  979. objPos.Z = pos.z;
  980. //get position of top of object, assuming world z roughly along local z.
  981. objPos += boundingSphereRadius * 1.0f * zaxis;
  982. Vector3 objview = transform.Get_X_Vector(); //get view vector of object
  983. //move camera back behind object far enough not to intersect bounding sphere
  984. Vector3 camtran = objPos - objview * boundingSphereRadius*4.5f;
  985. Vector3 prevCamTran = m_3DCamera->Get_Position(); //get current camera position.
  986. Vector3 tranDiff = (camtran - prevCamTran); //vector old position to new position.
  987. camtran = prevCamTran + tranDiff * 0.1f; //slowly move camera to new position.
  988. Matrix3D camXForm;
  989. camXForm.Look_At(camtran,objPos,0);
  990. m_3DCamera->Set_Transform(camXForm);
  991. recalcCamera = false; //we already did it
  992. }
  993. }
  994. }
  995. else
  996. { Coord3D objpos = *cameraLockObj->getPosition();
  997. Coord3D curpos = *getPosition();
  998. // don't "snap" directly to the pos, but move there smoothly.
  999. Real snapThreshSqr = sqr(TheGlobalData->m_partitionCellSize);
  1000. Real curDistSqr = sqr(curpos.x - objpos.x) + sqr(curpos.y - objpos.y);
  1001. if ( m_snapImmediate)
  1002. {
  1003. // close enough.
  1004. curpos.x = objpos.x;
  1005. curpos.y = objpos.y;
  1006. }
  1007. else
  1008. {
  1009. // Real ratio = 1.0f - snapThreshSqr/curDistSqr;
  1010. Real dx = objpos.x-curpos.x;
  1011. Real dy = objpos.y-curpos.y;
  1012. if (m_lockType == LOCK_TETHER)
  1013. {
  1014. //snapThreshSqr = sqr( m_lockDist * TheGlobalData->m_partitionCellSize );
  1015. if (curDistSqr >= snapThreshSqr)
  1016. {
  1017. Real ratio = 1.0f - snapThreshSqr/curDistSqr;
  1018. // move halfway there.
  1019. curpos.x += dx*ratio*0.5f;
  1020. curpos.y += dy*ratio*0.5f;
  1021. }
  1022. else
  1023. {
  1024. // we're inside our 'play' tolerance. Move slowly to the obj
  1025. Real ratio = 0.01f * m_lockDist;
  1026. Real dx = objpos.x-curpos.x;
  1027. Real dy = objpos.y-curpos.y;
  1028. curpos.x += dx*ratio;
  1029. curpos.y += dy*ratio;
  1030. }
  1031. }
  1032. else
  1033. {
  1034. curpos.x += dx*followFactor;
  1035. curpos.y += dy*followFactor;
  1036. }
  1037. }
  1038. if (!(TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript()) && !TheGameLogic->isGamePaused()) {
  1039. m_previousLookAtPosition = *getPosition();
  1040. }
  1041. setPosition(&curpos);
  1042. if (m_lockType == LOCK_FOLLOW)
  1043. {
  1044. // camera follow objects if they are flying
  1045. if (cameraLockObj->isUsingAirborneLocomotor() && cameraLockObj->isAboveTerrainOrWater())
  1046. {
  1047. Matrix3D camXForm;
  1048. Real oldZRot = m_angle;
  1049. Real idealZRot = cameraLockObj->getOrientation() - M_PI_2;
  1050. normAngle(oldZRot);
  1051. normAngle(idealZRot);
  1052. Real diff = idealZRot - oldZRot;
  1053. normAngle(diff);
  1054. if (m_snapImmediate)
  1055. {
  1056. m_angle = idealZRot;
  1057. }
  1058. else
  1059. {
  1060. m_angle += diff * 0.1f;
  1061. }
  1062. normAngle(m_angle);
  1063. }
  1064. }
  1065. if (m_snapImmediate)
  1066. m_snapImmediate = FALSE;
  1067. m_groundLevel = objpos.z;
  1068. didScriptedMovement = true;
  1069. recalcCamera = true;
  1070. }
  1071. }
  1072. }
  1073. if (!(TheScriptEngine->isTimeFrozenDebug()/* || TheScriptEngine->isTimeFrozenScript()*/) && !TheGameLogic->isGamePaused()) {
  1074. // If we aren't frozen for debug, allow the camera to follow scripted movements.
  1075. if (updateCameraMovements()) {
  1076. didScriptedMovement = true;
  1077. recalcCamera = true;
  1078. }
  1079. } else {
  1080. if (m_doingRotateCamera || m_doingMoveCameraOnWaypointPath || m_doingPitchCamera || m_doingZoomCamera || m_doingScriptedCameraLock) {
  1081. didScriptedMovement = true; // don't mess up the scripted movement
  1082. }
  1083. }
  1084. //
  1085. // Process camera shake
  1086. /// @todo Make this framerate-independent
  1087. //
  1088. if (m_shakeIntensity > 0.01f)
  1089. {
  1090. m_shakeOffset.x = m_shakeIntensity * m_shakeAngleCos;
  1091. m_shakeOffset.y = m_shakeIntensity * m_shakeAngleSin;
  1092. // fake a stiff spring/damper
  1093. const Real dampingCoeff = 0.75f;
  1094. m_shakeIntensity *= dampingCoeff;
  1095. // spring is so "stiff", it pulls 180 degrees opposite each frame
  1096. m_shakeAngleCos = -m_shakeAngleCos;
  1097. m_shakeAngleSin = -m_shakeAngleSin;
  1098. recalcCamera = true;
  1099. }
  1100. else
  1101. {
  1102. m_shakeIntensity = 0.0f;
  1103. m_shakeOffset.x = 0.0f;
  1104. m_shakeOffset.y = 0.0f;
  1105. }
  1106. //Process New C3 Camera Shaker system
  1107. if (CameraShakerSystem.IsCameraShaking())
  1108. {
  1109. recalcCamera = true;
  1110. }
  1111. /*
  1112. * In order to have the camera follow the terrain in a non-dizzying way, we will have a
  1113. * "desired height" value that the user sets. While scrolling, the actual height (set by
  1114. * zoom) will not get updated unless we are scrolling uphill and our view either goes
  1115. * underground or higher than the max allowed height. When the camera is at rest (not
  1116. * scrolling), the zoom will move toward matching the desired height.
  1117. */
  1118. m_terrainHeightUnderCamera = getHeightAroundPos(m_pos.x, m_pos.y);
  1119. m_currentHeightAboveGround = m_cameraOffset.z * m_zoom - m_terrainHeightUnderCamera;
  1120. if (TheTerrainLogic && TheGlobalData && TheInGameUI && m_okToAdjustHeight && !TheGameLogic->isGamePaused())
  1121. {
  1122. Real desiredHeight = (m_terrainHeightUnderCamera + m_heightAboveGround);
  1123. Real desiredZoom = desiredHeight / m_cameraOffset.z;
  1124. if (didScriptedMovement || (TheGameLogic->isInReplayGame() && TheGlobalData->m_useCameraInReplay))
  1125. {
  1126. // if we are in a scripted camera movement, take its height above ground as our desired height.
  1127. m_heightAboveGround = m_currentHeightAboveGround;
  1128. //DEBUG_LOG(("Frame %d: height above ground: %g %g %g %g\n", TheGameLogic->getFrame(), m_heightAboveGround,
  1129. // m_cameraOffset.z, m_zoom, m_terrainHeightUnderCamera));
  1130. }
  1131. if (TheInGameUI->isScrolling())
  1132. {
  1133. // if scrolling, only adjust if we're too close or too far
  1134. if (m_scrollAmount.length() < m_scrollAmountCutoff || (m_currentHeightAboveGround < m_minHeightAboveGround) || (TheGlobalData->m_enforceMaxCameraHeight && m_currentHeightAboveGround > m_maxHeightAboveGround))
  1135. {
  1136. Real zoomAdj = (desiredZoom - m_zoom)*TheGlobalData->m_cameraAdjustSpeed;
  1137. if (fabs(zoomAdj) >= 0.0001) // only do positive
  1138. {
  1139. m_zoom += zoomAdj;
  1140. recalcCamera = true;
  1141. }
  1142. }
  1143. }
  1144. else
  1145. {
  1146. // we're not scrolling; settle toward desired height above ground
  1147. Real zoomAdj = (m_zoom - desiredZoom)*TheGlobalData->m_cameraAdjustSpeed;
  1148. Real zoomAdjAbs = fabs(zoomAdj);
  1149. if (zoomAdjAbs >= 0.0001 && !didScriptedMovement)
  1150. {
  1151. //DEBUG_LOG(("W3DView::update() - m_zoom=%g, desiredHeight=%g\n", m_zoom, desiredZoom));
  1152. m_zoom -= zoomAdj;
  1153. recalcCamera = true;
  1154. }
  1155. }
  1156. }
  1157. if (TheScriptEngine->isTimeFast()) {
  1158. return; // don't draw - makes it faster :) jba.
  1159. }
  1160. // (gth) C&C3 if m_isCameraSlaved then force the camera to update each frame
  1161. if ((recalcCamera) || (m_isCameraSlaved)) {
  1162. setCameraTransform();
  1163. }
  1164. #ifdef DO_SEISMIC_SIMULATIONS
  1165. // Give the terrain a chance to refresh animaing (Seismic) regions, if any.
  1166. TheTerrainVisual->updateSeismicSimulations();
  1167. #endif
  1168. Region3D axisAlignedRegion;
  1169. getAxisAlignedViewRegion(axisAlignedRegion);
  1170. // render all of the visible Drawables
  1171. /// @todo this needs to use a real region partition or something
  1172. if (WW3D::Get_Frame_Time()) //make sure some time actually elapsed
  1173. TheGameClient->iterateDrawablesInRegion( &axisAlignedRegion, drawDrawable, this );
  1174. }
  1175. //-------------------------------------------------------------------------------------------------
  1176. /** Find region which contains all drawables in 3D space. */
  1177. //-------------------------------------------------------------------------------------------------
  1178. void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion)
  1179. {
  1180. //
  1181. // get the 4 points in 3D space of the 4 corners of the view, we will use a z = 0.0f
  1182. // value so that we can get everything ... even stuff below the terrain
  1183. //
  1184. Coord3D box[ 4 ];
  1185. getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f );
  1186. //
  1187. // take those 4 corners projected into the world and create an axis aligned bounding
  1188. // box, we will use this box to iterate the drawables in 3D space
  1189. //
  1190. axisAlignedRegion.lo = box[ 0 ];
  1191. axisAlignedRegion.hi = box[ 0 ];
  1192. for( Int i = 0; i < 4; i++ )
  1193. {
  1194. if( box[ i ].x < axisAlignedRegion.lo.x )
  1195. axisAlignedRegion.lo.x = box[ i ].x;
  1196. if( box[ i ].y < axisAlignedRegion.lo.y )
  1197. axisAlignedRegion.lo.y = box[ i ].y;
  1198. if( box[ i ].x > axisAlignedRegion.hi.x )
  1199. axisAlignedRegion.hi.x = box[ i ].x;
  1200. if( box[ i ].y > axisAlignedRegion.hi.y )
  1201. axisAlignedRegion.hi.y = box[ i ].y;
  1202. } // end for i
  1203. // low and high regions will be based of the extent of the map
  1204. Region3D mapExtent;
  1205. Real safeValue = 999999;
  1206. TheTerrainLogic->getExtent( &mapExtent );
  1207. axisAlignedRegion.lo.z = mapExtent.lo.z - safeValue;
  1208. axisAlignedRegion.hi.z = mapExtent.hi.z + safeValue;
  1209. // we want to overscan a little bit so that we get objects that are partially offscreen
  1210. axisAlignedRegion.lo.x -= (DRAWABLE_OVERSCAN + m_guardBandBias.x);
  1211. axisAlignedRegion.lo.y -= (DRAWABLE_OVERSCAN + m_guardBandBias.y + 60.0f );
  1212. axisAlignedRegion.hi.x += (DRAWABLE_OVERSCAN + m_guardBandBias.x);
  1213. axisAlignedRegion.hi.y += (DRAWABLE_OVERSCAN + m_guardBandBias.y);
  1214. }
  1215. // ------------------------------------------------------------------------------------------------
  1216. // ------------------------------------------------------------------------------------------------
  1217. void W3DView::setFadeParameters(Int fadeFrames, Int direction)
  1218. {
  1219. ScreenBWFilter::setFadeParameters(fadeFrames, direction);
  1220. ScreenCrossFadeFilter::setFadeParameters(fadeFrames,direction);
  1221. }
  1222. void W3DView::set3DWireFrameMode(Bool enable)
  1223. {
  1224. m_nextWireFrameEnabled = enable;
  1225. }
  1226. //-------------------------------------------------------------------------------------------------
  1227. /** Sets the view filter mode. */
  1228. //-------------------------------------------------------------------------------------------------
  1229. void W3DView::setViewFilterPos(const Coord3D *pos)
  1230. {
  1231. ScreenMotionBlurFilter::setZoomToPos(pos);
  1232. }
  1233. //-------------------------------------------------------------------------------------------------
  1234. /** Sets the view filter mode. */
  1235. //-------------------------------------------------------------------------------------------------
  1236. Bool W3DView::setViewFilterMode(enum FilterModes filterMode)
  1237. {
  1238. FilterModes oldMode = m_viewFilterMode; //save previous mode in case setup fails.
  1239. m_viewFilterMode = filterMode;
  1240. if (m_viewFilterMode != FM_NULL_MODE &&
  1241. m_viewFilter != FT_NULL_FILTER) {
  1242. if (!W3DShaderManager::filterSetup(m_viewFilter, m_viewFilterMode))
  1243. { //setup failed so restore previous mode.
  1244. m_viewFilterMode = oldMode;
  1245. return FALSE;
  1246. }
  1247. }
  1248. return TRUE;
  1249. }
  1250. //-------------------------------------------------------------------------------------------------
  1251. /** Sets the view filter. */
  1252. //-------------------------------------------------------------------------------------------------
  1253. Bool W3DView::setViewFilter(enum FilterTypes filter)
  1254. {
  1255. FilterTypes oldFilter = m_viewFilter; //save previous filter in case setup fails.
  1256. m_viewFilter = filter;
  1257. if (m_viewFilterMode != FM_NULL_MODE &&
  1258. m_viewFilter != FT_NULL_FILTER) {
  1259. if (!W3DShaderManager::filterSetup(m_viewFilter, m_viewFilterMode))
  1260. { //setup failed so restore previous mode.
  1261. m_viewFilter = oldFilter;
  1262. return FALSE;
  1263. };
  1264. }
  1265. return TRUE;
  1266. }
  1267. //-------------------------------------------------------------------------------------------------
  1268. /** Calculates how many pixels we scrolled since last frame for motion blur calculations. */
  1269. //-------------------------------------------------------------------------------------------------
  1270. void W3DView::calcDeltaScroll(Coord2D &screenDelta)
  1271. {
  1272. screenDelta.x = 0;
  1273. screenDelta.y = 0;
  1274. Vector3 prevPos(m_previousLookAtPosition.x,m_previousLookAtPosition.y, m_groundLevel);
  1275. Vector3 prevScreen;
  1276. if (m_3DCamera->Project( prevScreen, prevPos ) != CameraClass::INSIDE_FRUSTUM)
  1277. {
  1278. return;
  1279. }
  1280. Vector3 pos(m_pos.x,m_pos.y, m_groundLevel);
  1281. Vector3 screen;
  1282. if (m_3DCamera->Project( screen, pos ) != CameraClass::INSIDE_FRUSTUM)
  1283. {
  1284. return;
  1285. }
  1286. screenDelta.x = screen.X-prevScreen.X;
  1287. screenDelta.y = screen.Y-prevScreen.Y;
  1288. }
  1289. //-------------------------------------------------------------------------------------------------
  1290. /** Draw member for the W3D window, this will literally draw the window
  1291. * for this view */
  1292. //-------------------------------------------------------------------------------------------------
  1293. void W3DView::drawView( void )
  1294. {
  1295. DRAW();
  1296. }
  1297. //DECLARE_PERF_TIMER(W3DView_drawView)
  1298. void W3DView::draw( void )
  1299. {
  1300. //USE_PERF_TIMER(W3DView_drawView)
  1301. Bool skipRender = false;
  1302. Bool doExtraRender = false;
  1303. CustomScenePassModes customScenePassMode = SCENE_PASS_DEFAULT;
  1304. Bool preRenderResult = false;
  1305. if (m_viewFilterMode &&
  1306. m_viewFilter > FT_NULL_FILTER &&
  1307. m_viewFilter < FT_MAX)
  1308. {
  1309. // Most likely will redirect rendering to a texture.
  1310. preRenderResult=W3DShaderManager::filterPreRender(m_viewFilter, skipRender, customScenePassMode);
  1311. if (!skipRender && getCameraLock())
  1312. {
  1313. Object* cameraLockObj = TheGameLogic->findObjectByID(getCameraLock());
  1314. if (cameraLockObj)
  1315. {
  1316. Drawable *drawable = cameraLockObj->getDrawable();
  1317. drawable->setDrawableHidden(true);
  1318. }
  1319. }
  1320. }
  1321. if (!skipRender)
  1322. {
  1323. // Render 3D scene from our camera
  1324. W3DDisplay::m_3DScene->setCustomPassMode(customScenePassMode);
  1325. if (m_isWireFrameEnabled)
  1326. W3DDisplay::m_3DScene->Set_Extra_Pass_Polygon_Mode(SceneClass::EXTRA_PASS_CLEAR_LINE);
  1327. W3DDisplay::m_3DScene->doRender( m_3DCamera );
  1328. W3DDisplay::m_3DScene->Set_Extra_Pass_Polygon_Mode(SceneClass::EXTRA_PASS_DISABLE);
  1329. m_isWireFrameEnabled = m_nextWireFrameEnabled;
  1330. }
  1331. if (m_viewFilterMode &&
  1332. m_viewFilter > FT_NULL_FILTER &&
  1333. m_viewFilter < FT_MAX)
  1334. {
  1335. Coord2D deltaScroll;
  1336. calcDeltaScroll(deltaScroll);
  1337. Bool continueTheEffect = false;
  1338. if (preRenderResult) //if prerender passed, do the post render.
  1339. continueTheEffect = W3DShaderManager::filterPostRender(m_viewFilter, m_viewFilterMode, deltaScroll,doExtraRender);
  1340. if (!skipRender && getCameraLock())
  1341. {
  1342. Object* cameraLockObj = TheGameLogic->findObjectByID(getCameraLock());
  1343. if (cameraLockObj)
  1344. {
  1345. Drawable *drawable = cameraLockObj->getDrawable();
  1346. drawable->setDrawableHidden(false);
  1347. RenderInfoClass rinfo(*m_3DCamera);
  1348. // Apply the camera and viewport (including depth range)
  1349. m_3DCamera->Apply();
  1350. TheDX8MeshRenderer.Set_Camera(&rinfo.Camera);
  1351. W3DDisplay::m_3DScene->renderSpecificDrawables(rinfo, 1, &drawable);
  1352. WW3D::Flush(rinfo);
  1353. }
  1354. }
  1355. if (!continueTheEffect)
  1356. {
  1357. // shut it down.
  1358. m_viewFilter = FT_VIEW_DEFAULT;
  1359. m_viewFilterMode = FM_VIEW_DEFAULT;
  1360. }
  1361. }
  1362. //Some effects require that we render a modified version of the scene into a texture but also require
  1363. //an unaltered version in the framebuffer. So we re-render again into framebuffer after texture rendering
  1364. //was turned off by filterPostRender().
  1365. if (doExtraRender)
  1366. {
  1367. //Reset to normal scene rendering.
  1368. //The pass that rendered into a texture may have left the z-buffer in a weird state
  1369. //so clear it before rendering normal scene.
  1370. ///@todo: Don't clear z-buffer unless shader uses z-bias or anything else that would cause <= z to fail on normal render.
  1371. DX8Wrapper::Clear(false, true, Vector3(0.0f,0.0f,0.0f), TheWaterTransparency->m_minWaterOpacity); // Clear z but not color
  1372. W3DDisplay::m_3DScene->setCustomPassMode(SCENE_PASS_DEFAULT);
  1373. W3DDisplay::m_3DScene->doRender( m_3DCamera );
  1374. Coord2D deltaScroll;
  1375. W3DShaderManager::filterPostRender(m_viewFilter, m_viewFilterMode, deltaScroll, doExtraRender);
  1376. }
  1377. if( TheGlobalData->m_debugAI )
  1378. {
  1379. if (TheAI->pathfinder()->getDebugPath())
  1380. {
  1381. // setup screen clipping region
  1382. IRegion2D clipRegion;
  1383. clipRegion.lo.x = 0;
  1384. clipRegion.lo.y = 0;
  1385. clipRegion.hi.x = getWidth();
  1386. clipRegion.hi.y = getHeight();
  1387. UnsignedInt color = 0xFFFFFF00; //0xAARRGGBB
  1388. ICoord2D start, end;
  1389. PathNode *prevNode = TheAI->pathfinder()->getDebugPath()->getFirstNode();
  1390. if (worldToScreen( prevNode->getPosition(), &start )) {
  1391. TheDisplay->drawLine( start.x-3, start.y-3, start.x+3, start.y-3, 1.0f, color );
  1392. TheDisplay->drawLine( start.x+3, start.y-3, start.x+3, start.y+3, 1.0f, color );
  1393. TheDisplay->drawLine( start.x+3, start.y+3, start.x-3, start.y+3, 1.0f, color );
  1394. TheDisplay->drawLine( start.x-3, start.y+3, start.x-3, start.y-3, 1.0f, color );
  1395. }
  1396. for( PathNode *node = prevNode->getNext(); node; node = node->getNext() )
  1397. {
  1398. Int k;
  1399. Coord3D s, e;
  1400. Coord3D delta;
  1401. s = *node->getPosition();
  1402. e = *prevNode->getPosition();
  1403. delta.x = e.x-s.x;
  1404. delta.y = e.y-s.y;
  1405. delta.z = e.z-s.z;
  1406. for (k = 0; k<10; k++) {
  1407. Real factor1 = (k)/10.0;
  1408. Real factor2 = (k+1)/10.0;
  1409. s = *node->getPosition();
  1410. e = *node->getPosition();
  1411. s.x += delta.x*factor1;
  1412. s.y += delta.y*factor1;
  1413. s.z += delta.z*factor1;
  1414. e.x += delta.x*factor2;
  1415. e.y += delta.y*factor2;
  1416. e.z += delta.z*factor2;
  1417. Bool onScreen1 = worldToScreen( &e, &end );
  1418. Bool onScreen2 = worldToScreen( &s, &start );
  1419. if (!onScreen1 && !onScreen2) {
  1420. continue; // neither point visible.
  1421. }
  1422. ICoord2D clipStart, clipEnd;
  1423. if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) {
  1424. TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, 1.0f, color );
  1425. }
  1426. }
  1427. prevNode = node;
  1428. if (node->getNext()) {
  1429. if (worldToScreen( node->getPosition(), &start )) {
  1430. TheDisplay->drawLine( start.x-4, start.y, start.x+3, start.y, 1.0f, color );
  1431. }
  1432. }
  1433. }
  1434. if (prevNode && worldToScreen( prevNode->getPosition(), &start )) {
  1435. TheDisplay->drawLine( start.x-4, start.y, start.x+3, start.y, 1.0f, color );
  1436. TheDisplay->drawLine( start.x, start.y-4, start.x, start.y+3, 1.0f, color );
  1437. }
  1438. color = 0xFFFF0000; //0xAARRGGBB
  1439. if (worldToScreen( TheAI->pathfinder()->getDebugPathPosition(), &start )) {
  1440. TheDisplay->drawLine( start.x-3, start.y, start.x+3, start.y, 1.0f, color );
  1441. TheDisplay->drawLine( start.x, start.y-3, start.x, start.y+3, 1.0f, color );
  1442. }
  1443. }
  1444. } // end if, show debug AI
  1445. #if defined(_DEBUG) || defined(_INTERNAL)
  1446. if( TheGlobalData->m_debugCamera )
  1447. {
  1448. UnsignedInt c = 0xaaffffff;
  1449. Coord3D worldPos = *getPosition();
  1450. worldPos.z = TheTerrainLogic->getGroundHeight(worldPos.x, worldPos.y);
  1451. Coord3D p1, p2;
  1452. ICoord2D s1, s2;
  1453. p1 = worldPos;
  1454. p1.x += TERRAIN_SAMPLE_SIZE;
  1455. p1.y += TERRAIN_SAMPLE_SIZE;
  1456. p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
  1457. p2 = worldPos;
  1458. p2.x += TERRAIN_SAMPLE_SIZE;
  1459. p2.y -= TERRAIN_SAMPLE_SIZE;
  1460. p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
  1461. worldToScreen( &p1, &s1 );
  1462. worldToScreen( &p2, &s2 );
  1463. TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
  1464. p1 = worldPos;
  1465. p1.x += TERRAIN_SAMPLE_SIZE;
  1466. p1.y -= TERRAIN_SAMPLE_SIZE;
  1467. p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
  1468. p2 = worldPos;
  1469. p2.x -= TERRAIN_SAMPLE_SIZE;
  1470. p2.y -= TERRAIN_SAMPLE_SIZE;
  1471. p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
  1472. worldToScreen( &p1, &s1 );
  1473. worldToScreen( &p2, &s2 );
  1474. TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
  1475. p1 = worldPos;
  1476. p1.x -= TERRAIN_SAMPLE_SIZE;
  1477. p1.y -= TERRAIN_SAMPLE_SIZE;
  1478. p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
  1479. p2 = worldPos;
  1480. p2.x -= TERRAIN_SAMPLE_SIZE;
  1481. p2.y += TERRAIN_SAMPLE_SIZE;
  1482. p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
  1483. worldToScreen( &p1, &s1 );
  1484. worldToScreen( &p2, &s2 );
  1485. TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
  1486. p1 = worldPos;
  1487. p1.x -= TERRAIN_SAMPLE_SIZE;
  1488. p1.y += TERRAIN_SAMPLE_SIZE;
  1489. p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
  1490. p2 = worldPos;
  1491. p2.x += TERRAIN_SAMPLE_SIZE;
  1492. p2.y += TERRAIN_SAMPLE_SIZE;
  1493. p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
  1494. worldToScreen( &p1, &s1 );
  1495. worldToScreen( &p2, &s2 );
  1496. TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
  1497. }
  1498. if ( TheGlobalData->m_showAudioLocations )
  1499. {
  1500. // Draw audio radii for ALL drawables, not just those on screen
  1501. const Drawable * drawable = TheGameClient->getDrawableList();
  1502. while ( drawable != NULL )
  1503. {
  1504. drawAudioRadii( drawable );
  1505. drawable = drawable->getNextDrawable();
  1506. }
  1507. }
  1508. #endif // DEBUG or INTERNAL
  1509. Region3D axisAlignedRegion;
  1510. getAxisAlignedViewRegion(axisAlignedRegion);
  1511. //
  1512. // there are several things we might want to do as a post pass on the objects after
  1513. // they are all drawn
  1514. /// @todo we might want to consider wiping this iterate out if there is nothing to post draw
  1515. //
  1516. TheGameClient->resetRenderedObjectCount();
  1517. TheGameClient->iterateDrawablesInRegion( &axisAlignedRegion, drawablePostDraw, this );
  1518. TheGameClient->flushTextBearingDrawables();
  1519. // Render 2D scene
  1520. W3DDisplay::m_2DScene->doRender( m_2DCamera );
  1521. }
  1522. // ------------------------------------------------------------------------------------------------
  1523. // ------------------------------------------------------------------------------------------------
  1524. void W3DView::setCameraLock(ObjectID id)
  1525. {
  1526. // If we're disabling camera movements, don't lock onto the object.
  1527. if (TheGlobalData->m_disableCameraMovement && id!=INVALID_ID) {
  1528. return;
  1529. }
  1530. View::setCameraLock(id);
  1531. m_doingScriptedCameraLock = FALSE;
  1532. }
  1533. // ------------------------------------------------------------------------------------------------
  1534. // ------------------------------------------------------------------------------------------------
  1535. void W3DView::setSnapMode( CameraLockType lockType, Real lockDist )
  1536. {
  1537. View::setSnapMode(lockType, lockDist);
  1538. m_doingScriptedCameraLock = TRUE;
  1539. }
  1540. //-------------------------------------------------------------------------------------------------
  1541. /** Scroll the view by the given delta in SCREEN COORDINATES, this interface
  1542. * assumes we will be scrolling along the X,Y plane */
  1543. //-------------------------------------------------------------------------------------------------
  1544. void W3DView::scrollBy( Coord2D *delta )
  1545. {
  1546. // if we haven't moved, ignore
  1547. if( delta && (delta->x != 0 || delta->y != 0) )
  1548. {
  1549. const Real SCROLL_RESOLUTION = 250.0f;
  1550. Vector3 world, worldStart, worldEnd;
  1551. Vector2 screen, start, end;
  1552. m_scrollAmount = *delta;
  1553. screen.X = delta->x;
  1554. screen.Y = delta->y;
  1555. start.X = getWidth();
  1556. start.Y = getHeight();
  1557. Real aspect = getWidth()/getHeight();
  1558. end.X = start.X + delta->x * SCROLL_RESOLUTION;
  1559. end.Y = start.Y + delta->y * SCROLL_RESOLUTION*aspect;
  1560. m_3DCamera->Device_To_World_Space( start, &worldStart );
  1561. m_3DCamera->Device_To_World_Space( end, &worldEnd );
  1562. world.X = worldEnd.X - worldStart.X;
  1563. world.Y = worldEnd.Y - worldStart.Y;
  1564. world.Z = worldEnd.Z - worldStart.Z;
  1565. // scroll by delta
  1566. Coord3D pos = *getPosition();
  1567. pos.x += world.X;
  1568. pos.y += world.Y;
  1569. //DEBUG_LOG(("Delta %.2f, %.2f\n", world.X, world.Z));
  1570. // no change to z
  1571. setPosition(&pos);
  1572. //m_cameraConstraintValid = false; // pos change does NOT invalidate cam constraints
  1573. m_doingRotateCamera = false;
  1574. // set new camera position
  1575. setCameraTransform();
  1576. } // end if
  1577. } // end scrollBy
  1578. //-------------------------------------------------------------------------------------------------
  1579. //-------------------------------------------------------------------------------------------------
  1580. void W3DView::forceRedraw()
  1581. {
  1582. // set the camera
  1583. setCameraTransform();
  1584. }
  1585. //-------------------------------------------------------------------------------------------------
  1586. /** Rotate the view around the up axis to the given angle. */
  1587. //-------------------------------------------------------------------------------------------------
  1588. void W3DView::setAngle( Real angle )
  1589. {
  1590. // Normalize to +-PI.
  1591. normAngle(angle);
  1592. // call our base class, we are adding functionality
  1593. View::setAngle( angle );
  1594. m_doingMoveCameraOnWaypointPath = false;
  1595. m_CameraArrivedAtWaypointOnPathFlag = false;
  1596. m_doingRotateCamera = false;
  1597. m_doingPitchCamera = false;
  1598. m_doingZoomCamera = false;
  1599. m_doingScriptedCameraLock = false;
  1600. // set the camera
  1601. setCameraTransform();
  1602. }
  1603. //-------------------------------------------------------------------------------------------------
  1604. /** Rotate the view around the horizontal (X) axis to the given angle. */
  1605. //-------------------------------------------------------------------------------------------------
  1606. void W3DView::setPitch( Real angle )
  1607. {
  1608. // call our base class, we are extending functionality
  1609. View::setPitch( angle );
  1610. m_doingMoveCameraOnWaypointPath = false;
  1611. m_doingRotateCamera = false;
  1612. m_doingPitchCamera = false;
  1613. m_doingZoomCamera = false;
  1614. m_doingScriptedCameraLock = false;
  1615. // set the camera
  1616. setCameraTransform();
  1617. }
  1618. //-------------------------------------------------------------------------------------------------
  1619. /** Set the view angle & pitch back to default */
  1620. //-------------------------------------------------------------------------------------------------
  1621. void W3DView::setAngleAndPitchToDefault( void )
  1622. {
  1623. // call our base class, we are adding functionality
  1624. View::setAngleAndPitchToDefault();
  1625. this->m_FXPitch = 1.0;
  1626. // set the camera
  1627. setCameraTransform();
  1628. }
  1629. //-------------------------------------------------------------------------------------------------
  1630. //-------------------------------------------------------------------------------------------------
  1631. void W3DView::setDefaultView(Real pitch, Real angle, Real maxHeight)
  1632. {
  1633. // MDC - we no longer want to rotate maps (design made all of them right to begin with)
  1634. // m_defaultAngle = angle * M_PI/180.0f;
  1635. m_defaultPitchAngle = pitch;
  1636. m_maxHeightAboveGround = TheGlobalData->m_maxCameraHeight*maxHeight;
  1637. if (m_minHeightAboveGround > m_maxHeightAboveGround)
  1638. m_maxHeightAboveGround = m_minHeightAboveGround;
  1639. }
  1640. //-------------------------------------------------------------------------------------------------
  1641. //-------------------------------------------------------------------------------------------------
  1642. void W3DView::setHeightAboveGround(Real z)
  1643. {
  1644. m_heightAboveGround = z;
  1645. // if our zoom is limited, we will stay within a predefined distance from the terrain
  1646. if( m_zoomLimited )
  1647. {
  1648. if (m_heightAboveGround < m_minHeightAboveGround)
  1649. m_heightAboveGround = m_minHeightAboveGround;
  1650. if (m_heightAboveGround > m_maxHeightAboveGround)
  1651. m_heightAboveGround = m_maxHeightAboveGround;
  1652. } // end if
  1653. m_doingMoveCameraOnWaypointPath = false;
  1654. m_CameraArrivedAtWaypointOnPathFlag = false;
  1655. m_doingRotateCamera = false;
  1656. m_doingPitchCamera = false;
  1657. m_doingZoomCamera = false;
  1658. m_doingScriptedCameraLock = false;
  1659. m_cameraConstraintValid = false; // recalc it.
  1660. setCameraTransform();
  1661. }
  1662. //-------------------------------------------------------------------------------------------------
  1663. //-------------------------------------------------------------------------------------------------
  1664. void W3DView::setZoom(Real z)
  1665. {
  1666. m_zoom = z;
  1667. if (m_zoom < m_minZoom)
  1668. m_zoom = m_minZoom;
  1669. if (m_zoom > m_maxZoom)
  1670. m_zoom = m_maxZoom;
  1671. m_doingMoveCameraOnWaypointPath = false;
  1672. m_CameraArrivedAtWaypointOnPathFlag = false;
  1673. m_doingRotateCamera = false;
  1674. m_doingPitchCamera = false;
  1675. m_doingZoomCamera = false;
  1676. m_doingScriptedCameraLock = false;
  1677. m_cameraConstraintValid = false; // recalc it.
  1678. setCameraTransform();
  1679. }
  1680. //-------------------------------------------------------------------------------------------------
  1681. //-------------------------------------------------------------------------------------------------
  1682. void W3DView::setZoomToDefault( void )
  1683. {
  1684. // default zoom has to be max, otherwise players will just zoom to max always
  1685. // terrain height + desired height offset == cameraOffset * actual zoom
  1686. // find best approximation of max terrain height we can see
  1687. Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
  1688. Real desiredHeight = (terrainHeightMax + m_maxHeightAboveGround);
  1689. Real desiredZoom = desiredHeight / m_cameraOffset.z;
  1690. //DEBUG_LOG(("W3DView::setZoomToDefault() Current zoom: %g Desired zoom: %g\n", m_zoom, desiredZoom));
  1691. m_zoom = desiredZoom;
  1692. m_heightAboveGround = m_maxHeightAboveGround;
  1693. m_doingMoveCameraOnWaypointPath = false;
  1694. m_CameraArrivedAtWaypointOnPathFlag = false;
  1695. m_doingRotateCamera = false;
  1696. m_doingPitchCamera = false;
  1697. m_doingZoomCamera = false;
  1698. m_doingScriptedCameraLock = false;
  1699. m_cameraConstraintValid = false; // recalc it.
  1700. setCameraTransform();
  1701. }
  1702. //-------------------------------------------------------------------------------------------------
  1703. /** Set the horizontal field of view angle */
  1704. //-------------------------------------------------------------------------------------------------
  1705. void W3DView::setFieldOfView( Real angle )
  1706. {
  1707. View::setFieldOfView( angle );
  1708. #if defined(_DEBUG) || defined(_INTERNAL)
  1709. // this is only for testing, and recalculating the
  1710. // camera every frame is wasteful
  1711. setCameraTransform();
  1712. #endif
  1713. }
  1714. //-------------------------------------------------------------------------------------------------
  1715. /** Using the W3D camera translate the world coordinate to a screen coord.
  1716. Screen coordinates returned in absolute values relative to full display resolution.
  1717. Returns if the point is on screen, off screen, or not transformable */
  1718. //-------------------------------------------------------------------------------------------------
  1719. View::WorldToScreenReturn W3DView::worldToScreenTriReturn( const Coord3D *w, ICoord2D *s )
  1720. {
  1721. // sanity
  1722. if( w == NULL || s == NULL )
  1723. return WTS_INVALID;
  1724. if( m_3DCamera )
  1725. {
  1726. Vector3 world;
  1727. Vector3 screen;
  1728. world.Set( w->x, w->y, w->z );
  1729. enum CameraClass::ProjectionResType projection = m_3DCamera->Project( screen, world );
  1730. if (projection != CameraClass::INSIDE_FRUSTUM && projection!=CameraClass::OUTSIDE_FRUSTUM)
  1731. {
  1732. // Can't get a valid number if it's beyond the clip planes. jba
  1733. s->x = 0;
  1734. s->y = 0;
  1735. return WTS_INVALID;
  1736. }
  1737. //
  1738. // note that the screen coord returned from the project W3D camera
  1739. // gave us a screen coords that range from (-1,-1) bottom left to
  1740. // (1,1) top right ... we are turning that into (0,0) upper left
  1741. // coords now
  1742. //
  1743. W3DLogicalScreenToPixelScreen( screen.X, screen.Y,
  1744. &s->x, &s->y,
  1745. getWidth(), getHeight());
  1746. s->x += m_originX; //convert viewport coordinates to full screen coordinates
  1747. s->y += m_originY;
  1748. // s->x = (getWidth() * (screen.X + 1.0f)) / 2.0f;
  1749. // s->y = (getHeight() * (-screen.Y + 1.0f)) / 2.0f;
  1750. if (projection != CameraClass::INSIDE_FRUSTUM)
  1751. {
  1752. return WTS_OUTSIDE_FRUSTUM;
  1753. }
  1754. return WTS_INSIDE_FRUSTUM;
  1755. } // end if
  1756. return WTS_INVALID;
  1757. } // end worldToScreenTriReturn
  1758. //-------------------------------------------------------------------------------------------------
  1759. /** Using the W3D camera translate the screen coord to world coord */
  1760. //-------------------------------------------------------------------------------------------------
  1761. void W3DView::screenToWorld( const ICoord2D *s, Coord3D *w )
  1762. {
  1763. // sanity
  1764. if( s == NULL || w == NULL )
  1765. return;
  1766. if( m_3DCamera )
  1767. {
  1768. DEBUG_CRASH(("implement me"));
  1769. } // end if
  1770. } // end screenToWorld
  1771. //-------------------------------------------------------------------------------------------------
  1772. /** all the drawables in the view, that fall within the 2D screen region
  1773. * will call the callback function. The number of drawables that passed
  1774. * the test are returned.
  1775. Screen coordinates assumed in absolute values relative to full display resolution. */
  1776. //-------------------------------------------------------------------------------------------------
  1777. Int W3DView::iterateDrawablesInRegion( IRegion2D *screenRegion,
  1778. Bool (*callback)( Drawable *draw, void *userData ),
  1779. void *userData )
  1780. {
  1781. Bool inside = FALSE;
  1782. Int count = 0;
  1783. Drawable *draw;
  1784. Vector3 screen, world;
  1785. Coord3D pos;
  1786. Region2D normalizedRegion;
  1787. /** @todo we need to have partitions of which drawables are in the
  1788. view so we don't have to march through the whole list */
  1789. //
  1790. // to do this we are projecting the drawable centers onto the screen,
  1791. // the W3D camera->project method is used to do this and that method
  1792. // will return normalized screen coords from (-1,-1) bottom left to
  1793. // (1,1) top right, normalize our screen region for comparison
  1794. //
  1795. /// @todo use fast int->real type casts here later
  1796. Bool regionIsPoint = FALSE;
  1797. if( screenRegion )
  1798. {
  1799. if (screenRegion->height() == 0 && screenRegion->width() == 0)
  1800. {
  1801. regionIsPoint = TRUE;
  1802. }
  1803. normalizedRegion.lo.x = ((Real)(screenRegion->lo.x - m_originX) / (Real)getWidth()) * 2.0f - 1.0f;
  1804. normalizedRegion.lo.y = -(((Real)(screenRegion->hi.y - m_originY) / (Real)getHeight()) * 2.0f - 1.0f);
  1805. normalizedRegion.hi.x = ((Real)(screenRegion->hi.x - m_originX) / (Real)getWidth()) * 2.0f - 1.0f;
  1806. normalizedRegion.hi.y = -(((Real)(screenRegion->lo.y - m_originY) / (Real)getHeight()) * 2.0f - 1.0f);
  1807. } // end if
  1808. Drawable *onlyDrawableToTest = NULL;
  1809. if (regionIsPoint)
  1810. {
  1811. // Allow all drawables to be picked.
  1812. onlyDrawableToTest = pickDrawable(&screenRegion->lo, TRUE, (PickType) getPickTypesForContext(TheInGameUI->isInForceAttackMode()));
  1813. if (onlyDrawableToTest == NULL) {
  1814. return 0;
  1815. }
  1816. }
  1817. for( draw = TheGameClient->firstDrawable();
  1818. draw;
  1819. draw = draw->getNextDrawable() )
  1820. {
  1821. if (onlyDrawableToTest)
  1822. {
  1823. draw = onlyDrawableToTest;
  1824. inside = TRUE;
  1825. }
  1826. else
  1827. {
  1828. // not inside
  1829. inside = FALSE;
  1830. // no screen region, means all drawbles
  1831. if( screenRegion == NULL )
  1832. inside = TRUE;
  1833. else
  1834. {
  1835. // project the center of the drawable to the screen
  1836. /// @todo use a real 3D position in the drawable
  1837. pos = *draw->getPosition();
  1838. world.X = pos.x;
  1839. world.Y = pos.y;
  1840. world.Z = pos.z;
  1841. // project the world point to the screen
  1842. if( m_3DCamera->Project( screen, world ) == CameraClass::INSIDE_FRUSTUM &&
  1843. screen.X >= normalizedRegion.lo.x &&
  1844. screen.X <= normalizedRegion.hi.x &&
  1845. screen.Y >= normalizedRegion.lo.y &&
  1846. screen.Y <= normalizedRegion.hi.y )
  1847. {
  1848. inside = TRUE;
  1849. } // end if
  1850. }
  1851. } //end else
  1852. // if inside do the callback and count up
  1853. if( inside )
  1854. {
  1855. if( callback( draw, userData ) )
  1856. ++count;
  1857. } // end if
  1858. // If onlyDrawableToTest, then we should bail out now.
  1859. if (onlyDrawableToTest != NULL)
  1860. break;
  1861. } // end for draw
  1862. return count;
  1863. } // end iterateDrawablesInRegion
  1864. //-------------------------------------------------------------------------------------------------
  1865. /** cast a ray from the screen coords into the scene and return a drawable
  1866. * there if present. Screen coordinates assumed in absolute values relative
  1867. * to full display resolution. */
  1868. //-------------------------------------------------------------------------------------------------
  1869. Drawable *W3DView::pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType )
  1870. {
  1871. RenderObjClass *renderObj = NULL;
  1872. Drawable *draw = NULL;
  1873. DrawableInfo *drawInfo = NULL;
  1874. // sanity
  1875. if( screen == NULL )
  1876. return NULL;
  1877. // don't pick a drawable if there is a window under the cursor
  1878. GameWindow *window = NULL;
  1879. if (TheWindowManager)
  1880. window = TheWindowManager->getWindowUnderCursor(screen->x, screen->y);
  1881. while (window)
  1882. {
  1883. // check to see if it or any of its parents are opaque. If so, we can't select anything.
  1884. if (!BitTest( window->winGetStatus(), WIN_STATUS_SEE_THRU ))
  1885. return NULL;
  1886. window = window->winGetParent();
  1887. }
  1888. Vector3 rayStart,rayEnd;
  1889. getPickRay(screen,&rayStart,&rayEnd);
  1890. LineSegClass lineseg;
  1891. lineseg.Set(rayStart,rayEnd);
  1892. CastResultStruct result;
  1893. if (forceAttack)
  1894. result.ComputeContactPoint = true;
  1895. //Don't check against translucent or hidden objects
  1896. RayCollisionTestClass raytest(lineseg,&result,COLL_TYPE_ALL,false,false);
  1897. if( W3DDisplay::m_3DScene->castRay( raytest, false, (Int)pickType ) )
  1898. renderObj = raytest.CollidedRenderObj;
  1899. // for right now there is no drawable data in a render object which is // if we've found a render object, return our drawable associated with it,
  1900. // the terrain, therefore the userdata is NULL
  1901. /// @todo terrain and picking!
  1902. if( renderObj )
  1903. drawInfo = (DrawableInfo *)renderObj->Get_User_Data();
  1904. if (drawInfo)
  1905. draw=drawInfo->m_drawable;
  1906. return draw;
  1907. } // end pickDrawable
  1908. //-------------------------------------------------------------------------------------------------
  1909. /** convert a pixel (x,y) to a location in the world on the terrain.
  1910. Screen coordinates assumed in absolute values relative to full display resolution. */
  1911. //-------------------------------------------------------------------------------------------------
  1912. void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world )
  1913. {
  1914. // sanity
  1915. if( screen == NULL || world == NULL || TheTerrainRenderObject == NULL )
  1916. return;
  1917. if (m_cameraHasMovedSinceRequest) {
  1918. m_locationRequests.clear();
  1919. m_cameraHasMovedSinceRequest = false;
  1920. }
  1921. if (m_locationRequests.size() > MAX_REQUEST_CACHE_SIZE) {
  1922. m_locationRequests.erase(m_locationRequests.begin(), m_locationRequests.begin() + 10);
  1923. }
  1924. // We insert them at the end for speed (no copies needed), but using the princ of locality, we should
  1925. // start searching where we most recently inserted
  1926. for (int i = m_locationRequests.size() - 1; i >= 0; --i) {
  1927. if (m_locationRequests[i].first.x == screen->x && m_locationRequests[i].first.y == screen->y) {
  1928. (*world) = m_locationRequests[i].second;
  1929. return;
  1930. }
  1931. }
  1932. Vector3 rayStart,rayEnd;
  1933. LineSegClass lineseg;
  1934. CastResultStruct result;
  1935. Vector3 intersection(0,0,0);
  1936. getPickRay(screen,&rayStart,&rayEnd);
  1937. lineseg.Set(rayStart,rayEnd);
  1938. RayCollisionTestClass raytest(lineseg,&result);
  1939. if( TheTerrainRenderObject->Cast_Ray(raytest) )
  1940. {
  1941. // get the point of intersection according to W3D
  1942. intersection = result.ContactPoint;
  1943. } // end if
  1944. // Pick bridges.
  1945. Vector3 bridgePt;
  1946. Drawable *bridge = TheTerrainLogic->pickBridge(rayStart, rayEnd, &bridgePt);
  1947. if (bridge && bridgePt.Z > intersection.Z) {
  1948. intersection = bridgePt;
  1949. }
  1950. world->x = intersection.X;
  1951. world->y = intersection.Y;
  1952. world->z = intersection.Z;
  1953. PosRequest req;
  1954. req.first = (*screen);
  1955. req.second = (*world);
  1956. m_locationRequests.push_back(req); // Insert this request at the end, requires no extra copies
  1957. } // end screenToTerrain
  1958. //-------------------------------------------------------------------------------------------------
  1959. //-------------------------------------------------------------------------------------------------
  1960. void W3DView::lookAt( const Coord3D *o )
  1961. {
  1962. Coord3D pos = *o;
  1963. // no, don't call the super-lookAt, since it will munge our coords
  1964. // as for a 2d view. just call setPosition.
  1965. //View::lookAt(&pos);
  1966. if (o->z > PATHFIND_CELL_SIZE_F+TheTerrainLogic->getGroundHeight(pos.x, pos.y)) {
  1967. // Pos.z is not used, so if we want to look at something off the ground,
  1968. // we have to look at the spot on the ground such that the object intersects
  1969. // with the look at vector in the center of the screen. jba.
  1970. Vector3 rayStart,rayEnd;
  1971. LineSegClass lineseg;
  1972. CastResultStruct result;
  1973. Vector3 intersection(0,0,0);
  1974. rayStart = m_3DCamera->Get_Position(); //get camera location
  1975. m_3DCamera->Un_Project(rayEnd,Vector2(0.0f,0.0f)); //get world space point
  1976. rayEnd -= rayStart; //vector camera to world space point
  1977. rayEnd.Normalize(); //make unit vector
  1978. rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane
  1979. rayStart.Set(pos.x, pos.y, pos.z);
  1980. rayEnd += rayStart; //get point on far clip plane along ray from camera.
  1981. lineseg.Set(rayStart,rayEnd);
  1982. RayCollisionTestClass raytest(lineseg,&result);
  1983. if( TheTerrainRenderObject->Cast_Ray(raytest) )
  1984. {
  1985. // get the point of intersection according to W3D
  1986. pos.x = result.ContactPoint.X;
  1987. pos.y = result.ContactPoint.Y;
  1988. } // end if
  1989. }
  1990. pos.z = 0;
  1991. setPosition(&pos);
  1992. m_doingRotateCamera = false;
  1993. m_doingMoveCameraOnWaypointPath = false;
  1994. m_CameraArrivedAtWaypointOnPathFlag = false;
  1995. m_doingScriptedCameraLock = false;
  1996. setCameraTransform();
  1997. }
  1998. //-------------------------------------------------------------------------------------------------
  1999. //-------------------------------------------------------------------------------------------------
  2000. void W3DView::initHeightForMap( void )
  2001. {
  2002. m_groundLevel = TheTerrainLogic->getGroundHeight(m_pos.x, m_pos.y);
  2003. const Real MAX_GROUND_LEVEL = 120.0; // jba - starting ground level can't exceed this height.
  2004. if (m_groundLevel>MAX_GROUND_LEVEL) {
  2005. m_groundLevel = MAX_GROUND_LEVEL;
  2006. }
  2007. m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight;
  2008. m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
  2009. m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
  2010. m_cameraConstraintValid = false; // possible ground level change invalidates cam constraints
  2011. setCameraTransform();
  2012. }
  2013. //-------------------------------------------------------------------------------------------------
  2014. /** Move camera to in an interesting fashion. Sets up parameters that get
  2015. * evaluated in draw(). */
  2016. //-------------------------------------------------------------------------------------------------
  2017. void W3DView::moveCameraTo(const Coord3D *o, Int milliseconds, Int shutter, Bool orient, Real easeIn, Real easeOut)
  2018. {
  2019. m_mcwpInfo.waypoints[0] = *getPosition();
  2020. m_mcwpInfo.cameraAngle[0] = getAngle();
  2021. m_mcwpInfo.waySegLength[0] = 0;
  2022. m_mcwpInfo.waypoints[1] = *getPosition();
  2023. m_mcwpInfo.waySegLength[1] = 0;
  2024. m_mcwpInfo.waypoints[2] = *o;
  2025. m_mcwpInfo.waySegLength[2] = 0;
  2026. m_mcwpInfo.numWaypoints = 2;
  2027. if (milliseconds<1) milliseconds = 1;
  2028. m_mcwpInfo.totalTimeMilliseconds = milliseconds;
  2029. m_mcwpInfo.shutter = 1;
  2030. m_mcwpInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2031. m_mcwpInfo.curSegment = 1;
  2032. m_mcwpInfo.curSegDistance = 0;
  2033. m_mcwpInfo.totalDistance = 0;
  2034. setupWaypointPath(orient);
  2035. if (m_mcwpInfo.totalTimeMilliseconds==1) {
  2036. // do it instantly.
  2037. moveAlongWaypointPath(1);
  2038. m_doingMoveCameraOnWaypointPath = true;
  2039. m_CameraArrivedAtWaypointOnPathFlag = false;
  2040. }
  2041. }
  2042. //-------------------------------------------------------------------------------------------------
  2043. /** Rotate the camera */
  2044. //-------------------------------------------------------------------------------------------------
  2045. void W3DView::rotateCamera(Real rotations, Int milliseconds, Real easeIn, Real easeOut)
  2046. {
  2047. m_rcInfo.numHoldFrames = 0;
  2048. m_rcInfo.trackObject = FALSE;
  2049. if (milliseconds<1) milliseconds = 1;
  2050. m_rcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
  2051. if (m_rcInfo.numFrames < 1) {
  2052. m_rcInfo.numFrames = 1;
  2053. }
  2054. m_rcInfo.curFrame = 0;
  2055. m_doingRotateCamera = true;
  2056. m_rcInfo.angle.startAngle = m_angle;
  2057. m_rcInfo.angle.endAngle = m_angle + 2*PI*rotations;
  2058. m_rcInfo.startTimeMultiplier = m_timeMultiplier;
  2059. m_rcInfo.endTimeMultiplier = m_timeMultiplier;
  2060. m_rcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2061. m_doingMoveCameraOnWaypointPath = false;
  2062. m_CameraArrivedAtWaypointOnPathFlag = false;
  2063. }
  2064. //-------------------------------------------------------------------------------------------------
  2065. /** Rotate the camera to follow a unit */
  2066. //-------------------------------------------------------------------------------------------------
  2067. void W3DView::rotateCameraTowardObject(ObjectID id, Int milliseconds, Int holdMilliseconds, Real easeIn, Real easeOut)
  2068. {
  2069. m_rcInfo.trackObject = TRUE;
  2070. if (holdMilliseconds<1) holdMilliseconds = 0;
  2071. m_rcInfo.numHoldFrames = holdMilliseconds/TheW3DFrameLengthInMsec;
  2072. if (m_rcInfo.numHoldFrames < 1) {
  2073. m_rcInfo.numHoldFrames = 0;
  2074. }
  2075. if (milliseconds<1) milliseconds = 1;
  2076. m_rcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
  2077. if (m_rcInfo.numFrames < 1) {
  2078. m_rcInfo.numFrames = 1;
  2079. }
  2080. m_rcInfo.curFrame = 0;
  2081. m_doingRotateCamera = true;
  2082. m_rcInfo.target.targetObjectID = id;
  2083. m_rcInfo.startTimeMultiplier = m_timeMultiplier;
  2084. m_rcInfo.endTimeMultiplier = m_timeMultiplier;
  2085. m_rcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2086. m_doingMoveCameraOnWaypointPath = false;
  2087. m_CameraArrivedAtWaypointOnPathFlag = false;
  2088. }
  2089. //-------------------------------------------------------------------------------------------------
  2090. /** Rotate camera to face a location */
  2091. //-------------------------------------------------------------------------------------------------
  2092. void W3DView::rotateCameraTowardPosition(const Coord3D *pLoc, Int milliseconds, Real easeIn, Real easeOut, Bool reverseRotation)
  2093. {
  2094. m_rcInfo.numHoldFrames = 0;
  2095. m_rcInfo.trackObject = FALSE;
  2096. if (milliseconds<1) milliseconds = 1;
  2097. m_rcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
  2098. if (m_rcInfo.numFrames < 1) {
  2099. m_rcInfo.numFrames = 1;
  2100. }
  2101. Coord3D curPos = *getPosition();
  2102. Vector2 dir(pLoc->x-curPos.x, pLoc->y-curPos.y);
  2103. const Real dirLength = dir.Length();
  2104. if (dirLength<0.1f) return;
  2105. Real angle = WWMath::Acos(dir.X/dirLength);
  2106. if (dir.Y<0.0f) {
  2107. angle = -angle;
  2108. }
  2109. // Default camera is rotated 90 degrees, so match.
  2110. angle -= PI/2;
  2111. normAngle(angle);
  2112. if (reverseRotation) {
  2113. if (m_angle < angle) {
  2114. angle -= 2.0f*WWMATH_PI;
  2115. } else {
  2116. angle += 2.0f*WWMATH_PI;
  2117. }
  2118. }
  2119. m_rcInfo.curFrame = 0;
  2120. m_doingRotateCamera = true;
  2121. m_rcInfo.angle.startAngle = m_angle;
  2122. m_rcInfo.angle.endAngle = angle;
  2123. m_rcInfo.startTimeMultiplier = m_timeMultiplier;
  2124. m_rcInfo.endTimeMultiplier = m_timeMultiplier;
  2125. m_rcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2126. m_doingMoveCameraOnWaypointPath = false;
  2127. m_CameraArrivedAtWaypointOnPathFlag = false;
  2128. }
  2129. //-------------------------------------------------------------------------------------------------
  2130. //-------------------------------------------------------------------------------------------------
  2131. void W3DView::zoomCamera( Real finalZoom, Int milliseconds, Real easeIn, Real easeOut )
  2132. {
  2133. if (milliseconds<1) milliseconds = 1;
  2134. m_zcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
  2135. if (m_zcInfo.numFrames < 1) {
  2136. m_zcInfo.numFrames = 1;
  2137. }
  2138. m_zcInfo.curFrame = 0;
  2139. m_doingZoomCamera = TRUE;
  2140. m_zcInfo.startZoom = m_zoom;
  2141. m_zcInfo.endZoom = finalZoom;
  2142. m_zcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2143. }
  2144. //-------------------------------------------------------------------------------------------------
  2145. //-------------------------------------------------------------------------------------------------
  2146. void W3DView::pitchCamera( Real finalPitch, Int milliseconds, Real easeIn, Real easeOut )
  2147. {
  2148. if (milliseconds<1) milliseconds = 1;
  2149. m_pcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
  2150. if (m_pcInfo.numFrames < 1) {
  2151. m_pcInfo.numFrames = 1;
  2152. }
  2153. m_pcInfo.curFrame = 0;
  2154. m_doingPitchCamera = TRUE;
  2155. m_pcInfo.startPitch = m_FXPitch;
  2156. m_pcInfo.endPitch = finalPitch;
  2157. m_pcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2158. }
  2159. //-------------------------------------------------------------------------------------------------
  2160. /** Sets the final zoom for a camera movement. */
  2161. //-------------------------------------------------------------------------------------------------
  2162. void W3DView::cameraModFinalZoom( Real finalZoom, Real easeIn, Real easeOut )
  2163. {
  2164. if (m_doingRotateCamera)
  2165. {
  2166. Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
  2167. Real maxHeight = (terrainHeightMax + m_maxHeightAboveGround);
  2168. Real maxZoom = maxHeight / m_cameraOffset.z;
  2169. Real time = (m_rcInfo.numFrames + m_rcInfo.numHoldFrames - m_rcInfo.curFrame)*TheW3DFrameLengthInMsec;
  2170. zoomCamera( finalZoom*maxZoom, time, time*easeIn, time*easeOut );
  2171. }
  2172. if (m_doingMoveCameraOnWaypointPath)
  2173. {
  2174. Coord3D pos = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2175. Real terrainHeightMax = getHeightAroundPos(pos.x, pos.y);
  2176. Real maxHeight = (terrainHeightMax + m_maxHeightAboveGround);
  2177. Real maxZoom = maxHeight / m_cameraOffset.z;
  2178. Real time = m_mcwpInfo.totalTimeMilliseconds - m_mcwpInfo.elapsedTimeMilliseconds;
  2179. zoomCamera( finalZoom*maxZoom, time, time*easeIn, time*easeOut );
  2180. }
  2181. }
  2182. //-------------------------------------------------------------------------------------------------
  2183. /** Sets the final zoom for a camera movement. */
  2184. //-------------------------------------------------------------------------------------------------
  2185. void W3DView::cameraModFreezeAngle(void)
  2186. {
  2187. if (m_doingRotateCamera) {
  2188. if (m_rcInfo.trackObject) {
  2189. m_rcInfo.target.targetObjectID = INVALID_ID;
  2190. } else {
  2191. m_rcInfo.angle.startAngle = m_rcInfo.angle.endAngle = m_angle; // Silly, but consistent.
  2192. }
  2193. }
  2194. if (m_doingMoveCameraOnWaypointPath) {
  2195. Int i;
  2196. // Real curDistance = 0;
  2197. for (i=0; i<m_mcwpInfo.numWaypoints; i++) {
  2198. m_mcwpInfo.cameraAngle[i+1] = m_mcwpInfo.cameraAngle[0];
  2199. }
  2200. }
  2201. }
  2202. // ------------------------------------------------------------------------------------------------
  2203. /** Sets the look toward point for a camera movement. */
  2204. // ------------------------------------------------------------------------------------------------
  2205. void W3DView::cameraModLookToward(Coord3D *pLoc)
  2206. {
  2207. if (m_doingRotateCamera) {
  2208. return; // Doesn't apply to rotate about a point.
  2209. }
  2210. if (m_doingMoveCameraOnWaypointPath) {
  2211. Int i;
  2212. // Real curDistance = 0;
  2213. for (i=2; i<=m_mcwpInfo.numWaypoints; i++) {
  2214. Coord3D start, mid, end;
  2215. Real factor = 0.5;
  2216. start = m_mcwpInfo.waypoints[i-1];
  2217. start.x += m_mcwpInfo.waypoints[i].x;
  2218. start.y += m_mcwpInfo.waypoints[i].y;
  2219. start.x /= 2;
  2220. start.y /= 2;
  2221. mid = m_mcwpInfo.waypoints[i];
  2222. end = m_mcwpInfo.waypoints[i];
  2223. end.x += m_mcwpInfo.waypoints[i+1].x;
  2224. end.y += m_mcwpInfo.waypoints[i+1].y;
  2225. end.x /= 2;
  2226. end.y /= 2;
  2227. Coord3D result = start;
  2228. result.x += factor*(end.x-start.x);
  2229. result.y += factor*(end.y-start.y);
  2230. result.x += (1-factor)*factor*(mid.x-end.x + mid.x-start.x);
  2231. result.y += (1-factor)*factor*(mid.y-end.y + mid.y-start.y);
  2232. result.z = 0;
  2233. Vector2 dir(pLoc->x-result.x, pLoc->y-result.y);
  2234. const Real dirLength = dir.Length();
  2235. if (dirLength<0.1f) continue;
  2236. Real angle = WWMath::Acos(dir.X/dirLength);
  2237. if (dir.Y<0.0f) {
  2238. angle = -angle;
  2239. }
  2240. // Default camera is rotated 90 degrees, so match.
  2241. angle -= PI/2;
  2242. normAngle(angle);
  2243. m_mcwpInfo.cameraAngle[i] = angle;
  2244. }
  2245. if (m_mcwpInfo.totalTimeMilliseconds==1) {
  2246. // do it instantly.
  2247. moveAlongWaypointPath(1);
  2248. m_doingMoveCameraOnWaypointPath = true;
  2249. m_CameraArrivedAtWaypointOnPathFlag = false;
  2250. }
  2251. }
  2252. }
  2253. // ------------------------------------------------------------------------------------------------
  2254. /** Sets the look toward point for the end of a camera movement. */
  2255. // ------------------------------------------------------------------------------------------------
  2256. void W3DView::cameraModFinalMoveTo(Coord3D *pLoc)
  2257. {
  2258. if (m_doingRotateCamera) {
  2259. return; // Doesn't apply to rotate about a point.
  2260. }
  2261. if (m_doingMoveCameraOnWaypointPath) {
  2262. Int i;
  2263. Coord3D start, delta;
  2264. start = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2265. delta.x = pLoc->x - start.x;
  2266. delta.y = pLoc->y - start.y;
  2267. for (i=2; i<=m_mcwpInfo.numWaypoints; i++) {
  2268. Coord3D result = m_mcwpInfo.waypoints[i];
  2269. result.x += delta.x;
  2270. result.y += delta.y;
  2271. m_mcwpInfo.waypoints[i] = result;
  2272. }
  2273. }
  2274. }
  2275. // ------------------------------------------------------------------------------------------------
  2276. /** Sets the look toward point for the end of a camera movement. */
  2277. // ------------------------------------------------------------------------------------------------
  2278. void W3DView::cameraModFinalLookToward(Coord3D *pLoc)
  2279. {
  2280. if (m_doingRotateCamera) {
  2281. return; // Doesn't apply to rotate about a point.
  2282. }
  2283. if (m_doingMoveCameraOnWaypointPath) {
  2284. Int i;
  2285. Int min = m_mcwpInfo.numWaypoints-1;
  2286. if (min<2) min=2;
  2287. // Real curDistance = 0;
  2288. for (i=min; i<=m_mcwpInfo.numWaypoints; i++) {
  2289. Coord3D start, mid, end;
  2290. Real factor = 0.5;
  2291. start = m_mcwpInfo.waypoints[i-1];
  2292. start.x += m_mcwpInfo.waypoints[i].x;
  2293. start.y += m_mcwpInfo.waypoints[i].y;
  2294. start.x /= 2;
  2295. start.y /= 2;
  2296. mid = m_mcwpInfo.waypoints[i];
  2297. end = m_mcwpInfo.waypoints[i];
  2298. end.x += m_mcwpInfo.waypoints[i+1].x;
  2299. end.y += m_mcwpInfo.waypoints[i+1].y;
  2300. end.x /= 2;
  2301. end.y /= 2;
  2302. Coord3D result = start;
  2303. result.x += factor*(end.x-start.x);
  2304. result.y += factor*(end.y-start.y);
  2305. result.x += (1-factor)*factor*(mid.x-end.x + mid.x-start.x);
  2306. result.y += (1-factor)*factor*(mid.y-end.y + mid.y-start.y);
  2307. result.z = 0;
  2308. Vector2 dir(pLoc->x-result.x, pLoc->y-result.y);
  2309. const Real dirLength = dir.Length();
  2310. if (dirLength<0.1f) continue;
  2311. Real angle = WWMath::Acos(dir.X/dirLength);
  2312. if (dir.Y<0.0f) {
  2313. angle = -angle;
  2314. }
  2315. // Default camera is rotated 90 degrees, so match.
  2316. angle -= PI/2;
  2317. normAngle(angle);
  2318. if (i==m_mcwpInfo.numWaypoints) {
  2319. m_mcwpInfo.cameraAngle[i] = angle;
  2320. } else {
  2321. Real deltaAngle = angle - m_mcwpInfo.cameraAngle[i];
  2322. normAngle(deltaAngle);
  2323. angle = m_mcwpInfo.cameraAngle[i] + deltaAngle/2;
  2324. normAngle(angle);
  2325. m_mcwpInfo.cameraAngle[i] = angle;
  2326. }
  2327. }
  2328. }
  2329. }
  2330. // ------------------------------------------------------------------------------------------------
  2331. /** Sets the final time multiplier for a camera movement. */
  2332. // ------------------------------------------------------------------------------------------------
  2333. void W3DView::cameraModFinalTimeMultiplier(Int finalMultiplier)
  2334. {
  2335. if (m_doingZoomCamera)
  2336. m_zcInfo.endTimeMultiplier = finalMultiplier;
  2337. if (m_doingPitchCamera)
  2338. m_pcInfo.endTimeMultiplier = finalMultiplier;
  2339. if (m_doingRotateCamera) {
  2340. m_rcInfo.endTimeMultiplier = finalMultiplier;
  2341. } else if (m_doingMoveCameraOnWaypointPath) {
  2342. Int i;
  2343. Real curDistance = 0;
  2344. for (i=0; i<m_mcwpInfo.numWaypoints; i++) {
  2345. curDistance += m_mcwpInfo.waySegLength[i];
  2346. Real factor2 = curDistance / m_mcwpInfo.totalDistance;
  2347. Real factor1 = 1.0-factor2;
  2348. m_mcwpInfo.timeMultiplier[i+1] = REAL_TO_INT_FLOOR(0.5+m_mcwpInfo.timeMultiplier[i+1]*factor1 + finalMultiplier*factor2);
  2349. }
  2350. } else {
  2351. // If we aren't doing a camera movement, just set the time.
  2352. m_timeMultiplier = finalMultiplier;
  2353. }
  2354. }
  2355. // ------------------------------------------------------------------------------------------------
  2356. /** Sets the number of frames to average motion for a camera movement */
  2357. // ------------------------------------------------------------------------------------------------
  2358. void W3DView::cameraModRollingAverage(Int framesToAverage)
  2359. {
  2360. if (framesToAverage < 1) framesToAverage = 1;
  2361. m_mcwpInfo.rollingAverageFrames = framesToAverage;
  2362. }
  2363. // ------------------------------------------------------------------------------------------------
  2364. /** Sets the final pitch for a camera movement. */
  2365. // ------------------------------------------------------------------------------------------------
  2366. void W3DView::cameraModFinalPitch(Real finalPitch, Real easeIn, Real easeOut) {
  2367. if (m_doingRotateCamera) {
  2368. Real time = (m_rcInfo.numFrames + m_rcInfo.numHoldFrames - m_rcInfo.curFrame)*TheW3DFrameLengthInMsec;
  2369. pitchCamera( finalPitch, time, time*easeIn, time*easeOut );
  2370. }
  2371. if (m_doingMoveCameraOnWaypointPath) {
  2372. Real time = m_mcwpInfo.totalTimeMilliseconds - m_mcwpInfo.elapsedTimeMilliseconds;
  2373. pitchCamera( finalPitch, time, time*easeIn, time*easeOut );
  2374. }
  2375. }
  2376. // ------------------------------------------------------------------------------------------------
  2377. /** Move camera to a waypoint, resetting the default angle, pitch & zoom along the way.. */
  2378. // ------------------------------------------------------------------------------------------------
  2379. void W3DView::resetCamera(const Coord3D *location, Int milliseconds, Real easeIn, Real easeOut)
  2380. {
  2381. moveCameraTo(location, milliseconds, 0, false, easeIn, easeOut);
  2382. m_mcwpInfo.cameraAngle[2] = 0.0; // default angle.
  2383. // m_mcwpInfo.cameraAngle[2] = m_defaultAngle;
  2384. m_angle = m_mcwpInfo.cameraAngle[0];
  2385. // terrain height + desired height offset == cameraOffset * actual zoom
  2386. // find best approximation of max terrain height we can see
  2387. //Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
  2388. Real terrainHeightMax = getHeightAroundPos(location->x, location->y);
  2389. Real desiredHeight = (terrainHeightMax + m_maxHeightAboveGround);
  2390. Real desiredZoom = desiredHeight / m_cameraOffset.z;
  2391. zoomCamera( desiredZoom, milliseconds, easeIn, easeOut ); // this isn't right... or is it?
  2392. pitchCamera( 1.0, milliseconds, easeIn, easeOut );
  2393. // pitchCamera( m_defaultPitchAngle, milliseconds, easeIn, easeOut );
  2394. //DEBUG_LOG(("W3DView::resetCamera() Current zoom: %g Desired zoom: %g Current pitch: %g Desired pitch: %g\n",
  2395. // m_zoom, desiredZoom, m_pitchAngle, m_defaultPitchAngle));
  2396. }
  2397. // ------------------------------------------------------------------------------------------------
  2398. // ------------------------------------------------------------------------------------------------
  2399. Bool W3DView::isCameraMovementFinished(void)
  2400. {
  2401. if (m_viewFilter == FT_VIEW_MOTION_BLUR_FILTER) {
  2402. // Several of the motion blur effects are similar to camera movements.
  2403. if (m_viewFilterMode == FM_VIEW_MB_IN_AND_OUT_ALPHA ||
  2404. m_viewFilterMode == FM_VIEW_MB_IN_AND_OUT_SATURATE ||
  2405. m_viewFilterMode == FM_VIEW_MB_IN_ALPHA ||
  2406. m_viewFilterMode == FM_VIEW_MB_OUT_ALPHA ||
  2407. m_viewFilterMode == FM_VIEW_MB_IN_SATURATE ||
  2408. m_viewFilterMode == FM_VIEW_MB_OUT_SATURATE ) {
  2409. return true;
  2410. }
  2411. }
  2412. return !m_doingMoveCameraOnWaypointPath && !m_doingRotateCamera && !m_doingPitchCamera && !m_doingZoomCamera;
  2413. }
  2414. Bool W3DView::isCameraMovementAtWaypointAlongPath(void)
  2415. {
  2416. // WWDEBUG_SAY((( "MBL: Polling W3DView::isCameraMovementAtWaypointAlongPath\n" )));
  2417. Bool return_value = m_CameraArrivedAtWaypointOnPathFlag;
  2418. #pragma message( "MBL: Clearing variable after polling - for scripting - see Adam.\n" )
  2419. m_CameraArrivedAtWaypointOnPathFlag = false;
  2420. return( return_value );
  2421. }
  2422. // ------------------------------------------------------------------------------------------------
  2423. /** Move camera along a waypoint path in an interesting fashion. Sets up parameters that get
  2424. * evaluated in draw(). */
  2425. // ------------------------------------------------------------------------------------------------
  2426. void W3DView::moveCameraAlongWaypointPath(Waypoint *pWay, Int milliseconds, Int shutter, Bool orient, Real easeIn, Real easeOut)
  2427. {
  2428. const Real MIN_DELTA = MAP_XY_FACTOR;
  2429. m_mcwpInfo.waypoints[0] = *getPosition();
  2430. m_mcwpInfo.cameraAngle[0] = getAngle();
  2431. m_mcwpInfo.waySegLength[0] = 0;
  2432. m_mcwpInfo.waypoints[1] = *getPosition();
  2433. m_mcwpInfo.numWaypoints = 1;
  2434. if (milliseconds<1) milliseconds = 1;
  2435. m_mcwpInfo.totalTimeMilliseconds = milliseconds;
  2436. m_mcwpInfo.shutter = shutter/TheW3DFrameLengthInMsec;
  2437. if (m_mcwpInfo.shutter<1) m_mcwpInfo.shutter = 1;
  2438. m_mcwpInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
  2439. while (pWay && m_mcwpInfo.numWaypoints <MAX_WAYPOINTS) {
  2440. m_mcwpInfo.numWaypoints++;
  2441. m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints] = *pWay->getLocation();
  2442. if (pWay->getNumLinks()>0) {
  2443. pWay = pWay->getLink(0);
  2444. } else {
  2445. pWay = NULL;
  2446. }
  2447. Vector2 dir(m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints].x-m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints-1].x, m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints].y-m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints-1].y);
  2448. if (dir.Length()<MIN_DELTA) {
  2449. if (pWay) {
  2450. m_mcwpInfo.numWaypoints--; // drop this one.
  2451. } else {
  2452. m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints-1] = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2453. m_mcwpInfo.numWaypoints--; // Push this one back.
  2454. }
  2455. }
  2456. }
  2457. setupWaypointPath(orient);
  2458. }
  2459. // ------------------------------------------------------------------------------------------------
  2460. /** Calculates angles and distances for moving along a waypoint path. Sets up parameters that get
  2461. * evaluated in draw(). */
  2462. // ------------------------------------------------------------------------------------------------
  2463. void W3DView::setupWaypointPath(Bool orient)
  2464. {
  2465. m_mcwpInfo.curSegment = 1;
  2466. m_mcwpInfo.curSegDistance = 0;
  2467. m_mcwpInfo.totalDistance = 0;
  2468. m_mcwpInfo.rollingAverageFrames = 1;
  2469. Int i;
  2470. Real angle = getAngle();
  2471. for (i=1; i<m_mcwpInfo.numWaypoints; i++) {
  2472. Vector2 dir(m_mcwpInfo.waypoints[i+1].x-m_mcwpInfo.waypoints[i].x, m_mcwpInfo.waypoints[i+1].y-m_mcwpInfo.waypoints[i].y);
  2473. m_mcwpInfo.waySegLength[i] = dir.Length();
  2474. m_mcwpInfo.totalDistance += m_mcwpInfo.waySegLength[i];
  2475. if (orient) {
  2476. angle = WWMath::Acos(dir.X/m_mcwpInfo.waySegLength[i]);
  2477. if (dir.Y<0.0f) {
  2478. angle = -angle;
  2479. }
  2480. // Default camera is rotated 90 degrees, so match.
  2481. angle -= PI/2;
  2482. normAngle(angle);
  2483. }
  2484. //DEBUG_LOG(("Original Index %d, angle %.2f\n", i, angle*180/PI));
  2485. m_mcwpInfo.cameraAngle[i] = angle;
  2486. }
  2487. m_mcwpInfo.cameraAngle[1] = getAngle();
  2488. m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints] = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints-1];
  2489. for (i=m_mcwpInfo.numWaypoints-1; i>1; i--) {
  2490. m_mcwpInfo.cameraAngle[i] = (m_mcwpInfo.cameraAngle[i] + m_mcwpInfo.cameraAngle[i-1]) / 2;
  2491. }
  2492. m_mcwpInfo.waySegLength[m_mcwpInfo.numWaypoints+1] = m_mcwpInfo.waySegLength[m_mcwpInfo.numWaypoints];
  2493. // Prevent a possible divide by zero.
  2494. if (m_mcwpInfo.totalDistance<1.0) {
  2495. m_mcwpInfo.waySegLength[m_mcwpInfo.numWaypoints-1] += 1.0-m_mcwpInfo.totalDistance;
  2496. m_mcwpInfo.totalDistance = 1.0;
  2497. }
  2498. Real curDistance = 0;
  2499. Coord3D finalPos = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2500. Real newGround = TheTerrainLogic->getGroundHeight(finalPos.x, finalPos.y);
  2501. for (i=0; i<=m_mcwpInfo.numWaypoints+1; i++) {
  2502. Real factor2 = curDistance / m_mcwpInfo.totalDistance;
  2503. Real factor1 = 1.0-factor2;
  2504. m_mcwpInfo.timeMultiplier[i] = m_timeMultiplier;
  2505. m_mcwpInfo.groundHeight[i] = m_groundLevel*factor1 + newGround*factor2;
  2506. curDistance += m_mcwpInfo.waySegLength[i];
  2507. //DEBUG_LOG(("New Index %d, angle %.2f\n", i, m_mcwpInfo.cameraAngle[i]*180/PI));
  2508. }
  2509. // Pad the end.
  2510. m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints+1] = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2511. Coord3D cur = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2512. Coord3D prev = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints-1];
  2513. m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints+1].x += cur.x-prev.x;
  2514. m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints+1].y += cur.y-prev.y;
  2515. m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints+1] = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints];
  2516. m_mcwpInfo.groundHeight[m_mcwpInfo.numWaypoints+1] = newGround;
  2517. cur = m_mcwpInfo.waypoints[2];
  2518. prev = m_mcwpInfo.waypoints[1];
  2519. m_mcwpInfo.waypoints[0].x -= cur.x-prev.x;
  2520. m_mcwpInfo.waypoints[0].y -= cur.y-prev.y;
  2521. m_doingMoveCameraOnWaypointPath = m_mcwpInfo.numWaypoints>1;
  2522. m_CameraArrivedAtWaypointOnPathFlag = false;
  2523. m_doingRotateCamera = false;
  2524. m_mcwpInfo.elapsedTimeMilliseconds = 0;
  2525. m_mcwpInfo.curShutter = m_mcwpInfo.shutter;
  2526. }
  2527. // ------------------------------------------------------------------------------------------------
  2528. // ------------------------------------------------------------------------------------------------
  2529. static Real makeQuadraticS(Real t)
  2530. {
  2531. // for t = linear 0-1, convert to quadratic s where 0==0, 0.5==0.5 && 1.0 == 1.0.
  2532. Real tPrime = t;
  2533. if (t<0.5) {
  2534. tPrime = 0.5 * (2*t*2*t);
  2535. } else {
  2536. tPrime = (t-0.5)*2;
  2537. tPrime = WWMath::Sqrt(tPrime);
  2538. tPrime = 0.5 + 0.5*(tPrime);
  2539. }
  2540. return tPrime*0.5 + t*0.5;
  2541. }
  2542. // ------------------------------------------------------------------------------------------------
  2543. // ------------------------------------------------------------------------------------------------
  2544. void W3DView::rotateCameraOneFrame(void)
  2545. {
  2546. m_rcInfo.curFrame++;
  2547. if (TheGlobalData->m_disableCameraMovement) {
  2548. if (m_rcInfo.curFrame >= m_rcInfo.numFrames + m_rcInfo.numHoldFrames) {
  2549. m_doingRotateCamera = false;
  2550. m_freezeTimeForCameraMovement = false;
  2551. }
  2552. return;
  2553. }
  2554. if (m_rcInfo.trackObject)
  2555. {
  2556. if (m_rcInfo.curFrame <= m_rcInfo.numFrames + m_rcInfo.numHoldFrames)
  2557. {
  2558. const Object *obj = TheGameLogic->findObjectByID(m_rcInfo.target.targetObjectID);
  2559. if (obj)
  2560. {
  2561. // object has not been destroyed
  2562. m_rcInfo.target.targetObjectPos = *obj->getPosition();
  2563. }
  2564. const Vector2 dir(m_rcInfo.target.targetObjectPos.x - m_pos.x, m_rcInfo.target.targetObjectPos.y - m_pos.y);
  2565. const Real dirLength = dir.Length();
  2566. if (dirLength>=0.1f)
  2567. {
  2568. Real angle = WWMath::Acos(dir.X/dirLength);
  2569. if (dir.Y<0.0f) {
  2570. angle = -angle;
  2571. }
  2572. // Default camera is rotated 90 degrees, so match.
  2573. angle -= PI/2;
  2574. normAngle(angle);
  2575. if (m_rcInfo.curFrame <= m_rcInfo.numFrames)
  2576. {
  2577. Real factor = m_rcInfo.ease(((Real)m_rcInfo.curFrame)/m_rcInfo.numFrames);
  2578. Real angleDiff = angle - m_angle;
  2579. normAngle(angleDiff);
  2580. angleDiff *= factor;
  2581. m_angle += angleDiff;
  2582. normAngle(m_angle);
  2583. m_timeMultiplier = m_rcInfo.startTimeMultiplier + REAL_TO_INT_FLOOR(0.5 + (m_rcInfo.endTimeMultiplier-m_rcInfo.startTimeMultiplier)*factor);
  2584. }
  2585. else
  2586. {
  2587. m_angle = angle;
  2588. }
  2589. }
  2590. }
  2591. }
  2592. else if (m_rcInfo.curFrame <= m_rcInfo.numFrames)
  2593. {
  2594. Real factor = m_rcInfo.ease(((Real)m_rcInfo.curFrame)/m_rcInfo.numFrames);
  2595. m_angle = WWMath::Lerp(m_rcInfo.angle.startAngle, m_rcInfo.angle.endAngle, factor);
  2596. normAngle(m_angle);
  2597. m_timeMultiplier = m_rcInfo.startTimeMultiplier + REAL_TO_INT_FLOOR(0.5 + (m_rcInfo.endTimeMultiplier-m_rcInfo.startTimeMultiplier)*factor);
  2598. }
  2599. if (m_rcInfo.curFrame >= m_rcInfo.numFrames + m_rcInfo.numHoldFrames) {
  2600. m_doingRotateCamera = false;
  2601. m_freezeTimeForCameraMovement = false;
  2602. if (! m_rcInfo.trackObject)
  2603. {
  2604. m_angle = m_rcInfo.angle.endAngle;
  2605. }
  2606. }
  2607. }
  2608. // ------------------------------------------------------------------------------------------------
  2609. // ------------------------------------------------------------------------------------------------
  2610. void W3DView::zoomCameraOneFrame(void)
  2611. {
  2612. m_zcInfo.curFrame++;
  2613. if (TheGlobalData->m_disableCameraMovement) {
  2614. if (m_zcInfo.curFrame >= m_zcInfo.numFrames) {
  2615. m_doingZoomCamera = false;
  2616. }
  2617. return;
  2618. }
  2619. if (m_zcInfo.curFrame <= m_zcInfo.numFrames)
  2620. {
  2621. // not just holding; do the camera adjustment
  2622. Real factor = m_zcInfo.ease(((Real)m_zcInfo.curFrame)/m_zcInfo.numFrames);
  2623. m_zoom = WWMath::Lerp(m_zcInfo.startZoom, m_zcInfo.endZoom, factor);
  2624. }
  2625. if (m_zcInfo.curFrame >= m_zcInfo.numFrames) {
  2626. m_doingZoomCamera = false;
  2627. m_zoom = m_zcInfo.endZoom;
  2628. }
  2629. //DEBUG_LOG(("W3DView::zoomCameraOneFrame() - m_zoom = %g\n", m_zoom));
  2630. }
  2631. // ------------------------------------------------------------------------------------------------
  2632. // ------------------------------------------------------------------------------------------------
  2633. void W3DView::pitchCameraOneFrame(void)
  2634. {
  2635. m_pcInfo.curFrame++;
  2636. if (TheGlobalData->m_disableCameraMovement) {
  2637. if (m_pcInfo.curFrame >= m_pcInfo.numFrames) {
  2638. m_doingPitchCamera = false;
  2639. }
  2640. return;
  2641. }
  2642. if (m_pcInfo.curFrame <= m_pcInfo.numFrames)
  2643. {
  2644. // not just holding; do the camera adjustment
  2645. Real factor = m_pcInfo.ease(((Real)m_pcInfo.curFrame)/m_pcInfo.numFrames);
  2646. m_FXPitch = WWMath::Lerp(m_pcInfo.startPitch, m_pcInfo.endPitch, factor);
  2647. }
  2648. if (m_pcInfo.curFrame >= m_pcInfo.numFrames) {
  2649. m_doingPitchCamera = false;
  2650. m_FXPitch = m_pcInfo.endPitch;
  2651. }
  2652. }
  2653. // ------------------------------------------------------------------------------------------------
  2654. // ------------------------------------------------------------------------------------------------
  2655. void W3DView::moveAlongWaypointPath(Int milliseconds)
  2656. {
  2657. m_mcwpInfo.elapsedTimeMilliseconds += milliseconds;
  2658. if (TheGlobalData->m_disableCameraMovement) {
  2659. if (m_mcwpInfo.elapsedTimeMilliseconds>m_mcwpInfo.totalTimeMilliseconds) {
  2660. m_doingMoveCameraOnWaypointPath = false;
  2661. m_freezeTimeForCameraMovement = false;
  2662. }
  2663. return;
  2664. }
  2665. if (m_mcwpInfo.elapsedTimeMilliseconds>m_mcwpInfo.totalTimeMilliseconds) {
  2666. m_doingMoveCameraOnWaypointPath = false;
  2667. m_CameraArrivedAtWaypointOnPathFlag = false;
  2668. m_freezeTimeForCameraMovement = false;
  2669. m_angle = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints];
  2670. m_groundLevel = m_mcwpInfo.groundHeight[m_mcwpInfo.numWaypoints];
  2671. /////////////////////m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight;
  2672. m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
  2673. m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
  2674. Coord3D pos = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
  2675. pos.z = 0;
  2676. setPosition(&pos);
  2677. // Note - assuming that the scripter knows what he is doing, we adjust the constraints so that
  2678. // the scripted action can occur.
  2679. m_cameraConstraint.lo.x = minf(m_cameraConstraint.lo.x, pos.x);
  2680. m_cameraConstraint.hi.x = maxf(m_cameraConstraint.hi.x, pos.x);
  2681. m_cameraConstraint.lo.y = minf(m_cameraConstraint.lo.y, pos.y);
  2682. m_cameraConstraint.hi.y = maxf(m_cameraConstraint.hi.y, pos.y);
  2683. return;
  2684. }
  2685. const Real totalTime = m_mcwpInfo.totalTimeMilliseconds;
  2686. const Real deltaTime = m_mcwpInfo.ease(m_mcwpInfo.elapsedTimeMilliseconds/totalTime) -
  2687. m_mcwpInfo.ease((m_mcwpInfo.elapsedTimeMilliseconds - milliseconds)/totalTime);
  2688. m_mcwpInfo.curSegDistance += deltaTime*m_mcwpInfo.totalDistance;
  2689. while (m_mcwpInfo.curSegDistance >= m_mcwpInfo.waySegLength[m_mcwpInfo.curSegment]) {
  2690. if ( m_doingMoveCameraOnWaypointPath )
  2691. {
  2692. //WWDEBUG_SAY(( "MBL TEST: Camera waypoint along path reached!\n" ));
  2693. m_CameraArrivedAtWaypointOnPathFlag = true;
  2694. }
  2695. m_mcwpInfo.curSegDistance -= m_mcwpInfo.waySegLength[m_mcwpInfo.curSegment];
  2696. m_mcwpInfo.curSegment++;
  2697. if (m_mcwpInfo.curSegment >= m_mcwpInfo.numWaypoints) {
  2698. m_mcwpInfo.totalTimeMilliseconds = 0; // Will end following next frame.
  2699. return;
  2700. }
  2701. }
  2702. Real avgFactor = 1.0/m_mcwpInfo.rollingAverageFrames;
  2703. m_mcwpInfo.curShutter--;
  2704. if (m_mcwpInfo.curShutter>0) {
  2705. return;
  2706. }
  2707. m_mcwpInfo.curShutter = m_mcwpInfo.shutter;
  2708. Real factor = m_mcwpInfo.curSegDistance / m_mcwpInfo.waySegLength[m_mcwpInfo.curSegment];
  2709. if (m_mcwpInfo.curSegment == m_mcwpInfo.numWaypoints-1) {
  2710. avgFactor = avgFactor + (1.0-avgFactor)*factor;
  2711. }
  2712. Real factor1;
  2713. Real factor2;
  2714. factor1 = 1.0-factor;
  2715. //factor1 = makeQuadraticS(factor1);
  2716. factor2 = 1.0-factor1;
  2717. Real angle1 = m_mcwpInfo.cameraAngle[m_mcwpInfo.curSegment];
  2718. Real angle2 = m_mcwpInfo.cameraAngle[m_mcwpInfo.curSegment+1];
  2719. if (angle2-angle1 > PI) angle1 += 2*PI;
  2720. if (angle2-angle1 < -PI) angle1 -= 2*PI;
  2721. Real angle = angle1 * (factor1) + angle2 * (factor2);
  2722. normAngle(angle);
  2723. Real deltaAngle = angle-m_angle;
  2724. normAngle(deltaAngle);
  2725. if (fabs(deltaAngle) > PI/10) {
  2726. DEBUG_LOG(("Huh.\n"));
  2727. }
  2728. m_angle += avgFactor*(deltaAngle);
  2729. normAngle(m_angle);
  2730. Real timeMultiplier = m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment]*factor1 +
  2731. m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment+1]*factor2;
  2732. m_timeMultiplier = REAL_TO_INT_FLOOR(0.5 + timeMultiplier);
  2733. m_groundLevel = m_mcwpInfo.groundHeight[m_mcwpInfo.curSegment]*factor1 +
  2734. m_mcwpInfo.groundHeight[m_mcwpInfo.curSegment+1]*factor2;
  2735. //////////////m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight;
  2736. m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
  2737. m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
  2738. Coord3D start, mid, end;
  2739. if (factor<0.5) {
  2740. start = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment-1];
  2741. start.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment].x;
  2742. start.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment].y;
  2743. start.x /= 2;
  2744. start.y /= 2;
  2745. mid = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment];
  2746. end = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment];
  2747. end.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].x;
  2748. end.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].y;
  2749. end.x /= 2;
  2750. end.y /= 2;
  2751. factor += 0.5;
  2752. } else {
  2753. start = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment];
  2754. start.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].x;
  2755. start.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].y;
  2756. start.x /= 2;
  2757. start.y /= 2;
  2758. mid = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1];
  2759. end = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1];
  2760. end.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+2].x;
  2761. end.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+2].y;
  2762. end.x /= 2;
  2763. end.y /= 2;
  2764. factor -= 0.5;
  2765. }
  2766. Coord3D result = start;
  2767. result.x += factor*(end.x-start.x);
  2768. result.y += factor*(end.y-start.y);
  2769. result.x += (1-factor)*factor*(mid.x-end.x + mid.x-start.x);
  2770. result.y += (1-factor)*factor*(mid.y-end.y + mid.y-start.y);
  2771. result.z = 0;
  2772. /*
  2773. static Real prevGround = 0;
  2774. DEBUG_LOG(("Dx %.2f, dy %.2f, DeltaANgle = %.2f, %.2f DeltaGround %.2f\n", m_pos.x-result.x, m_pos.y-result.y, deltaAngle, m_groundLevel, m_groundLevel-prevGround));
  2775. prevGround = m_groundLevel;
  2776. */
  2777. setPosition(&result);
  2778. // Note - assuming that the scripter knows what he is doing, we adjust the constraints so that
  2779. // the scripted action can occur.
  2780. m_cameraConstraint.lo.x = minf(m_cameraConstraint.lo.x, result.x);
  2781. m_cameraConstraint.hi.x = maxf(m_cameraConstraint.hi.x, result.x);
  2782. m_cameraConstraint.lo.y = minf(m_cameraConstraint.lo.y, result.y);
  2783. m_cameraConstraint.hi.y = maxf(m_cameraConstraint.hi.y, result.y);
  2784. }
  2785. // ------------------------------------------------------------------------------------------------
  2786. /** Add an impulse force to shake the camera.
  2787. * The camera shake is a simple simulation of an oscillating spring/damper.
  2788. * The idea is that some sort of shock has "pushed" the camera once, as an
  2789. * impluse, after which the camera vibrates back to its rest position.
  2790. * @todo This should be part of "View", not "W3DView". */
  2791. // ------------------------------------------------------------------------------------------------
  2792. void W3DView::shake( const Coord3D *epicenter, CameraShakeType shakeType )
  2793. {
  2794. Real angle = GameClientRandomValueReal( 0, 2*PI );
  2795. m_shakeAngleCos = (Real)cos( angle );
  2796. m_shakeAngleSin = (Real)sin( angle );
  2797. Real intensity = 0.0f;
  2798. switch( shakeType )
  2799. {
  2800. case SHAKE_SUBTLE:
  2801. intensity = TheGlobalData->m_shakeSubtleIntensity;
  2802. break;
  2803. case SHAKE_NORMAL:
  2804. intensity = TheGlobalData->m_shakeNormalIntensity;
  2805. break;
  2806. case SHAKE_STRONG:
  2807. intensity = TheGlobalData->m_shakeStrongIntensity;
  2808. break;
  2809. case SHAKE_SEVERE:
  2810. intensity = TheGlobalData->m_shakeSevereIntensity;
  2811. break;
  2812. case SHAKE_CINE_EXTREME:
  2813. intensity = TheGlobalData->m_shakeCineExtremeIntensity;
  2814. break;
  2815. case SHAKE_CINE_INSANE:
  2816. intensity = TheGlobalData->m_shakeCineInsaneIntensity;
  2817. break;
  2818. }
  2819. // intensity falls off with distance
  2820. const Coord3D *viewPos = getPosition();
  2821. Coord3D d;
  2822. d.x = epicenter->x - viewPos->x;
  2823. d.y = epicenter->y - viewPos->y;
  2824. /// @todo make this 3D once we have the real "lookat" spot
  2825. //d.z = epicenter->z - viewPos->z;
  2826. Real dist = (Real)sqrt( d.x*d.x + d.y*d.y );
  2827. if (dist > TheGlobalData->m_maxShakeRange)
  2828. return;
  2829. intensity *= 1.0f - (dist/TheGlobalData->m_maxShakeRange);
  2830. // add intensity and clamp
  2831. m_shakeIntensity += intensity;
  2832. //const Real maxIntensity = 10.0f;
  2833. const Real maxIntensity = 3.0f;
  2834. if (m_shakeIntensity > TheGlobalData->m_maxShakeIntensity)
  2835. m_shakeIntensity = maxIntensity;
  2836. }
  2837. //-------------------------------------------------------------------------------------------------
  2838. /** Transformt he screen pixel coord passed in, to a world coordinate at the specified
  2839. * z value */
  2840. //-------------------------------------------------------------------------------------------------
  2841. void W3DView::screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z )
  2842. {
  2843. Vector3 rayStart, rayEnd;
  2844. getPickRay( s, &rayStart, &rayEnd );
  2845. w->x = Vector3::Find_X_At_Z( z, rayStart, rayEnd );
  2846. w->y = Vector3::Find_Y_At_Z( z, rayStart, rayEnd );
  2847. w->z = z;
  2848. } // end screenToWorldAtZ
  2849. void W3DView::cameraEnableSlaveMode(const AsciiString & objectName, const AsciiString & boneName)
  2850. {
  2851. m_isCameraSlaved = true;
  2852. m_cameraSlaveObjectName = objectName;
  2853. m_cameraSlaveObjectBoneName = boneName;
  2854. }
  2855. void W3DView::cameraDisableSlaveMode(void)
  2856. {
  2857. m_isCameraSlaved = false;
  2858. }
  2859. void W3DView::cameraEnableRealZoomMode(void) //WST added 10/18/2002
  2860. {
  2861. m_useRealZoomCam = true;
  2862. m_FXPitch = 1.0f; //Reset to default
  2863. //m_zoom = 1.0f;
  2864. updateView();
  2865. }
  2866. void W3DView::cameraDisableRealZoomMode(void) //WST added 10/18/2002
  2867. {
  2868. m_useRealZoomCam = false;
  2869. m_FXPitch = 1.0f; //Reset to default
  2870. //m_zoom = 1.0f;
  2871. m_FOV = 50.0f * PI/180.0f;
  2872. setCameraTransform();
  2873. updateView();
  2874. }
  2875. void W3DView::Add_Camera_Shake (const Coord3D & position,float radius,float duration,float power) //WST added 11/13/02
  2876. {
  2877. Vector3 vpos;
  2878. vpos.X = position.x;
  2879. vpos.Y = position.y;
  2880. vpos.Z = position.z;
  2881. CameraShakerSystem.Add_Camera_Shake(vpos,radius,duration,power);
  2882. }