Linux multi-monitor fullscreen support
[ryzomcore.git] / snowballs2 / client / src / snowballs_client.cpp
blob0d18b53610d3f61138411da37bf8e8fd47e4e16c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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"
24 // STL includes
25 #include <ctime>
26 #include <string>
27 #include <vector>
28 #include <stdio.h>
29 #if defined(NL_OS_WINDOWS)
30 # include <direct.h>
31 # include <tchar.h>
32 #endif
34 // NeL includes
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>
60 // Project includes
61 #include "pacs.h"
62 #include "radar.h"
63 #include "graph.h"
64 #include "camera.h"
65 #include "compass.h"
66 #include "commands.h"
67 #include "entities.h"
68 #include "network.h"
69 #include "landscape.h"
70 #include "animation.h"
71 #include "interface.h"
72 #include "lens_flare.h"
73 #include "mouse_listener.h"
74 #include "sound.h"
75 #include "configuration.h"
76 #include "internationalization.h"
77 #include "game_time.h"
79 #ifdef NL_OS_WINDOWS
80 #include <Windows.h>
81 #endif
83 using namespace std;
84 using namespace NLMISC;
85 using namespace NL3D;
86 using namespace NLNET;
88 namespace SBCLIENT {
90 /*******************************************************************
91 * GLOBALS *
92 *******************************************************************/
94 void CGlobals::assertNull()
96 // extra verification against stupid typos
97 nlassert(!Driver);
98 nlassert(!Scene);
99 nlassert(!TextContext);
100 nlassert(!ConfigFile);
101 nlassert(!Landscape);
102 nlassert(!MouseListener);
105 // The 3d driver
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
116 //// Log file
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
135 ucstring Login;
136 static string FSAddr, Cookie;
138 /*******************************************************************
139 * SNOWBALLS CLIENT *
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;
164 // Prototypes
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);
175 void update3dLogo();
176 void renderInformation();
177 void switchGameState();
178 void loopLogin();
179 void loopIngame();
180 void initCore();
181 void initLogin();
182 void initIngame();
183 void initOnline();
184 void initOffline();
185 void releaseCore();
186 void releaseLogin();
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);
197 // Functions
200 void switchGameState()
202 SwitchNextGameState:
203 nlinfo("Switching to the next game state");
204 if (CurrentGameState == NextGameState)
206 nlwarning("NextGameState wasn't changed");
208 else
210 switch(CurrentGameState)
212 case GameStateOnline:
213 releaseOnline(); // always release online after switch
214 break;
215 case GameStateOffline:
216 releaseOffline(); // always releaes offline after switch
217 break;
219 switch(NextGameState)
221 case GameStateLoad:
224 initCore(); // core is required
226 catch (NLMISC::Exception e)
228 #ifdef NL_OS_WINDOWS
229 MessageBox(NULL, e.what(), "NeL Exception", MB_OK | MB_ICONSTOP);
230 #else
231 printf("%s\n", e.what());
232 #endif
233 return; // exit if driver loading failed
235 break;
236 case GameStateUnload:
237 displayLoadingState("Unloading");
238 releaseLogin(); // release all
239 releaseIngame();
240 break;
241 case GameStateReset:
242 displayLoadingState("Reset");
243 releaseLogin(); // release all
244 releaseIngame();
245 releaseCore();
246 break;
247 case GameStateExit:
248 displayLoadingState("See you later!");
249 releaseLogin(); // release all
250 releaseIngame();
251 releaseCore();
252 break;
253 case GameStateLogin:
254 initCore(); // core is required
255 initLogin(); // login is required
256 break;
257 case GameStateOnline:
258 initCore(); // core is required
259 releaseLogin(); //login can be released
260 initIngame(); // ingame is required
261 initOnline(); // connection is required
262 break;
263 case GameStateOffline:
264 initCore(); // core is required
265 releaseLogin(); //login can be released
266 initIngame(); // ingame is required
267 initOffline(); // offline entity required
268 break;
271 CurrentGameState = NextGameState;
272 switch(CurrentGameState)
274 case GameStateLoad: // switch to the default state
275 NextGameState = GameStateLogin;
276 break;
277 case GameStateUnload: // test state, switch back to load for default
278 NextGameState = GameStateLoad;
279 break;
280 case GameStateReset: // used to reset everything
281 NextGameState = GameStateLoad;
282 break;
283 case GameStateExit: // exit the loop
284 return;
285 case GameStateLogin: // loop the login screen
286 loopLogin(); // must loop by itself
287 break;
288 case GameStateOnline: // start offline if not online
289 if (!LoadedOnline)
291 NextGameState = GameStateOffline;
292 break;
294 case GameStateOffline: // loop ingame
295 loopIngame(); // must loop by itself
296 break;
298 goto SwitchNextGameState;
301 void initCore()
303 if (!LoadedCore)
305 LoadedCore = true;
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
313 CGameTime::init();
314 // Set the ShowCommands with the value set in the client config file
315 ShowCommands = ConfigFile->getVar("ShowCommands").asInt() == 1;
316 // Create a driver
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");
338 initLoadingState();
339 // Initialize sound for loading screens etc
340 displayLoadingState("Initialize Sound");
341 initSound();
342 playMusic(SBCLIENT_MUSIC_WAIT);
343 // Required for 3d rendering (3d nel logo etc)
344 displayLoadingState("Initialize Light");
345 initLight();
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);
358 void initLogin()
360 if (!LoadedLogin)
362 LoadedLogin = true;
366 void initIngame()
368 if (!LoadedIngame)
370 LoadedIngame = true;
371 playMusic(SBCLIENT_MUSIC_WAIT);
372 displayLoadingState("Initialize");
374 // Create a scene
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");
387 initLandscape();
388 // Init the pacs
389 displayLoadingState("Initialize PACS ");
390 initPACS();
391 // Init the aiming system
392 displayLoadingState("Initialize Aiming ");
393 initAiming();
394 // Init the user camera
395 displayLoadingState("Initialize Camera ");
396 initCamera();
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();
407 // Init interface
408 displayLoadingState("Initialize Interface ");
409 initInterface();
410 // Init radar
411 displayLoadingState("Initialize Radar ");
412 initRadar();
413 // Init compass
414 displayLoadingState("Initialize Compass ");
415 initCompass();
416 // Init graph
417 displayLoadingState("Initialize Graph ");
418 initGraph();
419 // Init the command control
420 displayLoadingState("Initialize Commands ");
421 initCommands();
422 // Init the entities prefs
423 displayLoadingState("Initialize Entities ");
424 initEntities();
425 // Init animation system
426 displayLoadingState("Initialize Animation ");
427 initAnimation();
428 // Init the lens flare
429 displayLoadingState("Initialize LensFlare ");
430 initLensFlare();
431 // Init the sky
432 displayLoadingState("Initialize Sky ");
433 initSky();
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);
442 void initOnline()
444 if (LoadedOnline)
445 return;
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);
463 LoadedOnline = true;
466 void initOffline()
468 if (!LoadedOffline)
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);
494 void releaseCore()
496 if (LoadedCore)
498 LoadedCore = false;
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 */
508 // Release the sun
509 releaseLight();
510 // Release the loading state textures
511 releaseLoadingState();
512 // Release the sound
513 releaseSound();
514 // Release the text context
515 Driver->deleteTextContext(TextContext);
516 TextContext = NULL;
517 // Release the 3d driver
518 Driver->release();
519 delete Driver;
520 Driver = NULL;
522 // Release timing system
523 CGameTime::release();
524 // Release language file
525 CInternationalization::release();
526 // Release the configuration
527 CConfiguration::release();
531 void releaseLogin()
533 if (LoadedLogin)
535 LoadedLogin = false;
539 void releaseIngame()
541 if (LoadedIngame)
543 LoadedIngame = false;
545 // Release the mouse cursor
546 if (CaptureState)
548 Driver->setCapture(false);
549 Driver->showCursor(true);
552 // Release all before quit
554 releaseSky();
555 releaseLensFlare();
556 releaseRadar();
557 releaseCommands();
558 releaseEntities();
559 releaseGraph();
560 releaseCompass();
561 releaseInterface();
562 releaseNetwork();
563 releaseAnimation();
564 releaseMouseListenerConfig();
565 releaseCamera();
566 releaseAiming();
567 releasePACS();
568 releaseLandscape();
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);
580 Scene = NULL;
584 void releaseOnline()
586 if (LoadedOnline)
588 LoadedOnline = false;
589 releaseNetwork();
590 deleteAllEntities();
594 void releaseOffline()
596 if (LoadedOffline)
598 LoadedOffline = false;
599 deleteAllEntities();
603 void loopLogin()
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)
615 string result;
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();
625 // 1/ Authenticate
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;
634 AuthenticateFail:
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;
639 return;
641 AuthenticateSuccess:
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);
648 // 2/ Select shard
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;
655 goto SelectSuccess;
657 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;
662 return;
664 SelectSuccess:;
667 NextGameState = GameStateOnline;
668 return;
670 NextGameState = GameStateOffline;
671 return;
674 void loopIngame()
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)
689 updateNetwork();
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)
703 updateAnimation();
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)
715 updateCamera();
716 if (StereoHMD) StereoHMD->updateCamera(0, &Camera);
718 // 10. Update Interface (login, ui, etc)
719 // ...
721 // 11. Update Sound (sound driver)
722 updateSound(); // Update the sound
724 // 12. Update Outgoing (network, send new position etc)
725 // ...
727 // 13. Update Debug (stuff for dev)
728 // ...
730 // if driver is lost (d3d) do nothing for a while
731 if (Driver->isLost()) nlSleep(10);
732 else
734 uint i = 0;
735 bool effectRender = false;
736 CTextureUser *effectRenderTarget = NULL;
737 bool haveEffects = Driver->getPolygonMode() == UDriver::Filled
738 && (s_EnableBloom || s_FXAA);
739 bool defaultRenderTarget = false;
740 if (haveEffects)
742 if (!StereoDisplay)
744 Driver->beginDefaultRenderTarget();
745 defaultRenderTarget = true;
748 while ((!StereoDisplay && i == 0) || (StereoDisplay && StereoDisplay->nextPass()))
750 ++i;
751 if (StereoDisplay)
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);
762 if (StereoDisplay)
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())
789 if (effectRender)
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)
802 // ...
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
814 renderInformation();
815 if (!StereoDisplay) update3dLogo(); // broken with stereo
817 // 08. Render Debug (stuff for dev)
818 // ...
821 if (StereoDisplay)
823 StereoDisplay->endRenderTarget();
827 // 09. Render Buffer
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
853 clearCommands();
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
868 RadarDistance += 50;
870 else if (Driver->AsyncListener.isKeyDown(KeyF8))
872 // F8 -> radar zoom in
873 RadarDistance -= 50;
875 else if (Driver->AsyncListener.isKeyPushed(KeyF9))
877 // F9 -> release/capture the mouse cursor
878 if (!CaptureState)
880 Driver->setCapture(false);
881 Driver->showCursor(true);
882 MouseListener->removeFromServer(Driver->EventServer);
884 else
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 :-\)
901 if (Self != NULL)
902 resetEntityPosition(Self->Id);
904 else if (Driver->AsyncListener.isKeyPushed(KeyF12))
906 // F12 -> take a screenshot
907 CBitmap btm;
908 Driver->getBuffer(btm);
909 string filename = CFile::findNewFile("screenshot.tga");
910 COFile fs(filename);
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);
935 // one more frame
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))
970 if (enable)
972 s_FXAA = new CFXAA(Driver);
974 else
976 delete s_FXAA;
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);
1009 CViewport v;
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"));
1069 #else
1070 TextContext->printAt(0.99f, 0.01f, ucstring("(compiled " __DATE__ " " __TIME__ ")"));
1071 #endif
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");
1083 #else
1084 ucstring version = ucstring("Unknown Version");
1085 #endif
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!!!
1108 updateSound();
1109 renderLoadingState(state, true);
1110 if (information) renderInformation();
1111 if (network) updateNetwork();
1112 Driver->swapBuffers();
1113 Driver->EventServer.pump();
1116 void update3dLogo()
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()
1128 // Sanity check
1129 CGlobals::assertNull();
1132 bool CSnowballsClient::run()
1134 // Run the game state loop switcher
1135 switchGameState();
1136 return true;
1139 void CSnowballsClient::release()
1141 // Make sure everything's released
1142 releaseOnline();
1143 releaseOffline();
1144 releaseIngame();
1145 releaseLogin();
1146 releaseCore();
1147 CGlobals::assertNull();
1150 } /* namespace SBCLIENT */
1152 void end();
1153 #ifdef NL_OS_WINDOWS
1154 # ifdef _UNICODE
1155 # define tstring wstring
1156 # else
1157 # define tstring string
1158 # endif
1159 sint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdline, int nCmdShow)
1160 #else
1161 sint main(int argc, char **argv)
1162 #endif
1164 // must do this to allow deallocation when closing with X
1165 atexit(end);
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);
1197 #else
1199 if (argc>=3)
1201 SBCLIENT::Cookie = argv[1];
1202 SBCLIENT::FSAddr = argv[2];
1205 #endif
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"));
1217 if (!f)
1219 f = _tfopen(_T(SBCLIENT_CONFIG_FILE), _T("r"));
1220 if (!f)
1222 OutputDebugString(" ******************************** \n");
1223 OutputDebugString(" * CHANGING WORKING DIRECTORY * \n");
1224 OutputDebugString(" ******************************** \n\n");
1225 char cwd[256];
1226 _tgetcwd(cwd, 256);
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"));
1231 if (!f)
1233 f = _tfopen(_T(SBCLIENT_CONFIG_FILE), _T("r"));
1234 if (!f)
1236 OutputDebugString(" ******************************** \n");
1237 OutputDebugString(" * DEFAULT CONFIG MISSING * \n");
1238 OutputDebugString(" ******************************** \n\n");
1239 return EXIT_FAILURE;
1244 fclose(f);
1246 #endif
1248 // go nel!
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);
1267 #endif
1269 nlinfo("Welcome to NeL!");
1272 SBCLIENT::CSnowballsClient::init();
1273 exit(SBCLIENT::CSnowballsClient::run() ? EXIT_SUCCESS : EXIT_FAILURE);
1274 return EXIT_FAILURE;
1276 void end()
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;
1288 #endif
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;
1301 return true;
1304 NLMISC_COMMAND(sb_offline, "go offline", "")
1306 if (args.size() != 0) return false;
1307 SBCLIENT::NextGameState = SBCLIENT::GameStateOffline;
1308 return true;
1311 NLMISC_COMMAND(sb_unload, "unload game", "")
1313 if (args.size() != 0) return false;
1314 SBCLIENT::NextGameState = SBCLIENT::GameStateUnload;
1315 return true;
1318 NLMISC_COMMAND(sb_reset, "reset game", "")
1320 if (args.size() != 0) return false;
1321 SBCLIENT::NextGameState = SBCLIENT::GameStateReset;
1322 return true;
1325 NLMISC_COMMAND(sb_login, "go to the login screen", "")
1327 if (args.size() != 0) return false;
1328 SBCLIENT::NextGameState = SBCLIENT::GameStateLogin;
1329 return true;
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
1339 lineNumber);
1340 #endif
1341 class CEnableCrtDebug
1343 public:
1344 CEnableCrtDebug()
1346 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
1347 _CrtSetBreakAlloc(0);
1348 #if defined(DEBUG_ALLOC_HOOK)
1349 LastSize = 0;
1350 _CrtSetAllocHook(debugAllocHook);
1351 #endif
1353 #if defined(DEBUG_ALLOC_HOOK)
1354 size_t LastSize;
1355 #endif
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
1361 lineNumber)
1363 if (allocType == _HOOK_ALLOC)
1365 //if (requestNumber == 14806)
1366 // _CrtSetBreakAlloc(14809);
1367 //if (_EnableCrtDebug.LastSize == 4 && size == 40 && requestNumber > 291000 && requestNumber < 292000)
1368 // _CrtDbgBreak();
1369 //if (_EnableCrtDebug.LastSize == 36 && size == 112 && requestNumber > 300000)
1370 // _CrtDbgBreak();
1371 _EnableCrtDebug.LastSize = size;
1373 return TRUE;
1375 #endif
1376 #endif
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);
1396 return TRUE;
1398 #endif
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);
1403 class CCleanupNeL
1405 public:
1406 CCleanupNeL() : _CfBufferState(NULL)
1408 _CfBufferState = cf_create_buffer(NULL, 16384);
1409 cf_switch_to_buffer(_CfBufferState);
1411 ~CCleanupNeL()
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
1416 #endif
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();
1438 #endif
1440 private:
1441 yy_buffer_state *_CfBufferState;
1443 CCleanupNeL _CleanupNeL;
1444 #endif
1446 /* end of file */