| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: W3DView.cpp //////////////////////////////////////////////////////////////////////////////
- //
- // W3D implementation of the game view class. This view allows us to have
- // a "window" into the game world that can change its width, height as
- // well as camera positioning controls
- //
- // Author: Colin Day, April 2001
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // SYSTEM INCLUDES ////////////////////////////////////////////////////////////////////////////////
- #include <stdlib.h>
- #include <windows.h>
- // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
- #include "Common/BuildAssistant.h"
- #include "Common/GlobalData.h"
- #include "Common/Module.h"
- #include "Common/RandomValue.h"
- #include "Common/ThingTemplate.h"
- #include "Common/ThingSort.h"
- #include "Common/PerfTimer.h"
- #include "Common/PlayerList.h"
- #include "Common/Player.h"
- #include "GameClient/Color.h"
- #include "GameClient/CommandXlat.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/GameWindowManager.h"
- #include "GameClient/Image.h"
- #include "GameClient/InGameUI.h"
- #include "GameClient/Line2D.h"
- #include "GameClient/SelectionInfo.h"
- #include "GameClient/Shell.h"
- #include "GameClient/TerrainVisual.h"
- #include "GameClient/Water.h"
- #include "GameLogic/AI.h" ///< For AI debug (yes, I'm cheating for now)
- #include "GameLogic/AIPathfind.h" ///< For AI debug (yes, I'm cheating for now)
- #include "GameLogic/ExperienceTracker.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Module/AIUpdate.h"
- #include "GameLogic/Module/BodyModule.h"
- #include "GameLogic/Module/ContainModule.h"
- #include "GameLogic/Module/OpenContain.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/ScriptEngine.h"
- #include "GameLogic/TerrainLogic.h" ///< @todo This should be TerrainVisual (client side)
- #include "Common/AudioEventInfo.h"
- #include "W3DDevice/Common/W3DConvert.h"
- #include "W3DDevice/GameClient/HeightMap.h"
- #include "W3DDevice/GameClient/W3DAssetManager.h"
- #include "W3DDevice/GameClient/W3DDisplay.h"
- #include "W3DDevice/GameClient/W3DScene.h"
- #include "W3DDevice/GameClient/W3DView.h"
- #include "D3dx8math.h"
- #include "W3DDevice/GameClient/W3DShaderManager.h"
- #include "W3DDevice/GameClient/Module/W3DModelDraw.h"
- #include "W3DDevice/GameClient/W3DCustomScene.h"
- #include "WW3D2/DX8Renderer.h"
- #include "WW3D2/Light.h"
- #include "WW3D2/Camera.h"
- #include "WW3D2/Coltype.h"
- #include "WW3D2/PredLod.h"
- #include "WW3D2/WW3D.h"
- #include "W3DDevice/GameClient/camerashakesystem.h"
- #include "WinMain.h" /** @todo Remove this, it's only here because we
- are using timeGetTime, but we can remove that
- when we have our own timer */
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- // 30 fps
- Int TheW3DFrameLengthInMsec = 1000/LOGICFRAMES_PER_SECOND; // default is 33msec/frame == 30fps. but we may change it depending on sys config.
- static const Int MAX_REQUEST_CACHE_SIZE = 40; // Any size larger than 10, or examine code below for changes. jkmcd.
- static const Real DRAWABLE_OVERSCAN = 75.0f; ///< 3D world coords of how much to overscan in the 3D screen region
- //=================================================================================================
- inline Real minf(Real a, Real b) { if (a < b) return a; else return b; }
- inline Real maxf(Real a, Real b) { if (a > b) return a; else return b; }
- //-------------------------------------------------------------------------------------------------
- // Normalizes angle to +- PI.
- //-------------------------------------------------------------------------------------------------
- static void normAngle(Real &angle)
- {
- if (angle < -10*PI) {
- angle = 0;
- }
- if (angle > 10*PI) {
- angle = 0;
- }
- while (angle < -PI) {
- angle += 2*PI;
- }
- while (angle > PI) {
- angle -= 2*PI;
- }
- }
- #define TERRAIN_SAMPLE_SIZE 40.0f
- static Real getHeightAroundPos(Real x, Real y)
- {
- // terrain height + desired height offset == cameraOffset * actual zoom
- Real terrainHeight = TheTerrainLogic->getGroundHeight(x, y);
- // find best approximation of max terrain height we can see
- Real terrainHeightMax = terrainHeight;
- terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x+TERRAIN_SAMPLE_SIZE, y-TERRAIN_SAMPLE_SIZE));
- terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x-TERRAIN_SAMPLE_SIZE, y-TERRAIN_SAMPLE_SIZE));
- terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x+TERRAIN_SAMPLE_SIZE, y+TERRAIN_SAMPLE_SIZE));
- terrainHeightMax = max(terrainHeightMax, TheTerrainLogic->getGroundHeight(x-TERRAIN_SAMPLE_SIZE, y+TERRAIN_SAMPLE_SIZE));
- return terrainHeightMax;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- W3DView::W3DView()
- {
-
- m_3DCamera = NULL;
- m_2DCamera = NULL;
- m_groundLevel = 10.0;
- m_cameraOffset.z = TheGlobalData->m_cameraHeight;
- m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
- m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
- m_viewFilterMode = FM_VIEW_DEFAULT;
- m_viewFilter = FT_VIEW_DEFAULT;
- m_isWireFrameEnabled = m_nextWireFrameEnabled = FALSE;
- m_shakeOffset.x = 0.0f;
- m_shakeOffset.y = 0.0f;
- m_shakeIntensity = 0.0f;
- m_FXPitch = 1.0f;
- m_freezeTimeForCameraMovement = false;
- m_cameraHasMovedSinceRequest = true;
- m_locationRequests.clear();
- m_locationRequests.reserve(MAX_REQUEST_CACHE_SIZE + 10); // This prevents the vector from ever re-allocing
- //Enhancements from CNC3 WST 4/15/2003. JSC Integrated 5/20/03.
- m_CameraArrivedAtWaypointOnPathFlag = false; // Scripts for polling camera reached targets
- m_isCameraSlaved = false; // This is for 3DSMax camera playback
- m_useRealZoomCam = false; // true; //WST 10/18/2002
- m_shakerAngles.X =0.0f; // Proper camera shake generator & sources
- m_shakerAngles.Y =0.0f;
- m_shakerAngles.Z =0.0f;
- } // end W3DView
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- W3DView::~W3DView()
- {
- REF_PTR_RELEASE( m_2DCamera );
- REF_PTR_RELEASE( m_3DCamera );
- } // end ~W3DView
- //-------------------------------------------------------------------------------------------------
- /** Sets the height of the viewport, while maintaining original camera perspective. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setHeight(Int height)
- {
- // extend View functionality
- View::setHeight(height);
- Vector2 vMin,vMax;
- m_3DCamera->Set_Aspect_Ratio((Real)getWidth()/(Real)height);
- m_3DCamera->Get_Viewport(vMin,vMax);
- vMax.Y=(Real)(m_originY+height)/(Real)TheDisplay->getHeight();
- m_3DCamera->Set_Viewport(vMin,vMax);
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets the width of the viewport, while maintaining original camera perspective. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setWidth(Int width)
- {
- // extend View functionality
- View::setWidth(width);
- Vector2 vMin,vMax;
- m_3DCamera->Set_Aspect_Ratio((Real)width/(Real)getHeight());
- m_3DCamera->Get_Viewport(vMin,vMax);
- vMax.X=(Real)(m_originX+width)/(Real)TheDisplay->getWidth();
- m_3DCamera->Set_Viewport(vMin,vMax);
- //we want to maintain the same scale, so we'll need to adjust the fov.
- //default W3D fov for full-screen is 50 degrees.
- m_3DCamera->Set_View_Plane((Real)width/(Real)TheDisplay->getWidth()*DEG_TO_RADF(50.0f),-1);
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets location of top-left view corner on display */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setOrigin( Int x, Int y)
- {
- // extend View functionality
- View::setOrigin(x,y);
- Vector2 vMin,vMax;
- m_3DCamera->Get_Viewport(vMin,vMax);
- vMin.X=(Real)x/(Real)TheDisplay->getWidth();
- vMin.Y=(Real)y/(Real)TheDisplay->getHeight();
- m_3DCamera->Set_Viewport(vMin,vMax);
- // bottom-right border was also moved my this call, so force an update of extents.
- setWidth(m_width);
- setHeight(m_height);
- }
- //-------------------------------------------------------------------------------------------------
- /** @todo This is inefficient. We should construct the matrix directly using vectors. */
- //-------------------------------------------------------------------------------------------------
- #define MIN_CAPPED_ZOOM (0.5f) //WST 10.19.2002. JSC integrated 5/20/03.
- void W3DView::buildCameraTransform( Matrix3D *transform )
- {
- Vector3 sourcePos, targetPos;
- Real groundLevel = m_groundLevel; // 93.0f;
- Real zoom = getZoom();
- Real angle = getAngle();
- Real pitch = getPitch();
- Coord3D pos = *getPosition();
- // add in the camera shake, if any
- pos.x += m_shakeOffset.x;
- pos.y += m_shakeOffset.y;
- if (m_cameraConstraintValid)
- {
- pos.x = maxf(m_cameraConstraint.lo.x, pos.x);
- pos.x = minf(m_cameraConstraint.hi.x, pos.x);
- pos.y = maxf(m_cameraConstraint.lo.y, pos.y);
- pos.y = minf(m_cameraConstraint.hi.y, pos.y);
- }
- // set position of camera itself
- if (m_useRealZoomCam) //WST 10/10/2002 Real Zoom using FOV
- {
- sourcePos.X = m_cameraOffset.x;
- sourcePos.Y = m_cameraOffset.y;
- sourcePos.Z = m_cameraOffset.z;
- Real capped_zoom = zoom;
- if (capped_zoom > 1.0f)
- {
- capped_zoom= 1.0f;
- }
- if (capped_zoom < MIN_CAPPED_ZOOM)
- {
- capped_zoom = MIN_CAPPED_ZOOM;
- }
- m_FOV = 50.0f * PI/180.0f * capped_zoom * capped_zoom;
- }
- else
- {
- sourcePos.X = m_cameraOffset.x*zoom;
- sourcePos.Y = m_cameraOffset.y*zoom;
- sourcePos.Z = m_cameraOffset.z*zoom;
- }
- #ifdef NOT_IN_USE
- if (TheGlobalData->m_isOffsetCameraZ && TheTerrainLogic)
- {
- sourcePos.Z += TheTerrainLogic->getGroundHeight(pos.x, pos.y);
- if (m_prevSourcePosZ != SOURCEPOS_INVALID)
- {
- const Real MAX_SPZ_VARIATION = 0.05f;
- Real spzMin = m_prevSourcePosZ*(1.0-MAX_SPZ_VARIATION);
- Real spzMax Coord3D center;
- = m_prevSourcePosZ*(1.0+MAX_SPZ_VARIATION);
- if (sourcePos.Z < spzMin) sourcePos.Z = spzMin;
- if (sourcePos.Z > spzMax) sourcePos.Z = spzMax;
- }
- m_prevSourcePosZ = sourcePos.Z;
- }
- #endif
- // camera looking at origin
- targetPos.X = 0;
- targetPos.Y = 0;
- targetPos.Z = 0;
- Real factor = 1.0 - (groundLevel/sourcePos.Z );
- // construct a matrix to rotate around the up vector by the given angle
- Matrix3D angleTransform( Vector3( 0.0f, 0.0f, 1.0f ), angle );
- // construct a matrix to rotate around the horizontal vector by the given angle
- Matrix3D pitchTransform( Vector3( 1.0f, 0.0f, 0.0f ), pitch );
- // rotate camera position (pitch, then angle)
- #ifdef ALLOW_TEMPORARIES
- sourcePos = pitchTransform * sourcePos;
- sourcePos = angleTransform * sourcePos;
- #else
- pitchTransform.mulVector3(sourcePos);
- angleTransform.mulVector3(sourcePos);
- #endif
- sourcePos *= factor;
- // translate to current XY position
- sourcePos.X += pos.x;
- sourcePos.Y += pos.y;
- sourcePos.Z += groundLevel;
-
- targetPos.X += pos.x;
- targetPos.Y += pos.y;
- targetPos.Z += groundLevel;
- // do m_FXPitch adjustment.
- //WST Real height = sourcePos.Z - targetPos.Z;
- //WST height *= m_FXPitch;
- //WST targetPos.Z = sourcePos.Z - height;
- // The following code moves camera down and pitch up when player zooms in.
- // Use scripts to switch to useRealZoomCam
- if (m_useRealZoomCam)
- {
- Real pitch_adjust = 1.0f;
- if (!TheDisplay->isLetterBoxed())
- {
- Real capped_zoom = zoom;
- if (capped_zoom > 1.0f)
- {
- capped_zoom= 1.0f;
- }
- if (capped_zoom < MIN_CAPPED_ZOOM)
- {
- capped_zoom = MIN_CAPPED_ZOOM;
- }
- sourcePos.Z = sourcePos.Z * ( 0.5f + capped_zoom * 0.5f); // move camera down physically
- pitch_adjust = capped_zoom; // adjust camera to pitch up
- }
- m_FXPitch = 1.0f * (0.25f + pitch_adjust*0.75f);
- }
- // do fxPitch adjustment
- if (m_useRealZoomCam)
- {
- sourcePos.X = targetPos.X + ((sourcePos.X - targetPos.X) / m_FXPitch);
- sourcePos.Y = targetPos.Y + ((sourcePos.Y - targetPos.Y) / m_FXPitch);
- }
- else
- {
- if (m_FXPitch <= 1.0f)
- {
- Real height = sourcePos.Z - targetPos.Z;
- height *= m_FXPitch;
- targetPos.Z = sourcePos.Z - height;
- }
- else
- {
- sourcePos.X = targetPos.X + ((sourcePos.X - targetPos.X) / m_FXPitch);
- sourcePos.Y = targetPos.Y + ((sourcePos.Y - targetPos.Y) / m_FXPitch);
- }
- }
- //m_3DCamera->Set_View_Plane(DEG_TO_RADF(50.0f));
- //DEBUG_LOG(("zoom %f, SourceZ %f, posZ %f, groundLevel %f CamOffZ %f\n",
- // zoom, sourcePos.Z, pos.z, groundLevel,m_cameraOffset.z));
- // build new camera transform
- transform->Make_Identity();
- transform->Look_At( sourcePos, targetPos, 0 );
- //WST 11/12/2002 New camera shaker system
- CameraShakerSystem.Timestep(1.0f/30.0f);
- CameraShakerSystem.Update_Camera_Shaker(sourcePos, &m_shakerAngles);
- transform->Rotate_X(m_shakerAngles.X);
- transform->Rotate_Y(m_shakerAngles.Y);
- transform->Rotate_Z(m_shakerAngles.Z);
- //if (m_shakerAngles.X >= 0.0f)
- //{
- // DEBUG_LOG(("m_shakerAngles %f, %f, %f\n", m_shakerAngles.X, m_shakerAngles.Y, m_shakerAngles.Z));
- //}
- // (gth) check if the camera is being controlled by an animation
- if (m_isCameraSlaved) {
- // find object named m_cameraSlaveObjectName
- Object * obj = TheScriptEngine->getUnitNamed(m_cameraSlaveObjectName);
-
- if (obj != NULL) {
- // dig out the drawable
- Drawable * draw = obj->getDrawable();
- if (draw != NULL) {
- // dig out the first draw module with an ObjectDrawInterface
- for (DrawModule ** dm = draw->getDrawModules(); *dm; ++dm) {
- const ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
- if (di) {
- Matrix3D tm;
- di->clientOnly_getRenderObjBoneTransform(m_cameraSlaveObjectBoneName,&tm);
- // Ok, slam it into the camera!
- *transform = tm;
- //--------------------------------------------------------------------
- // WST 10.22.2002. Update the Listener positions used by audio system
- //--------------------------------------------------------------------
- Vector3 position = transform->Get_Translation();
- m_pos.x = position.X;
- m_pos.y = position.Y;
- m_pos.z = position.Z;
-
- //DEBUG_LOG(("mpos x%f, y%f, z%f\n", m_pos.x, m_pos.y, m_pos.z ));
- break;
- }
- }
- } else {
- m_isCameraSlaved = false;
- }
- } else {
- m_isCameraSlaved = false;
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::calcCameraConstraints()
- {
- // const Matrix3D& cameraTransform = m_3DCamera->Get_Transform();
- // DEBUG_LOG(("*** rebuilding cam constraints\n"));
- // ok, now check to ensure that we can't see outside the map region,
- // and twiddle the camera if needed
- if (TheTerrainLogic)
- {
- Region3D mapRegion;
- TheTerrainLogic->getExtent( &mapRegion );
-
- /*
- Note the following restrictions on camera constraints!
- -- they assume that all maps are height 'm_groundLevel' at the edges.
- (since you need to add some "buffer" around the edges of your map
- anyway, this shouldn't be an issue.)
- -- for angles/pitches other than zero, it may show boundaries.
- since we currently plan the game to be restricted to this,
- it shouldn't be an issue.
- */
- Real maxEdgeZ = m_groundLevel;
- // const Real BORDER_FUDGE = MAP_XY_FACTOR * 1.414f;
- Coord3D center, bottom;
- ICoord2D screen;
- //Pick at the center
- screen.x=0.5f*getWidth()+m_originX;
- screen.y=0.5f*getHeight()+m_originY;
- Vector3 rayStart,rayEnd;
- getPickRay(&screen,&rayStart,&rayEnd);
- center.x = Vector3::Find_X_At_Z(maxEdgeZ, rayStart, rayEnd);
- center.y = Vector3::Find_Y_At_Z(maxEdgeZ, rayStart, rayEnd);
- center.z = maxEdgeZ;
- screen.y = m_originY+ 0.95f*getHeight();
- getPickRay(&screen,&rayStart,&rayEnd);
- bottom.x = Vector3::Find_X_At_Z(maxEdgeZ, rayStart, rayEnd);
- bottom.y = Vector3::Find_Y_At_Z(maxEdgeZ, rayStart, rayEnd);
- bottom.z = maxEdgeZ;
- center.x -= bottom.x;
- center.y -= bottom.y;
- Real offset = center.length();
- if (TheGlobalData->m_debugAI) {
- offset = -1000; // push out the constraints so we can look at staging areas.
- }
- m_cameraConstraint.lo.x = mapRegion.lo.x + offset;
- m_cameraConstraint.hi.x = mapRegion.hi.x - offset;
- // this looks inverted, but is correct
- m_cameraConstraint.lo.y = mapRegion.lo.y + offset;
- m_cameraConstraint.hi.y = mapRegion.hi.y - offset;
- m_cameraConstraintValid = true;
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** Returns a world-space ray originating at a given screen pixel position
- and ending at the far clip plane for current camera. Screen coordinates
- assumed in absolute values relative to full display resolution.*/
- //-------------------------------------------------------------------------------------------------
- void W3DView::getPickRay(const ICoord2D *screen, Vector3 *rayStart, Vector3 *rayEnd)
- {
- Real logX,logY;
- //W3D Screen coordinates are -1 to 1, so we need to do some conversion:
- PixelScreenToW3DLogicalScreen(screen->x - m_originX,screen->y - m_originY, &logX, &logY,getWidth(),getHeight());
- *rayStart = m_3DCamera->Get_Position(); //get camera location
- m_3DCamera->Un_Project(*rayEnd,Vector2(logX,logY)); //get world space point
- *rayEnd -= *rayStart; //vector camera to world space point
- rayEnd->Normalize(); //make unit vector
- *rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane
- *rayEnd += *rayStart; //get point on far clip plane along ray from camera.
- }
- //-------------------------------------------------------------------------------------------------
- /** set the transform matrix of m_3DCamera, based on m_pos & m_angle */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setCameraTransform( void )
- {
- m_cameraHasMovedSinceRequest = true;
- Matrix3D cameraTransform( 1 );
-
- Real nearZ, farZ;
- // m_3DCamera->Get_Clip_Planes(nearZ, farZ);
- // Set the near to MAP_XY_FACTOR. Improves zbuffer resolution.
- nearZ = MAP_XY_FACTOR;
- farZ = 1200.0f;
- if (m_useRealZoomCam) //WST 10.19.2002
- {
- if (m_FXPitch<0.95f)
- {
- farZ = farZ / m_FXPitch; //Extend far Z when we pitch up for RealZoomCam
- }
- }
- else
- {
- if ((TheGlobalData && TheGlobalData->m_drawEntireTerrain) || (m_FXPitch<0.95f || m_zoom>1.05))
- { //need to extend far clip plane so entire terrain can be visible
- farZ *= MAP_XY_FACTOR;
- }
- }
- m_3DCamera->Set_Clip_Planes(nearZ, farZ);
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData->m_useCameraConstraints)
- #endif
- {
- if (!m_cameraConstraintValid)
- {
- buildCameraTransform(&cameraTransform);
- m_3DCamera->Set_Transform( cameraTransform );
- calcCameraConstraints();
- }
- DEBUG_ASSERTLOG(m_cameraConstraintValid,("*** cam constraints are not valid!!!\n"));
- if (m_cameraConstraintValid)
- {
- Coord3D pos = *getPosition();
- pos.x = maxf(m_cameraConstraint.lo.x, pos.x);
- pos.x = minf(m_cameraConstraint.hi.x, pos.x);
- pos.y = maxf(m_cameraConstraint.lo.y, pos.y);
- pos.y = minf(m_cameraConstraint.hi.y, pos.y);
- setPosition(&pos);
- }
- }
- #if defined(_DEBUG) || defined(_INTERNAL)
- m_3DCamera->Set_View_Plane( m_FOV, -1 );
- #endif
- // rebuild it (even if we just did it due to camera constraints)
- buildCameraTransform( &cameraTransform );
- m_3DCamera->Set_Transform( cameraTransform );
- if (TheTerrainRenderObject)
- {
- RefRenderObjListIterator *it = W3DDisplay::m_3DScene->createLightsIterator();
- TheTerrainRenderObject->updateCenter(m_3DCamera, it);
- if (it)
- {
- W3DDisplay::m_3DScene->destroyLightsIterator(it);
- it = NULL;
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::init( void )
- {
- // extend View functionality
- View::init();
- setName("W3DView");
- // set default camera "lookat" point
- Coord3D pos;
- pos.x = 87.0f;
- pos.y = 77.0f;
- pos.z = 0;
- pos.x *= MAP_XY_FACTOR;
- pos.y *= MAP_XY_FACTOR;
- setPosition(&pos);
- // create our 3D camera
- m_3DCamera = NEW_REF( CameraClass, () );
- setCameraTransform();
- // create our 2D camera for the GUI overlay
- m_2DCamera = NEW_REF( CameraClass, () );
- m_2DCamera->Set_Position( Vector3( 0, 0, 1 ) );
- Vector2 min = Vector2( -1, -0.75f );
- Vector2 max = Vector2( +1, +0.75f );
- m_2DCamera->Set_View_Plane( min, max );
- m_2DCamera->Set_Clip_Planes( 0.995f, 2.0f );
- m_cameraConstraintValid = false;
- m_scrollAmountCutoff = TheGlobalData->m_scrollAmountCutoff;
- } // end init
- //-------------------------------------------------------------------------------------------------
- const Coord3D& W3DView::get3DCameraPosition() const
- {
- Vector3 camera = m_3DCamera->Get_Position();
- static Coord3D pos;
- pos.set( camera.X, camera.Y, camera.Z );
- return pos;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::reset( void )
- {
- View::reset();
- // Just in case...
- setTimeMultiplier(1); // Set time rate back to 1.
- Coord3D arbitraryPos = { 0, 0, 0 };
- // Just move the camera to 0, 0, 0. It'll get repositioned at the beginning of the next game
- // anyways.
- resetCamera(&arbitraryPos, 1, 0.0f, 0.0f);
- setViewFilter(FT_VIEW_DEFAULT);
- Coord2D gb = { 0,0 };
- setGuardBandBias( &gb );
- }
- //-------------------------------------------------------------------------------------------------
- /** draw worker for drawables in the view region */
- //-------------------------------------------------------------------------------------------------
- static void drawDrawable( Drawable *draw, void *userData )
- {
- draw->draw( (View *)userData );
- } // end drawDrawable
- // ------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- static void drawTerrainNormal( Drawable *draw, void *userData )
- {
- UnsignedInt color = GameMakeColor( 255, 255, 0, 255 );
- if (TheTerrainLogic)
- {
- Coord3D pos = *draw->getPosition();
- Coord3D normal;
- pos.z = TheTerrainLogic->getGroundHeight(pos.x, pos.y, &normal);
- const Real NORMLEN = 20;
- normal.x = pos.x + normal.x * NORMLEN;
- normal.y = pos.y + normal.y * NORMLEN;
- normal.z = pos.z + normal.z * NORMLEN;
- ICoord2D start, end;
- TheTacticalView->worldToScreen(&pos, &start);
- TheTacticalView->worldToScreen(&normal, &end);
- TheDisplay->drawLine(start.x, start.y, end.x, end.y, 1.0f, color);
- }
- }
- #if defined(_DEBUG) || defined(_INTERNAL)
- // ------------------------------------------------------------------------------------------------
- // Draw a crude circle. Appears on top of any world geometry
- // ------------------------------------------------------------------------------------------------
- void drawDebugCircle( const Coord3D & center, Real radius, Real width, Color color )
- {
- const Real inc = PI/4.0f;
- Real angle = 0.0f;
- Coord3D pnt, lastPnt;
- ICoord2D start, end;
- Bool endValid, startValid;
- lastPnt.x = center.x + radius * (Real)cos(angle);
- lastPnt.y = center.y + radius * (Real)sin(angle);
- lastPnt.z = center.z;
- endValid = ( TheTacticalView->worldToScreenTriReturn( &lastPnt, &end ) != View::WTS_INVALID );
-
- for( angle = inc; angle <= 2.0f * PI; angle += inc )
- {
- pnt.x = center.x + radius * (Real)cos(angle);
- pnt.y = center.y + radius * (Real)sin(angle);
- pnt.z = center.z;
- startValid = ( TheTacticalView->worldToScreenTriReturn( &pnt, &start ) != View::WTS_INVALID );
-
- if ( startValid && endValid )
- TheDisplay->drawLine( start.x, start.y, end.x, end.y, width, color );
-
- lastPnt = pnt;
- end = start;
- endValid = startValid;
- }
- }
- void drawDrawableExtents( Drawable *draw, void *userData ); // FORWARD DECLARATION
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- static void drawContainedDrawable( Object *obj, void *userData )
- {
- Drawable *draw = obj->getDrawable();
- if( draw )
- drawDrawableExtents( draw, userData );
- } // end drawContainedDrawable
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- static void drawDrawableExtents( Drawable *draw, void *userData )
- {
- UnsignedInt color = GameMakeColor( 0, 255, 0, 255 );
- switch( draw->getDrawableGeometryInfo().getGeomType() )
- {
- //---------------------------------------------------------------------------------------------
- case GEOMETRY_BOX:
- {
- Real angle = draw->getOrientation();
- Real c = (Real)cos(angle);
- Real s = (Real)sin(angle);
- Real exc = draw->getDrawableGeometryInfo().getMajorRadius()*c;
- Real eyc = draw->getDrawableGeometryInfo().getMinorRadius()*c;
- Real exs = draw->getDrawableGeometryInfo().getMajorRadius()*s;
- Real eys = draw->getDrawableGeometryInfo().getMinorRadius()*s;
- Coord3D pts[4];
- pts[0].x = draw->getPosition()->x - exc - eys;
- pts[0].y = draw->getPosition()->y + eyc - exs;
- pts[0].z = 0;
- pts[1].x = draw->getPosition()->x + exc - eys;
- pts[1].y = draw->getPosition()->y + eyc + exs;
- pts[1].z = 0;
- pts[2].x = draw->getPosition()->x + exc + eys;
- pts[2].y = draw->getPosition()->y - eyc + exs;
- pts[2].z = 0;
- pts[3].x = draw->getPosition()->x - exc + eys;
- pts[3].y = draw->getPosition()->y - eyc - exs;
- pts[3].z = 0;
- Real z = draw->getPosition()->z;
- for( int i = 0; i < 2; i++ )
- {
- for (int corner = 0; corner < 4; corner++)
- {
- ICoord2D start, end;
- pts[corner].z = z;
- pts[(corner+1)&3].z = z;
- TheTacticalView->worldToScreen(&pts[corner], &start);
- TheTacticalView->worldToScreen(&pts[(corner+1)&3], &end);
- TheDisplay->drawLine(start.x, start.y, end.x, end.y, 1.0f, color);
- }
- z += draw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
- } // end for i
- break;
- } // end case box
- //---------------------------------------------------------------------------------------------
- case GEOMETRY_SPHERE: // not quite right, but close enough
- case GEOMETRY_CYLINDER:
- {
- Coord3D center = *draw->getPosition();
- const Real radius = draw->getDrawableGeometryInfo().getMajorRadius();
- // draw cylinder
- for( int i=0; i<2; i++ )
- {
- drawDebugCircle( center, radius, 1.0f, color );
- // next time 'round, draw the top of the cylinder
- center.z += draw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
- } // end for i
- // draw centerline
- ICoord2D start, end;
- center = *draw->getPosition();
- TheTacticalView->worldToScreen( ¢er, &start );
- center.z += draw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
- TheTacticalView->worldToScreen( ¢er, &end );
- TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
- break;
- } // case CYLINDER
- } // end switch
- // draw any extents for things that are contained by this
- Object *obj = draw->getObject();
- if( obj )
- {
- ContainModuleInterface *contain = obj->getContain();
- if( contain )
- contain->iterateContained( drawContainedDrawable, userData, FALSE );
- } // end if
- } // end drawDrawableExtents
- void drawAudioLocations( Drawable *draw, void *userData );
- // ------------------------------------------------------------------------------------------------
- // Helper for drawAudioLocations
- // ------------------------------------------------------------------------------------------------
- static void drawContainedAudioLocations( Object *obj, void *userData )
- {
- Drawable *draw = obj->getDrawable();
-
- if( draw )
- drawAudioLocations( draw, userData );
-
- } // end drawContainedAudio
- //-------------------------------------------------------------------------------------------------
- // Draw the location of audio objects in the world
- //-------------------------------------------------------------------------------------------------
- static void drawAudioLocations( Drawable *draw, void *userData )
- {
- // draw audio for things that are contained by this
- Object *obj = draw->getObject();
- if( obj )
- {
- ContainModuleInterface *contain = obj->getContain();
-
- if( contain )
- contain->iterateContained( drawContainedAudioLocations, userData, FALSE );
-
- } // end if
- const ThingTemplate * thingTemplate = draw->getTemplate();
- if ( thingTemplate == NULL || thingTemplate->getEditorSorting() != ES_AUDIO )
- {
- return; // All done
- }
- // Copied in hideously inappropriate code copying ways from DrawObject.cpp
- // Should definately be a global, probably read in from an INI file <gasp>
- static const Int poleHeight = 20;
- static const Int flagHeight = 10;
- static const Int flagWidth = 10;
- const Color color = GameMakeColor(0x25, 0x25, 0xEF, 0xFF);
- // Draw flag for audio-only objects:
- // *
- // * *
- // * *
- // * *
- // * *
- // * *
- // *
- // *
- // *
- // *
- // *
- Coord3D worldPoint;
- ICoord2D start, end;
- worldPoint = *draw->getPosition();
- TheTacticalView->worldToScreen( &worldPoint, &start );
- worldPoint.z += poleHeight;
- TheTacticalView->worldToScreen( &worldPoint, &end );
- TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
-
- worldPoint.z -= flagHeight / 2;
- worldPoint.x += flagWidth;
- TheTacticalView->worldToScreen( &worldPoint, &start );
- TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
- worldPoint.z -= flagHeight / 2;
- worldPoint.x -= flagWidth;
- TheTacticalView->worldToScreen( &worldPoint, &end );
- TheDisplay->drawLine( start.x, start.y, end.x, end.y, 1.0f, color );
- }
- //-------------------------------------------------------------------------------------------------
- // Draw the radii of sounds attached to any type of object.
- //-------------------------------------------------------------------------------------------------
- static void drawAudioRadii( const Drawable * drawable )
- {
-
- // Draw radii, if sound is playing
- const AudioEventRTS * ambientSound = drawable->getAmbientSound();
-
- if ( ambientSound && ambientSound->isCurrentlyPlaying() )
- {
- const AudioEventInfo * ambientInfo = ambientSound->getAudioEventInfo();
-
- if ( ambientInfo == NULL )
- {
- // I don't think that's right...
- OutputDebugString( ("Playing sound has NULL AudioEventInfo?\n" ) );
-
- if ( TheAudio != NULL )
- {
- ambientInfo = TheAudio->findAudioEventInfo( ambientSound->getEventName() );
- }
- }
-
- if ( ambientInfo != NULL )
- {
- // Colors match those used in WorldBuilder
- drawDebugCircle( *drawable->getPosition(), ambientInfo->m_minDistance, 1.0f, GameMakeColor(0x00, 0x00, 0xFF, 0xFF) );
- drawDebugCircle( *drawable->getPosition(), ambientInfo->m_maxDistance, 1.0f, GameMakeColor(0xFF, 0x00, 0xFF, 0xFF) );
- }
- }
- }
- #endif
- //-------------------------------------------------------------------------------------------------
- /** An opportunity to draw something after all drawables have been drawn once */
- //-------------------------------------------------------------------------------------------------
- static void drawablePostDraw( Drawable *draw, void *userData )
- {
- Real FXPitch = TheTacticalView->getFXPitch();
- if (draw->isDrawableEffectivelyHidden() || FXPitch < 0.0f)
- return;
- Object* obj = draw->getObject();
- Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
- #if defined(_DEBUG) || defined(_INTERNAL)
- ObjectShroudStatus ss = (!obj || !TheGlobalData->m_shroudOn) ? OBJECTSHROUD_CLEAR : obj->getShroudedStatus(localPlayerIndex);
- #else
- ObjectShroudStatus ss = (!obj) ? OBJECTSHROUD_CLEAR : obj->getShroudedStatus(localPlayerIndex);
- #endif
- if (ss > OBJECTSHROUD_PARTIAL_CLEAR)
- return;
- // draw the any "icon" UI for a drawable (health bars, veterency, etc);
-
- //*****
- //@TODO: Create a way to reject this call easily -- like objects that have no compatible modules.
- //*****
- //if( draw->getStatusBits() )
- //{
- draw->drawIconUI();
- //}
- #if defined(_DEBUG) || defined(_INTERNAL)
- // debug collision extents
- if( TheGlobalData->m_showCollisionExtents )
- drawDrawableExtents( draw, userData );
- if ( TheGlobalData->m_showAudioLocations )
- drawAudioLocations( draw, userData );
- #endif
- // debug terrain normals at object positions
- if( TheGlobalData->m_showTerrainNormals )
- drawTerrainNormal( draw, userData );
- TheGameClient->incrementRenderedObjectCount();
- } // end drawablePostDraw
- //-------------------------------------------------------------------------------------------------
- // Display AI debug visuals
- //-------------------------------------------------------------------------------------------------
- static void renderAIDebug( void )
- {
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool W3DView::updateCameraMovements()
- {
- Bool didUpdate = false;
- if (m_doingZoomCamera)
- {
- zoomCameraOneFrame();
- didUpdate = true;
- }
- if (m_doingPitchCamera)
- {
- pitchCameraOneFrame();
- didUpdate = true;
- }
- if (m_doingRotateCamera) {
- m_previousLookAtPosition = *getPosition();
- rotateCameraOneFrame();
- didUpdate = true;
- } else if (m_doingMoveCameraOnWaypointPath) {
- m_previousLookAtPosition = *getPosition();
- moveAlongWaypointPath(TheW3DFrameLengthInMsec);
- didUpdate = true;
- }
- if (m_doingScriptedCameraLock)
- {
- didUpdate = true;
- }
- return didUpdate;
- }
- /** This function performs all actions which affect the camera transform or 3D objects
- rendered in this frame.
- MW: I moved this code out out W3DView::draw() so that we can get final camera and object
- positions before any rendering begins. This was necessary so that reflection textures
- (which update before the main rendering loop) could get a correct version of the scene.
- Without this change, the reflections were always 1 frame behind the non-reflected view.
- */
- void W3DView::updateView(void)
- {
- UPDATE();
- }
- //DECLARE_PERF_TIMER(W3DView_updateView)
- void W3DView::update(void)
- {
- //USE_PERF_TIMER(W3DView_updateView)
- Bool recalcCamera = false;
- Bool didScriptedMovement = false;
- #ifdef LOG_FRAME_TIMES
- __int64 curTime64,freq64;
- static __int64 prevTime64=0;
- QueryPerformanceFrequency((LARGE_INTEGER *)&freq64);
- QueryPerformanceCounter((LARGE_INTEGER *)&curTime64);
- freq64 /= 1000;
- Int elapsedTimeMs = (curTime64 - prevTime64)/freq64;
- prevTime64 = curTime64;
- #endif
- // Int elapsedTimeMs = TheW3DFrameLengthInMsec; // Assume a constant time flow. It just works out better. jba.
- if (TheTerrainRenderObject->doesNeedFullUpdate()) {
- RefRenderObjListIterator *it = W3DDisplay::m_3DScene->createLightsIterator();
- TheTerrainRenderObject->updateCenter(m_3DCamera, it);
- if (it)
- {
- W3DDisplay::m_3DScene->destroyLightsIterator(it);
- it = NULL;
- }
- }
- static Real followFactor = -1;
- ObjectID cameraLock = getCameraLock();
- if (cameraLock == INVALID_ID)
- {
- followFactor = -1;
- }
- if (cameraLock != INVALID_ID)
- {
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- Object* cameraLockObj = TheGameLogic->findObjectByID(cameraLock);
- Bool loseLock = false;
- // check if object has been destroyed or is dead -> lose lock
- if (cameraLockObj == NULL)
- {
- loseLock = true;
- }
- #if 0
- else
- {
- AIUpdateInterface *ai = cameraLockObj->getAIUpdateInterface();
- if (ai && ai->isDead())
- loseLock = true;
- }
- #endif
- if (loseLock)
- {
- setCameraLock(INVALID_ID);
- setCameraLockDrawable(NULL);
- followFactor = -1;
- }
- else
- {
- if (followFactor<0) {
- followFactor = 0.05f;
- } else {
- followFactor += 0.05f;
- if (followFactor>1.0f) followFactor = 1.0f;
- }
- if (getCameraLockDrawable() != NULL)
- {
- Drawable* cameraLockDrawable = (Drawable *)getCameraLockDrawable();
- if (!cameraLockDrawable)
- {
- setCameraLockDrawable(NULL);
- }
- else
- {
- Coord3D pos;
- Real boundingSphereRadius;
- Matrix3D transform;
- // this method must ONLY be called from the client, NEVER From the logic, not even indirectly.
- if (cameraLockDrawable->clientOnly_getFirstRenderObjInfo(&pos, &boundingSphereRadius, &transform))
- {
- Vector3 zaxis(0,0,1);
- Vector3 objPos;
- objPos.X = pos.x;
- objPos.Y = pos.y;
- objPos.Z = pos.z;
- //get position of top of object, assuming world z roughly along local z.
- objPos += boundingSphereRadius * 1.0f * zaxis;
- Vector3 objview = transform.Get_X_Vector(); //get view vector of object
- //move camera back behind object far enough not to intersect bounding sphere
- Vector3 camtran = objPos - objview * boundingSphereRadius*4.5f;
- Vector3 prevCamTran = m_3DCamera->Get_Position(); //get current camera position.
- Vector3 tranDiff = (camtran - prevCamTran); //vector old position to new position.
- camtran = prevCamTran + tranDiff * 0.1f; //slowly move camera to new position.
- Matrix3D camXForm;
- camXForm.Look_At(camtran,objPos,0);
- m_3DCamera->Set_Transform(camXForm);
- recalcCamera = false; //we already did it
- }
- }
- }
- else
- { Coord3D objpos = *cameraLockObj->getPosition();
- Coord3D curpos = *getPosition();
- // don't "snap" directly to the pos, but move there smoothly.
- Real snapThreshSqr = sqr(TheGlobalData->m_partitionCellSize);
- Real curDistSqr = sqr(curpos.x - objpos.x) + sqr(curpos.y - objpos.y);
- if ( m_snapImmediate)
- {
- // close enough.
- curpos.x = objpos.x;
- curpos.y = objpos.y;
- }
- else
- {
- // Real ratio = 1.0f - snapThreshSqr/curDistSqr;
- Real dx = objpos.x-curpos.x;
- Real dy = objpos.y-curpos.y;
- if (m_lockType == LOCK_TETHER)
- {
- //snapThreshSqr = sqr( m_lockDist * TheGlobalData->m_partitionCellSize );
- if (curDistSqr >= snapThreshSqr)
- {
- Real ratio = 1.0f - snapThreshSqr/curDistSqr;
-
- // move halfway there.
- curpos.x += dx*ratio*0.5f;
- curpos.y += dy*ratio*0.5f;
- }
- else
- {
- // we're inside our 'play' tolerance. Move slowly to the obj
- Real ratio = 0.01f * m_lockDist;
- Real dx = objpos.x-curpos.x;
- Real dy = objpos.y-curpos.y;
- curpos.x += dx*ratio;
- curpos.y += dy*ratio;
- }
- }
- else
- {
- curpos.x += dx*followFactor;
- curpos.y += dy*followFactor;
- }
- }
- if (!(TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript()) && !TheGameLogic->isGamePaused()) {
- m_previousLookAtPosition = *getPosition();
- }
- setPosition(&curpos);
- if (m_lockType == LOCK_FOLLOW)
- {
- // camera follow objects if they are flying
- if (cameraLockObj->isUsingAirborneLocomotor() && cameraLockObj->isAboveTerrainOrWater())
- {
- Matrix3D camXForm;
- Real oldZRot = m_angle;
- Real idealZRot = cameraLockObj->getOrientation() - M_PI_2;
- normAngle(oldZRot);
- normAngle(idealZRot);
- Real diff = idealZRot - oldZRot;
- normAngle(diff);
- if (m_snapImmediate)
- {
- m_angle = idealZRot;
- }
- else
- {
- m_angle += diff * 0.1f;
- }
- normAngle(m_angle);
- }
- }
- if (m_snapImmediate)
- m_snapImmediate = FALSE;
- m_groundLevel = objpos.z;
- didScriptedMovement = true;
- recalcCamera = true;
- }
- }
- }
- if (!(TheScriptEngine->isTimeFrozenDebug()/* || TheScriptEngine->isTimeFrozenScript()*/) && !TheGameLogic->isGamePaused()) {
- // If we aren't frozen for debug, allow the camera to follow scripted movements.
- if (updateCameraMovements()) {
- didScriptedMovement = true;
- recalcCamera = true;
- }
- } else {
- if (m_doingRotateCamera || m_doingMoveCameraOnWaypointPath || m_doingPitchCamera || m_doingZoomCamera || m_doingScriptedCameraLock) {
- didScriptedMovement = true; // don't mess up the scripted movement
- }
- }
- //
- // Process camera shake
- /// @todo Make this framerate-independent
- //
- if (m_shakeIntensity > 0.01f)
- {
- m_shakeOffset.x = m_shakeIntensity * m_shakeAngleCos;
- m_shakeOffset.y = m_shakeIntensity * m_shakeAngleSin;
- // fake a stiff spring/damper
- const Real dampingCoeff = 0.75f;
- m_shakeIntensity *= dampingCoeff;
- // spring is so "stiff", it pulls 180 degrees opposite each frame
- m_shakeAngleCos = -m_shakeAngleCos;
- m_shakeAngleSin = -m_shakeAngleSin;
- recalcCamera = true;
- }
- else
- {
- m_shakeIntensity = 0.0f;
- m_shakeOffset.x = 0.0f;
- m_shakeOffset.y = 0.0f;
- }
- //Process New C3 Camera Shaker system
- if (CameraShakerSystem.IsCameraShaking())
- {
- recalcCamera = true;
- }
- /*
- * In order to have the camera follow the terrain in a non-dizzying way, we will have a
- * "desired height" value that the user sets. While scrolling, the actual height (set by
- * zoom) will not get updated unless we are scrolling uphill and our view either goes
- * underground or higher than the max allowed height. When the camera is at rest (not
- * scrolling), the zoom will move toward matching the desired height.
- */
- m_terrainHeightUnderCamera = getHeightAroundPos(m_pos.x, m_pos.y);
- m_currentHeightAboveGround = m_cameraOffset.z * m_zoom - m_terrainHeightUnderCamera;
- if (TheTerrainLogic && TheGlobalData && TheInGameUI && m_okToAdjustHeight && !TheGameLogic->isGamePaused())
- {
- Real desiredHeight = (m_terrainHeightUnderCamera + m_heightAboveGround);
- Real desiredZoom = desiredHeight / m_cameraOffset.z;
- if (didScriptedMovement || (TheGameLogic->isInReplayGame() && TheGlobalData->m_useCameraInReplay))
- {
- // if we are in a scripted camera movement, take its height above ground as our desired height.
- m_heightAboveGround = m_currentHeightAboveGround;
- //DEBUG_LOG(("Frame %d: height above ground: %g %g %g %g\n", TheGameLogic->getFrame(), m_heightAboveGround,
- // m_cameraOffset.z, m_zoom, m_terrainHeightUnderCamera));
- }
- if (TheInGameUI->isScrolling())
- {
- // if scrolling, only adjust if we're too close or too far
- if (m_scrollAmount.length() < m_scrollAmountCutoff || (m_currentHeightAboveGround < m_minHeightAboveGround) || (TheGlobalData->m_enforceMaxCameraHeight && m_currentHeightAboveGround > m_maxHeightAboveGround))
- {
- Real zoomAdj = (desiredZoom - m_zoom)*TheGlobalData->m_cameraAdjustSpeed;
- if (fabs(zoomAdj) >= 0.0001) // only do positive
- {
- m_zoom += zoomAdj;
- recalcCamera = true;
- }
- }
- }
- else
- {
- // we're not scrolling; settle toward desired height above ground
- Real zoomAdj = (m_zoom - desiredZoom)*TheGlobalData->m_cameraAdjustSpeed;
- Real zoomAdjAbs = fabs(zoomAdj);
- if (zoomAdjAbs >= 0.0001 && !didScriptedMovement)
- {
- //DEBUG_LOG(("W3DView::update() - m_zoom=%g, desiredHeight=%g\n", m_zoom, desiredZoom));
- m_zoom -= zoomAdj;
- recalcCamera = true;
- }
- }
- }
- if (TheScriptEngine->isTimeFast()) {
- return; // don't draw - makes it faster :) jba.
- }
-
- // (gth) C&C3 if m_isCameraSlaved then force the camera to update each frame
- if ((recalcCamera) || (m_isCameraSlaved)) {
- setCameraTransform();
- }
- #ifdef DO_SEISMIC_SIMULATIONS
- // Give the terrain a chance to refresh animaing (Seismic) regions, if any.
- TheTerrainVisual->updateSeismicSimulations();
- #endif
-
- Region3D axisAlignedRegion;
- getAxisAlignedViewRegion(axisAlignedRegion);
- // render all of the visible Drawables
- /// @todo this needs to use a real region partition or something
- if (WW3D::Get_Frame_Time()) //make sure some time actually elapsed
- TheGameClient->iterateDrawablesInRegion( &axisAlignedRegion, drawDrawable, this );
- }
- //-------------------------------------------------------------------------------------------------
- /** Find region which contains all drawables in 3D space. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion)
- {
- //
- // get the 4 points in 3D space of the 4 corners of the view, we will use a z = 0.0f
- // value so that we can get everything ... even stuff below the terrain
- //
- Coord3D box[ 4 ];
- getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f );
- //
- // take those 4 corners projected into the world and create an axis aligned bounding
- // box, we will use this box to iterate the drawables in 3D space
- //
- axisAlignedRegion.lo = box[ 0 ];
- axisAlignedRegion.hi = box[ 0 ];
- for( Int i = 0; i < 4; i++ )
- {
- if( box[ i ].x < axisAlignedRegion.lo.x )
- axisAlignedRegion.lo.x = box[ i ].x;
- if( box[ i ].y < axisAlignedRegion.lo.y )
- axisAlignedRegion.lo.y = box[ i ].y;
- if( box[ i ].x > axisAlignedRegion.hi.x )
- axisAlignedRegion.hi.x = box[ i ].x;
- if( box[ i ].y > axisAlignedRegion.hi.y )
- axisAlignedRegion.hi.y = box[ i ].y;
- } // end for i
- // low and high regions will be based of the extent of the map
- Region3D mapExtent;
- Real safeValue = 999999;
- TheTerrainLogic->getExtent( &mapExtent );
- axisAlignedRegion.lo.z = mapExtent.lo.z - safeValue;
- axisAlignedRegion.hi.z = mapExtent.hi.z + safeValue;
- // we want to overscan a little bit so that we get objects that are partially offscreen
- axisAlignedRegion.lo.x -= (DRAWABLE_OVERSCAN + m_guardBandBias.x);
- axisAlignedRegion.lo.y -= (DRAWABLE_OVERSCAN + m_guardBandBias.y + 60.0f );
- axisAlignedRegion.hi.x += (DRAWABLE_OVERSCAN + m_guardBandBias.x);
- axisAlignedRegion.hi.y += (DRAWABLE_OVERSCAN + m_guardBandBias.y);
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::setFadeParameters(Int fadeFrames, Int direction)
- {
- ScreenBWFilter::setFadeParameters(fadeFrames, direction);
- ScreenCrossFadeFilter::setFadeParameters(fadeFrames,direction);
- }
- void W3DView::set3DWireFrameMode(Bool enable)
- {
- m_nextWireFrameEnabled = enable;
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets the view filter mode. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setViewFilterPos(const Coord3D *pos)
- {
- ScreenMotionBlurFilter::setZoomToPos(pos);
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets the view filter mode. */
- //-------------------------------------------------------------------------------------------------
- Bool W3DView::setViewFilterMode(enum FilterModes filterMode)
- {
- FilterModes oldMode = m_viewFilterMode; //save previous mode in case setup fails.
- m_viewFilterMode = filterMode;
- if (m_viewFilterMode != FM_NULL_MODE &&
- m_viewFilter != FT_NULL_FILTER) {
- if (!W3DShaderManager::filterSetup(m_viewFilter, m_viewFilterMode))
- { //setup failed so restore previous mode.
- m_viewFilterMode = oldMode;
- return FALSE;
- }
- }
- return TRUE;
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets the view filter. */
- //-------------------------------------------------------------------------------------------------
- Bool W3DView::setViewFilter(enum FilterTypes filter)
- {
- FilterTypes oldFilter = m_viewFilter; //save previous filter in case setup fails.
- m_viewFilter = filter;
- if (m_viewFilterMode != FM_NULL_MODE &&
- m_viewFilter != FT_NULL_FILTER) {
- if (!W3DShaderManager::filterSetup(m_viewFilter, m_viewFilterMode))
- { //setup failed so restore previous mode.
- m_viewFilter = oldFilter;
- return FALSE;
- };
- }
- return TRUE;
- }
- //-------------------------------------------------------------------------------------------------
- /** Calculates how many pixels we scrolled since last frame for motion blur calculations. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::calcDeltaScroll(Coord2D &screenDelta)
- {
- screenDelta.x = 0;
- screenDelta.y = 0;
- Vector3 prevPos(m_previousLookAtPosition.x,m_previousLookAtPosition.y, m_groundLevel);
- Vector3 prevScreen;
- if (m_3DCamera->Project( prevScreen, prevPos ) != CameraClass::INSIDE_FRUSTUM)
- {
- return;
- }
- Vector3 pos(m_pos.x,m_pos.y, m_groundLevel);
- Vector3 screen;
- if (m_3DCamera->Project( screen, pos ) != CameraClass::INSIDE_FRUSTUM)
- {
- return;
- }
- screenDelta.x = screen.X-prevScreen.X;
- screenDelta.y = screen.Y-prevScreen.Y;
- }
- //-------------------------------------------------------------------------------------------------
- /** Draw member for the W3D window, this will literally draw the window
- * for this view */
- //-------------------------------------------------------------------------------------------------
- void W3DView::drawView( void )
- {
- DRAW();
- }
- //DECLARE_PERF_TIMER(W3DView_drawView)
- void W3DView::draw( void )
- {
- //USE_PERF_TIMER(W3DView_drawView)
- Bool skipRender = false;
- Bool doExtraRender = false;
- CustomScenePassModes customScenePassMode = SCENE_PASS_DEFAULT;
- Bool preRenderResult = false;
- if (m_viewFilterMode &&
- m_viewFilter > FT_NULL_FILTER &&
- m_viewFilter < FT_MAX)
- {
- // Most likely will redirect rendering to a texture.
- preRenderResult=W3DShaderManager::filterPreRender(m_viewFilter, skipRender, customScenePassMode);
- if (!skipRender && getCameraLock())
- {
- Object* cameraLockObj = TheGameLogic->findObjectByID(getCameraLock());
- if (cameraLockObj)
- {
- Drawable *drawable = cameraLockObj->getDrawable();
- drawable->setDrawableHidden(true);
- }
- }
- }
- if (!skipRender)
- {
- // Render 3D scene from our camera
- W3DDisplay::m_3DScene->setCustomPassMode(customScenePassMode);
- if (m_isWireFrameEnabled)
- W3DDisplay::m_3DScene->Set_Extra_Pass_Polygon_Mode(SceneClass::EXTRA_PASS_CLEAR_LINE);
- W3DDisplay::m_3DScene->doRender( m_3DCamera );
- W3DDisplay::m_3DScene->Set_Extra_Pass_Polygon_Mode(SceneClass::EXTRA_PASS_DISABLE);
- m_isWireFrameEnabled = m_nextWireFrameEnabled;
- }
- if (m_viewFilterMode &&
- m_viewFilter > FT_NULL_FILTER &&
- m_viewFilter < FT_MAX)
- {
- Coord2D deltaScroll;
- calcDeltaScroll(deltaScroll);
- Bool continueTheEffect = false;
- if (preRenderResult) //if prerender passed, do the post render.
- continueTheEffect = W3DShaderManager::filterPostRender(m_viewFilter, m_viewFilterMode, deltaScroll,doExtraRender);
- if (!skipRender && getCameraLock())
- {
- Object* cameraLockObj = TheGameLogic->findObjectByID(getCameraLock());
- if (cameraLockObj)
- {
- Drawable *drawable = cameraLockObj->getDrawable();
- drawable->setDrawableHidden(false);
- RenderInfoClass rinfo(*m_3DCamera);
- // Apply the camera and viewport (including depth range)
- m_3DCamera->Apply();
- TheDX8MeshRenderer.Set_Camera(&rinfo.Camera);
- W3DDisplay::m_3DScene->renderSpecificDrawables(rinfo, 1, &drawable);
- WW3D::Flush(rinfo);
- }
- }
- if (!continueTheEffect)
- {
- // shut it down.
- m_viewFilter = FT_VIEW_DEFAULT;
- m_viewFilterMode = FM_VIEW_DEFAULT;
- }
- }
- //Some effects require that we render a modified version of the scene into a texture but also require
- //an unaltered version in the framebuffer. So we re-render again into framebuffer after texture rendering
- //was turned off by filterPostRender().
- if (doExtraRender)
- {
- //Reset to normal scene rendering.
- //The pass that rendered into a texture may have left the z-buffer in a weird state
- //so clear it before rendering normal scene.
- ///@todo: Don't clear z-buffer unless shader uses z-bias or anything else that would cause <= z to fail on normal render.
- DX8Wrapper::Clear(false, true, Vector3(0.0f,0.0f,0.0f), TheWaterTransparency->m_minWaterOpacity); // Clear z but not color
- W3DDisplay::m_3DScene->setCustomPassMode(SCENE_PASS_DEFAULT);
- W3DDisplay::m_3DScene->doRender( m_3DCamera );
- Coord2D deltaScroll;
- W3DShaderManager::filterPostRender(m_viewFilter, m_viewFilterMode, deltaScroll, doExtraRender);
- }
- if( TheGlobalData->m_debugAI )
- {
- if (TheAI->pathfinder()->getDebugPath())
- {
- // setup screen clipping region
- IRegion2D clipRegion;
- clipRegion.lo.x = 0;
- clipRegion.lo.y = 0;
- clipRegion.hi.x = getWidth();
- clipRegion.hi.y = getHeight();
- UnsignedInt color = 0xFFFFFF00; //0xAARRGGBB
- ICoord2D start, end;
- PathNode *prevNode = TheAI->pathfinder()->getDebugPath()->getFirstNode();
- if (worldToScreen( prevNode->getPosition(), &start )) {
- TheDisplay->drawLine( start.x-3, start.y-3, start.x+3, start.y-3, 1.0f, color );
- TheDisplay->drawLine( start.x+3, start.y-3, start.x+3, start.y+3, 1.0f, color );
- TheDisplay->drawLine( start.x+3, start.y+3, start.x-3, start.y+3, 1.0f, color );
- TheDisplay->drawLine( start.x-3, start.y+3, start.x-3, start.y-3, 1.0f, color );
- }
- for( PathNode *node = prevNode->getNext(); node; node = node->getNext() )
- {
- Int k;
- Coord3D s, e;
- Coord3D delta;
- s = *node->getPosition();
- e = *prevNode->getPosition();
- delta.x = e.x-s.x;
- delta.y = e.y-s.y;
- delta.z = e.z-s.z;
- for (k = 0; k<10; k++) {
- Real factor1 = (k)/10.0;
- Real factor2 = (k+1)/10.0;
- s = *node->getPosition();
- e = *node->getPosition();
- s.x += delta.x*factor1;
- s.y += delta.y*factor1;
- s.z += delta.z*factor1;
- e.x += delta.x*factor2;
- e.y += delta.y*factor2;
- e.z += delta.z*factor2;
- Bool onScreen1 = worldToScreen( &e, &end );
- Bool onScreen2 = worldToScreen( &s, &start );
- if (!onScreen1 && !onScreen2) {
- continue; // neither point visible.
- }
- ICoord2D clipStart, clipEnd;
- if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) {
- TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, 1.0f, color );
- }
- }
- prevNode = node;
- if (node->getNext()) {
- if (worldToScreen( node->getPosition(), &start )) {
- TheDisplay->drawLine( start.x-4, start.y, start.x+3, start.y, 1.0f, color );
- }
- }
- }
- if (prevNode && worldToScreen( prevNode->getPosition(), &start )) {
- TheDisplay->drawLine( start.x-4, start.y, start.x+3, start.y, 1.0f, color );
- TheDisplay->drawLine( start.x, start.y-4, start.x, start.y+3, 1.0f, color );
- }
- color = 0xFFFF0000; //0xAARRGGBB
- if (worldToScreen( TheAI->pathfinder()->getDebugPathPosition(), &start )) {
- TheDisplay->drawLine( start.x-3, start.y, start.x+3, start.y, 1.0f, color );
- TheDisplay->drawLine( start.x, start.y-3, start.x, start.y+3, 1.0f, color );
- }
- }
- } // end if, show debug AI
- #if defined(_DEBUG) || defined(_INTERNAL)
- if( TheGlobalData->m_debugCamera )
- {
- UnsignedInt c = 0xaaffffff;
- Coord3D worldPos = *getPosition();
- worldPos.z = TheTerrainLogic->getGroundHeight(worldPos.x, worldPos.y);
- Coord3D p1, p2;
- ICoord2D s1, s2;
- p1 = worldPos;
- p1.x += TERRAIN_SAMPLE_SIZE;
- p1.y += TERRAIN_SAMPLE_SIZE;
- p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
- p2 = worldPos;
- p2.x += TERRAIN_SAMPLE_SIZE;
- p2.y -= TERRAIN_SAMPLE_SIZE;
- p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
- worldToScreen( &p1, &s1 );
- worldToScreen( &p2, &s2 );
- TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
- p1 = worldPos;
- p1.x += TERRAIN_SAMPLE_SIZE;
- p1.y -= TERRAIN_SAMPLE_SIZE;
- p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
- p2 = worldPos;
- p2.x -= TERRAIN_SAMPLE_SIZE;
- p2.y -= TERRAIN_SAMPLE_SIZE;
- p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
- worldToScreen( &p1, &s1 );
- worldToScreen( &p2, &s2 );
- TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
- p1 = worldPos;
- p1.x -= TERRAIN_SAMPLE_SIZE;
- p1.y -= TERRAIN_SAMPLE_SIZE;
- p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
- p2 = worldPos;
- p2.x -= TERRAIN_SAMPLE_SIZE;
- p2.y += TERRAIN_SAMPLE_SIZE;
- p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
- worldToScreen( &p1, &s1 );
- worldToScreen( &p2, &s2 );
- TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
- p1 = worldPos;
- p1.x -= TERRAIN_SAMPLE_SIZE;
- p1.y += TERRAIN_SAMPLE_SIZE;
- p1.z = TheTerrainLogic->getGroundHeight(p1.x, p1.y);
- p2 = worldPos;
- p2.x += TERRAIN_SAMPLE_SIZE;
- p2.y += TERRAIN_SAMPLE_SIZE;
- p2.z = TheTerrainLogic->getGroundHeight(p2.x, p2.y);
- worldToScreen( &p1, &s1 );
- worldToScreen( &p2, &s2 );
- TheDisplay->drawLine(s1.x, s1.y, s2.x, s2.y, 1.0f, c);
- }
- if ( TheGlobalData->m_showAudioLocations )
- {
- // Draw audio radii for ALL drawables, not just those on screen
- const Drawable * drawable = TheGameClient->getDrawableList();
- while ( drawable != NULL )
- {
- drawAudioRadii( drawable );
- drawable = drawable->getNextDrawable();
- }
- }
- #endif // DEBUG or INTERNAL
- Region3D axisAlignedRegion;
- getAxisAlignedViewRegion(axisAlignedRegion);
- //
- // there are several things we might want to do as a post pass on the objects after
- // they are all drawn
- /// @todo we might want to consider wiping this iterate out if there is nothing to post draw
- //
- TheGameClient->resetRenderedObjectCount();
- TheGameClient->iterateDrawablesInRegion( &axisAlignedRegion, drawablePostDraw, this );
- TheGameClient->flushTextBearingDrawables();
- // Render 2D scene
- W3DDisplay::m_2DScene->doRender( m_2DCamera );
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::setCameraLock(ObjectID id)
- {
- // If we're disabling camera movements, don't lock onto the object.
- if (TheGlobalData->m_disableCameraMovement && id!=INVALID_ID) {
- return;
- }
- View::setCameraLock(id);
- m_doingScriptedCameraLock = FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::setSnapMode( CameraLockType lockType, Real lockDist )
- {
- View::setSnapMode(lockType, lockDist);
- m_doingScriptedCameraLock = TRUE;
- }
- //-------------------------------------------------------------------------------------------------
- /** Scroll the view by the given delta in SCREEN COORDINATES, this interface
- * assumes we will be scrolling along the X,Y plane */
- //-------------------------------------------------------------------------------------------------
- void W3DView::scrollBy( Coord2D *delta )
- {
- // if we haven't moved, ignore
- if( delta && (delta->x != 0 || delta->y != 0) )
- {
- const Real SCROLL_RESOLUTION = 250.0f;
- Vector3 world, worldStart, worldEnd;
- Vector2 screen, start, end;
- m_scrollAmount = *delta;
- screen.X = delta->x;
- screen.Y = delta->y;
-
- start.X = getWidth();
- start.Y = getHeight();
- Real aspect = getWidth()/getHeight();
- end.X = start.X + delta->x * SCROLL_RESOLUTION;
- end.Y = start.Y + delta->y * SCROLL_RESOLUTION*aspect;
- m_3DCamera->Device_To_World_Space( start, &worldStart );
- m_3DCamera->Device_To_World_Space( end, &worldEnd );
- world.X = worldEnd.X - worldStart.X;
- world.Y = worldEnd.Y - worldStart.Y;
- world.Z = worldEnd.Z - worldStart.Z;
- // scroll by delta
- Coord3D pos = *getPosition();
- pos.x += world.X;
- pos.y += world.Y;
- //DEBUG_LOG(("Delta %.2f, %.2f\n", world.X, world.Z));
- // no change to z
- setPosition(&pos);
- //m_cameraConstraintValid = false; // pos change does NOT invalidate cam constraints
- m_doingRotateCamera = false;
- // set new camera position
- setCameraTransform();
- } // end if
- } // end scrollBy
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::forceRedraw()
- {
- // set the camera
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- /** Rotate the view around the up axis to the given angle. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setAngle( Real angle )
- {
- // Normalize to +-PI.
- normAngle(angle);
- // call our base class, we are adding functionality
- View::setAngle( angle );
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_doingRotateCamera = false;
- m_doingPitchCamera = false;
- m_doingZoomCamera = false;
- m_doingScriptedCameraLock = false;
- // set the camera
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- /** Rotate the view around the horizontal (X) axis to the given angle. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setPitch( Real angle )
- {
- // call our base class, we are extending functionality
- View::setPitch( angle );
- m_doingMoveCameraOnWaypointPath = false;
- m_doingRotateCamera = false;
- m_doingPitchCamera = false;
- m_doingZoomCamera = false;
- m_doingScriptedCameraLock = false;
- // set the camera
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- /** Set the view angle & pitch back to default */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setAngleAndPitchToDefault( void )
- {
- // call our base class, we are adding functionality
- View::setAngleAndPitchToDefault();
- this->m_FXPitch = 1.0;
- // set the camera
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::setDefaultView(Real pitch, Real angle, Real maxHeight)
- {
- // MDC - we no longer want to rotate maps (design made all of them right to begin with)
- // m_defaultAngle = angle * M_PI/180.0f;
- m_defaultPitchAngle = pitch;
- m_maxHeightAboveGround = TheGlobalData->m_maxCameraHeight*maxHeight;
- if (m_minHeightAboveGround > m_maxHeightAboveGround)
- m_maxHeightAboveGround = m_minHeightAboveGround;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::setHeightAboveGround(Real z)
- {
- m_heightAboveGround = z;
- // if our zoom is limited, we will stay within a predefined distance from the terrain
- if( m_zoomLimited )
- {
- if (m_heightAboveGround < m_minHeightAboveGround)
- m_heightAboveGround = m_minHeightAboveGround;
- if (m_heightAboveGround > m_maxHeightAboveGround)
- m_heightAboveGround = m_maxHeightAboveGround;
- } // end if
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_doingRotateCamera = false;
- m_doingPitchCamera = false;
- m_doingZoomCamera = false;
- m_doingScriptedCameraLock = false;
- m_cameraConstraintValid = false; // recalc it.
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::setZoom(Real z)
- {
- m_zoom = z;
- if (m_zoom < m_minZoom)
- m_zoom = m_minZoom;
- if (m_zoom > m_maxZoom)
- m_zoom = m_maxZoom;
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_doingRotateCamera = false;
- m_doingPitchCamera = false;
- m_doingZoomCamera = false;
- m_doingScriptedCameraLock = false;
- m_cameraConstraintValid = false; // recalc it.
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::setZoomToDefault( void )
- {
- // default zoom has to be max, otherwise players will just zoom to max always
- // terrain height + desired height offset == cameraOffset * actual zoom
- // find best approximation of max terrain height we can see
- Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
- Real desiredHeight = (terrainHeightMax + m_maxHeightAboveGround);
- Real desiredZoom = desiredHeight / m_cameraOffset.z;
- //DEBUG_LOG(("W3DView::setZoomToDefault() Current zoom: %g Desired zoom: %g\n", m_zoom, desiredZoom));
- m_zoom = desiredZoom;
- m_heightAboveGround = m_maxHeightAboveGround;
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_doingRotateCamera = false;
- m_doingPitchCamera = false;
- m_doingZoomCamera = false;
- m_doingScriptedCameraLock = false;
- m_cameraConstraintValid = false; // recalc it.
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- /** Set the horizontal field of view angle */
- //-------------------------------------------------------------------------------------------------
- void W3DView::setFieldOfView( Real angle )
- {
- View::setFieldOfView( angle );
- #if defined(_DEBUG) || defined(_INTERNAL)
- // this is only for testing, and recalculating the
- // camera every frame is wasteful
- setCameraTransform();
- #endif
- }
- //-------------------------------------------------------------------------------------------------
- /** Using the W3D camera translate the world coordinate to a screen coord.
- Screen coordinates returned in absolute values relative to full display resolution.
- Returns if the point is on screen, off screen, or not transformable */
- //-------------------------------------------------------------------------------------------------
- View::WorldToScreenReturn W3DView::worldToScreenTriReturn( const Coord3D *w, ICoord2D *s )
- {
- // sanity
- if( w == NULL || s == NULL )
- return WTS_INVALID;
- if( m_3DCamera )
- {
- Vector3 world;
- Vector3 screen;
- world.Set( w->x, w->y, w->z );
- enum CameraClass::ProjectionResType projection = m_3DCamera->Project( screen, world );
- if (projection != CameraClass::INSIDE_FRUSTUM && projection!=CameraClass::OUTSIDE_FRUSTUM)
- {
- // Can't get a valid number if it's beyond the clip planes. jba
- s->x = 0;
- s->y = 0;
- return WTS_INVALID;
- }
- //
- // note that the screen coord returned from the project W3D camera
- // gave us a screen coords that range from (-1,-1) bottom left to
- // (1,1) top right ... we are turning that into (0,0) upper left
- // coords now
- //
- W3DLogicalScreenToPixelScreen( screen.X, screen.Y,
- &s->x, &s->y,
- getWidth(), getHeight());
- s->x += m_originX; //convert viewport coordinates to full screen coordinates
- s->y += m_originY;
- // s->x = (getWidth() * (screen.X + 1.0f)) / 2.0f;
- // s->y = (getHeight() * (-screen.Y + 1.0f)) / 2.0f;
- if (projection != CameraClass::INSIDE_FRUSTUM)
- {
- return WTS_OUTSIDE_FRUSTUM;
- }
- return WTS_INSIDE_FRUSTUM;
- } // end if
- return WTS_INVALID;
- } // end worldToScreenTriReturn
- //-------------------------------------------------------------------------------------------------
- /** Using the W3D camera translate the screen coord to world coord */
- //-------------------------------------------------------------------------------------------------
- void W3DView::screenToWorld( const ICoord2D *s, Coord3D *w )
- {
- // sanity
- if( s == NULL || w == NULL )
- return;
- if( m_3DCamera )
- {
- DEBUG_CRASH(("implement me"));
- } // end if
- } // end screenToWorld
- //-------------------------------------------------------------------------------------------------
- /** all the drawables in the view, that fall within the 2D screen region
- * will call the callback function. The number of drawables that passed
- * the test are returned.
- Screen coordinates assumed in absolute values relative to full display resolution. */
- //-------------------------------------------------------------------------------------------------
- Int W3DView::iterateDrawablesInRegion( IRegion2D *screenRegion,
- Bool (*callback)( Drawable *draw, void *userData ),
- void *userData )
- {
- Bool inside = FALSE;
- Int count = 0;
- Drawable *draw;
- Vector3 screen, world;
- Coord3D pos;
- Region2D normalizedRegion;
- /** @todo we need to have partitions of which drawables are in the
- view so we don't have to march through the whole list */
- //
- // to do this we are projecting the drawable centers onto the screen,
- // the W3D camera->project method is used to do this and that method
- // will return normalized screen coords from (-1,-1) bottom left to
- // (1,1) top right, normalize our screen region for comparison
- //
- /// @todo use fast int->real type casts here later
- Bool regionIsPoint = FALSE;
- if( screenRegion )
- {
- if (screenRegion->height() == 0 && screenRegion->width() == 0)
- {
- regionIsPoint = TRUE;
- }
- normalizedRegion.lo.x = ((Real)(screenRegion->lo.x - m_originX) / (Real)getWidth()) * 2.0f - 1.0f;
- normalizedRegion.lo.y = -(((Real)(screenRegion->hi.y - m_originY) / (Real)getHeight()) * 2.0f - 1.0f);
- normalizedRegion.hi.x = ((Real)(screenRegion->hi.x - m_originX) / (Real)getWidth()) * 2.0f - 1.0f;
- normalizedRegion.hi.y = -(((Real)(screenRegion->lo.y - m_originY) / (Real)getHeight()) * 2.0f - 1.0f);
- } // end if
- Drawable *onlyDrawableToTest = NULL;
- if (regionIsPoint)
- {
- // Allow all drawables to be picked.
- onlyDrawableToTest = pickDrawable(&screenRegion->lo, TRUE, (PickType) getPickTypesForContext(TheInGameUI->isInForceAttackMode()));
- if (onlyDrawableToTest == NULL) {
- return 0;
- }
- }
- for( draw = TheGameClient->firstDrawable();
- draw;
- draw = draw->getNextDrawable() )
- {
- if (onlyDrawableToTest)
- {
- draw = onlyDrawableToTest;
- inside = TRUE;
- }
- else
- {
- // not inside
- inside = FALSE;
- // no screen region, means all drawbles
- if( screenRegion == NULL )
- inside = TRUE;
- else
- {
- // project the center of the drawable to the screen
- /// @todo use a real 3D position in the drawable
- pos = *draw->getPosition();
- world.X = pos.x;
- world.Y = pos.y;
- world.Z = pos.z;
- // project the world point to the screen
- if( m_3DCamera->Project( screen, world ) == CameraClass::INSIDE_FRUSTUM &&
- screen.X >= normalizedRegion.lo.x &&
- screen.X <= normalizedRegion.hi.x &&
- screen.Y >= normalizedRegion.lo.y &&
- screen.Y <= normalizedRegion.hi.y )
- {
- inside = TRUE;
- } // end if
- }
-
- } //end else
- // if inside do the callback and count up
- if( inside )
- {
-
- if( callback( draw, userData ) )
- ++count;
- } // end if
- // If onlyDrawableToTest, then we should bail out now.
- if (onlyDrawableToTest != NULL)
- break;
- } // end for draw
- return count;
- } // end iterateDrawablesInRegion
- //-------------------------------------------------------------------------------------------------
- /** cast a ray from the screen coords into the scene and return a drawable
- * there if present. Screen coordinates assumed in absolute values relative
- * to full display resolution. */
- //-------------------------------------------------------------------------------------------------
- Drawable *W3DView::pickDrawable( const ICoord2D *screen, Bool forceAttack, PickType pickType )
- {
- RenderObjClass *renderObj = NULL;
- Drawable *draw = NULL;
- DrawableInfo *drawInfo = NULL;
- // sanity
- if( screen == NULL )
- return NULL;
- // don't pick a drawable if there is a window under the cursor
- GameWindow *window = NULL;
- if (TheWindowManager)
- window = TheWindowManager->getWindowUnderCursor(screen->x, screen->y);
- while (window)
- {
- // check to see if it or any of its parents are opaque. If so, we can't select anything.
- if (!BitTest( window->winGetStatus(), WIN_STATUS_SEE_THRU ))
- return NULL;
- window = window->winGetParent();
- }
- Vector3 rayStart,rayEnd;
- getPickRay(screen,&rayStart,&rayEnd);
- LineSegClass lineseg;
- lineseg.Set(rayStart,rayEnd);
- CastResultStruct result;
- if (forceAttack)
- result.ComputeContactPoint = true;
- //Don't check against translucent or hidden objects
- RayCollisionTestClass raytest(lineseg,&result,COLL_TYPE_ALL,false,false);
- if( W3DDisplay::m_3DScene->castRay( raytest, false, (Int)pickType ) )
- renderObj = raytest.CollidedRenderObj;
- // 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,
- // the terrain, therefore the userdata is NULL
- /// @todo terrain and picking!
- if( renderObj )
- drawInfo = (DrawableInfo *)renderObj->Get_User_Data();
- if (drawInfo)
- draw=drawInfo->m_drawable;
- return draw;
- } // end pickDrawable
- //-------------------------------------------------------------------------------------------------
- /** convert a pixel (x,y) to a location in the world on the terrain.
- Screen coordinates assumed in absolute values relative to full display resolution. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world )
- {
- // sanity
- if( screen == NULL || world == NULL || TheTerrainRenderObject == NULL )
- return;
- if (m_cameraHasMovedSinceRequest) {
- m_locationRequests.clear();
- m_cameraHasMovedSinceRequest = false;
- }
- if (m_locationRequests.size() > MAX_REQUEST_CACHE_SIZE) {
- m_locationRequests.erase(m_locationRequests.begin(), m_locationRequests.begin() + 10);
- }
- // We insert them at the end for speed (no copies needed), but using the princ of locality, we should
- // start searching where we most recently inserted
- for (int i = m_locationRequests.size() - 1; i >= 0; --i) {
- if (m_locationRequests[i].first.x == screen->x && m_locationRequests[i].first.y == screen->y) {
- (*world) = m_locationRequests[i].second;
- return;
- }
- }
- Vector3 rayStart,rayEnd;
- LineSegClass lineseg;
- CastResultStruct result;
- Vector3 intersection(0,0,0);
- getPickRay(screen,&rayStart,&rayEnd);
- lineseg.Set(rayStart,rayEnd);
- RayCollisionTestClass raytest(lineseg,&result);
- if( TheTerrainRenderObject->Cast_Ray(raytest) )
- {
- // get the point of intersection according to W3D
- intersection = result.ContactPoint;
-
- } // end if
- // Pick bridges.
- Vector3 bridgePt;
- Drawable *bridge = TheTerrainLogic->pickBridge(rayStart, rayEnd, &bridgePt);
- if (bridge && bridgePt.Z > intersection.Z) {
- intersection = bridgePt;
- }
- world->x = intersection.X;
- world->y = intersection.Y;
- world->z = intersection.Z;
- PosRequest req;
- req.first = (*screen);
- req.second = (*world);
- m_locationRequests.push_back(req); // Insert this request at the end, requires no extra copies
- } // end screenToTerrain
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::lookAt( const Coord3D *o )
- {
- Coord3D pos = *o;
- // no, don't call the super-lookAt, since it will munge our coords
- // as for a 2d view. just call setPosition.
- //View::lookAt(&pos);
- if (o->z > PATHFIND_CELL_SIZE_F+TheTerrainLogic->getGroundHeight(pos.x, pos.y)) {
- // Pos.z is not used, so if we want to look at something off the ground,
- // we have to look at the spot on the ground such that the object intersects
- // with the look at vector in the center of the screen. jba.
- Vector3 rayStart,rayEnd;
- LineSegClass lineseg;
- CastResultStruct result;
- Vector3 intersection(0,0,0);
- rayStart = m_3DCamera->Get_Position(); //get camera location
- m_3DCamera->Un_Project(rayEnd,Vector2(0.0f,0.0f)); //get world space point
- rayEnd -= rayStart; //vector camera to world space point
- rayEnd.Normalize(); //make unit vector
- rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane
- rayStart.Set(pos.x, pos.y, pos.z);
- rayEnd += rayStart; //get point on far clip plane along ray from camera.
- lineseg.Set(rayStart,rayEnd);
- RayCollisionTestClass raytest(lineseg,&result);
- if( TheTerrainRenderObject->Cast_Ray(raytest) )
- {
- // get the point of intersection according to W3D
- pos.x = result.ContactPoint.X;
- pos.y = result.ContactPoint.Y;
-
- } // end if
- }
- pos.z = 0;
- setPosition(&pos);
- m_doingRotateCamera = false;
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_doingScriptedCameraLock = false;
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::initHeightForMap( void )
- {
- m_groundLevel = TheTerrainLogic->getGroundHeight(m_pos.x, m_pos.y);
- const Real MAX_GROUND_LEVEL = 120.0; // jba - starting ground level can't exceed this height.
- if (m_groundLevel>MAX_GROUND_LEVEL) {
- m_groundLevel = MAX_GROUND_LEVEL;
- }
- m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight;
- m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
- m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
- m_cameraConstraintValid = false; // possible ground level change invalidates cam constraints
- setCameraTransform();
- }
- //-------------------------------------------------------------------------------------------------
- /** Move camera to in an interesting fashion. Sets up parameters that get
- * evaluated in draw(). */
- //-------------------------------------------------------------------------------------------------
- void W3DView::moveCameraTo(const Coord3D *o, Int milliseconds, Int shutter, Bool orient, Real easeIn, Real easeOut)
- {
- m_mcwpInfo.waypoints[0] = *getPosition();
- m_mcwpInfo.cameraAngle[0] = getAngle();
- m_mcwpInfo.waySegLength[0] = 0;
- m_mcwpInfo.waypoints[1] = *getPosition();
- m_mcwpInfo.waySegLength[1] = 0;
- m_mcwpInfo.waypoints[2] = *o;
- m_mcwpInfo.waySegLength[2] = 0;
- m_mcwpInfo.numWaypoints = 2;
- if (milliseconds<1) milliseconds = 1;
- m_mcwpInfo.totalTimeMilliseconds = milliseconds;
- m_mcwpInfo.shutter = 1;
- m_mcwpInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- m_mcwpInfo.curSegment = 1;
- m_mcwpInfo.curSegDistance = 0;
- m_mcwpInfo.totalDistance = 0;
- setupWaypointPath(orient);
- if (m_mcwpInfo.totalTimeMilliseconds==1) {
- // do it instantly.
- moveAlongWaypointPath(1);
- m_doingMoveCameraOnWaypointPath = true;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** Rotate the camera */
- //-------------------------------------------------------------------------------------------------
- void W3DView::rotateCamera(Real rotations, Int milliseconds, Real easeIn, Real easeOut)
- {
- m_rcInfo.numHoldFrames = 0;
- m_rcInfo.trackObject = FALSE;
- if (milliseconds<1) milliseconds = 1;
- m_rcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
- if (m_rcInfo.numFrames < 1) {
- m_rcInfo.numFrames = 1;
- }
- m_rcInfo.curFrame = 0;
- m_doingRotateCamera = true;
- m_rcInfo.angle.startAngle = m_angle;
- m_rcInfo.angle.endAngle = m_angle + 2*PI*rotations;
- m_rcInfo.startTimeMultiplier = m_timeMultiplier;
- m_rcInfo.endTimeMultiplier = m_timeMultiplier;
- m_rcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- }
- //-------------------------------------------------------------------------------------------------
- /** Rotate the camera to follow a unit */
- //-------------------------------------------------------------------------------------------------
- void W3DView::rotateCameraTowardObject(ObjectID id, Int milliseconds, Int holdMilliseconds, Real easeIn, Real easeOut)
- {
- m_rcInfo.trackObject = TRUE;
- if (holdMilliseconds<1) holdMilliseconds = 0;
- m_rcInfo.numHoldFrames = holdMilliseconds/TheW3DFrameLengthInMsec;
- if (m_rcInfo.numHoldFrames < 1) {
- m_rcInfo.numHoldFrames = 0;
- }
- if (milliseconds<1) milliseconds = 1;
- m_rcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
- if (m_rcInfo.numFrames < 1) {
- m_rcInfo.numFrames = 1;
- }
- m_rcInfo.curFrame = 0;
- m_doingRotateCamera = true;
- m_rcInfo.target.targetObjectID = id;
- m_rcInfo.startTimeMultiplier = m_timeMultiplier;
- m_rcInfo.endTimeMultiplier = m_timeMultiplier;
- m_rcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- }
- //-------------------------------------------------------------------------------------------------
- /** Rotate camera to face a location */
- //-------------------------------------------------------------------------------------------------
- void W3DView::rotateCameraTowardPosition(const Coord3D *pLoc, Int milliseconds, Real easeIn, Real easeOut, Bool reverseRotation)
- {
- m_rcInfo.numHoldFrames = 0;
- m_rcInfo.trackObject = FALSE;
- if (milliseconds<1) milliseconds = 1;
- m_rcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
- if (m_rcInfo.numFrames < 1) {
- m_rcInfo.numFrames = 1;
- }
- Coord3D curPos = *getPosition();
- Vector2 dir(pLoc->x-curPos.x, pLoc->y-curPos.y);
- const Real dirLength = dir.Length();
- if (dirLength<0.1f) return;
- Real angle = WWMath::Acos(dir.X/dirLength);
- if (dir.Y<0.0f) {
- angle = -angle;
- }
- // Default camera is rotated 90 degrees, so match.
- angle -= PI/2;
- normAngle(angle);
- if (reverseRotation) {
- if (m_angle < angle) {
- angle -= 2.0f*WWMATH_PI;
- } else {
- angle += 2.0f*WWMATH_PI;
- }
- }
- m_rcInfo.curFrame = 0;
- m_doingRotateCamera = true;
- m_rcInfo.angle.startAngle = m_angle;
- m_rcInfo.angle.endAngle = angle;
- m_rcInfo.startTimeMultiplier = m_timeMultiplier;
- m_rcInfo.endTimeMultiplier = m_timeMultiplier;
- m_rcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::zoomCamera( Real finalZoom, Int milliseconds, Real easeIn, Real easeOut )
- {
- if (milliseconds<1) milliseconds = 1;
- m_zcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
- if (m_zcInfo.numFrames < 1) {
- m_zcInfo.numFrames = 1;
- }
- m_zcInfo.curFrame = 0;
- m_doingZoomCamera = TRUE;
- m_zcInfo.startZoom = m_zoom;
- m_zcInfo.endZoom = finalZoom;
- m_zcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DView::pitchCamera( Real finalPitch, Int milliseconds, Real easeIn, Real easeOut )
- {
- if (milliseconds<1) milliseconds = 1;
- m_pcInfo.numFrames = milliseconds/TheW3DFrameLengthInMsec;
- if (m_pcInfo.numFrames < 1) {
- m_pcInfo.numFrames = 1;
- }
- m_pcInfo.curFrame = 0;
- m_doingPitchCamera = TRUE;
- m_pcInfo.startPitch = m_FXPitch;
- m_pcInfo.endPitch = finalPitch;
- m_pcInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets the final zoom for a camera movement. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::cameraModFinalZoom( Real finalZoom, Real easeIn, Real easeOut )
- {
- if (m_doingRotateCamera)
- {
- Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
- Real maxHeight = (terrainHeightMax + m_maxHeightAboveGround);
- Real maxZoom = maxHeight / m_cameraOffset.z;
- Real time = (m_rcInfo.numFrames + m_rcInfo.numHoldFrames - m_rcInfo.curFrame)*TheW3DFrameLengthInMsec;
- zoomCamera( finalZoom*maxZoom, time, time*easeIn, time*easeOut );
- }
- if (m_doingMoveCameraOnWaypointPath)
- {
- Coord3D pos = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- Real terrainHeightMax = getHeightAroundPos(pos.x, pos.y);
- Real maxHeight = (terrainHeightMax + m_maxHeightAboveGround);
- Real maxZoom = maxHeight / m_cameraOffset.z;
- Real time = m_mcwpInfo.totalTimeMilliseconds - m_mcwpInfo.elapsedTimeMilliseconds;
- zoomCamera( finalZoom*maxZoom, time, time*easeIn, time*easeOut );
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** Sets the final zoom for a camera movement. */
- //-------------------------------------------------------------------------------------------------
- void W3DView::cameraModFreezeAngle(void)
- {
- if (m_doingRotateCamera) {
- if (m_rcInfo.trackObject) {
- m_rcInfo.target.targetObjectID = INVALID_ID;
- } else {
- m_rcInfo.angle.startAngle = m_rcInfo.angle.endAngle = m_angle; // Silly, but consistent.
- }
- }
- if (m_doingMoveCameraOnWaypointPath) {
- Int i;
- // Real curDistance = 0;
- for (i=0; i<m_mcwpInfo.numWaypoints; i++) {
- m_mcwpInfo.cameraAngle[i+1] = m_mcwpInfo.cameraAngle[0];
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Sets the look toward point for a camera movement. */
- // ------------------------------------------------------------------------------------------------
- void W3DView::cameraModLookToward(Coord3D *pLoc)
- {
- if (m_doingRotateCamera) {
- return; // Doesn't apply to rotate about a point.
- }
- if (m_doingMoveCameraOnWaypointPath) {
- Int i;
- // Real curDistance = 0;
- for (i=2; i<=m_mcwpInfo.numWaypoints; i++) {
- Coord3D start, mid, end;
- Real factor = 0.5;
- start = m_mcwpInfo.waypoints[i-1];
- start.x += m_mcwpInfo.waypoints[i].x;
- start.y += m_mcwpInfo.waypoints[i].y;
- start.x /= 2;
- start.y /= 2;
- mid = m_mcwpInfo.waypoints[i];
- end = m_mcwpInfo.waypoints[i];
- end.x += m_mcwpInfo.waypoints[i+1].x;
- end.y += m_mcwpInfo.waypoints[i+1].y;
- end.x /= 2;
- end.y /= 2;
- Coord3D result = start;
- result.x += factor*(end.x-start.x);
- result.y += factor*(end.y-start.y);
- result.x += (1-factor)*factor*(mid.x-end.x + mid.x-start.x);
- result.y += (1-factor)*factor*(mid.y-end.y + mid.y-start.y);
- result.z = 0;
- Vector2 dir(pLoc->x-result.x, pLoc->y-result.y);
- const Real dirLength = dir.Length();
- if (dirLength<0.1f) continue;
- Real angle = WWMath::Acos(dir.X/dirLength);
- if (dir.Y<0.0f) {
- angle = -angle;
- }
- // Default camera is rotated 90 degrees, so match.
- angle -= PI/2;
- normAngle(angle);
- m_mcwpInfo.cameraAngle[i] = angle;
- }
- if (m_mcwpInfo.totalTimeMilliseconds==1) {
- // do it instantly.
- moveAlongWaypointPath(1);
- m_doingMoveCameraOnWaypointPath = true;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Sets the look toward point for the end of a camera movement. */
- // ------------------------------------------------------------------------------------------------
- void W3DView::cameraModFinalMoveTo(Coord3D *pLoc)
- {
- if (m_doingRotateCamera) {
- return; // Doesn't apply to rotate about a point.
- }
- if (m_doingMoveCameraOnWaypointPath) {
- Int i;
- Coord3D start, delta;
- start = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- delta.x = pLoc->x - start.x;
- delta.y = pLoc->y - start.y;
- for (i=2; i<=m_mcwpInfo.numWaypoints; i++) {
- Coord3D result = m_mcwpInfo.waypoints[i];
- result.x += delta.x;
- result.y += delta.y;
- m_mcwpInfo.waypoints[i] = result;
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Sets the look toward point for the end of a camera movement. */
- // ------------------------------------------------------------------------------------------------
- void W3DView::cameraModFinalLookToward(Coord3D *pLoc)
- {
- if (m_doingRotateCamera) {
- return; // Doesn't apply to rotate about a point.
- }
- if (m_doingMoveCameraOnWaypointPath) {
- Int i;
- Int min = m_mcwpInfo.numWaypoints-1;
- if (min<2) min=2;
- // Real curDistance = 0;
- for (i=min; i<=m_mcwpInfo.numWaypoints; i++) {
- Coord3D start, mid, end;
- Real factor = 0.5;
- start = m_mcwpInfo.waypoints[i-1];
- start.x += m_mcwpInfo.waypoints[i].x;
- start.y += m_mcwpInfo.waypoints[i].y;
- start.x /= 2;
- start.y /= 2;
- mid = m_mcwpInfo.waypoints[i];
- end = m_mcwpInfo.waypoints[i];
- end.x += m_mcwpInfo.waypoints[i+1].x;
- end.y += m_mcwpInfo.waypoints[i+1].y;
- end.x /= 2;
- end.y /= 2;
- Coord3D result = start;
- result.x += factor*(end.x-start.x);
- result.y += factor*(end.y-start.y);
- result.x += (1-factor)*factor*(mid.x-end.x + mid.x-start.x);
- result.y += (1-factor)*factor*(mid.y-end.y + mid.y-start.y);
- result.z = 0;
- Vector2 dir(pLoc->x-result.x, pLoc->y-result.y);
- const Real dirLength = dir.Length();
- if (dirLength<0.1f) continue;
- Real angle = WWMath::Acos(dir.X/dirLength);
- if (dir.Y<0.0f) {
- angle = -angle;
- }
- // Default camera is rotated 90 degrees, so match.
- angle -= PI/2;
- normAngle(angle);
- if (i==m_mcwpInfo.numWaypoints) {
- m_mcwpInfo.cameraAngle[i] = angle;
- } else {
- Real deltaAngle = angle - m_mcwpInfo.cameraAngle[i];
- normAngle(deltaAngle);
- angle = m_mcwpInfo.cameraAngle[i] + deltaAngle/2;
- normAngle(angle);
- m_mcwpInfo.cameraAngle[i] = angle;
- }
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Sets the final time multiplier for a camera movement. */
- // ------------------------------------------------------------------------------------------------
- void W3DView::cameraModFinalTimeMultiplier(Int finalMultiplier)
- {
- if (m_doingZoomCamera)
- m_zcInfo.endTimeMultiplier = finalMultiplier;
- if (m_doingPitchCamera)
- m_pcInfo.endTimeMultiplier = finalMultiplier;
- if (m_doingRotateCamera) {
- m_rcInfo.endTimeMultiplier = finalMultiplier;
- } else if (m_doingMoveCameraOnWaypointPath) {
- Int i;
- Real curDistance = 0;
- for (i=0; i<m_mcwpInfo.numWaypoints; i++) {
- curDistance += m_mcwpInfo.waySegLength[i];
- Real factor2 = curDistance / m_mcwpInfo.totalDistance;
- Real factor1 = 1.0-factor2;
- m_mcwpInfo.timeMultiplier[i+1] = REAL_TO_INT_FLOOR(0.5+m_mcwpInfo.timeMultiplier[i+1]*factor1 + finalMultiplier*factor2);
- }
- } else {
- // If we aren't doing a camera movement, just set the time.
- m_timeMultiplier = finalMultiplier;
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Sets the number of frames to average motion for a camera movement */
- // ------------------------------------------------------------------------------------------------
- void W3DView::cameraModRollingAverage(Int framesToAverage)
- {
- if (framesToAverage < 1) framesToAverage = 1;
- m_mcwpInfo.rollingAverageFrames = framesToAverage;
- }
-
- // ------------------------------------------------------------------------------------------------
- /** Sets the final pitch for a camera movement. */
- // ------------------------------------------------------------------------------------------------
- void W3DView::cameraModFinalPitch(Real finalPitch, Real easeIn, Real easeOut) {
- if (m_doingRotateCamera) {
- Real time = (m_rcInfo.numFrames + m_rcInfo.numHoldFrames - m_rcInfo.curFrame)*TheW3DFrameLengthInMsec;
- pitchCamera( finalPitch, time, time*easeIn, time*easeOut );
- }
- if (m_doingMoveCameraOnWaypointPath) {
- Real time = m_mcwpInfo.totalTimeMilliseconds - m_mcwpInfo.elapsedTimeMilliseconds;
- pitchCamera( finalPitch, time, time*easeIn, time*easeOut );
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** Move camera to a waypoint, resetting the default angle, pitch & zoom along the way.. */
- // ------------------------------------------------------------------------------------------------
- void W3DView::resetCamera(const Coord3D *location, Int milliseconds, Real easeIn, Real easeOut)
- {
- moveCameraTo(location, milliseconds, 0, false, easeIn, easeOut);
- m_mcwpInfo.cameraAngle[2] = 0.0; // default angle.
- // m_mcwpInfo.cameraAngle[2] = m_defaultAngle;
- m_angle = m_mcwpInfo.cameraAngle[0];
- // terrain height + desired height offset == cameraOffset * actual zoom
- // find best approximation of max terrain height we can see
- //Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
- Real terrainHeightMax = getHeightAroundPos(location->x, location->y);
- Real desiredHeight = (terrainHeightMax + m_maxHeightAboveGround);
- Real desiredZoom = desiredHeight / m_cameraOffset.z;
- zoomCamera( desiredZoom, milliseconds, easeIn, easeOut ); // this isn't right... or is it?
- pitchCamera( 1.0, milliseconds, easeIn, easeOut );
- // pitchCamera( m_defaultPitchAngle, milliseconds, easeIn, easeOut );
- //DEBUG_LOG(("W3DView::resetCamera() Current zoom: %g Desired zoom: %g Current pitch: %g Desired pitch: %g\n",
- // m_zoom, desiredZoom, m_pitchAngle, m_defaultPitchAngle));
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool W3DView::isCameraMovementFinished(void)
- {
- if (m_viewFilter == FT_VIEW_MOTION_BLUR_FILTER) {
- // Several of the motion blur effects are similar to camera movements.
- if (m_viewFilterMode == FM_VIEW_MB_IN_AND_OUT_ALPHA ||
- m_viewFilterMode == FM_VIEW_MB_IN_AND_OUT_SATURATE ||
- m_viewFilterMode == FM_VIEW_MB_IN_ALPHA ||
- m_viewFilterMode == FM_VIEW_MB_OUT_ALPHA ||
- m_viewFilterMode == FM_VIEW_MB_IN_SATURATE ||
- m_viewFilterMode == FM_VIEW_MB_OUT_SATURATE ) {
- return true;
- }
- }
- return !m_doingMoveCameraOnWaypointPath && !m_doingRotateCamera && !m_doingPitchCamera && !m_doingZoomCamera;
- }
- Bool W3DView::isCameraMovementAtWaypointAlongPath(void)
- {
- // WWDEBUG_SAY((( "MBL: Polling W3DView::isCameraMovementAtWaypointAlongPath\n" )));
-
- Bool return_value = m_CameraArrivedAtWaypointOnPathFlag;
- #pragma message( "MBL: Clearing variable after polling - for scripting - see Adam.\n" )
- m_CameraArrivedAtWaypointOnPathFlag = false;
- return( return_value );
- }
- // ------------------------------------------------------------------------------------------------
- /** Move camera along a waypoint path in an interesting fashion. Sets up parameters that get
- * evaluated in draw(). */
- // ------------------------------------------------------------------------------------------------
- void W3DView::moveCameraAlongWaypointPath(Waypoint *pWay, Int milliseconds, Int shutter, Bool orient, Real easeIn, Real easeOut)
- {
- const Real MIN_DELTA = MAP_XY_FACTOR;
- m_mcwpInfo.waypoints[0] = *getPosition();
- m_mcwpInfo.cameraAngle[0] = getAngle();
- m_mcwpInfo.waySegLength[0] = 0;
- m_mcwpInfo.waypoints[1] = *getPosition();
- m_mcwpInfo.numWaypoints = 1;
- if (milliseconds<1) milliseconds = 1;
- m_mcwpInfo.totalTimeMilliseconds = milliseconds;
- m_mcwpInfo.shutter = shutter/TheW3DFrameLengthInMsec;
- if (m_mcwpInfo.shutter<1) m_mcwpInfo.shutter = 1;
- m_mcwpInfo.ease.setEaseTimes(easeIn/milliseconds, easeOut/milliseconds);
- while (pWay && m_mcwpInfo.numWaypoints <MAX_WAYPOINTS) {
- m_mcwpInfo.numWaypoints++;
- m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints] = *pWay->getLocation();
- if (pWay->getNumLinks()>0) {
- pWay = pWay->getLink(0);
- } else {
- pWay = NULL;
- }
- 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);
- if (dir.Length()<MIN_DELTA) {
- if (pWay) {
- m_mcwpInfo.numWaypoints--; // drop this one.
- } else {
- m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints-1] = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- m_mcwpInfo.numWaypoints--; // Push this one back.
- }
- }
- }
- setupWaypointPath(orient);
- }
- // ------------------------------------------------------------------------------------------------
- /** Calculates angles and distances for moving along a waypoint path. Sets up parameters that get
- * evaluated in draw(). */
- // ------------------------------------------------------------------------------------------------
- void W3DView::setupWaypointPath(Bool orient)
- {
- m_mcwpInfo.curSegment = 1;
- m_mcwpInfo.curSegDistance = 0;
- m_mcwpInfo.totalDistance = 0;
- m_mcwpInfo.rollingAverageFrames = 1;
- Int i;
- Real angle = getAngle();
- for (i=1; i<m_mcwpInfo.numWaypoints; i++) {
- Vector2 dir(m_mcwpInfo.waypoints[i+1].x-m_mcwpInfo.waypoints[i].x, m_mcwpInfo.waypoints[i+1].y-m_mcwpInfo.waypoints[i].y);
- m_mcwpInfo.waySegLength[i] = dir.Length();
- m_mcwpInfo.totalDistance += m_mcwpInfo.waySegLength[i];
- if (orient) {
- angle = WWMath::Acos(dir.X/m_mcwpInfo.waySegLength[i]);
- if (dir.Y<0.0f) {
- angle = -angle;
- }
- // Default camera is rotated 90 degrees, so match.
- angle -= PI/2;
- normAngle(angle);
- }
- //DEBUG_LOG(("Original Index %d, angle %.2f\n", i, angle*180/PI));
- m_mcwpInfo.cameraAngle[i] = angle;
- }
- m_mcwpInfo.cameraAngle[1] = getAngle();
- m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints] = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints-1];
- for (i=m_mcwpInfo.numWaypoints-1; i>1; i--) {
- m_mcwpInfo.cameraAngle[i] = (m_mcwpInfo.cameraAngle[i] + m_mcwpInfo.cameraAngle[i-1]) / 2;
- }
- m_mcwpInfo.waySegLength[m_mcwpInfo.numWaypoints+1] = m_mcwpInfo.waySegLength[m_mcwpInfo.numWaypoints];
- // Prevent a possible divide by zero.
- if (m_mcwpInfo.totalDistance<1.0) {
- m_mcwpInfo.waySegLength[m_mcwpInfo.numWaypoints-1] += 1.0-m_mcwpInfo.totalDistance;
- m_mcwpInfo.totalDistance = 1.0;
- }
- Real curDistance = 0;
- Coord3D finalPos = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- Real newGround = TheTerrainLogic->getGroundHeight(finalPos.x, finalPos.y);
- for (i=0; i<=m_mcwpInfo.numWaypoints+1; i++) {
- Real factor2 = curDistance / m_mcwpInfo.totalDistance;
- Real factor1 = 1.0-factor2;
- m_mcwpInfo.timeMultiplier[i] = m_timeMultiplier;
- m_mcwpInfo.groundHeight[i] = m_groundLevel*factor1 + newGround*factor2;
- curDistance += m_mcwpInfo.waySegLength[i];
- //DEBUG_LOG(("New Index %d, angle %.2f\n", i, m_mcwpInfo.cameraAngle[i]*180/PI));
- }
- // Pad the end.
- m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints+1] = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- Coord3D cur = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- Coord3D prev = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints-1];
- m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints+1].x += cur.x-prev.x;
- m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints+1].y += cur.y-prev.y;
- m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints+1] = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints];
- m_mcwpInfo.groundHeight[m_mcwpInfo.numWaypoints+1] = newGround;
- cur = m_mcwpInfo.waypoints[2];
- prev = m_mcwpInfo.waypoints[1];
- m_mcwpInfo.waypoints[0].x -= cur.x-prev.x;
- m_mcwpInfo.waypoints[0].y -= cur.y-prev.y;
- m_doingMoveCameraOnWaypointPath = m_mcwpInfo.numWaypoints>1;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_doingRotateCamera = false;
- m_mcwpInfo.elapsedTimeMilliseconds = 0;
- m_mcwpInfo.curShutter = m_mcwpInfo.shutter;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- static Real makeQuadraticS(Real t)
- {
- // for t = linear 0-1, convert to quadratic s where 0==0, 0.5==0.5 && 1.0 == 1.0.
- Real tPrime = t;
- if (t<0.5) {
- tPrime = 0.5 * (2*t*2*t);
- } else {
- tPrime = (t-0.5)*2;
- tPrime = WWMath::Sqrt(tPrime);
- tPrime = 0.5 + 0.5*(tPrime);
- }
- return tPrime*0.5 + t*0.5;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::rotateCameraOneFrame(void)
- {
- m_rcInfo.curFrame++;
- if (TheGlobalData->m_disableCameraMovement) {
- if (m_rcInfo.curFrame >= m_rcInfo.numFrames + m_rcInfo.numHoldFrames) {
- m_doingRotateCamera = false;
- m_freezeTimeForCameraMovement = false;
- }
- return;
- }
- if (m_rcInfo.trackObject)
- {
- if (m_rcInfo.curFrame <= m_rcInfo.numFrames + m_rcInfo.numHoldFrames)
- {
- const Object *obj = TheGameLogic->findObjectByID(m_rcInfo.target.targetObjectID);
- if (obj)
- {
- // object has not been destroyed
- m_rcInfo.target.targetObjectPos = *obj->getPosition();
- }
- const Vector2 dir(m_rcInfo.target.targetObjectPos.x - m_pos.x, m_rcInfo.target.targetObjectPos.y - m_pos.y);
- const Real dirLength = dir.Length();
- if (dirLength>=0.1f)
- {
- Real angle = WWMath::Acos(dir.X/dirLength);
- if (dir.Y<0.0f) {
- angle = -angle;
- }
- // Default camera is rotated 90 degrees, so match.
- angle -= PI/2;
- normAngle(angle);
- if (m_rcInfo.curFrame <= m_rcInfo.numFrames)
- {
- Real factor = m_rcInfo.ease(((Real)m_rcInfo.curFrame)/m_rcInfo.numFrames);
- Real angleDiff = angle - m_angle;
- normAngle(angleDiff);
- angleDiff *= factor;
- m_angle += angleDiff;
- normAngle(m_angle);
- m_timeMultiplier = m_rcInfo.startTimeMultiplier + REAL_TO_INT_FLOOR(0.5 + (m_rcInfo.endTimeMultiplier-m_rcInfo.startTimeMultiplier)*factor);
- }
- else
- {
- m_angle = angle;
- }
- }
- }
- }
- else if (m_rcInfo.curFrame <= m_rcInfo.numFrames)
- {
- Real factor = m_rcInfo.ease(((Real)m_rcInfo.curFrame)/m_rcInfo.numFrames);
- m_angle = WWMath::Lerp(m_rcInfo.angle.startAngle, m_rcInfo.angle.endAngle, factor);
- normAngle(m_angle);
- m_timeMultiplier = m_rcInfo.startTimeMultiplier + REAL_TO_INT_FLOOR(0.5 + (m_rcInfo.endTimeMultiplier-m_rcInfo.startTimeMultiplier)*factor);
- }
- if (m_rcInfo.curFrame >= m_rcInfo.numFrames + m_rcInfo.numHoldFrames) {
- m_doingRotateCamera = false;
- m_freezeTimeForCameraMovement = false;
- if (! m_rcInfo.trackObject)
- {
- m_angle = m_rcInfo.angle.endAngle;
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::zoomCameraOneFrame(void)
- {
- m_zcInfo.curFrame++;
- if (TheGlobalData->m_disableCameraMovement) {
- if (m_zcInfo.curFrame >= m_zcInfo.numFrames) {
- m_doingZoomCamera = false;
- }
- return;
- }
- if (m_zcInfo.curFrame <= m_zcInfo.numFrames)
- {
- // not just holding; do the camera adjustment
- Real factor = m_zcInfo.ease(((Real)m_zcInfo.curFrame)/m_zcInfo.numFrames);
- m_zoom = WWMath::Lerp(m_zcInfo.startZoom, m_zcInfo.endZoom, factor);
- }
- if (m_zcInfo.curFrame >= m_zcInfo.numFrames) {
- m_doingZoomCamera = false;
- m_zoom = m_zcInfo.endZoom;
- }
- //DEBUG_LOG(("W3DView::zoomCameraOneFrame() - m_zoom = %g\n", m_zoom));
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::pitchCameraOneFrame(void)
- {
- m_pcInfo.curFrame++;
- if (TheGlobalData->m_disableCameraMovement) {
- if (m_pcInfo.curFrame >= m_pcInfo.numFrames) {
- m_doingPitchCamera = false;
- }
- return;
- }
- if (m_pcInfo.curFrame <= m_pcInfo.numFrames)
- {
- // not just holding; do the camera adjustment
- Real factor = m_pcInfo.ease(((Real)m_pcInfo.curFrame)/m_pcInfo.numFrames);
- m_FXPitch = WWMath::Lerp(m_pcInfo.startPitch, m_pcInfo.endPitch, factor);
- }
- if (m_pcInfo.curFrame >= m_pcInfo.numFrames) {
- m_doingPitchCamera = false;
- m_FXPitch = m_pcInfo.endPitch;
- }
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DView::moveAlongWaypointPath(Int milliseconds)
- {
- m_mcwpInfo.elapsedTimeMilliseconds += milliseconds;
- if (TheGlobalData->m_disableCameraMovement) {
- if (m_mcwpInfo.elapsedTimeMilliseconds>m_mcwpInfo.totalTimeMilliseconds) {
- m_doingMoveCameraOnWaypointPath = false;
- m_freezeTimeForCameraMovement = false;
- }
- return;
- }
- if (m_mcwpInfo.elapsedTimeMilliseconds>m_mcwpInfo.totalTimeMilliseconds) {
- m_doingMoveCameraOnWaypointPath = false;
- m_CameraArrivedAtWaypointOnPathFlag = false;
- m_freezeTimeForCameraMovement = false;
- m_angle = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints];
- m_groundLevel = m_mcwpInfo.groundHeight[m_mcwpInfo.numWaypoints];
- /////////////////////m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight;
- m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
- m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
- Coord3D pos = m_mcwpInfo.waypoints[m_mcwpInfo.numWaypoints];
- pos.z = 0;
- setPosition(&pos);
- // Note - assuming that the scripter knows what he is doing, we adjust the constraints so that
- // the scripted action can occur.
- m_cameraConstraint.lo.x = minf(m_cameraConstraint.lo.x, pos.x);
- m_cameraConstraint.hi.x = maxf(m_cameraConstraint.hi.x, pos.x);
- m_cameraConstraint.lo.y = minf(m_cameraConstraint.lo.y, pos.y);
- m_cameraConstraint.hi.y = maxf(m_cameraConstraint.hi.y, pos.y);
- return;
- }
- const Real totalTime = m_mcwpInfo.totalTimeMilliseconds;
- const Real deltaTime = m_mcwpInfo.ease(m_mcwpInfo.elapsedTimeMilliseconds/totalTime) -
- m_mcwpInfo.ease((m_mcwpInfo.elapsedTimeMilliseconds - milliseconds)/totalTime);
- m_mcwpInfo.curSegDistance += deltaTime*m_mcwpInfo.totalDistance;
- while (m_mcwpInfo.curSegDistance >= m_mcwpInfo.waySegLength[m_mcwpInfo.curSegment]) {
- if ( m_doingMoveCameraOnWaypointPath )
- {
- //WWDEBUG_SAY(( "MBL TEST: Camera waypoint along path reached!\n" ));
- m_CameraArrivedAtWaypointOnPathFlag = true;
- }
- m_mcwpInfo.curSegDistance -= m_mcwpInfo.waySegLength[m_mcwpInfo.curSegment];
- m_mcwpInfo.curSegment++;
- if (m_mcwpInfo.curSegment >= m_mcwpInfo.numWaypoints) {
- m_mcwpInfo.totalTimeMilliseconds = 0; // Will end following next frame.
- return;
- }
- }
- Real avgFactor = 1.0/m_mcwpInfo.rollingAverageFrames;
- m_mcwpInfo.curShutter--;
- if (m_mcwpInfo.curShutter>0) {
- return;
- }
- m_mcwpInfo.curShutter = m_mcwpInfo.shutter;
- Real factor = m_mcwpInfo.curSegDistance / m_mcwpInfo.waySegLength[m_mcwpInfo.curSegment];
- if (m_mcwpInfo.curSegment == m_mcwpInfo.numWaypoints-1) {
- avgFactor = avgFactor + (1.0-avgFactor)*factor;
- }
- Real factor1;
- Real factor2;
- factor1 = 1.0-factor;
- //factor1 = makeQuadraticS(factor1);
- factor2 = 1.0-factor1;
- Real angle1 = m_mcwpInfo.cameraAngle[m_mcwpInfo.curSegment];
- Real angle2 = m_mcwpInfo.cameraAngle[m_mcwpInfo.curSegment+1];
- if (angle2-angle1 > PI) angle1 += 2*PI;
- if (angle2-angle1 < -PI) angle1 -= 2*PI;
- Real angle = angle1 * (factor1) + angle2 * (factor2);
- normAngle(angle);
- Real deltaAngle = angle-m_angle;
- normAngle(deltaAngle);
- if (fabs(deltaAngle) > PI/10) {
- DEBUG_LOG(("Huh.\n"));
- }
- m_angle += avgFactor*(deltaAngle);
- normAngle(m_angle);
- Real timeMultiplier = m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment]*factor1 +
- m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment+1]*factor2;
- m_timeMultiplier = REAL_TO_INT_FLOOR(0.5 + timeMultiplier);
- m_groundLevel = m_mcwpInfo.groundHeight[m_mcwpInfo.curSegment]*factor1 +
- m_mcwpInfo.groundHeight[m_mcwpInfo.curSegment+1]*factor2;
- //////////////m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight;
- m_cameraOffset.y = -(m_cameraOffset.z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
- m_cameraOffset.x = -(m_cameraOffset.y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
- Coord3D start, mid, end;
- if (factor<0.5) {
- start = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment-1];
- start.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment].x;
- start.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment].y;
- start.x /= 2;
- start.y /= 2;
- mid = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment];
- end = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment];
- end.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].x;
- end.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].y;
- end.x /= 2;
- end.y /= 2;
- factor += 0.5;
- } else {
- start = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment];
- start.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].x;
- start.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1].y;
- start.x /= 2;
- start.y /= 2;
- mid = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1];
- end = m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+1];
- end.x += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+2].x;
- end.y += m_mcwpInfo.waypoints[m_mcwpInfo.curSegment+2].y;
- end.x /= 2;
- end.y /= 2;
- factor -= 0.5;
- }
- Coord3D result = start;
- result.x += factor*(end.x-start.x);
- result.y += factor*(end.y-start.y);
- result.x += (1-factor)*factor*(mid.x-end.x + mid.x-start.x);
- result.y += (1-factor)*factor*(mid.y-end.y + mid.y-start.y);
- result.z = 0;
- /*
- static Real prevGround = 0;
- 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));
- prevGround = m_groundLevel;
- */
- setPosition(&result);
- // Note - assuming that the scripter knows what he is doing, we adjust the constraints so that
- // the scripted action can occur.
- m_cameraConstraint.lo.x = minf(m_cameraConstraint.lo.x, result.x);
- m_cameraConstraint.hi.x = maxf(m_cameraConstraint.hi.x, result.x);
- m_cameraConstraint.lo.y = minf(m_cameraConstraint.lo.y, result.y);
- m_cameraConstraint.hi.y = maxf(m_cameraConstraint.hi.y, result.y);
- }
- // ------------------------------------------------------------------------------------------------
- /** Add an impulse force to shake the camera.
- * The camera shake is a simple simulation of an oscillating spring/damper.
- * The idea is that some sort of shock has "pushed" the camera once, as an
- * impluse, after which the camera vibrates back to its rest position.
- * @todo This should be part of "View", not "W3DView". */
- // ------------------------------------------------------------------------------------------------
- void W3DView::shake( const Coord3D *epicenter, CameraShakeType shakeType )
- {
- Real angle = GameClientRandomValueReal( 0, 2*PI );
- m_shakeAngleCos = (Real)cos( angle );
- m_shakeAngleSin = (Real)sin( angle );
- Real intensity = 0.0f;
- switch( shakeType )
- {
- case SHAKE_SUBTLE:
- intensity = TheGlobalData->m_shakeSubtleIntensity;
- break;
- case SHAKE_NORMAL:
- intensity = TheGlobalData->m_shakeNormalIntensity;
- break;
- case SHAKE_STRONG:
- intensity = TheGlobalData->m_shakeStrongIntensity;
- break;
- case SHAKE_SEVERE:
- intensity = TheGlobalData->m_shakeSevereIntensity;
- break;
-
- case SHAKE_CINE_EXTREME:
- intensity = TheGlobalData->m_shakeCineExtremeIntensity;
- break;
- case SHAKE_CINE_INSANE:
- intensity = TheGlobalData->m_shakeCineInsaneIntensity;
- break;
- }
- // intensity falls off with distance
- const Coord3D *viewPos = getPosition();
- Coord3D d;
- d.x = epicenter->x - viewPos->x;
- d.y = epicenter->y - viewPos->y;
- /// @todo make this 3D once we have the real "lookat" spot
- //d.z = epicenter->z - viewPos->z;
- Real dist = (Real)sqrt( d.x*d.x + d.y*d.y );
- if (dist > TheGlobalData->m_maxShakeRange)
- return;
- intensity *= 1.0f - (dist/TheGlobalData->m_maxShakeRange);
- // add intensity and clamp
- m_shakeIntensity += intensity;
- //const Real maxIntensity = 10.0f;
- const Real maxIntensity = 3.0f;
- if (m_shakeIntensity > TheGlobalData->m_maxShakeIntensity)
- m_shakeIntensity = maxIntensity;
- }
- //-------------------------------------------------------------------------------------------------
- /** Transformt he screen pixel coord passed in, to a world coordinate at the specified
- * z value */
- //-------------------------------------------------------------------------------------------------
- void W3DView::screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z )
- {
- Vector3 rayStart, rayEnd;
-
- getPickRay( s, &rayStart, &rayEnd );
- w->x = Vector3::Find_X_At_Z( z, rayStart, rayEnd );
- w->y = Vector3::Find_Y_At_Z( z, rayStart, rayEnd );
- w->z = z;
- } // end screenToWorldAtZ
- void W3DView::cameraEnableSlaveMode(const AsciiString & objectName, const AsciiString & boneName)
- {
- m_isCameraSlaved = true;
- m_cameraSlaveObjectName = objectName;
- m_cameraSlaveObjectBoneName = boneName;
- }
- void W3DView::cameraDisableSlaveMode(void)
- {
- m_isCameraSlaved = false;
- }
- void W3DView::cameraEnableRealZoomMode(void) //WST added 10/18/2002
- {
- m_useRealZoomCam = true;
- m_FXPitch = 1.0f; //Reset to default
- //m_zoom = 1.0f;
- updateView();
- }
- void W3DView::cameraDisableRealZoomMode(void) //WST added 10/18/2002
- {
- m_useRealZoomCam = false;
- m_FXPitch = 1.0f; //Reset to default
- //m_zoom = 1.0f;
- m_FOV = 50.0f * PI/180.0f;
- setCameraTransform();
- updateView();
- }
- void W3DView::Add_Camera_Shake (const Coord3D & position,float radius,float duration,float power) //WST added 11/13/02
- {
- Vector3 vpos;
- vpos.X = position.x;
- vpos.Y = position.y;
- vpos.Z = position.z;
- CameraShakerSystem.Add_Camera_Shake(vpos,radius,duration,power);
- }
|