1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <nel/misc/types_nl.h>
21 #include "snowballs_client.h"
22 #include "snowballs_config.h"
29 #if defined(NL_OS_WINDOWS)
35 #include <nel/misc/config_file.h>
36 #include <nel/misc/path.h>
37 #include <nel/misc/debug.h>
38 #include <nel/misc/md5.h>
39 #include <nel/misc/path.h>
40 #include <nel/misc/file.h>
41 #include <nel/misc/vectord.h>
42 #include <nel/misc/time_nl.h>
43 #include <nel/misc/command.h>
44 #include <nel/misc/config_file.h>
45 #include <nel/net/login_client.h>
46 #include <nel/3d/u_scene.h>
47 #include <nel/3d/u_camera.h>
48 #include <nel/3d/u_driver.h>
49 #include <nel/3d/u_texture.h>
50 #include <nel/3d/u_instance.h>
51 #include <nel/3d/u_material.h>
52 #include <nel/3d/u_text_context.h>
53 #include <nel/3d/bloom_effect.h>
54 #include <nel/3d/fxaa.h>
55 #if SBCLIENT_DEV_STEREO
56 # include <nel/3d/stereo_render.h>
57 #endif /* #if SBCLIENT_DEV_STEREO */
58 #include <nel/3d/stereo_hmd.h>
69 #include "landscape.h"
70 #include "animation.h"
71 #include "interface.h"
72 #include "lens_flare.h"
73 #include "mouse_listener.h"
75 #include "configuration.h"
76 #include "internationalization.h"
77 #include "game_time.h"
84 using namespace NLMISC
;
86 using namespace NLNET
;
90 /*******************************************************************
92 *******************************************************************/
94 void CGlobals::assertNull()
96 // extra verification against stupid typos
99 nlassert(!TextContext
);
100 nlassert(!ConfigFile
);
101 nlassert(!Landscape
);
102 nlassert(!MouseListener
);
106 NL3D::UDriver
*Driver
= NULL
; // core
107 // This is the main scene
108 NL3D::UScene
*Scene
= NULL
; // ingame
109 // This variable is used to display text on the screen
110 NL3D::UTextContext
*TextContext
= NULL
; // core
111 // This class contains all variables that are in the snowballs_client.cfg
112 NLMISC::CConfigFile
*ConfigFile
= NULL
; // core
113 NL3D::ULandscape
*Landscape
= NULL
; // ingame
114 // This class is used to handle mouse/keyboard input for camera movement
115 C3dMouseListener
*MouseListener
= NULL
; // ingame
117 //CFileDisplayer FileDisplayer; // main
119 // stuff not initialized
120 // The previous and current frame dates
121 NLMISC::TLocalTime LocalTime
;
122 NLMISC::TLocalTime LocalTimeDelta
;
123 // NLMISC::TLocalTime ServerTime;
124 // NLMISC::TLocalTime ServerTimeDelta;
125 // NLMISC::TGameTime GameTime;
126 // NLMISC::TGameTime GameTimeDelta;
127 // NLMISC::TGameCycle GameCycle;
128 // NLMISC::TGameCycle GameCycleDelta;
129 NL3D::TGlobalAnimationTime AnimationTime
;
130 NL3D::TAnimationTime AnimationTimeDelta
;
131 float FramesPerSecond
;
132 float FramesPerSecondSmooth
;
134 // Stuff for connection
136 static string FSAddr
, Cookie
;
138 /*******************************************************************
140 *******************************************************************/
142 static CFileDisplayer
*_FileDisplayer
= NULL
;
143 static const uint8 GameStateLoad
= 0, GameStateUnload
= 1, GameStateReset
= 2, GameStateExit
= 3,
144 GameStateLogin
= 4, GameStateOnline
= 5, GameStateOffline
= 6;
146 // true if the commands(chat) interface must be display. This variable is set automatically with the config file
147 static bool ShowCommands
; // ingame
148 // if true, the mouse can't go out the client window(work only on Windows)
149 static bool CaptureState
= false; // ingame
150 // Set NextGameState to switch the current game state
151 static uint8 CurrentGameState
= -1, NextGameState
= 0; // state
152 // To know which data has been loaded
153 static bool LoadedCore
= false, LoadedIngame
= false, LoadedLogin
= false,
154 LoadedOnline
= false, LoadedOffline
= false; // state
156 #if SBCLIENT_DEV_STEREO
157 static IStereoRender
*_StereoRender
= NULL
;
158 #endif /* #if SBCLIENT_DEV_STEREO */
160 static bool s_EnableBloom
= false;
161 static CFXAA
*s_FXAA
= NULL
;
167 void initLoadingState();
168 void releaseLoadingState();
169 void renderLoadingState(const char *state
, bool logo3d
);
170 void updateLoadingState(const char *state
, bool network
, bool information
);
171 void displayLoadingState(const char *state
);
172 void renderLoadingState(ucstring state
, bool logo3d
);
173 void updateLoadingState(ucstring state
, bool network
, bool information
);
174 void displayLoadingState(ucstring state
);
176 void renderInformation();
177 void switchGameState();
187 void releaseIngame();
188 void releaseOnline();
189 void releaseOffline();
190 void cbGraphicsDriver(CConfigFile::CVar
&var
);
191 void cbSquareBloom(CConfigFile::CVar
&var
);
192 void cbDensityBloom(CConfigFile::CVar
&var
);
193 void cbEnableBloom(CConfigFile::CVar
&var
);
194 void cbEnableFXAA(CConfigFile::CVar
&var
);
200 void switchGameState()
203 nlinfo("Switching to the next game state");
204 if (CurrentGameState
== NextGameState
)
206 nlwarning("NextGameState wasn't changed");
210 switch(CurrentGameState
)
212 case GameStateOnline
:
213 releaseOnline(); // always release online after switch
215 case GameStateOffline
:
216 releaseOffline(); // always releaes offline after switch
219 switch(NextGameState
)
224 initCore(); // core is required
226 catch (NLMISC::Exception e
)
229 MessageBox(NULL
, e
.what(), "NeL Exception", MB_OK
| MB_ICONSTOP
);
231 printf("%s\n", e
.what());
233 return; // exit if driver loading failed
236 case GameStateUnload
:
237 displayLoadingState("Unloading");
238 releaseLogin(); // release all
242 displayLoadingState("Reset");
243 releaseLogin(); // release all
248 displayLoadingState("See you later!");
249 releaseLogin(); // release all
254 initCore(); // core is required
255 initLogin(); // login is required
257 case GameStateOnline
:
258 initCore(); // core is required
259 releaseLogin(); //login can be released
260 initIngame(); // ingame is required
261 initOnline(); // connection is required
263 case GameStateOffline
:
264 initCore(); // core is required
265 releaseLogin(); //login can be released
266 initIngame(); // ingame is required
267 initOffline(); // offline entity required
271 CurrentGameState
= NextGameState
;
272 switch(CurrentGameState
)
274 case GameStateLoad
: // switch to the default state
275 NextGameState
= GameStateLogin
;
277 case GameStateUnload
: // test state, switch back to load for default
278 NextGameState
= GameStateLoad
;
280 case GameStateReset
: // used to reset everything
281 NextGameState
= GameStateLoad
;
283 case GameStateExit
: // exit the loop
285 case GameStateLogin
: // loop the login screen
286 loopLogin(); // must loop by itself
288 case GameStateOnline
: // start offline if not online
291 NextGameState
= GameStateOffline
;
294 case GameStateOffline
: // loop ingame
295 loopIngame(); // must loop by itself
298 goto SwitchNextGameState
;
306 // Seed the randomizer
307 srand(uint(time(0)));
308 // Load configuration file, set paths, extension remapping
309 CConfiguration::init();
310 // Load language file
311 CInternationalization::init();
312 // Start timing system
314 // Set the ShowCommands with the value set in the client config file
315 ShowCommands
= ConfigFile
->getVar("ShowCommands").asInt() == 1;
317 Driver
= UDriver::createDriver(0, ConfigFile
->getVar("OpenGL").asInt() == 0);
318 // Create the window with config file values
319 Driver
->setDisplay(UDriver::CMode(ConfigFile
->getVar("ScreenWidth").asInt(),
320 ConfigFile
->getVar("ScreenHeight").asInt(),
321 ConfigFile
->getVar("ScreenDepth").asInt(),
322 (ConfigFile
->getVar("OpenGL").asInt() == 1 ? true : ConfigFile
->getVar("ScreenFull").asInt()==0)));
323 // Set the cache size for the font manager(in bytes)
324 Driver
->setFontManagerMaxMemory(2097152);
325 // Create a Text context for later text rendering
326 displayLoadingState("Initialize Text");
327 if (ConfigFile
->getVar("OpenGL").asInt() == 1)
328 Driver
->setMode(UDriver::CMode(ConfigFile
->getVar("ScreenWidth").asInt(),
329 ConfigFile
->getVar("ScreenHeight").asInt(),
330 ConfigFile
->getVar("ScreenDepth").asInt(),
331 ConfigFile
->getVar("ScreenFull").asInt()==0));
332 TextContext
= Driver
->createTextContext(CPath::lookup(ConfigFile
->getVar("FontName").asString()));
333 TextContext
->setShaded(true);
334 TextContext
->setShadeOutline(false);
335 TextContext
->setKeep800x600Ratio(false);
336 // You can't call displayLoadingState() before init the loading state system
337 displayLoadingState("Initialize Loading");
339 // Initialize sound for loading screens etc
340 displayLoadingState("Initialize Sound");
342 playMusic(SBCLIENT_MUSIC_WAIT
);
343 // Required for 3d rendering (3d nel logo etc)
344 displayLoadingState("Initialize Light");
346 #if SBCLIENT_DEV_STEREO
347 displayLoadingState("Initialize Stereo Renderer");
348 _StereoRender
= Driver
->createStereoRender();
349 _StereoRender
->setMode("AnaglyphRedCyan");
350 //_StereoRender->setMode("SideBySideHalf");
351 //_StereoRender->setMode("Mono");
352 #endif /* #if SBCLIENT_DEV_STEREO */
354 ConfigFile
->setCallback("OpenGL", cbGraphicsDriver
);
371 playMusic(SBCLIENT_MUSIC_WAIT
);
372 displayLoadingState("Initialize");
375 Scene
= Driver
->createScene(false);
377 // initialize bloom effect
378 CBloomEffect::instance().setDriver(Driver
);
379 CBloomEffect::instance().setScene(Scene
);
380 CBloomEffect::instance().init();
381 CConfiguration::setAndCallback("SquareBloom", cbSquareBloom
);
382 CConfiguration::setAndCallback("DensityBloom", cbDensityBloom
);
383 CConfiguration::setAndCallback("EnableBloom", cbEnableBloom
);
384 CConfiguration::setAndCallback("EnableFXAA", cbEnableFXAA
);
385 // Init the landscape using the previously created UScene
386 displayLoadingState("Initialize Landscape");
389 displayLoadingState("Initialize PACS ");
391 // Init the aiming system
392 displayLoadingState("Initialize Aiming ");
394 // Init the user camera
395 displayLoadingState("Initialize Camera ");
397 // Create a 3D mouse listener
398 displayLoadingState("Initialize MouseListener ");
399 MouseListener
= new C3dMouseListener();
400 MouseListener
->addToServer(Driver
->EventServer
);
401 MouseListener
->setCamera(Camera
);
402 MouseListener
->setHotSpot(CVectorD(0,0,0));
403 MouseListener
->setFrustrum(Camera
.getFrustum());
404 MouseListener
->setMatrix(Camera
.getMatrix());
405 MouseListener
->setSpeed(PlayerSpeed
);
406 initMouseListenerConfig();
408 displayLoadingState("Initialize Interface ");
411 displayLoadingState("Initialize Radar ");
414 displayLoadingState("Initialize Compass ");
417 displayLoadingState("Initialize Graph ");
419 // Init the command control
420 displayLoadingState("Initialize Commands ");
422 // Init the entities prefs
423 displayLoadingState("Initialize Entities ");
425 // Init animation system
426 displayLoadingState("Initialize Animation ");
428 // Init the lens flare
429 displayLoadingState("Initialize LensFlare ");
432 displayLoadingState("Initialize Sky ");
435 // Init the mouse so it's trapped by the main window.
436 Driver
->showCursor(false);
437 Driver
->setCapture(true);
438 Driver
->setMousePos(0.5f
, 0.5f
);
446 playMusic(SBCLIENT_MUSIC_WAIT
);
448 displayLoadingState("Connecting");
450 // connect to the server
451 nlinfo("Try to connect to FS addr '%s' and identify with the cookie '%s'", FSAddr
.c_str(), Cookie
.c_str());
452 initNetwork(Cookie
, FSAddr
);
454 while (Self
== NULL
) // wait for position etc from server
455 updateLoadingState(ucstring("Connecting"), true, true);
457 displayLoadingState("Load Landscape");
458 loadAllZonesAround();
460 displayLoadingState("Ready!");
462 playMusic(SBCLIENT_MUSIC_BACKGROUND
);
470 LoadedOffline
= true;
471 playMusic(SBCLIENT_MUSIC_WAIT
);
473 uint32 id
= NextEID
++;
474 Login
= ucstring("Entity" + toString(id
));
476 // Creates the self entity
477 displayLoadingState("Creating offline entity");
478 CVector startPoint
= CVector(ConfigFile
->getVar("StartPoint").asFloat(0), ConfigFile
->getVar("StartPoint").asFloat(1), ConfigFile
->getVar("StartPoint").asFloat(2));
479 addEntity(id
, Login
.toUtf8(), CEntity::Self
, startPoint
, startPoint
);
481 displayLoadingState("Load Landscape");
482 loadAllZonesAround();
484 // Display a local welcome message
485 addLine(">>>>> Welcome to Snowballs!");
486 addLine(">>>>> Press SHIFT-ESC to exit the game.");
488 displayLoadingState("Ready!");
490 playMusic(SBCLIENT_MUSIC_BACKGROUND
);
499 // Release configuration callbacks
500 CConfiguration::dropCallback("OpenGL");
502 #if SBCLIENT_DEV_STEREO
503 // Release stereo render
504 Driver
->deleteStereoRender(_StereoRender
);
505 _StereoRender
= NULL
;
506 #endif /* #if SBCLIENT_DEV_STEREO */
510 // Release the loading state textures
511 releaseLoadingState();
514 // Release the text context
515 Driver
->deleteTextContext(TextContext
);
517 // Release the 3d driver
522 // Release timing system
523 CGameTime::release();
524 // Release language file
525 CInternationalization::release();
526 // Release the configuration
527 CConfiguration::release();
543 LoadedIngame
= false;
545 // Release the mouse cursor
548 Driver
->setCapture(false);
549 Driver
->showCursor(true);
552 // Release all before quit
564 releaseMouseListenerConfig();
569 // Release the mouse listener
570 MouseListener
->removeFromServer(Driver
->EventServer
);
571 delete MouseListener
;
572 MouseListener
= NULL
;
574 // release bloom effect
575 CConfiguration::dropCallback("SquareBloom");
576 CConfiguration::dropCallback("DensityBloom");
577 CBloomEffect::instance().releaseInstance();
579 Driver
->deleteScene(Scene
);
588 LoadedOnline
= false;
594 void releaseOffline()
598 LoadedOffline
= false;
605 playMusic(SBCLIENT_MUSIC_LOGIN
);
606 // todo: login screen, move this stuff to a button or something
607 displayLoadingState("Login");
608 if (ConfigFile
->getVar("Local").asInt() == 0)
610 // Only attempt to directly log in if we haven't been passed a cookie already.
611 if(Cookie
.empty() || FSAddr
.empty())
613 if (ConfigFile
->getVar("UseDirectClient").asInt() == 1)
616 string
LSHost(ConfigFile
->getVar("LSHost").asString());
617 Login
= ConfigFile
->getVar("Login").asString();
618 string Password
= ConfigFile
->getVar("Password").asString();
619 CHashKeyMD5 hk
= getMD5((uint8
*)Password
.c_str(), (uint32
)Password
.size());
620 string CPassword
= hk
.toString();
621 nlinfo("The crypted password is %s", CPassword
.c_str());
622 string Application
= ConfigFile
->getVar("ClientApplication").asString();
623 sint32 sid
= ConfigFile
->getVar("ShardId").asInt();
626 updateLoadingState(ucstring("Authenticate"), false, false);
627 result
= CLoginClient::authenticateBegin(LSHost
, Login
, CPassword
, Application
);
628 if (!result
.empty()) goto AuthenticateFail
;
629 while (CLoginClient::authenticateUpdate(result
))
630 updateLoadingState(ucstring("Authenticate"), false, false);
631 if (!result
.empty()) goto AuthenticateFail
;
632 goto AuthenticateSuccess
;
635 nlinfo("*** Authenticate failed '%s' ***", result
.c_str());
636 for (TLocalTime t
= 0; t
< 5.000; t
+= LocalTimeDelta
)
637 updateLoadingState(ucstring("Authenticate failed: ") + ucstring(result
), false, false);
638 NextGameState
= GameStateOffline
;
642 nlinfo("%d Shards are available:", CLoginClient::ShardList
.size());
643 for (uint i
= 0; i
< CLoginClient::ShardList
.size(); i
++)
645 nlinfo(" ShardId %3d: %s(%d online players)", CLoginClient::ShardList
[i
].Id
, CLoginClient::ShardList
[i
].Name
.toUtf8().c_str(), CLoginClient::ShardList
[i
].NbPlayers
);
649 updateLoadingState(ucstring("Select shard"), false, false);
650 result
= CLoginClient::selectShardBegin(sid
);
651 if (!result
.empty()) goto SelectFail
;
652 while (CLoginClient::selectShardUpdate(result
, FSAddr
, Cookie
))
653 updateLoadingState(ucstring("Select shard"), false, false);
654 if (!result
.empty()) goto SelectFail
;
658 nlinfo("*** Connection to the shard failed '%s' ***", result
.c_str());
659 for (TLocalTime t
= 0; t
< 5.000; t
+= LocalTimeDelta
)
660 updateLoadingState(ucstring("Select shard failed: ") + ucstring(result
), false, false);
661 NextGameState
= GameStateOffline
;
667 NextGameState
= GameStateOnline
;
670 NextGameState
= GameStateOffline
;
676 while (CurrentGameState
== NextGameState
)
678 if (!Driver
->isActive()) { NextGameState
= GameStateExit
; return; }
680 // call all update functions
681 // 01. Update Utilities (configuration etc)
682 CConfiguration::updateUtilities(); // update configuration files
684 // 02. Update Time (deltas)
685 CGameTime::updateTime();
686 CGameTime::advanceTime(1.0);
688 // 03. Update Incoming (network, receive messages)
691 // 04. Update Input (keyboard controls, etc)
692 Driver
->EventServer
.pump(); // Pump user input messages
693 MouseListener
->update();
694 MouseListener
->updateCamera();
696 // 05. Update Weather (sky, snow, wind, fog, sun)
697 animateSky(LocalTimeDelta
);
699 // 06. Update Landscape (async zone loading near entity)
700 updateLandscape(); // Update the landscape
702 // ... Update Animations (TEST)
705 // 07. Update Entities (collisions and actions)
706 // - Move Other Entities (move//, animations, etc)
707 // - Update Self Collision (move)
708 // - Update Self Entity (animations//, etc)
709 updateEntities(); // Update network messages FIXME_NETWORK_OUTGOING
711 // 08. Update Animations (playlists)
712 Scene
->animate(AnimationTime
); // Set new animation date
714 // 09. Update Camera (depends on entities)
716 if (StereoHMD
) StereoHMD
->updateCamera(0, &Camera
);
718 // 10. Update Interface (login, ui, etc)
721 // 11. Update Sound (sound driver)
722 updateSound(); // Update the sound
724 // 12. Update Outgoing (network, send new position etc)
727 // 13. Update Debug (stuff for dev)
730 // if driver is lost (d3d) do nothing for a while
731 if (Driver
->isLost()) nlSleep(10);
735 bool effectRender
= false;
736 CTextureUser
*effectRenderTarget
= NULL
;
737 bool haveEffects
= Driver
->getPolygonMode() == UDriver::Filled
738 && (s_EnableBloom
|| s_FXAA
);
739 bool defaultRenderTarget
= false;
744 Driver
->beginDefaultRenderTarget();
745 defaultRenderTarget
= true;
748 while ((!StereoDisplay
&& i
== 0) || (StereoDisplay
&& StereoDisplay
->nextPass()))
753 const CViewport
&vp
= StereoDisplay
->getCurrentViewport();
754 Driver
->setViewport(vp
);
755 Scene
->setViewport(vp
);
756 SkyScene
->setViewport(vp
);
757 StereoDisplay
->getCurrentFrustum(0, &Camera
);
758 StereoDisplay
->getCurrentFrustum(0, &SkyCamera
);
759 StereoDisplay
->getCurrentMatrix(0, &Camera
);
764 StereoDisplay
->beginRenderTarget();
767 if (!StereoDisplay
|| StereoDisplay
->wantClear())
769 effectRender
= haveEffects
;
771 // 01. Render Driver (background color)
772 Driver
->clearBuffers(CRGBA(0, 0, 127)); // clear all buffers, if you see this blue there's a problem with scene rendering
775 if (!StereoDisplay
|| StereoDisplay
->wantScene())
777 // 02. Render Sky (sky scene)
778 updateSky(); // Render the sky scene before the main scene
780 // 04. Render Scene (entity scene)
781 Scene
->render(); // Render
783 // 05. Render Effects (flare)
784 if (!StereoHMD
) updateLensFlare(); // Render the lens flare (left eye stretched with stereo...)
787 if (!StereoDisplay
|| StereoDisplay
->wantInterface3D())
791 if (StereoDisplay
) Driver
->setViewport(NL3D::CViewport());
792 UCamera pCam
= Scene
->getCam();
793 Driver
->setMatrixMode2D11();
794 if (s_FXAA
) s_FXAA
->applyEffect();
795 if (s_EnableBloom
) CBloomEffect::instance().applyBloom();
796 Driver
->setMatrixMode3D(pCam
);
797 if (StereoDisplay
) Driver
->setViewport(StereoDisplay
->getCurrentViewport());
798 effectRender
= false;
801 // 06. Render Interface 3D (player names)
805 if (!StereoDisplay
|| StereoDisplay
->wantInterface2D())
807 // 07. Render Interface 2D (chatboxes etc, optionally does have 3d)
808 updateCompass(); // Update the compass
809 updateRadar(); // Update the radar
810 updateGraph(); // Update the radar
811 if (ShowCommands
) updateCommands(); // Update the commands panel
812 renderEntitiesNames(); // Render the name on top of the other players
813 updateInterface(); // Update interface
815 if (!StereoDisplay
) update3dLogo(); // broken with stereo
817 // 08. Render Debug (stuff for dev)
823 StereoDisplay
->endRenderTarget();
828 if (defaultRenderTarget
)
830 // draw final result to backbuffer
831 Driver
->endDefaultRenderTarget(Scene
);
833 Driver
->swapBuffers();
836 // begin various extra keys stuff ...
838 if (Driver
->AsyncListener
.isKeyDown(KeySHIFT
) && Driver
->AsyncListener
.isKeyPushed(KeyESCAPE
))
840 // Shift Escape -> quit
841 NextGameState
= GameStateExit
;
843 else if (Driver
->AsyncListener
.isKeyPushed(KeyF3
))
845 // F3 -> toggle wireframe/solid
846 UDriver::TPolygonMode p
= Driver
->getPolygonMode();
847 p
= UDriver::TPolygonMode(((int)p
+1)%3);
848 Driver
->setPolygonMode(p
);
850 else if (Driver
->AsyncListener
.isKeyPushed(KeyF4
))
852 // F4 -> clear the command(chat) output
855 else if (Driver
->AsyncListener
.isKeyPushed(KeyF5
))
857 // F5 -> display/hide the commands(chat) interface
858 ShowCommands
= !ShowCommands
;
860 else if (Driver
->AsyncListener
.isKeyPushed(KeyF6
))
862 // F6 -> display/hide the radar interface
863 RadarState
=(RadarState
+ 1) % 3;
865 else if (Driver
->AsyncListener
.isKeyDown(KeyF7
))
867 // F7 -> radar zoom out
870 else if (Driver
->AsyncListener
.isKeyDown(KeyF8
))
872 // F8 -> radar zoom in
875 else if (Driver
->AsyncListener
.isKeyPushed(KeyF9
))
877 // F9 -> release/capture the mouse cursor
880 Driver
->setCapture(false);
881 Driver
->showCursor(true);
882 MouseListener
->removeFromServer(Driver
->EventServer
);
886 Driver
->setCapture(true);
887 Driver
->showCursor(false);
888 MouseListener
->addToServer(Driver
->EventServer
);
890 CaptureState
= !CaptureState
;
892 else if (Driver
->AsyncListener
.isKeyPushed(KeyF10
))
894 // F10 -> switch beteen online and offline
895 if (isOnline()) NextGameState
= GameStateOffline
;
896 else NextGameState
= GameStateLogin
;
898 else if (Driver
->AsyncListener
.isKeyPushed(KeyF11
))
900 // F11 -> reset the PACS global position of the self entity(in case of a pacs failure :-\)
902 resetEntityPosition(Self
->Id
);
904 else if (Driver
->AsyncListener
.isKeyPushed(KeyF12
))
906 // F12 -> take a screenshot
908 Driver
->getBuffer(btm
);
909 string filename
= CFile::findNewFile("screenshot.tga");
911 btm
.writeTGA(fs
,24,false);
912 nlinfo("Screenshot '%s' saved", filename
.c_str());
915 // end of various keys
919 void renderInformation()
921 // Display if we are online or offline
922 TextContext
->setHotSpot(UTextContext::TopRight
);
923 TextContext
->setColor(isOnline()?CRGBA(0, 255, 0):CRGBA(255, 0, 0));
924 TextContext
->setFontSize(18);
925 TextContext
->printfAt(0.99f
, 0.99f
, isOnline() ? "Online" : "Offline");
927 // Display the frame rate
928 TextContext
->setHotSpot(UTextContext::TopLeft
);
929 TextContext
->setColor(CRGBA(255, 255, 255, 255));
930 TextContext
->setFontSize(14);
931 TextContext
->printfAt(0.01f
, 0.99f
, "%.2f(%.2f)fps %.3fs", FramesPerSecondSmooth
, FramesPerSecond
, (float)LocalTimeDelta
);
932 CVector camPos
= Camera
.getMatrix().getPos();
933 TextContext
->printfAt(0.01f
, 0.89f
, "CAM POS: %.3f %.3f %.3f", camPos
.x
, camPos
.y
, camPos
.z
);
936 FpsGraph
.addValue(1.0f
);
937 SpfGraph
.addOneValue((float)LocalTimeDelta
);
941 // Configuration callbacks
944 void cbGraphicsDriver(CConfigFile::CVar
&var
)
946 // -- give ingame warning or something instead =)
947 NextGameState
= GameStateReset
;
950 void cbSquareBloom(CConfigFile::CVar
&var
)
952 CBloomEffect::instance().setSquareBloom(var
.asBool());
955 void cbDensityBloom(CConfigFile::CVar
&var
)
957 CBloomEffect::instance().setDensityBloom((uint8
)(var
.asInt() & 0xFF));
960 void cbEnableBloom(CConfigFile::CVar
&var
)
962 s_EnableBloom
= var
.asBool();
965 void cbEnableFXAA(CConfigFile::CVar
&var
)
967 bool enable
= var
.asBool();
968 if (enable
!= (s_FXAA
!= NULL
))
972 s_FXAA
= new CFXAA(Driver
);
982 // Loading state procedure
985 static UTextureFile
*NelLogo
= NULL
;
986 // static UTextureFile *NevraxLogo = NULL;
987 static UTextureFile
*SnowballsBackground
= NULL
;
988 static float ScreenWidth
, ScreenHeight
;
989 // The logo 3D objects
990 static UScene
*LogoScene
= NULL
;
991 static UInstance Logo
= NULL
;
993 void initLoadingState()
995 NelLogo
= Driver
->createTextureFile("nel128.tga");
996 // NevraxLogo = Driver->createTextureFile("nevrax.tga");
997 SnowballsBackground
= Driver
->createTextureFile("snowbg.tga");
998 uint32 width
, height
;
999 Driver
->getWindowSize(width
, height
);
1000 ScreenWidth
=(float)width
;
1001 ScreenHeight
=(float)height
;
1004 // Setup the logo scene
1007 LogoScene
= Driver
->createScene(false);
1010 v
.init(0.0f
, 0.80f
, 0.2f
, 0.2f
);
1011 LogoScene
->setViewport(v
);
1013 Logo
= LogoScene
->createInstance("nel_logo.shape");
1014 Logo
.setPos(0.0f
, 3.0f
, 0.0f
);
1015 Logo
.setTransformMode(UTransformable::RotEuler
);
1018 void releaseLoadingState()
1020 LogoScene
->deleteInstance(Logo
); Logo
= NULL
;
1021 Driver
->deleteScene(LogoScene
); LogoScene
= NULL
;
1023 Driver
->deleteTextureFile(NelLogo
); NelLogo
= NULL
;
1024 // Driver->deleteTextureFile(NevraxLogo); NevraxLogo = NULL;
1025 Driver
->deleteTextureFile(SnowballsBackground
); SnowballsBackground
= NULL
;
1028 void renderLoadingState(const char *state
, bool logo3d
)
1030 renderLoadingState(ucstring(state
), logo3d
);
1032 void renderLoadingState(ucstring state
, bool logo3d
)
1034 if (!Driver
) return;
1036 Driver
->clearBuffers(CRGBA(0,0,0));
1038 Driver
->setMatrixMode2D(CFrustum(0.0f
, ScreenWidth
, 0.0f
, ScreenHeight
, 0.0f
, 1.0f
, false));
1040 if (SnowballsBackground
!= NULL
)
1042 float imageAspect
= 16.0f
/ 9.0f
; // 1.777
1043 float minTransform
= 4.0f
/ 3.0f
; // 1.333
1044 float screenAspect
= ScreenWidth
/ ScreenHeight
;
1045 float transform
= screenAspect
> imageAspect
? 1.0f
: (screenAspect
< minTransform
? imageAspect
/ minTransform
: imageAspect
/ screenAspect
);
1046 float newWidth
= ScreenWidth
* transform
;
1047 Driver
->drawBitmap((newWidth
- ScreenWidth
) * -0.5f
, 0, newWidth
, ScreenHeight
, *SnowballsBackground
);
1050 /*if (logo3d) update3dLogo();
1051 else */ if (NelLogo
!= NULL
) Driver
->drawBitmap(16, 32 - 42, 128, 128, *NelLogo
);
1052 // if (NevraxLogo != NULL) Driver->drawBitmap(ScreenWidth - 128 - 16, 32, 128, 16, *NevraxLogo);
1054 if (!TextContext
) return;
1056 TextContext
->setColor(CRGBA(255, 255, 255));
1057 TextContext
->setHotSpot(UTextContext::MiddleMiddle
);
1059 TextContext
->setFontSize(40);
1060 TextContext
->printAt(0.5f
, 0.5f
, ucstring("Welcome to Snowballs!"));
1062 TextContext
->setFontSize(30);
1063 TextContext
->printAt(0.5f
, 0.2f
, state
);
1065 TextContext
->setHotSpot(UTextContext::BottomRight
);
1066 TextContext
->setFontSize(15);
1067 #if (FINAL_VERSION == 1)
1068 TextContext
->printAt(0.99f
, 0.01f
, ucstring("Final Version"));
1070 TextContext
->printAt(0.99f
, 0.01f
, ucstring("(compiled " __DATE__
" " __TIME__
")"));
1073 TextContext
->setHotSpot(UTextContext::BottomLeft
);
1074 TextContext
->setFontSize(15);
1075 #if defined(NL_DEBUG_FAST)
1076 ucstring version
= ucstring("DebugFast Version");
1077 #elif defined(NL_DEBUG)
1078 ucstring version
= ucstring("Debug Version");
1079 #elif defined(NL_RELEASE)
1080 ucstring version
= ucstring("Release Version");
1081 #elif defined(NL_RELEASE_DEBUG)
1082 ucstring version
= ucstring("ReleaseDebug Version");
1084 ucstring version
= ucstring("Unknown Version");
1086 TextContext
->printAt(0.01f
, 0.01f
, version
);
1089 void displayLoadingState(const char *state
)
1091 displayLoadingState(ucstring(state
));
1093 void displayLoadingState(ucstring state
)
1095 CGameTime::updateTime();
1096 renderLoadingState(state
, false);
1097 Driver
->swapBuffers();
1098 //Driver->EventServer.pump();
1101 void updateLoadingState(const char *state
, bool network
, bool information
)
1103 updateLoadingState(ucstring(state
), network
, information
);
1105 void updateLoadingState(ucstring state
, bool network
, bool information
)
1107 CGameTime::updateTime(); // important that time is updated here!!!
1109 renderLoadingState(state
, true);
1110 if (information
) renderInformation();
1111 if (network
) updateNetwork();
1112 Driver
->swapBuffers();
1113 Driver
->EventServer
.pump();
1118 Driver
->clearZBuffer();
1119 static float angle
= 0.0;
1120 angle
+= 2.0f
* (float)LocalTimeDelta
;
1121 Logo
.setRotEuler(0.0f
, 0.0f
, angle
);
1122 LogoScene
->animate(AnimationTime
);
1123 LogoScene
->render();
1126 void CSnowballsClient::init()
1129 CGlobals::assertNull();
1132 bool CSnowballsClient::run()
1134 // Run the game state loop switcher
1139 void CSnowballsClient::release()
1141 // Make sure everything's released
1147 CGlobals::assertNull();
1150 } /* namespace SBCLIENT */
1153 #ifdef NL_OS_WINDOWS
1155 # define tstring wstring
1157 # define tstring string
1159 sint WINAPI
WinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPSTR cmdline
, int nCmdShow
)
1161 sint
main(int argc
, char **argv
)
1164 // must do this to allow deallocation when closing with X
1167 #ifdef NL_OS_WINDOWS
1169 // extract the 2 first param (argv[1] and argv[2]) it must be cookie and addr
1171 string cmd
= cmdline
;
1172 string::size_type pos1
= cmd
.find_first_not_of (' ');
1173 string::size_type pos2
;
1174 if (pos1
!= string::npos
)
1176 pos2
= cmd
.find (' ', pos1
);
1177 if(pos2
!= string::npos
)
1179 SBCLIENT::Cookie
= cmd
.substr (pos1
, pos2
-pos1
);
1181 pos1
= cmd
.find_first_not_of (' ', pos2
);
1182 if (pos1
!= string::npos
)
1184 pos2
= cmd
.find (' ', pos1
);
1185 if(pos2
== string::npos
)
1187 SBCLIENT::FSAddr
= cmd
.substr (pos1
);
1189 else if (pos1
!= pos2
)
1191 SBCLIENT::FSAddr
= cmd
.substr (pos1
, pos2
-pos1
);
1201 SBCLIENT::Cookie
= argv
[1];
1202 SBCLIENT::FSAddr
= argv
[2];
1207 nlinfo ("cookie '%s' addr '%s'", SBCLIENT::Cookie
.c_str (), SBCLIENT::FSAddr
.c_str());
1210 #if defined(NL_OS_WINDOWS) && !FINAL_VERSION
1211 // ensure paths are ok before powering up nel
1213 OutputDebugString(" ******************************** \n");
1214 OutputDebugString(" * DEVELOPER MODE * \n");
1215 OutputDebugString(" ******************************** \n\n");
1216 FILE *f
= _tfopen(_T(SBCLIENT_CONFIG_FILE_DEFAULT
), _T("r"));
1219 f
= _tfopen(_T(SBCLIENT_CONFIG_FILE
), _T("r"));
1222 OutputDebugString(" ******************************** \n");
1223 OutputDebugString(" * CHANGING WORKING DIRECTORY * \n");
1224 OutputDebugString(" ******************************** \n\n");
1227 tstring
workdir(cwd
);
1228 workdir
= "R:\\build\\devw_x86\\bin\\Debug\\";
1229 _tchdir(workdir
.c_str());
1230 f
= _tfopen(_T(SBCLIENT_CONFIG_FILE_DEFAULT
), _T("r"));
1233 f
= _tfopen(_T(SBCLIENT_CONFIG_FILE
), _T("r"));
1236 OutputDebugString(" ******************************** \n");
1237 OutputDebugString(" * DEFAULT CONFIG MISSING * \n");
1238 OutputDebugString(" ******************************** \n\n");
1239 return EXIT_FAILURE
;
1250 // use log.log if NEL_LOG_IN_FILE and SBCLIENT_USE_LOG_LOG defined as 1
1251 createDebug(NULL
, SBCLIENT_USE_LOG_LOG
, false);
1252 INelContext::getInstance().setWindowedApplication(true);
1254 #if SBCLIENT_USE_LOG
1255 // create snowballs_client.log
1256 // filedisplayer only deletes the 001 etc
1257 if (SBCLIENT_ERASE_LOG
&& CFile::isExists(SBCLIENT_LOG_FILE
))
1258 CFile::deleteFile(SBCLIENT_LOG_FILE
);
1259 // initialize the log file
1260 SBCLIENT::_FileDisplayer
= new CFileDisplayer();
1261 SBCLIENT::_FileDisplayer
->setParam(SBCLIENT_LOG_FILE
, SBCLIENT_ERASE_LOG
);
1262 DebugLog
->addDisplayer(SBCLIENT::_FileDisplayer
);
1263 InfoLog
->addDisplayer(SBCLIENT::_FileDisplayer
);
1264 WarningLog
->addDisplayer(SBCLIENT::_FileDisplayer
);
1265 AssertLog
->addDisplayer(SBCLIENT::_FileDisplayer
);
1266 ErrorLog
->addDisplayer(SBCLIENT::_FileDisplayer
);
1269 nlinfo("Welcome to NeL!");
1272 SBCLIENT::CSnowballsClient::init();
1273 exit(SBCLIENT::CSnowballsClient::run() ? EXIT_SUCCESS
: EXIT_FAILURE
);
1274 return EXIT_FAILURE
;
1278 SBCLIENT::CSnowballsClient::release();
1279 nlinfo("See you later!");
1281 #if SBCLIENT_USE_LOG
1282 DebugLog
->removeDisplayer(SBCLIENT::_FileDisplayer
);
1283 InfoLog
->removeDisplayer(SBCLIENT::_FileDisplayer
);
1284 WarningLog
->removeDisplayer(SBCLIENT::_FileDisplayer
);
1285 AssertLog
->removeDisplayer(SBCLIENT::_FileDisplayer
);
1286 ErrorLog
->removeDisplayer(SBCLIENT::_FileDisplayer
);
1287 delete SBCLIENT::_FileDisplayer
; SBCLIENT::_FileDisplayer
= NULL
;
1291 // Command to quit the client
1292 NLMISC_COMMAND(sb_quit
,"quit the client","")
1294 // check args, if there s not the right number of parameter, return bad
1295 if (args
.size() != 0) return false;
1297 log
.displayNL("Exit requested");
1299 SBCLIENT::NextGameState
= SBCLIENT::GameStateExit
;
1304 NLMISC_COMMAND(sb_offline
, "go offline", "")
1306 if (args
.size() != 0) return false;
1307 SBCLIENT::NextGameState
= SBCLIENT::GameStateOffline
;
1311 NLMISC_COMMAND(sb_unload
, "unload game", "")
1313 if (args
.size() != 0) return false;
1314 SBCLIENT::NextGameState
= SBCLIENT::GameStateUnload
;
1318 NLMISC_COMMAND(sb_reset
, "reset game", "")
1320 if (args
.size() != 0) return false;
1321 SBCLIENT::NextGameState
= SBCLIENT::GameStateReset
;
1325 NLMISC_COMMAND(sb_login
, "go to the login screen", "")
1327 if (args
.size() != 0) return false;
1328 SBCLIENT::NextGameState
= SBCLIENT::GameStateLogin
;
1332 #if SBCLIENT_DEV_MEMLEAK
1333 // enable memory leak checks, trick to get _CrtSetBreakAlloc in before main
1334 #define DEBUG_ALLOC_HOOK
1335 #if defined(NL_OS_WINDOWS) && defined(NL_DEBUG)
1336 #if defined(DEBUG_ALLOC_HOOK)
1337 int debugAllocHook(int allocType
, void *userData
, size_t size
, int
1338 blockType
, long requestNumber
, const unsigned char *filename
, int
1341 class CEnableCrtDebug
1346 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF
| _CRTDBG_LEAK_CHECK_DF
);
1347 _CrtSetBreakAlloc(0);
1348 #if defined(DEBUG_ALLOC_HOOK)
1350 _CrtSetAllocHook(debugAllocHook
);
1353 #if defined(DEBUG_ALLOC_HOOK)
1357 static CEnableCrtDebug _EnableCrtDebug
;
1358 #if defined(DEBUG_ALLOC_HOOK)
1359 int debugAllocHook(int allocType
, void *userData
, size_t size
, int
1360 blockType
, long requestNumber
, const unsigned char *filename
, int
1363 if (allocType
== _HOOK_ALLOC
)
1365 //if (requestNumber == 14806)
1366 // _CrtSetBreakAlloc(14809);
1367 //if (_EnableCrtDebug.LastSize == 4 && size == 40 && requestNumber > 291000 && requestNumber < 292000)
1369 //if (_EnableCrtDebug.LastSize == 36 && size == 112 && requestNumber > 300000)
1371 _EnableCrtDebug
.LastSize
= size
;
1378 // trick to clean up nel memory trash! (todo: unload of loaded dynamic nel libs (nel drivers) in linux)
1379 #include <nel/misc/debug.h>
1380 #include <nel/misc/command.h>
1381 #include <nel/misc/dynloadlib.h>
1382 #include <nel/misc/object_arena_allocator.h>
1383 #include <nel/misc/class_registry.h>
1384 #include <nel/misc/async_file_manager.h>
1385 #include <nel/misc/big_file.h>
1386 #include <nel/3d/particle_system_manager.h>
1387 #include <nel/3d/particle_system_shape.h>
1388 #ifdef NL_OS_WINDOWS
1389 #include <dbghelp.h>
1390 BOOL CALLBACK
EnumerateLoadedModulesProc(PCSTR ModuleName
, ULONG ModuleBase
, ULONG ModuleSize
, PVOID UserContext
)
1392 // free nel libraries (cannot call nlwarning etc here, so nlGetProcAddress etc does not work)
1393 HMODULE hModule
= GetModuleHandle(ModuleName
);
1394 if (GetProcAddress(hModule
, NL_MACRO_TO_STR(NLMISC_PURE_LIB_ENTRY_POINT
)))
1395 FreeLibrary(hModule
);
1399 struct yy_buffer_state
;
1400 extern void cf_switch_to_buffer(yy_buffer_state
*new_buffer
);
1401 extern yy_buffer_state
*cf_create_buffer(FILE *file
, int size
);
1402 extern void cf_delete_buffer(yy_buffer_state
*b
);
1406 CCleanupNeL() : _CfBufferState(NULL
)
1408 _CfBufferState
= cf_create_buffer(NULL
, 16384);
1409 cf_switch_to_buffer(_CfBufferState
);
1413 #ifdef NL_OS_WINDOWS
1414 // must unload all other nel modules before killing nel context (or they will crash in static destructors)
1415 EnumerateLoadedModules(GetCurrentProcess(), EnumerateLoadedModulesProc
, NULL
); // todo: linux version
1418 // delete most stuff
1419 NL3D::CParticleSystemShape::releaseInstance();
1420 NLMISC::CAsyncFileManager::terminate();
1421 NL3D::CParticleSystemManager::release();
1422 NLMISC::CBigFile::releaseInstance();
1423 NLMISC::CStreamedPackageManager::releaseInstance();
1424 NLMISC::CClassRegistry::release();
1425 delete &NLMISC::CObjectArenaAllocator::getDefaultAllocator();
1426 cf_delete_buffer(_CfBufferState
); _CfBufferState
= NULL
;
1428 #ifdef NL_OS_WINDOWS
1429 // delete context related stuff (must unload all dynamic nel libs first)
1430 NLMISC::destroyDebug();
1431 if (NLMISC::INelContext::isContextInitialised())
1433 delete &NLMISC::INelContext::getInstance();
1434 delete &NLMISC::CInstanceCounterManager::getInstance();
1435 delete &NLMISC::CCommandRegistry::getInstance();
1437 NLMISC::CLog::releaseProcessName();
1441 yy_buffer_state
*_CfBufferState
;
1443 CCleanupNeL _CleanupNeL
;