diff --git a/.hgignore b/.hgignore index 16e7f1eef..7892f93af 100644 --- a/.hgignore +++ b/.hgignore @@ -260,3 +260,5 @@ code/web/public_php/role_support code/web/public_php/role_domain code/web/public_php/db_version_ring code/web/public_php/config_user.php +code/nel/tools/build_gamedata/processes/pz/build_world_packed_col.cfg +code/nel/tools/build_gamedata/processes/cartographer/island_screenshots.cfg diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 071554e06..372177889 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -2,7 +2,7 @@ # # NeL # Authors: Nevrax and the NeL Community -# Version: 0.10.0 +# Version: 0.11.0 # # Notes: # * Changing install location: add -DCMAKE_INSTALL_PREFIX:PATH=/my/new/path @@ -47,7 +47,7 @@ CHECK_OUT_OF_SOURCE() CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(RyzomCore CXX C) SET(NL_VERSION_MAJOR 0) -SET(NL_VERSION_MINOR 10) +SET(NL_VERSION_MINOR 11) SET(NL_VERSION_PATCH 0) SET(NL_VERSION "${NL_VERSION_MAJOR}.${NL_VERSION_MINOR}.${NL_VERSION_PATCH}") diff --git a/code/CMakeModules/FindDirectXSDK.cmake b/code/CMakeModules/FindDirectXSDK.cmake index 3cf91ec3c..b64fca6ea 100644 --- a/code/CMakeModules/FindDirectXSDK.cmake +++ b/code/CMakeModules/FindDirectXSDK.cmake @@ -52,12 +52,6 @@ IF(DXSDK_DIR) FIND_DXSDK_LIBRARY(DXSDK_XAUDIO_LIBRARY x3daudio) FIND_DXSDK_LIBRARY(DXSDK_D3DX9_LIBRARY d3dx9) FIND_DXSDK_LIBRARY(DXSDK_D3D9_LIBRARY d3d9) - - #FIND_DXSDK_LIBRARY(DXSDK_MESH_LIBRARY mesh) - #FIND_DXSDK_LIBRARY(DXSDK_MAXUTIL_LIBRARY maxutil) - #FIND_DXSDK_LIBRARY(DXSDK_MAXSCRIPT_LIBRARY maxscrpt) - #FIND_DXSDK_LIBRARY(DXSDK_PARAMBLK2_LIBRARY paramblk2) - #FIND_DXSDK_LIBRARY(DXSDK_BMM_LIBRARY bmm) ENDIF(DXSDK_DIR) # Handle the QUIETLY and REQUIRED arguments and set DXSDK_FOUND to TRUE if diff --git a/code/CMakeModules/FindLuabind.cmake b/code/CMakeModules/FindLuabind.cmake index f61885be8..14f67ce44 100644 --- a/code/CMakeModules/FindLuabind.cmake +++ b/code/CMakeModules/FindLuabind.cmake @@ -11,6 +11,12 @@ MACRO(FIND_CORRECT_LUA_VERSION) SET(LUA52_LIBRARY "liblua5.2") CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA52_LIBRARY LUALIB_FOUND) + + IF(NOT LUALIB_FOUND) + # fedora (v20) + SET(LUA52_LIBRARY "liblua-5.2") + CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA52_LIBRARY LUALIB_FOUND) + ENDIF(NOT LUALIB_FOUND) IF(LUALIB_FOUND) MESSAGE(STATUS "Luabind is using Lua 5.2") diff --git a/code/nel/include/nel/3d/anim_detail_trav.h b/code/nel/include/nel/3d/anim_detail_trav.h index 7b51afe84..0a94fe376 100644 --- a/code/nel/include/nel/3d/anim_detail_trav.h +++ b/code/nel/include/nel/3d/anim_detail_trav.h @@ -71,7 +71,7 @@ public: // For clipTrav. cleared at beginning of CClipTrav::traverse void clearVisibleList(); - // For ClipTrav only. NB: list is cleared at begininng of traverse(). NB: only CTransform are supported + // For ClipTrav only. NB: list is cleared at beginning of traverse(). NB: only CTransform are supported void addVisibleModel(CTransform *model) { _VisibleList[_CurrentNumVisibleModels]= model; diff --git a/code/nel/include/nel/3d/bloom_effect.h b/code/nel/include/nel/3d/bloom_effect.h index c10967254..49c959e23 100644 --- a/code/nel/include/nel/3d/bloom_effect.h +++ b/code/nel/include/nel/3d/bloom_effect.h @@ -31,6 +31,7 @@ namespace NL3D class UDriver; class UScene; +class CTextureUser; //----------------------------------------------------------------------------------------------------------- //---------------------------------------- CBloomEffect ----------------------------------------------------- @@ -52,19 +53,14 @@ public: // Destructor ~CBloomEffect(); - // Called after the Driver initialization to indicate if OpenGL or Direct3D is used. - // They are some differences in bloom algorithm depending on this API choice. - // If bloom effect is activated and supported, private method init() is called to initialize - // textures and materials. - // initBloomEffect = false => directx - // initBloomEffect = true => opengl - void init(bool initBloomEffect); + // Called after the Driver initialization. + void init(); // must be called before init void setDriver(UDriver *driver) { _Driver = driver; } UDriver* getDriver() const { return _Driver; } - // must be called before initBloom + // must be called before applyBloom void setScene(UScene *scene) { _Scene = scene; } UScene* getScene() const { return _Scene; } @@ -76,6 +72,9 @@ public: void setDensityBloom(uint8 densityBloom) { _DensityBloom = densityBloom; } uint8 getDensityBloom() const { return _DensityBloom; } + // Applies bloom to the current render target + void applyBloom(); + // Called at the beginning of renderAll method in the main loop, if window has been resized, // reinitialize bloom textures according to new window size. // The bloom texture (_InitText attribute) which is used as render target during scene render @@ -83,11 +82,11 @@ public: // If window size exceeds 256*256 the textures used to apply blur are reinitialized with // 256*256 size. If a dimension is less than 256, the texture is initialized with the nearer // power of 2, lower than this window dimension. - void initBloom(); + // void initBloom(); // Called at the end of renderAll method in the main loop, recover stretched texture, apply // both blur passes, and the blending operation between initial render target and the blured one. - void endBloom(); + // void endBloom(); // In OpenGL, the use of FBO implies that Z buffer values of scene render have been stored in // a depth render target. Then, to display 3D interfaces, we must display them in the same FBO, @@ -95,15 +94,12 @@ public: // This method is called at the end of interfaces display in the main loop, to display final render target // (with added interfaces) in the color frame buffer. // NB : In Direct3D, the final render target is displayed at the end of endBloom call. - void endInterfacesDisplayBloom(); + // void endInterfacesDisplayBloom(); private: - // Initialize textures and materials. - void init(); - // Initialize a bloom texture with new dimensions. - void initTexture(NLMISC::CSmartPtr & tex, bool isMode2D, uint32 width, uint32 height); + // void initTexture(NLMISC::CSmartPtr & tex, bool isMode2D, uint32 width, uint32 height); // Called in endBloom method to build a blurred texture. Two passes (then two calls) // are necessary : horizontal and vertical. @@ -130,6 +126,7 @@ private: // density of bloom uint8 _DensityBloom; +/* // render target textures // used to display scene NLMISC::CSmartPtr _InitText; @@ -140,13 +137,12 @@ private: NLMISC::CSmartPtr _BlurHorizontalTex; // original render target NLMISC::CSmartPtr _OriginalRenderTarget; +*/ // materials // used to display first texture in doBlur passes. NL3D::UMaterial _BlurMat; - // used to display final render target texture in endInterfacesDisplayBloom call (OpenGL). - NL3D::UMaterial _DisplayInitMat; // used to blend initial scene render target texture and blur texture according to a // dest+src - dest*src blend operation. NL3D::UMaterial _DisplayBlurMat; @@ -156,21 +152,24 @@ private: // quads NLMISC::CQuadUV _BlurQuad; - NLMISC::CQuadUV _DisplayQuad; - - // openGL or Direct3D? - bool _InitBloomEffect; // textures and materials already initialized? bool _Init; // current window dimensions - uint32 _WndWidth; - uint32 _WndHeight; + /*uint32 _WndWidth; + uint32 _WndHeight;*/ + // Temporary variables used during applyBloom(...) -> // current blur texture dimensions uint32 _BlurWidth; uint32 _BlurHeight; + // used as stretched texture from _InitText, as displayed texture in first blur pass, + // and as render target in second blur pass. + CTextureUser *_BlurFinalTex; + // used as render target in first blur pass, and as displayed texture on second blur pass. + CTextureUser *_BlurHorizontalTex; + // <- }; } // NL3D diff --git a/code/nel/include/nel/3d/driver.h b/code/nel/include/nel/3d/driver.h index 022246838..8738a7dda 100644 --- a/code/nel/include/nel/3d/driver.h +++ b/code/nel/include/nel/3d/driver.h @@ -42,9 +42,6 @@ namespace NLMISC { class IEventEmitter; -struct IMouseDevice; -struct IKeyboardDevice; -struct IInputDeviceManager; class CRect; class CLog; } @@ -75,6 +72,7 @@ struct IOcclusionQuery; /// A Graphic Mode descriptor. struct GfxMode { + std::string DisplayDevice; bool OffScreen; bool Windowed; uint16 Width; @@ -93,7 +91,7 @@ struct GfxMode Frequency = 0; AntiAlias = -1; } - GfxMode(uint16 w, uint16 h, uint8 d, bool windowed = true, bool offscreen = false, uint frequency = 0, sint8 aa = -1); + GfxMode(uint16 w, uint16 h, uint8 d, bool windowed = true, bool offscreen = false, uint frequency = 0, sint8 aa = -1, const std::string &displayDevice = std::string()); }; // **************************************************************************** @@ -259,7 +257,7 @@ public: virtual emptyProc getWindowProc() = 0; virtual NLMISC::IEventEmitter *getEventEmitter() = 0; - + /// Copy a string to system clipboard. virtual bool copyTextToClipboard(const ucstring &text) = 0; @@ -362,7 +360,7 @@ public: virtual void getDepthRange(float &znear, float &zfar) const = 0; // @} - + /// \name Textures // @{ @@ -434,7 +432,7 @@ public: * Under OpenGL this simply returns the maximum number of texture stages (getNbTextureStages) in both return values. */ virtual void getNumPerStageConstant(uint &lightedMaterial, uint &unlightedMaterial) const = 0; - + // [DEPRECATED] Return if this texture is a rectangle texture that requires RECT sampler (OpenGL specific pre-NPOT functionality) virtual bool isTextureRectangle(ITexture *tex) const = 0; @@ -442,7 +440,7 @@ public: virtual bool supportNonPowerOfTwoTextures() const = 0; // @} - + /// \name Texture operations // @{ @@ -536,7 +534,7 @@ public: virtual bool isForceNormalize() const = 0; // @} - + /// \name Vertex Buffer Hard: Features // @{ @@ -737,7 +735,7 @@ public: virtual uint getSwapVBLInterval() = 0; // @} - + @@ -869,29 +867,6 @@ public: /// x and y must be between 0.0 and 1.0 virtual void setMousePos(float x, float y) = 0; - /** Enable / disable low level mouse. This allow to take advantage of some options (speed of the mouse, automatic wrapping) - * It returns a interface to these parameters when it is supported, or NULL otherwise - * The interface pointer is valid as long as the low level mouse is enabled. - * A call to disable the mouse returns NULL, and restore the default mouse behavior - * NB : - In this mode the mouse cursor isn't drawn. - * - Calls to showCursor have no effects - * - Calls to setCapture have no effects - */ - virtual NLMISC::IMouseDevice *enableLowLevelMouse(bool enable, bool exclusive) = 0; - - /** Enable / disable a low level keyboard. - * Such a keyboard can only send KeyDown and KeyUp event. It just consider the keyboard as a - * gamepad with lots of buttons... - * This returns a interface to some parameters when it is supported, or NULL otherwise. - * The interface pointer is valid as long as the low level keyboard is enabled. - * A call to disable the keyboard returns NULL, and restore the default keyboard behavior - */ - virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable) = 0; - - /** Get the delay in ms for mouse double clicks. - */ - virtual uint getDoubleClickDelay(bool hardwareMouse) = 0; - /** If true, capture the mouse to force it to stay under the window. * NB : this has no effects if a low level mouse is used */ @@ -908,11 +883,6 @@ public: // Change default scale for all cursors virtual void setCursorScale(float scale) = 0; - - /** Check whether there is a low level device manager available, and get its interface. Return NULL if not available - * From this interface you can deal with mouse and keyboard as above, but you can also manage game device (joysticks, joypads ...) - */ - virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager() = 0; // @} @@ -1005,6 +975,9 @@ public: ) = 0; // @} + /// Hack for bloom + virtual bool textureCoordinateAlternativeMode() const = 0; + /// \name Render state: Polygon mode @@ -1106,7 +1079,7 @@ public: virtual bool supportVertexProgram(CVertexProgram::TProfile profile) const = 0; /** Compile the given vertex program, return if successful. - * If a vertex program was set active before compilation, + * If a vertex program was set active before compilation, * the state of the active vertex program is undefined behaviour afterwards. */ virtual bool compileVertexProgram(CVertexProgram *program) = 0; @@ -1133,7 +1106,7 @@ public: virtual bool supportPixelProgram(CPixelProgram::TProfile profile) const = 0; /** Compile the given pixel program, return if successful. - * If a pixel program was set active before compilation, + * If a pixel program was set active before compilation, * the state of the active pixel program is undefined behaviour afterwards. */ virtual bool compilePixelProgram(CPixelProgram *program) = 0; @@ -1160,7 +1133,7 @@ public: virtual bool supportGeometryProgram(CGeometryProgram::TProfile profile) const = 0; /** Compile the given pixel program, return if successful. - * If a pixel program was set active before compilation, + * If a pixel program was set active before compilation, * the state of the active pixel program is undefined behaviour afterwards. */ virtual bool compileGeometryProgram(CGeometryProgram *program) = 0; diff --git a/code/nel/include/nel/3d/driver_user.h b/code/nel/include/nel/3d/driver_user.h index ff9ba8973..f1e1fad84 100644 --- a/code/nel/include/nel/3d/driver_user.h +++ b/code/nel/include/nel/3d/driver_user.h @@ -34,7 +34,7 @@ #include "nel/3d/vertex_stream_manager.h" #include "nel/3d/async_texture_manager.h" #include "nel/3d/lod_character_manager.h" - +#include "nel/3d/render_target_manager.h" namespace NL3D { @@ -71,6 +71,7 @@ protected: bool _WindowInit; CMatrixContext _CurrentMatrixContext; CFontManager _FontManager; + CRenderTargetManager _RenderTargetManager; // Components List. typedef CPtrSet TTextureSet; typedef CPtrSet TTextContextSet; @@ -108,6 +109,11 @@ protected: CMaterial _MatTextInternal; CMaterial _MatTextStretchInternal; + // Default render target for effect pipeline + CTextureUser *_EffectRenderTarget; + UMaterial _MatRenderTarget; + CMaterial _MatRenderTargetInt; + NLMISC::CQuadUV _RenderTargetQuad; // StaticInit static bool _StaticInit; @@ -241,6 +247,16 @@ public: // @} + /// Get the render target manager + virtual CRenderTargetManager &getRenderTargetManager() { return _RenderTargetManager; } + + /// Set a texture the size of the window as render target + virtual void beginDefaultRenderTarget(uint32 width = 0, uint32 height = 0); + + /// Draw the render target to the back buffer + virtual void endDefaultRenderTarget(UScene *scene); + + /// \name Components gestion for Interface 2D/3D. // @{ @@ -410,21 +426,6 @@ public: virtual bool fillBuffer (CBitmap &bitmap); // @} - - /// \name Mouse / Keyboards / Game devices - // @{ - virtual NLMISC::IMouseDevice *enableLowLevelMouse(bool enable, bool exclusive); - // - virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable); - virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager(); - - /** - * wrapper for IEventEmitter::emulateMouseRawMode() - */ - virtual void emulateMouseRawMode(bool enable); - - virtual uint getDoubleClickDelay(bool hardwareMouse); - /// show cursor if b is true, or hide it if b is false virtual void showCursor (bool b); /// x and y must be between 0.0 and 1.0 diff --git a/code/nel/include/nel/3d/fxaa.h b/code/nel/include/nel/3d/fxaa.h new file mode 100644 index 000000000..f7ccf4866 --- /dev/null +++ b/code/nel/include/nel/3d/fxaa.h @@ -0,0 +1,84 @@ +/** + * \file fxaa.h + * \brief CFXAA + * \date 2014-08-03 21:41GMT + * \author Jan Boon (Kaetemi) + * CFXAA + */ + +/* + * Copyright (C) 2014 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#ifndef NL3D_FXAA_H +#define NL3D_FXAA_H +#include + +// STL includes + +// NeL includes +#include +#include + +// Project includes +#include +#include + +#define NL_STEREO_MAX_USER_CAMERAS 8 + +namespace NL3D { + +class ITexture; +class CTextureUser; +class CPixelProgram; +class CVertexProgram; + +/** + * \brief CFXAA + * \date 2014-08-03 21:41GMT + * \author Jan Boon (Kaetemi) + * CFXAA + */ +class CFXAA +{ +public: + CFXAA(NL3D::UDriver *driver); + virtual ~CFXAA(); + + /// Apply effect to current render target. Render target must be managed by render target manager + virtual void applyEffect(); + +private: + UDriver *m_Driver; + + NL3D::UMaterial m_Mat; + // NL3D::CVertexBuffer m_VB; + NLMISC::CQuadUV m_QuadUV; + CVertexProgram *m_VP; + CPixelProgram *m_PP; + + uint m_Width; + uint m_Height; + +}; /* class CFXAA */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_FXAA_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/render_target_manager.h b/code/nel/include/nel/3d/render_target_manager.h new file mode 100644 index 000000000..cae8e31b0 --- /dev/null +++ b/code/nel/include/nel/3d/render_target_manager.h @@ -0,0 +1,83 @@ +/** + * \file render_target_manager.h + * \brief CRenderTargetManager + * \date 2014-07-30 21:30GMT + * \author Jan Boon (Kaetemi) + * CRenderTargetManager + */ + +/* + * Copyright (C) 2013 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#ifndef NL3D_RENDER_TARGET_MANAGER_H +#define NL3D_RENDER_TARGET_MANAGER_H +#include + +// STL includes + +// NeL includes +#include +#include + +// Project includes +#include + +namespace NL3D { + +class UDriver; +class ITexture; +class CTextureUser; +class CDriverUser; + +struct CRenderTargetDescInt; + +/** + * \brief CRenderTargetManager + * \date 2013-07-03 20:17GMT + * \author Jan Boon (Kaetemi) + * CRenderTargetManager + * Usage: Call 'getRenderTarget' when you start using a render target, + * call 'recycledRenderTarget' when the render target can be recycled. + * At end of frame call cleanup. + * Assumes semi-constant render target quantity between frames, + * except on changes of resolution or feature settings. + */ +class CRenderTargetManager +{ +public: + CRenderTargetManager(); + ~CRenderTargetManager(); + + NL3D::CTextureUser *getRenderTarget(uint width, uint height, bool mode2D = false, UTexture::TUploadFormat format = UTexture::Auto); + void recycleRenderTarget(NL3D::CTextureUser *renderTarget); + + void cleanup(); + +private: + friend class CDriverUser; + NL3D::UDriver *m_Driver; + std::vector m_RenderTargets; + +}; /* class CRenderTargetManager */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_RENDER_TARGET_MANAGER_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/render_trav.h b/code/nel/include/nel/3d/render_trav.h index d50d2c242..6e41d8282 100644 --- a/code/nel/include/nel/3d/render_trav.h +++ b/code/nel/include/nel/3d/render_trav.h @@ -139,7 +139,7 @@ public: * \param renderPart : The part of the scene that must be rendered * \param newRender true If scene render is beginning. Otherwise other parts of the scene have already been rendered. */ - void traverse(UScene::TRenderPart renderPart, bool newRender); + void traverse(UScene::TRenderPart renderPart, bool newRender, bool generateShadows); //@} /// \name RenderList. diff --git a/code/nel/include/nel/3d/scene.h b/code/nel/include/nel/3d/scene.h index 50dfe6b8a..12c18b484 100644 --- a/code/nel/include/nel/3d/scene.h +++ b/code/nel/include/nel/3d/scene.h @@ -157,7 +157,7 @@ public: * \param doHrcPass set it to false to indicate that the CHrcTrav have not to be traversed. Useful to optimize if * you know that NONE of your models have moved (a good example is a shoot of the scene from different cameras). */ - void render(bool doHrcPass=true); + void render(bool doHrcPass = true); /** Begin Part Rendering * During beginPartRender()/endPartRender(), you can ask other scene to render their part, but you should @@ -171,10 +171,10 @@ public: * WARNING: always must begin rendering with at least UScene::RenderOpaque, else shadows won't work * WARNING: assert-crash if a part in 'rp' has already been rendered since the last beginPartRender() */ - void renderPart(UScene::TRenderPart rp, bool doHrcPass=true); + void renderPart(UScene::TRenderPart rp, bool doHrcPass = true, bool doTrav = true, bool keepTrav = false); /** End Part Rendering (commit model creation and deletion that were asked during rendering) */ - void endPartRender(); + void endPartRender(bool keepTrav = false); //@} diff --git a/code/nel/include/nel/3d/scene_user.h b/code/nel/include/nel/3d/scene_user.h index 708c8bfd7..639fa33d8 100644 --- a/code/nel/include/nel/3d/scene_user.h +++ b/code/nel/include/nel/3d/scene_user.h @@ -96,8 +96,8 @@ public: // render methods virtual void render(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true); virtual void beginPartRender(); - virtual void renderPart(TRenderPart rp); - virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true); + virtual void renderPart(TRenderPart rp, bool doHrcPass = true, bool doTrav = true, bool keepTrav = false); + virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true, bool keepTrav = true); // update async loading whithout a call to render virtual void updateWaitingInstances(double ellapsedTime); diff --git a/code/nel/include/nel/3d/stereo_debugger.h b/code/nel/include/nel/3d/stereo_debugger.h index b07a9630c..6c974f93d 100644 --- a/code/nel/include/nel/3d/stereo_debugger.h +++ b/code/nel/include/nel/3d/stereo_debugger.h @@ -65,10 +65,17 @@ public: /// Sets driver and generates necessary render targets virtual void setDriver(NL3D::UDriver *driver); - void releaseTextures(); + /*void releaseTextures(); void initTextures(); void setTextures(); - void verifyTextures(); + void verifyTextures();*/ + void getTextures(); + void recycleTextures(); + + /// Attach the driver to the display + virtual bool attachToDisplay(); + /// Detach the driver from the display + virtual void detachFromDisplay(); /// Gets the required screen resolution for this device virtual bool getScreenResolution(uint &width, uint &height); @@ -76,6 +83,8 @@ public: virtual void updateCamera(uint cid, const NL3D::UCamera *camera); /// Get the frustum to use for clipping virtual void getClippingFrustum(uint cid, NL3D::UCamera *camera) const; + /// Get the original frustum of the camera + virtual void getOriginalFrustum(uint cid, NL3D::UCamera *camera) const; /// Is there a next pass virtual bool nextPass(); @@ -89,14 +98,21 @@ public: virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const; /// At the start of a new render target - virtual bool wantClear(); + virtual bool wantClear(); /// The 3D scene virtual bool wantScene(); + /// Scene post processing effects + virtual bool wantSceneEffects(); /// Interface within the 3D scene virtual bool wantInterface3D(); /// 2D Interface virtual bool wantInterface2D(); + /// Is this the first 3D scene of the frame + virtual bool isSceneFirst(); + /// Is this the last 3D scene of the frame + virtual bool isSceneLast(); + /// Returns true if a new render target was set, always fase if not using render targets virtual bool beginRenderTarget(); /// Returns true if a render target was fully drawn, always false if not using render targets @@ -116,9 +132,7 @@ private: CFrustum m_Frustum[NL_STEREO_MAX_USER_CAMERAS]; CMatrix m_CameraMatrix[NL_STEREO_MAX_USER_CAMERAS]; - NLMISC::CSmartPtr m_LeftTex; NL3D::CTextureUser *m_LeftTexU; - NLMISC::CSmartPtr m_RightTex; NL3D::CTextureUser *m_RightTexU; NL3D::UMaterial m_Mat; NLMISC::CQuadUV m_QuadUV; diff --git a/code/nel/include/nel/3d/stereo_display.h b/code/nel/include/nel/3d/stereo_display.h index 3b9c73b74..3b6fdbb21 100644 --- a/code/nel/include/nel/3d/stereo_display.h +++ b/code/nel/include/nel/3d/stereo_display.h @@ -94,6 +94,11 @@ public: /// Sets driver and generates necessary render targets virtual void setDriver(NL3D::UDriver *driver) = 0; + + /// Attach the driver to the display, return true if attached + virtual bool attachToDisplay() = 0; + /// Detach the driver from the display + virtual void detachFromDisplay() = 0; /// Gets the required screen resolution for this device virtual bool getScreenResolution(uint &width, uint &height) = 0; @@ -101,6 +106,8 @@ public: virtual void updateCamera(uint cid, const NL3D::UCamera *camera) = 0; /// Get the frustum to use for clipping virtual void getClippingFrustum(uint cid, NL3D::UCamera *camera) const = 0; + /// Get the original frustum of the camera + virtual void getOriginalFrustum(uint cid, NL3D::UCamera *camera) const = 0; /// Is there a next pass virtual bool nextPass() = 0; @@ -114,20 +121,28 @@ public: virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const = 0; /// At the start of a new render target - virtual bool wantClear() = 0; + virtual bool wantClear() = 0; /// The 3D scene virtual bool wantScene() = 0; + /// Scene post processing effects + virtual bool wantSceneEffects() = 0; /// Interface within the 3D scene virtual bool wantInterface3D() = 0; /// 2D Interface virtual bool wantInterface2D() = 0; + /// Is this the first 3D scene of the frame + virtual bool isSceneFirst() = 0; + /// Is this the last 3D scene of the frame + virtual bool isSceneLast() = 0; + /// Returns true if a new render target was set, always fase if not using render targets virtual bool beginRenderTarget() = 0; /// Returns true if a render target was fully drawn, always false if not using render targets virtual bool endRenderTarget() = 0; static const char *getLibraryName(CStereoDeviceInfo::TStereoDeviceLibrary library); + // List all devices. Device creation factories are no longer valid after re-calling this function static void listDevices(std::vector &devicesOut); static IStereoDisplay *createDevice(const CStereoDeviceInfo &deviceInfo); static void releaseUnusedLibraries(); diff --git a/code/nel/include/nel/3d/stereo_hmd.h b/code/nel/include/nel/3d/stereo_hmd.h index 95c159cfd..3276e78fe 100644 --- a/code/nel/include/nel/3d/stereo_hmd.h +++ b/code/nel/include/nel/3d/stereo_hmd.h @@ -53,6 +53,9 @@ public: /// Get the HMD orientation virtual NLMISC::CQuat getOrientation() const = 0; + /// Set the GUI reference + virtual void setInterfaceMatrix(const NL3D::CMatrix &matrix) = 0; + /// Get GUI center (1 = width, 1 = height, 0 = center) virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const = 0; diff --git a/code/nel/include/nel/3d/stereo_ovr.h b/code/nel/include/nel/3d/stereo_ovr.h index ba6895bf0..750f32027 100644 --- a/code/nel/include/nel/3d/stereo_ovr.h +++ b/code/nel/include/nel/3d/stereo_ovr.h @@ -44,7 +44,7 @@ #ifndef NL3D_STEREO_OVR_H #define NL3D_STEREO_OVR_H -#ifdef HAVE_LIBOVR +#ifdef HAVE_LIBOVR_02 #include @@ -91,6 +91,8 @@ public: virtual void updateCamera(uint cid, const NL3D::UCamera *camera); /// Get the frustum to use for clipping virtual void getClippingFrustum(uint cid, NL3D::UCamera *camera) const; + /// Get the original frustum of the camera + virtual void getOriginalFrustum(uint cid, NL3D::UCamera *camera) const; /// Is there a next pass virtual bool nextPass(); @@ -121,6 +123,9 @@ public: /// Get the HMD orientation virtual NLMISC::CQuat getOrientation() const; + /// Set the GUI reference + virtual void setInterfaceMatrix(const NL3D::CMatrix &matrix); + /// Get GUI center (1 = width, 1 = height, 0 = center) virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const; @@ -132,33 +137,37 @@ public: /// Set the scale of the game in units per meter virtual void setScale(float s); + /// Calculates internal camera information based on the reference camera + void initCamera(uint cid, const NL3D::UCamera *camera); + /// Render GUI + void renderGUI(); + + /// Checks if the device used by this class was actually created + bool isDeviceCreated(); static void listDevices(std::vector &devicesOut); static bool isLibraryInUse(); static void releaseLibrary(); - - /// Calculates internal camera information based on the reference camera - void initCamera(uint cid, const NL3D::UCamera *camera); - /// Checks if the device used by this class was actually created - bool isDeviceCreated(); - private: CStereoOVRDevicePtr *m_DevicePtr; int m_Stage; int m_SubStage; + CViewport m_RegularViewport; CViewport m_LeftViewport; CViewport m_RightViewport; CFrustum m_ClippingFrustum[NL_STEREO_MAX_USER_CAMERAS]; CFrustum m_LeftFrustum[NL_STEREO_MAX_USER_CAMERAS]; CFrustum m_RightFrustum[NL_STEREO_MAX_USER_CAMERAS]; + CFrustum m_OriginalFrustum[NL_STEREO_MAX_USER_CAMERAS]; CMatrix m_CameraMatrix[NL_STEREO_MAX_USER_CAMERAS]; + CMatrix m_InterfaceCameraMatrix; mutable bool m_OrientationCached; mutable NLMISC::CQuat m_OrientationCache; UDriver *m_Driver; - NLMISC::CSmartPtr m_BarrelTex; - NL3D::CTextureUser *m_BarrelTexU; + NL3D::CTextureUser *m_SceneTexture; NL3D::UMaterial m_BarrelMat; + NL3D::CTextureUser *m_GUITexture; NLMISC::CQuadUV m_BarrelQuadLeft; NLMISC::CQuadUV m_BarrelQuadRight; NLMISC::CRefPtr m_PixelProgram; diff --git a/code/nel/include/nel/3d/stereo_ovr_04.h b/code/nel/include/nel/3d/stereo_ovr_04.h new file mode 100644 index 000000000..8bda88c88 --- /dev/null +++ b/code/nel/include/nel/3d/stereo_ovr_04.h @@ -0,0 +1,225 @@ +/** + * \file stereo_ovr.h + * \brief CStereoOVR + * \date 2014-08-04 16:21GMT + * \author Jan Boon (Kaetemi) + * CStereoOVR + */ + +/* + * Copyright (C) 2014 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + * + * Linking this library statically or dynamically with other modules + * is making a combined work based on this library. Thus, the terms + * and conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with the Oculus SDK to produce + * an executable, regardless of the license terms of the Oculus SDK, + * and distribute linked combinations including the two, provided that + * you also meet the terms and conditions of the license of the Oculus + * SDK. You must obey the GNU General Public License in all respects + * for all of the code used other than the Oculus SDK. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. + */ + +#ifndef NL3D_STEREO_OVR_04_H +#define NL3D_STEREO_OVR_04_H + +#ifdef HAVE_LIBOVR + +#include + +// STL includes + +// NeL includes +#include +#include + +// Project includes +#include +#include +#include +#include +#include +#include +#include + +struct ovrHmdDesc_; +typedef const ovrHmdDesc_ *ovrHmd; + +namespace NL3D { + +class ITexture; +class CTextureUser; +class CStereoOVRDeviceFactory; + +#define NL_STEREO_MAX_USER_CAMERAS 8 +#define NL_OVR_EYE_COUNT 2 + +/** + * \brief CStereoOVR + * \date 2014-08-04 16:21GMT + * \author Jan Boon (Kaetemi) + * CStereoOVR + */ +class CStereoOVR : public IStereoHMD +{ +public: + CStereoOVR(const CStereoOVRDeviceFactory *factory); + virtual ~CStereoOVR(); + + /// Sets driver and generates necessary render targets + virtual void setDriver(NL3D::UDriver *driver); + + /// Attach the driver to the display + virtual bool attachToDisplay(); + /// Detach the driver from the display + virtual void detachFromDisplay(); + + /// Gets the required screen resolution for this device + virtual bool getScreenResolution(uint &width, uint &height); + /// Set latest camera position etcetera + virtual void updateCamera(uint cid, const NL3D::UCamera *camera); + /// Get the frustum to use for clipping + virtual void getClippingFrustum(uint cid, NL3D::UCamera *camera) const; + /// Get the original frustum of the camera + virtual void getOriginalFrustum(uint cid, NL3D::UCamera *camera) const; + + /// Is there a next pass + virtual bool nextPass(); + /// Gets the current viewport + virtual const NL3D::CViewport &getCurrentViewport() const; + /// Gets the current camera frustum + virtual const NL3D::CFrustum &getCurrentFrustum(uint cid) const; + /// Gets the current camera frustum + virtual void getCurrentFrustum(uint cid, NL3D::UCamera *camera) const; + /// Gets the current camera matrix + virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const; + + /// At the start of a new render target + virtual bool wantClear(); + /// The 3D scene + virtual bool wantScene(); + /// Scene post processing effects + virtual bool wantSceneEffects(); + /// Interface within the 3D scene + virtual bool wantInterface3D(); + /// 2D Interface + virtual bool wantInterface2D(); + + /// Is this the first 3D scene of the frame + virtual bool isSceneFirst(); + /// Is this the last 3D scene of the frame + virtual bool isSceneLast(); + + /// Returns true if a new render target was set, always fase if not using render targets + virtual bool beginRenderTarget(); + /// Returns true if a render target was fully drawn, always false if not using render targets + virtual bool endRenderTarget(); + + + /// Get the HMD orientation + virtual NLMISC::CQuat getOrientation() const; + + /// Set the GUI reference + virtual void setInterfaceMatrix(const NL3D::CMatrix &matrix); + + /// Get GUI center (1 = width, 1 = height, 0 = center) + virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const; + + /// Set the head model, eye position relative to orientation point + virtual void setEyePosition(const NLMISC::CVector &v); + /// Get the head model, eye position relative to orientation point + virtual const NLMISC::CVector &getEyePosition() const; + + /// Set the scale of the game in units per meter + virtual void setScale(float s); + + /// Calculates internal camera information based on the reference camera + void initCamera(uint cid, const NL3D::UCamera *camera); + /// Render GUI + void renderGUI(); + + /// Checks if the device used by this class was actually created + bool isDeviceCreated(); + + static void listDevices(std::vector &devicesOut); + static bool isLibraryInUse(); + static void releaseLibrary(); + +private: + ovrHmd m_DevicePtr; + bool m_DebugDevice; + + int m_Stage; + int m_SubStage; + + CViewport m_RegularViewport; + CViewport m_EyeViewport[NL_OVR_EYE_COUNT]; + CFrustum m_EyeFrustumBase[NL_OVR_EYE_COUNT]; + uint m_RenderTargetWidth; + uint m_RenderTargetHeight; + NLMISC::CVector2f m_EyeUVScaleOffset[NL_OVR_EYE_COUNT][2]; + float m_EyeViewAdjustX[NL_OVR_EYE_COUNT]; + + CVertexBuffer m_VB[NL_OVR_EYE_COUNT]; + CIndexBuffer m_IB[NL_OVR_EYE_COUNT]; + uint32 m_NbTris[NL_OVR_EYE_COUNT]; + + CFrustum m_ClippingFrustum[NL_STEREO_MAX_USER_CAMERAS]; + CFrustum m_LeftFrustum[NL_STEREO_MAX_USER_CAMERAS]; + CFrustum m_RightFrustum[NL_STEREO_MAX_USER_CAMERAS]; + CFrustum m_OriginalFrustum[NL_STEREO_MAX_USER_CAMERAS]; + CMatrix m_CameraMatrix[NL_STEREO_MAX_USER_CAMERAS]; + CMatrix m_InterfaceCameraMatrix; + mutable bool m_OrientationCached; + mutable NLMISC::CQuat m_OrientationCache; + + UDriver *m_Driver; + + CTextureUser *m_GUITexture; + NL3D::CTextureUser *m_SceneTexture; + + UMaterial m_UnlitMat; + + UDriver::CMode m_OriginalMode; + sint32 m_OriginalWinPosX; + sint32 m_OriginalWinPosY; + bool m_AttachedDisplay; + + /* + NL3D::UMaterial m_BarrelMat; + NLMISC::CQuadUV m_BarrelQuadLeft; + NLMISC::CQuadUV m_BarrelQuadRight; + NLMISC::CRefPtr m_PixelProgram;*/ + NLMISC::CVector m_EyePosition; + float m_Scale; + +}; /* class CStereoOVR */ + +} /* namespace NL3D */ + +#endif /* HAVE_LIBOVR */ + +#endif /* #ifndef NL3D_STEREO_OVR_04_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/text_context.h b/code/nel/include/nel/3d/text_context.h index 203e2b3c3..8cf7ad7f0 100644 --- a/code/nel/include/nel/3d/text_context.h +++ b/code/nel/include/nel/3d/text_context.h @@ -82,6 +82,8 @@ public: void setShaded (bool b) { _Shaded = b; } + void setShadeOutline (bool b) { _ShadeOutline = b; } + void setShadeExtent (float shext) { _ShadeExtent = shext; } /// The alpha of the shade is multiplied at each draw with the alpha of the color. Default: (0,0,0,255) @@ -107,6 +109,8 @@ public: bool getShaded() const { return _Shaded; } + bool getShadeOutline() const { return _ShadeOutline; } + bool getKeep800x600Ratio() const {return _Keep800x600Ratio;} NLMISC::CRGBA getShadeColor () const { return _ShadeColor; } @@ -138,15 +142,30 @@ public: { nlassert (index < _CacheStrings.size()); CComputedString &rCS = _CacheStrings[index]; - if(_Shaded) + if (_Shaded) { - CRGBA bkup = rCS.Color; + CRGBA bkup = rCS.Color; rCS.Color = _ShadeColor; rCS.Color.A = (uint8)((uint(bkup.A) * uint(_ShadeColor.A)+1)>>8); - rCS.render2D (*_Driver, x+_ShadeExtent, z-_ShadeExtent, _HotSpot, _ScaleX, _ScaleZ); + if (_ShadeOutline) + { + float rext = _ShadeExtent * 0.7071f; + rCS.render2D(*_Driver, x+rext, z-rext, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x-rext, z-rext, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x-rext, z+rext, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x+rext, z+rext, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x+_ShadeExtent, z, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x-_ShadeExtent, z, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x, z-_ShadeExtent, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x, z-_ShadeExtent, _HotSpot, _ScaleX, _ScaleZ); + } + else + { + rCS.render2D(*_Driver, x+_ShadeExtent, z-_ShadeExtent, _HotSpot, _ScaleX, _ScaleZ); + } rCS.Color= bkup; } - rCS.render2D (*_Driver, x, z, _HotSpot, _ScaleX, _ScaleZ); + rCS.render2D(*_Driver, x, z, _HotSpot, _ScaleX, _ScaleZ); } /** Clip and print a string that is in the cache (it leaves the string in the cache) @@ -161,7 +180,22 @@ public: CRGBA bkup = rCS.Color; rCS.Color= _ShadeColor; rCS.Color.A = (uint8)((uint(bkup.A) * uint(_ShadeColor.A)+1)>>8); - rCS.render2DClip(*_Driver, rdrBuffer, x+_ShadeExtent, z-_ShadeExtent, xmin, ymin, xmax, ymax); + if (_ShadeOutline) + { + float rext = _ShadeExtent * 0.7071f; + rCS.render2DClip(*_Driver, rdrBuffer, x+rext, z-rext, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x-rext, z-rext, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x-rext, z+rext, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x+rext, z+rext, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x+_ShadeExtent, z, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x-_ShadeExtent, z, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x, z+_ShadeExtent, xmin, ymin, xmax, ymax); + rCS.render2DClip(*_Driver, rdrBuffer, x, z-_ShadeExtent, xmin, ymin, xmax, ymax); + } + else + { + rCS.render2DClip(*_Driver, rdrBuffer, x+_ShadeExtent, z-_ShadeExtent, xmin, ymin, xmax, ymax); + } rCS.Color= bkup; } rCS.render2DClip (*_Driver, rdrBuffer, x, z, xmin, ymin, xmax, ymax); @@ -174,12 +208,27 @@ public: { nlassert (index < _CacheStrings.size()); CComputedString &rCS = _CacheStrings[index]; - if(_Shaded) + if (_Shaded) { CRGBA bkup = rCS.Color; rCS.Color= _ShadeColor; rCS.Color.A = (uint8)((uint(bkup.A) * uint(_ShadeColor.A)+1)>>8); - rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x+_ShadeExtent, y-_ShadeExtent, depth, xmin, ymin, xmax, ymax); + if (_ShadeOutline) + { + float rext = _ShadeExtent * 0.7071f; + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x+rext, y-rext, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x-rext, y-rext, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x-rext, y+rext, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x+rext, y+rext, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x+_ShadeExtent, y, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x-_ShadeExtent, y, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x, y+_ShadeExtent, depth, xmin, ymin, xmax, ymax); + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x, y-_ShadeExtent, depth, xmin, ymin, xmax, ymax); + } + else + { + rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x+_ShadeExtent, y-_ShadeExtent, depth, xmin, ymin, xmax, ymax); + } rCS.Color= bkup; } rCS.render2DUnProjected (*_Driver, renderBuffer, frustum, scaleMatrix, x, y, depth, xmin, ymin, xmax, ymax); @@ -194,17 +243,32 @@ public: _FontManager->computeString (ucstr, _FontGen, _Color, _FontSize, _Driver, _TempString, _Keep800x600Ratio); // draw shaded - if(_Shaded) + if (_Shaded) { CRGBA bkup = _TempString.Color; - _TempString.Color= _ShadeColor; + _TempString.Color = _ShadeColor; _TempString.Color.A = (uint8)((uint(bkup.A) * uint(_ShadeColor.A)+1)>>8); - _TempString.render2D (*_Driver,x+_ShadeExtent,z-_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); - _TempString.Color= bkup; + if (_ShadeOutline) + { + float rext = _ShadeExtent * 0.7071f; + _TempString.render2D(*_Driver,x+rext,z-rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x-rext,z-rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x-rext,z+rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x+rext,z+rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x+_ShadeExtent,z,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x-_ShadeExtent,z,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x,z+_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x,z-_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); + } + else + { + _TempString.render2D(*_Driver,x+_ShadeExtent,z-_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); + } + _TempString.Color = bkup; } // draw - _TempString.render2D (*_Driver, x, z, _HotSpot, _ScaleX, _ScaleZ); + _TempString.render2D(*_Driver, x, z, _HotSpot, _ScaleX, _ScaleZ); } /// Directly print a string @@ -218,17 +282,32 @@ public: _FontManager->computeString (str, _FontGen, _Color, _FontSize, _Driver, _TempString, _Keep800x600Ratio); // draw shaded - if(_Shaded) + if (_Shaded) { CRGBA bkup = _TempString.Color; _TempString.Color = _ShadeColor; _TempString.Color.A = (uint8)((uint(bkup.A) * uint(_ShadeColor.A)+1)>>8); - _TempString.render2D (*_Driver,x+_ShadeExtent,z-_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); - _TempString.Color= bkup; + if (_ShadeOutline) + { + float rext = _ShadeExtent * 0.7071f; + _TempString.render2D(*_Driver,x+rext,z-rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x-rext,z-rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x-rext,z+rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x+rext,z+rext,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x+_ShadeExtent,z,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x-_ShadeExtent,z,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x,z+_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); + _TempString.render2D(*_Driver,x,z-_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); + } + else + { + _TempString.render2D(*_Driver,x+_ShadeExtent,z-_ShadeExtent,_HotSpot,_ScaleX,_ScaleZ); + } + _TempString.Color = bkup; } // draw - _TempString.render2D (*_Driver, x, z, _HotSpot, _ScaleX, _ScaleZ); + _TempString.render2D(*_Driver, x, z, _HotSpot, _ScaleX, _ScaleZ); } /// Get computed string from index @@ -317,6 +396,9 @@ private: /// true if text is shaded bool _Shaded; + /// true if shade appears as an outline + bool _ShadeOutline; + /// shade's extent (shadow size) float _ShadeExtent; diff --git a/code/nel/include/nel/3d/text_context_user.h b/code/nel/include/nel/3d/text_context_user.h index a95fb2ca1..8e14dc878 100644 --- a/code/nel/include/nel/3d/text_context_user.h +++ b/code/nel/include/nel/3d/text_context_user.h @@ -64,19 +64,21 @@ public: /// \name Text look. // @{ void setColor(NLMISC::CRGBA color); - void setFontSize(uint32 fontSize) ; - uint32 getFontSize() const ; - void setHotSpot(THotSpot hotSpot) ; - THotSpot getHotSpot() const ; - void setScaleX(float scaleX) ; - void setScaleY(float scaleY) ; - float getScaleX() const ; - float getScaleY() const ; - void setShaded(bool b) ; - bool getShaded() const ; - void setShadeExtent(float shext) ; - void setShadeColor (NLMISC::CRGBA sc); - NLMISC::CRGBA getShadeColor () const; + void setFontSize(uint32 fontSize); + uint32 getFontSize() const; + void setHotSpot(THotSpot hotSpot); + THotSpot getHotSpot() const; + void setScaleX(float scaleX); + void setScaleY(float scaleY); + float getScaleX() const; + float getScaleY() const; + void setShaded(bool b); + bool getShaded() const; + void setShadeOutline(bool b); + bool getShadeOutline() const; + void setShadeExtent(float shext) ; + void setShadeColor (NLMISC::CRGBA sc); + NLMISC::CRGBA getShadeColor () const; void setKeep800x600Ratio(bool keep); bool getKeep800x600Ratio() const; // @} diff --git a/code/nel/include/nel/3d/u_driver.h b/code/nel/include/nel/3d/u_driver.h index 67e0c30fd..dc2b02e56 100644 --- a/code/nel/include/nel/3d/u_driver.h +++ b/code/nel/include/nel/3d/u_driver.h @@ -35,9 +35,6 @@ namespace NLMISC { - struct IMouseDevice; - struct IKeyboardDevice; - struct IInputDeviceManager; class CLog; } @@ -63,6 +60,7 @@ class U3dMouseListener; class ULight; class UAnimationSet; class UWaterEnvMap; +class CRenderTargetManager; typedef void (*emptyProc)(void); @@ -94,6 +92,7 @@ public: /// A Graphic Mode descriptor. struct CMode { + std::string DisplayDevice; bool Windowed; uint16 Width; uint16 Height; @@ -110,8 +109,9 @@ public: Frequency = 0; AntiAlias = -1; } - CMode(uint16 w, uint16 h, uint8 d, bool windowed= true, uint frequency = 0, sint8 aa = -1) + CMode(uint16 w, uint16 h, uint8 d, bool windowed= true, uint frequency = 0, sint8 aa = -1, const std::string &displayDevice = std::string()) { + DisplayDevice = displayDevice; Windowed = windowed; Width = w; Height = h; @@ -309,6 +309,16 @@ public: // @} + /// Get the render target manager + virtual CRenderTargetManager &getRenderTargetManager() =0; + + /// Set a texture of specified size or of the size of the window as render target + virtual void beginDefaultRenderTarget(uint32 width = 0, uint32 height = 0) =0; + + /// Draw the render target to the back buffer + virtual void endDefaultRenderTarget(UScene *scene) =0; + + /// \name Components gestion for Interface 2D/3D. // @{ @@ -556,36 +566,6 @@ public: /// \name Mouse / Keyboard / Gamedevices // @{ - /** Enable / disable low level mouse. This allow to take advantage of some options (speed of the mouse, automatic wrapping) - * It returns a interface to these parameters when it is supported, or NULL otherwise - * The interface pointer is valid as long as the low level mouse is enabled. - * A call to disable the mouse returns NULL, and restore the default mouse behaviour - * NB : - In this mode the mouse cursor isn't drawn. - * - Calls to showCursor have no effects - * - Calls to setCapture have no effects - */ - virtual NLMISC::IMouseDevice *enableLowLevelMouse(bool enable, bool hardware) = 0; - - /** Enable / disable a low level keyboard. - * This returns a interface to some parameters when it is supported, or NULL otherwise. - * The interface pointer is valid as long as the low level keyboard is enabled. - * A call to disable the keyboard returns NULL, and restore the default keyboard behaviour. - */ - virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable) = 0; - - /** Check whether there is a low level device manager available, and get its interface. Return NULL if not available. - * From this interface you can deal with mouse and keyboard as above, but you can also manage game devices (joysticks, joypads ...) - */ - virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager() = 0; - - /** - * wrapper for IEventEmitter::emulateMouseRawMode() - */ - virtual void emulateMouseRawMode(bool enable) = 0; - - // get delay used for mouse double click - virtual uint getDoubleClickDelay(bool hardwareMouse) = 0; - /** show cursor if b is true, or hide it if b is false * NB: This has no effects if a low level mouse is used. */ diff --git a/code/nel/include/nel/3d/u_scene.h b/code/nel/include/nel/3d/u_scene.h index d60266afe..c0733c5d2 100644 --- a/code/nel/include/nel/3d/u_scene.h +++ b/code/nel/include/nel/3d/u_scene.h @@ -134,14 +134,17 @@ public: /** Render a part (see render() for what it does) * beginPartRender() must have been called * \param renderPart a combination of UScene::TRenderPart flags, allow to choose which part of the scene must be rendered + * \param doHrcPass set it to false to indicate that the CHrcTrav have not to be traversed. Useful to optimize if + * you know that NONE of your models have moved (a good example is a shoot of the scene from different cameras). + * \param doTrav set to false when processing a second frame for stereo rending to avoid unnecessary traversals. * WARNING: always must begin rendering with at least UScene::RenderOpaque, else shadows won't work * WARNING: assert-crash if a part in 'rp' has already been rendered since the last beginPartRender() */ - virtual void renderPart(UScene::TRenderPart rp) =0; + virtual void renderPart(UScene::TRenderPart rp, bool doHrcPass = true, bool doTrav = true, bool keepTrav = false) =0; /** End Part Rendering (commit model creation and deletion that were asked during rendering) */ - virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true) =0; + virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true, bool keepTrav = false) =0; /** Update waiting instances and igs that are loaded asynchronously diff --git a/code/nel/include/nel/3d/u_text_context.h b/code/nel/include/nel/3d/u_text_context.h index dcaa1949a..1056d3839 100644 --- a/code/nel/include/nel/3d/u_text_context.h +++ b/code/nel/include/nel/3d/u_text_context.h @@ -174,6 +174,15 @@ public: * \return the shade state */ virtual bool getShaded () const = 0; + /** + * set the shade states + * \param the shade state + */ + virtual void setShadeOutline (bool b) = 0; + /** + * \return the shade state + */ + virtual bool getShadeOutline () const = 0; /** * set the shadow's size * \param the shade extent diff --git a/code/nel/include/nel/gui/ctrl_text_button.h b/code/nel/include/nel/gui/ctrl_text_button.h index 183b6a65e..d2b49ffa9 100644 --- a/code/nel/include/nel/gui/ctrl_text_button.h +++ b/code/nel/include/nel/gui/ctrl_text_button.h @@ -126,6 +126,7 @@ namespace NLGUI void onRemoved(); void onWidgetDeleted( CInterfaceElement *e ); + void moveBy( sint32 x, sint32 y ); protected: diff --git a/code/nel/include/nel/gui/editor_selection_watcher.h b/code/nel/include/nel/gui/editor_selection_watcher.h index 415f4f9db..7e262bdf1 100644 --- a/code/nel/include/nel/gui/editor_selection_watcher.h +++ b/code/nel/include/nel/gui/editor_selection_watcher.h @@ -15,6 +15,7 @@ // along with this program. If not, see . #include +#include namespace NLGUI { @@ -24,7 +25,7 @@ namespace NLGUI public: /// Notifies the watcher about the change - virtual void selectionChanged( std::string &newSelection ) = 0; + virtual void selectionChanged() = 0; }; } diff --git a/code/nel/include/nel/gui/group_html.h b/code/nel/include/nel/gui/group_html.h index 3f5526197..21d609af3 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -285,7 +285,7 @@ namespace NLGUI void addImage(const char *image, bool globalColor, bool reloadImg=false); // Add a text area in the current paragraph - CInterfaceGroup *addTextArea (const std::string &templateName, const char *name, uint rows, uint cols, bool multiLine, const ucstring &content); + CInterfaceGroup *addTextArea (const std::string &templateName, const char *name, uint rows, uint cols, bool multiLine, const ucstring &content, uint maxlength); // Add a combo box in the current paragraph CDBGroupComboBox *addComboBox(const std::string &templateName, const char *name); @@ -528,7 +528,7 @@ namespace NLGUI CCellParams () : BgColor(0,0,0,0) { Align = CGroupCell::Left; - VAlign = CGroupCell::Top; + VAlign = CGroupCell::Middle; LeftMargin = 0; NoWrap = false; } @@ -557,6 +557,7 @@ namespace NLGUI std::string _TextAreaName; uint _TextAreaRow; uint _TextAreaCols; + uint _TextAreaMaxLength; // current mode is in select option bool _SelectOption; diff --git a/code/nel/include/nel/gui/group_menu.h b/code/nel/include/nel/gui/group_menu.h index 56b9fb0e3..420967347 100644 --- a/code/nel/include/nel/gui/group_menu.h +++ b/code/nel/include/nel/gui/group_menu.h @@ -381,6 +381,7 @@ namespace NLGUI bool _CloseSubMenuUsingPopModal; bool _Shadow; + bool _ShadowOutline; bool _Formatted; uint8 _Space; sint32 _FontSize; diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h index 60d3d9e63..746078908 100644 --- a/code/nel/include/nel/gui/group_table.h +++ b/code/nel/include/nel/gui/group_table.h @@ -78,6 +78,9 @@ namespace NLGUI // The Width you want in pixel. This is the parameter sint32 WidthWanted; + sint32 ColSpan; + sint32 RowSpan; + sint32 TableColumnIndex; // The min height of the cell sint32 Height; @@ -142,6 +145,7 @@ namespace NLGUI // Table borders sint32 Border; + NLMISC::CRGBA BorderColor; sint32 CellPadding; sint32 CellSpacing; @@ -191,13 +195,14 @@ namespace NLGUI WidthMax = 0; WidthWanted = 0; TableRatio = 0; - Height = 0; + RowSpan = 1; } sint32 Width; sint32 Height; sint32 WidthWanted; sint32 WidthMax; float TableRatio; + sint32 RowSpan; }; // Table row diff --git a/code/nel/include/nel/gui/interface_element.h b/code/nel/include/nel/gui/interface_element.h index 764d165ef..c1f6d20e7 100644 --- a/code/nel/include/nel/gui/interface_element.h +++ b/code/nel/include/nel/gui/interface_element.h @@ -233,6 +233,9 @@ namespace NLGUI virtual void setActive (bool state); + void setXReal( sint32 x ){ _XReal = x; } + void setYReal( sint32 y ){ _YReal = y; } + void setX (sint32 x) { _X = x; } void setXAndInvalidateCoords (sint32 x) { _X = x; invalidateCoords(); } @@ -488,8 +491,12 @@ namespace NLGUI void setEditorSelected( bool b ){ editorSelected = b; } bool isEditorSelected() const{ return editorSelected; } + void parsePosParent( const std::string &id ); void setPosParent( const std::string &id ); + void getPosParent( std::string &id ) const; + void parseSizeParent( const std::string &id ); void setSizeParent( const std::string &id ); + void getSizeParent( std::string &id ) const; void setSerializable( bool b ){ serializable = b; } bool IsSerializable() const{ return serializable; } @@ -505,7 +512,24 @@ namespace NLGUI /// Called when the widget is deleted, /// so other widgets in the group can check if it belongs to them - virtual void onWidgetDeleted( CInterfaceElement *e ){} + virtual void onWidgetDeleted( CInterfaceElement *e ); + + /// Move the element by x in the X direction and y in the Y direction + // Uses real coordinates + virtual void moveBy( sint32 x, sint32 y ) + { + _XReal += x; + _YReal += y; + } + + /// Retrieves the coordinates of the specified hotspot + void getHSCoords( const THotSpot &hs, sint32 &x, sint32 &y ) const; + + /// Tells which hotspot is the closest to the specified element + void getClosestHotSpot( const CInterfaceElement *other, THotSpot &hs ); + + /// Aligns the element to the other element specified + void alignTo( CInterfaceElement *other ); protected: diff --git a/code/nel/include/nel/gui/widget_addition_watcher.h b/code/nel/include/nel/gui/interface_factory.h similarity index 81% rename from code/nel/include/nel/gui/widget_addition_watcher.h rename to code/nel/include/nel/gui/interface_factory.h index a2717e398..bd7f8352a 100644 --- a/code/nel/include/nel/gui/widget_addition_watcher.h +++ b/code/nel/include/nel/gui/interface_factory.h @@ -14,19 +14,22 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -#ifndef WIDGET_ADD_WATCHER -#define WIDGET_ADD_WATCHER +#ifndef IFACE_FACTORY +#define IFACE_FACTORY #include namespace NLGUI { - class IWidgetAdditionWatcher + class CViewBase; + + /// Simple interface element ( widget ) factory + class CInterfaceFactory { public: - virtual void widgetAdded( const std::string &name ) = 0; + static CViewBase* createClass( const std::string &name ); }; } -#endif +#endif diff --git a/code/nel/include/nel/gui/interface_group.h b/code/nel/include/nel/gui/interface_group.h index f72bc6f1f..b9efd3357 100644 --- a/code/nel/include/nel/gui/interface_group.h +++ b/code/nel/include/nel/gui/interface_group.h @@ -57,6 +57,7 @@ namespace NLGUI CInterfaceElement* findFromShortId(const std::string &id); /// Dynamic creation + virtual void addElement (CInterfaceElement *child, sint eltOrder = -1 ); virtual void addView (CViewBase *child , sint eltOrder = -1); virtual void addCtrl (CCtrlBase *child, sint eltOrder = -1); virtual void addGroup (CInterfaceGroup *child, sint eltOrder = -1); @@ -79,6 +80,9 @@ namespace NLGUI bool delElement (const std::string &id, bool noWarning=false); bool delElement (CInterfaceElement *pIE, bool noWarning=false); + // Take the element from the group, but don't delete it! + CInterfaceElement* takeElement( CInterfaceElement *e ); + uint getNumGroup() const { return (uint)_ChildrenGroups.size(); } CInterfaceGroup *getGroup(uint index) const; @@ -324,6 +328,17 @@ namespace NLGUI void onWidgetDeleted( CInterfaceElement *e ); + void moveBy( sint32 x, sint32 y ); + + // Blows up the group, moves it's children to it's parent + bool explode(); + + /// Adjusts the group's size so that all elements are fully inside the borders + void spanElements(); + + /// Aligns the elements - used for forming groups + void alignElements(); + protected: void makeNewClip (sint32 &oldClipX, sint32 &oldClipY, sint32 &oldClipW, sint32 &oldClipH); diff --git a/code/nel/include/nel/gui/interface_options.h b/code/nel/include/nel/gui/interface_options.h index f52b9479a..da0ea7de8 100644 --- a/code/nel/include/nel/gui/interface_options.h +++ b/code/nel/include/nel/gui/interface_options.h @@ -150,16 +150,17 @@ namespace NLGUI sint32 TxId_E_Open, W_E_Open, H_E_Open; sint32 TxId_M_Open, W_M_Open, H_M_Open; - sint32 TxId_TL_HighLight; - sint32 TxId_T_HighLight; - sint32 TxId_TR_HighLight; - sint32 TxId_L_HighLight; - sint32 TxId_R_HighLight; - sint32 TxId_BL_HighLight; - sint32 TxId_B_HighLight; - sint32 TxId_BR_HighLight; + sint32 TxId_TL_HighLight, W_TL_HighLight, H_TL_HighLight; + sint32 TxId_T_HighLight, W_T_HighLight, H_T_HighLight; + sint32 TxId_TR_HighLight, W_TR_HighLight, H_TR_HighLight; + sint32 TxId_L_HighLight, W_L_HighLight, H_L_HighLight; + sint32 TxId_R_HighLight, W_R_HighLight, H_R_HighLight; + sint32 TxId_BL_HighLight, W_BL_HighLight, H_BL_HighLight; + sint32 TxId_B_HighLight, W_B_HighLight, H_B_HighLight; + sint32 TxId_BR_HighLight, W_BR_HighLight, H_BR_HighLight; - sint32 HeaderH; + sint32 HeaderH; + sint32 InsetT; // Offset height of top texture }; // *************************************************************************** diff --git a/code/nel/include/nel/gui/interface_parser.h b/code/nel/include/nel/gui/interface_parser.h index 2bf1df9a8..18ec9045a 100644 --- a/code/nel/include/nel/gui/interface_parser.h +++ b/code/nel/include/nel/gui/interface_parser.h @@ -28,6 +28,7 @@ #include "nel/gui/proc.h" #include "nel/gui/widget_manager.h" #include "nel/gui/link_data.h" +#include "nel/gui/variable_data.h" namespace NLGUI { @@ -100,20 +101,6 @@ namespace NLGUI virtual void setupOptions() = 0; }; - - struct VariableData - { - std::string entry; - std::string type; - std::string value; - uint32 size; - - VariableData() - { - size = 0; - } - }; - CInterfaceParser(); virtual ~CInterfaceParser(); @@ -353,7 +340,15 @@ namespace NLGUI std::map< std::string, std::string > pointerSettings; std::map< std::string, std::map< std::string, std::string > > keySettings; + std::string _WorkDir; + public: + /// Sets the working directory, where files should be looked for + void setWorkDir( const std::string &workdir ){ _WorkDir = workdir; } + + /// Looks up a file in either the working directory or using CPath::lookup + std::string lookup( const std::string &file ); + void initLUA(); void uninitLUA(); bool isLuaInitialized() const{ return luaInitialized; } @@ -378,6 +373,7 @@ namespace NLGUI void setEditorMode( bool b ){ editorMode = b; } + void setVariable( const VariableData &v ); bool serializeVariables( xmlNodePtr parentNode ) const; bool serializeProcs( xmlNodePtr parentNode ) const; bool serializePointerSettings( xmlNodePtr parentNode ) const; diff --git a/code/nel/include/nel/gui/libwww.h b/code/nel/include/nel/gui/libwww.h index 8da217382..6a744b8c0 100644 --- a/code/nel/include/nel/gui/libwww.h +++ b/code/nel/include/nel/gui/libwww.h @@ -79,6 +79,7 @@ namespace NLGUI HTML_ATTR(TABLE,ALIGN) = 0, HTML_ATTR(TABLE,BGCOLOR), HTML_ATTR(TABLE,BORDER), + HTML_ATTR(TABLE,BORDERCOLOR), HTML_ATTR(TABLE,CELLPADDING), HTML_ATTR(TABLE,CELLSPACING), HTML_ATTR(TABLE,CLASS), @@ -189,6 +190,7 @@ namespace NLGUI HTML_ATTR(TEXTAREA,DISABLED), HTML_ATTR(TEXTAREA,ID), HTML_ATTR(TEXTAREA,LANG), + HTML_ATTR(TEXTAREA,MAXLENGTH), HTML_ATTR(TEXTAREA,NAME), HTML_ATTR(TEXTAREA,READONLY), HTML_ATTR(TEXTAREA,ROWS), diff --git a/code/nel/include/nel/gui/parser.h b/code/nel/include/nel/gui/parser.h index db868f70d..bc53e402d 100644 --- a/code/nel/include/nel/gui/parser.h +++ b/code/nel/include/nel/gui/parser.h @@ -23,6 +23,7 @@ #include "nel/misc/types_nl.h" #include "nel/gui/proc.h" #include "nel/gui/link_data.h" +#include "nel/gui/variable_data.h" namespace NLGUI { @@ -83,11 +84,13 @@ namespace NLGUI virtual void removeLinkData( uint32 id ) = 0; virtual bool getLinkData( uint32 id, SLinkData &linkData ) = 0; virtual void updateLinkData( uint32 id, const SLinkData &linkData ) = 0; + virtual void setVariable( const VariableData &v ) = 0; virtual bool serializeVariables( xmlNodePtr parentNode ) const = 0; virtual bool serializeProcs( xmlNodePtr parentNode ) const = 0; virtual bool serializePointerSettings( xmlNodePtr parentNode ) const = 0; virtual bool serializeKeySettings( xmlNodePtr parentNode ) const = 0; virtual CViewBase* createClass( const std::string &name ) = 0; + virtual void setWorkDir( const std::string &workdir ) = 0; }; } diff --git a/code/nel/include/nel/gui/root_group.h b/code/nel/include/nel/gui/root_group.h new file mode 100644 index 000000000..58963a3b2 --- /dev/null +++ b/code/nel/include/nel/gui/root_group.h @@ -0,0 +1,46 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef ROOT_GROUP_H +#define ROOT_GROUP_H + +#include +#include + +#include "nel/gui/interface_group.h" + +namespace NLGUI +{ + + class CRootGroup : public CInterfaceGroup + { + public: + CRootGroup(const TCtorParam ¶m); + virtual ~CRootGroup(); + + virtual CInterfaceElement* getElement (const std::string &id); + virtual void addGroup (CInterfaceGroup *child, sint eltOrder = -1); + virtual bool delGroup (CInterfaceGroup *child, bool dontDelete = false); + + private: + std::map< std::string, CInterfaceGroup* > _Accel; + }; + +} + +#endif + diff --git a/code/nel/src/misc/game_device_events.cpp b/code/nel/include/nel/gui/variable_data.h similarity index 70% rename from code/nel/src/misc/game_device_events.cpp rename to code/nel/include/nel/gui/variable_data.h index bf64a1c4b..cffba2bce 100644 --- a/code/nel/src/misc/game_device_events.cpp +++ b/code/nel/include/nel/gui/variable_data.h @@ -1,4 +1,4 @@ -// NeL - MMORPG Framework +// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify @@ -14,20 +14,28 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -#include "stdmisc.h" -#include "nel/misc/game_device_events.h" +#ifndef VARIABLE_DATA_H +#define VARIABLE_DATA_H +#include "nel/misc/types_nl.h" -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NLMISC +namespace NLGUI { + struct VariableData + { + std::string entry; + std::string type; + std::string value; + uint32 size; + + VariableData() + { + size = 0; + } + }; -void dummyToAvoidStupidCompilerWarning_game_device_events_cpp() -{ - } -} // NLMISC + +#endif + diff --git a/code/nel/include/nel/gui/view_text.h b/code/nel/include/nel/gui/view_text.h index df3cf27e3..d4377f38e 100644 --- a/code/nel/include/nel/gui/view_text.h +++ b/code/nel/include/nel/gui/view_text.h @@ -48,7 +48,7 @@ namespace NLGUI /// Constructor CViewText (const std::string& id, const std::string Text="", sint FontSize=12, - NLMISC::CRGBA Color=NLMISC::CRGBA(255,255,255), bool Shadow=false); + NLMISC::CRGBA Color=NLMISC::CRGBA(255,255,255), bool Shadow=false, bool ShadowOutline=false); virtual ~CViewText(); @@ -83,6 +83,7 @@ namespace NLGUI void setFontSize (sint nFontSize); void setColor (const NLMISC::CRGBA &color); void setShadow (bool bShadow); + void setShadowOutline (bool bShadowOutline); void setShadowColor (const NLMISC::CRGBA &color); void setLineMaxW (sint nMaxW, bool invalidate=true); void setMultiLine (bool bMultiLine); @@ -102,6 +103,7 @@ namespace NLGUI sint getFontSize() const; NLMISC::CRGBA getColor() { return _Color; } bool getShadow() { return _Shadow; } + bool getShadowOutline() { return _ShadowOutline; } NLMISC::CRGBA getShadowColor() { return _ShadowColor; } sint getLineMaxW() const { return _LineMaxW; } bool getMultiLine() const { return _MultiLine; } @@ -202,7 +204,11 @@ namespace NLGUI REFLECT_EXPORT_END - virtual void serial(NLMISC::IStream &f); + virtual void serial(NLMISC::IStream &f); + + // Sets the parent element + // See the comment at the field + void setParentElm( CInterfaceElement *parent ){ _ParentElm = parent; } protected: std::string _HardtextFormat; @@ -225,6 +231,7 @@ namespace NLGUI NLMISC::CRGBA _Color; /// the shadow mode bool _Shadow; + bool _ShadowOutline; /// the case mode TCaseMode _CaseMode; /// the text shadow color @@ -379,6 +386,9 @@ namespace NLGUI /// Dynamic tooltips std::vector _Tooltips; + // Parent element is the element where this text belongs to + // For example: text button + CInterfaceElement *_ParentElm; private: void setup (); diff --git a/code/nel/include/nel/gui/widget_manager.h b/code/nel/include/nel/gui/widget_manager.h index 5fd75ac8a..6d2336047 100644 --- a/code/nel/include/nel/gui/widget_manager.h +++ b/code/nel/include/nel/gui/widget_manager.h @@ -75,6 +75,16 @@ namespace NLGUI virtual void process() = 0; }; + // Interface for event handlers that can be called when widgets are added or moved + class IWidgetWatcher + { + public: + IWidgetWatcher(){} + virtual ~IWidgetWatcher(){} + virtual void onWidgetAdded( const std::string &name ) = 0; + virtual void onWidgetMoved( const std::string &oldid, const std::string &newid ) = 0; + }; + /// Frame render times struct SInterfaceTimes { @@ -332,7 +342,13 @@ namespace NLGUI void drawViews( NL3D::UCamera camera ); bool handleEvent( const CEventDescriptor &evnt ); - + + bool handleSystemEvent( const CEventDescriptor &evnt ); + + bool handleKeyboardEvent( const CEventDescriptor &evnt ); + + bool handleMouseEvent( const CEventDescriptor &evnt ); + bool handleMouseMoveEvent( const CEventDescriptor &eventDesc ); // Relative move of pointer @@ -487,17 +503,33 @@ namespace NLGUI IParser* getParser() const{ return parser; } - std::string& getCurrentEditorSelection(){ return currentEditorSelection; } - void setCurrentEditorSelection( const std::string &name ); + /// Retrieves the Id of the currently selected widgets + void getEditorSelection( std::vector< std::string > &selection ); + + /// Adds the widget with the specified Id to the selected widgets + void selectWidget( const std::string &name ); + + /// Clears the selection + void clearEditorSelection(); + void notifySelectionWatchers(); void registerSelectionWatcher( IEditorSelectionWatcher *watcher ); void unregisterSelectionWatcher( IEditorSelectionWatcher *watcher ); - - void notifyAdditionWatchers( const std::string &widgetName ); - void registerAdditionWatcher( IWidgetAdditionWatcher *watcher ); - void unregisterAdditionWatcher( IWidgetAdditionWatcher *watcher ); + + + void onWidgetAdded( const std::string &id ); + void onWidgetMoved( const std::string &oldid, const std::string &newid ); + void registerWidgetWatcher( IWidgetWatcher *watcher ); + void unregisterWidgetWatcher( IWidgetWatcher *watcher ); CInterfaceElement* addWidgetToGroup( std::string &group, std::string &widgetClass, std::string &widgetName ); + + void setGroupSelection( bool b ){ _GroupSelection = b; } + bool groupSelection(); + bool unGroupSelection(); + void setMultiSelection( bool b ){ multiSelection = b; } + + bool createNewGUI( const std::string &project, const std::string &window ); private: CWidgetManager(); @@ -526,6 +558,11 @@ namespace NLGUI NLMISC::CRefPtr< CViewBase > _CapturedView; + NLMISC::CRefPtr< CInterfaceElement > draggedElement; // the element that we're currently dragging + + bool startDragging(); + void stopDragging(); + // What is under pointer std::vector< CViewBase* > _ViewsUnderPointer; std::vector< CCtrlBase* > _CtrlsUnderPointer; @@ -583,10 +620,12 @@ namespace NLGUI std::vector< INewScreenSizeHandler* > newScreenSizeHandlers; std::vector< IOnWidgetsDrawnHandler* > onWidgetsDrawnHandlers; std::vector< IEditorSelectionWatcher* > selectionWatchers; - std::vector< IWidgetAdditionWatcher* > additionWatchers; + std::vector< IWidgetWatcher* > widgetWatchers; - - std::string currentEditorSelection; + std::vector< std::string > editorSelection; + bool _GroupSelection; + bool multiSelection; + uint32 _WidgetCount; }; } diff --git a/code/nel/include/nel/misc/callback.h b/code/nel/include/nel/misc/callback.h new file mode 100644 index 000000000..ca5140f6f --- /dev/null +++ b/code/nel/include/nel/misc/callback.h @@ -0,0 +1,327 @@ +/* + +Copyright (c) 2009-2014, Jan BOON +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef NLMISC_CALLBACK_H +#define NLMISC_CALLBACK_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLMISC { + +#define NLMISC_CALLBACK_TEMPLATE \ +/** \ + * \brief NLMISC_CALLBACK_ARGS_CLASS \ + * \date 2009-03-03 18:09GMT \ + * \author Jan BOON \ + * Callback template \ + */ \ +template \ +class NLMISC_CALLBACK_ARGS_CLASS \ +{ \ + /* Very simple reference counting callback base */ \ + class CCallbackBase \ + { \ + public: \ + CCallbackBase() : m_RefCount(0) \ + { \ + \ + } \ + \ + virtual ~CCallbackBase() \ + { \ + nlassert(!m_RefCount); \ + } \ + \ + void refAdd() \ + { \ + ++m_RefCount; \ + } \ + \ + void refRemove() \ + { \ + --m_RefCount; \ + if (!m_RefCount) \ + delete this; \ + } \ + \ + virtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) = 0; \ + \ + virtual bool equals(const CCallbackBase *callbackBase) = 0; \ + \ + /* disable copy */ \ + CCallbackBase(const CCallbackBase &); \ + CCallbackBase &operator=(const CCallbackBase &); \ + \ + private: \ + uint m_RefCount; \ + }; \ + \ + typedef TReturn TCallbackFunction(NLMISC_CALLBACK_ARGS_DECL); \ + class CCallbackFunction : public CCallbackBase \ + { \ + public: \ + CCallbackFunction(TCallbackFunction *callbackFunction) : m_CallbackFunction(callbackFunction) \ + { \ + nlassert(m_CallbackFunction); \ + } \ + \ + virtual ~CCallbackFunction() \ + { \ + m_CallbackFunction = NULL; \ + } \ + \ + virtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \ + { \ + return m_CallbackFunction(NLMISC_CALLBACK_ARGS_IMPL); \ + } \ + \ + virtual bool equals(const CCallbackBase *callbackBase) \ + { \ + const CCallbackFunction *callbackFunction = \ + dynamic_cast(callbackBase); \ + if (!callbackFunction) return false; \ + return m_CallbackFunction == callbackFunction->m_CallbackFunction; \ + } \ + \ + private: \ + TCallbackFunction *m_CallbackFunction; \ + }; \ + \ + template \ + class CCallbackMethod : public CCallbackBase \ + { \ + typedef TReturn (TClass::*TCallbackMethod)(NLMISC_CALLBACK_ARGS_DECL); \ + public: \ + CCallbackMethod(TClass *callbackObject, TCallbackMethod callbackMethod) : m_CallbackObject(callbackObject), m_CallbackMethod(callbackMethod) \ + { \ + nlassert(m_CallbackObject); \ + nlassert(m_CallbackMethod); \ + } \ + \ + virtual ~CCallbackMethod() \ + { \ + m_CallbackObject = NULL; \ + m_CallbackMethod = NULL; \ + } \ + \ + virtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \ + { \ + return (m_CallbackObject->*m_CallbackMethod)(NLMISC_CALLBACK_ARGS_IMPL); \ + } \ + \ + virtual bool equals(const CCallbackBase *callbackBase) \ + { \ + const CCallbackMethod *callbackMethod = \ + dynamic_cast(callbackBase); \ + if (!callbackMethod) return false; \ + return m_CallbackObject == callbackMethod->m_CallbackObject \ + && m_CallbackMethod == callbackMethod->m_CallbackMethod; \ + } \ + \ + private: \ + TClass *m_CallbackObject; \ + TCallbackMethod m_CallbackMethod; \ + }; \ + \ +public: \ + CCallback() : m_CallbackBase(NULL) \ + { \ + \ + } \ + \ + CCallback(TCallbackFunction *callbackFunction) : m_CallbackBase(new CCallbackFunction(callbackFunction)) \ + { \ + nlassert(m_CallbackBase); \ + m_CallbackBase->refAdd(); \ + } \ + \ + template \ + CCallback(TClass *callbackObject, TReturn (TClass::*callbackMethod)(NLMISC_CALLBACK_ARGS_DECL)) : m_CallbackBase(new CCallbackMethod(callbackObject, callbackMethod)) \ + { \ + nlassert(m_CallbackBase); \ + m_CallbackBase->refAdd(); \ + } \ + \ + CCallback(const CCallback &callback) \ + { \ + m_CallbackBase = callback.m_CallbackBase; \ + if (m_CallbackBase) \ + m_CallbackBase->refAdd(); \ + } \ + \ + CCallback &operator=(const CCallback &callback) \ + { \ + if (m_CallbackBase != callback.m_CallbackBase) \ + { \ + if (m_CallbackBase) \ + m_CallbackBase->refRemove(); \ + m_CallbackBase = callback.m_CallbackBase; \ + if (m_CallbackBase) \ + m_CallbackBase->refAdd(); \ + } \ + return *this; \ + } \ + \ + ~CCallback() \ + { \ + if (m_CallbackBase) \ + { \ + m_CallbackBase->refRemove(); \ + m_CallbackBase = NULL; \ + } \ + } \ + \ + TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \ + { \ + nlassert(m_CallbackBase); \ + return m_CallbackBase->callback(NLMISC_CALLBACK_ARGS_IMPL); \ + } \ + \ + TReturn operator()(NLMISC_CALLBACK_ARGS_DECL) \ + { \ + nlassert(m_CallbackBase); \ + return m_CallbackBase->callback(NLMISC_CALLBACK_ARGS_IMPL); \ + } \ + \ + bool valid() const \ + { \ + return m_CallbackBase != NULL; \ + } \ + \ + operator bool() const \ + { \ + return m_CallbackBase != NULL; \ + } \ + \ + bool operator==(const CCallback &callback) \ + { \ + return m_CallbackBase->equals(callback.m_CallbackBase); \ + } \ + \ +private: \ + CCallbackBase *m_CallbackBase; \ + \ +}; /* class CCallback */ \ + +template +class CCallback; + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME +#define NLMISC_CALLBACK_ARGS_DECL +#define NLMISC_CALLBACK_ARGS_IMPL +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA +#define NLMISC_CALLBACK_ARGS_IMPL argsA +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB +#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC +#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD +#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE +#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF +#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL + +#define NLMISC_CALLBACK_ARGS_CLASS CCallback +#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF, typename TArgsG +#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF, TArgsG argsG +#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF, argsG +NLMISC_CALLBACK_TEMPLATE +#undef NLMISC_CALLBACK_ARGS_CLASS +#undef NLMISC_CALLBACK_ARGS_TYPENAME +#undef NLMISC_CALLBACK_ARGS_DECL +#undef NLMISC_CALLBACK_ARGS_IMPL +#undef NLMISC_CALLBACK_ARGS_CLASSNAME + +#undef NLMISC_CALLBACK_TEMPLATE + +} /* namespace NLMISC */ + +#endif /* #ifndef NLMISC_CALLBACK_H */ + +/* end of file */ diff --git a/code/nel/include/nel/misc/di_event_emitter.h b/code/nel/include/nel/misc/di_event_emitter.h deleted file mode 100644 index 41c7bbf47..000000000 --- a/code/nel/include/nel/misc/di_event_emitter.h +++ /dev/null @@ -1,204 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_DI_EVENT_EMITTER_H -#define NL_DI_EVENT_EMITTER_H - - - -#include "types_nl.h" - - -#ifdef NL_OS_WINDOWS - - -#define DIRECTINPUT_VERSION 0x0800 - -#include "input_device_server.h" -#include "input_device_manager.h" -#include "event_emitter.h" -#include "smart_ptr.h" -#include "events.h" -#include "rect.h" -#include "game_device.h" -#ifndef NL_COMP_MINGW -# define NOMINMAX -#endif -#include -#include - - - -namespace NLMISC -{ - - -class CWinEventEmitter; -class CDIKeyboard; -class CDIMouse; -struct IMouseDevice; -struct IKeyboardDevice; - -// -struct EDirectInput : public EInputDevice -{ - EDirectInput(const char *reason) : EInputDevice(reason) {} -}; -// -struct EDirectInputLibNotFound : public EDirectInput -{ - EDirectInputLibNotFound() : EDirectInput("can't found the direct input dll") {} -}; -// -struct EDirectInputInitFailed : public EDirectInput -{ - EDirectInputInitFailed() : EDirectInput("Direct input initialization failed") {} -}; -// -struct EDirectInputCooperativeLevelFailed : public EDirectInput -{ - EDirectInputCooperativeLevelFailed() : EDirectInput("Direct Input Device Cooperative level couldn't be set") {} -}; - - -// Class to represent Direct Inputs events -struct CDIEvent : public IInputDeviceEvent -{ - virtual bool operator < (const IInputDeviceEvent &ide) const - { - // just compare the dates - return Datas.dwTimeStamp < (safe_cast(&ide))->Datas.dwTimeStamp; - } - DIDEVICEOBJECTDATA Datas; -}; - -/** - * This manage events by using DirectInput8. - * This should be polled regularly. - * This can be mixed with a CWinEmitter (for example, you may have mouse using direct input, and keyboard using standard messages) - * \author Nicolas Vizerie - * \author Nevrax France - * \date 2002 - */ -class CDIEventEmitter : public IEventEmitter, public IInputDeviceManager -{ -public: - /** Build a Direct Input Event Emitter object. An exception containing the reason is thrown if the initialization failed. - * The obtained object must be released by deleting it. - * \param hinst the instance of the application. - * \param hwnd the main window of the application. - * \param we A windows eventsemitter. Can be NULL. Needed if you want to mix WIN32 events and Direct Input events - * (for example, a Direct Input Mouse and a Win32 Keyboard) - */ - static CDIEventEmitter *create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we) throw(EDirectInput); - ~CDIEventEmitter(); -public: - - /// This poll the direct input state, directly storing the result in the given server, or keeping the result in internal server if NULL. - void poll(CEventServer *server = NULL); - - ///\name From IDeviceManager, access to devices - //@{ - // Test if a mouse has been created (by a call to getMouseDeivce) - virtual bool isMouseCreated() { return _Mouse != NULL; } - /** Create the mouse device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it. An exception if thrown if it couldn't be obtained. - * If this object has a pointer on a win32 emiter, Win32 mouse messages are replaced by this mouse messages. - */ - virtual IMouseDevice *getMouseDevice(bool hardware) throw(EInputDevice); - /// remove the direct input mouse - virtual void releaseMouse(); - /** Create the keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it. - * If this object has a pointer on a win32 emiter, Win32 keyboard messages are replaced by this keyboard messages. - * NB: A direct input has no notion of localization or key combinations. See keyboard_device.h for more infos - */ - virtual IKeyboardDevice *getKeyboardDevice() throw(EInputDevice); - /// remove the direct input keyboard - virtual void releaseKeyboard(); - // Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector - virtual void enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice); - // Create the given game device from its instance name. It also means that it will begin to sends inputs - virtual IGameDevice *createGameDevice(const std::string &instanceName) throw(EInputDevice); - // Release the given game device - virtual void releaseGameDevice(IGameDevice *); - //@} - - /// from IEventEmitter - virtual void submitEvents(CEventServer &server, bool allWindows); - virtual void emulateMouseRawMode(bool enable); - - // Build a TMouseButton value from the current buttons state - TMouseButton buildButtonsFlags() const; - // Build a TMouseButton value (but with no mouse values) - TMouseButton buildKeyboardButtonFlags() const - { - return (TMouseButton) (buildButtonsFlags() & (ctrlButton|shiftButton|altButton)); - } - -//================================================================ -//================================================================ -//================================================================ -private: - typedef HRESULT (WINAPI * TPDirectInput8Create) (HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter); - // Private internal server message, used to stored all messages internally before to dispatch them, when no server is supplied to poll(... - class CDIEventServer : CEventServer - { - friend class CDIEventEmitter; - public: - void setServer (CEventServer *server) - { - _Server = server; - } - private: - bool pumpEvent(CEvent *event) - { - CEventServer::pumpEvent(event); - _Server->postEvent (event); - return false; - } - private: - CEventServer *_Server; - }; -private: - HWND _hWnd; - TMouseButton _ButtonsFlags; - NLMISC::CRefPtr _WE; - static HMODULE _DirectInputLibHandle; - static TPDirectInput8Create _PDirectInput8Create; - static uint _NumCreatedInterfaces; -private: - static bool loadLib(); - static void unloadLib(); -//==== -private: - CDIEventServer _InternalServer; - CInputDeviceServer _DeviceServer; - IDirectInput8 *_DInput8; - CDIMouse *_Mouse; - CDIKeyboard *_Keyboard; -private: - CDIEventEmitter(HWND hwnd, CWinEventEmitter *we); -}; - - - -} // NLMISC - -#endif // NL_WINDOWS - - -#endif // NL_DX_EVENT_EMITTER_H - -/* End of dx_event_emitter.h */ diff --git a/code/nel/include/nel/misc/event_emitter.h b/code/nel/include/nel/misc/event_emitter.h index 224e5159f..eab005b82 100644 --- a/code/nel/include/nel/misc/event_emitter.h +++ b/code/nel/include/nel/misc/event_emitter.h @@ -49,19 +49,6 @@ public: * \param server */ virtual void submitEvents(CEventServer & server, bool allWindows) = 0; - - /** - * Instruct the event emitter to send CGDMouseMove instead of CEventMouseMove. - * - * On windows, the mouse device can be set into RawMode. Using this mode, - * CGDMouseMove events (only containing the raw movement delta) are emitted - * instead of the normal CEventMouseMove events (containing the mouse position). - * - * On Linux and Mac OS X, there is no MouseDevice implementation, all the - * events are created by the event emitter. So the event emitter has to - * emulate the mouse raw mode. - */ - virtual void emulateMouseRawMode(bool) = 0; }; diff --git a/code/nel/include/nel/misc/event_emitter_multi.h b/code/nel/include/nel/misc/event_emitter_multi.h index 3c6860e53..e41ee2055 100644 --- a/code/nel/include/nel/misc/event_emitter_multi.h +++ b/code/nel/include/nel/misc/event_emitter_multi.h @@ -47,7 +47,6 @@ public: const IEventEmitter *getEmitter(uint index) const; /// From IEventEmitter. This call submitEvents on all the emitters virtual void submitEvents(CEventServer &server, bool allWindows); - virtual void emulateMouseRawMode(bool enable); virtual bool copyTextToClipboard(const ucstring &text); virtual bool pasteTextFromClipboard(ucstring &text); diff --git a/code/nel/include/nel/misc/game_device.h b/code/nel/include/nel/misc/game_device.h deleted file mode 100644 index 605c4fb53..000000000 --- a/code/nel/include/nel/misc/game_device.h +++ /dev/null @@ -1,114 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_GAME_DEVICE_H -#define NL_GAME_DEVICE_H - -#include "types_nl.h" -#include "input_device.h" -#include -#include - - -namespace NLMISC -{ - -/// Describe a game device -struct CGameDeviceDesc -{ - // type of the device - enum TDevType { GamePad, Joystick, DontKnow, DevTypeLast } DevType; - // Friendly name for the instance. For example, "Joystick 1." - std::string InstanceName; - // Friendly name for the product - std::string ProductName; - // Tells whether this device is connected - bool Connected; -}; - -// a list of game device description -typedef std::vector TDeviceDescVect; - -/// for devices comparison. The 'Connected' field is ignored. -inline bool operator == (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs) -{ - return lhs.InstanceName == rhs.InstanceName && lhs.ProductName == rhs.ProductName; -} -// -inline bool operator != (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs) -{ - return !(lhs == rhs); -} - - -/** - * This abstract a joystick or gamepad - * \author Nicolas Vizerie - * \author Nevrax France - * \date 2002 - */ -struct IGameDevice : public IInputDevice -{ - enum TAxis { XAxis = 0, YAxis, ZAxis, /* translation */ - RXAxis, RYAxis, RZAxis, /* rotations */ - MaxNumAxis - }; - - /// Get a general description of this device - virtual const CGameDeviceDesc &getDescription() const = 0; - - ///\name Controls presence - //@{ - // returns the number of buttons available on this game device - virtual uint getNumButtons() const = 0; - /** Check if the given axe is present on this game device - * NB : only absolute axis are managed - */ - virtual bool hasAxis(TAxis axis) const = 0; - // Check the number of sliders presents on this game device - virtual uint getNumSliders() const = 0; - // Check the number of point of views controls present on this game device - virtual uint getNumPOV() const = 0; - //@} - - ///\name Controls names. Must ensure that controls are present before calling these methods. - //@{ - virtual const char *getButtonName(uint index) const = 0; - virtual const char *getAxisName(TAxis axis) const = 0; - virtual const char *getSliderName(uint index) const = 0; - virtual const char *getPOVName(uint index) const = 0; - //@} - - ///\name Controls state. Must ensure that controls are present before calling these methods. - //@{ - // Return true if the given button is pushed. - virtual bool getButtonState(uint index) const = 0; - // Return a value in [-1, 1] for a translation axis, or an orientation. - virtual float getAxisValue(TAxis axis) const = 0; - // Return a value in [0, 1] - virtual float getSliderPos(uint index) const = 0; - // Return a CCW angle in degrees - virtual float getPOVAngle(uint index) const = 0; - //@} -}; - - -} // NLMISC - - -#endif // NL_GAME_DEVICE_H - -/* End of GAME_device.h */ diff --git a/code/nel/include/nel/misc/game_device_events.h b/code/nel/include/nel/misc/game_device_events.h deleted file mode 100644 index 6ddee4589..000000000 --- a/code/nel/include/nel/misc/game_device_events.h +++ /dev/null @@ -1,209 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_GAME_DEVICE_EVENT_H -#define NL_GAME_DEVICE_EVENT_H - -#include "types_nl.h" -#include "events.h" -#include "game_device.h" - - - - -namespace NLMISC -{ - -struct IMouseDevice; -struct IGameDevice; - -const CClassId EventGDMouseMove(0x12142bc4, 0x43c73e74); -const CClassId EventGDButtonDownId(0x57141957, 0x3efb143a); -const CClassId EventGDButtonUpId(0x16105e06, 0x302536b2); -const CClassId EventGDAxisMovedId(0x073306, 0x41173626); -const CClassId EventGDSliderMovedId(0x68776586, 0x394a6916); -const CClassId EventGDPOVChanged(0x362851b9, 0x395c4d61); - - -//========================================================================================== -/// A raw mouse move message, expressed in mickeys (relative values) -class CGDMouseMove : public CEvent -{ -public: - IMouseDevice *MD; - sint X, Y; -public: - CGDMouseMove(IEventEmitter *emitter, IMouseDevice *md, sint x, sint y) : CEvent(emitter, EventGDMouseMove), MD(md), X(x), Y(y) - {} - - virtual CEvent *clone() const {return new CGDMouseMove(*this);} -}; - - -//========================================================================================== -/** - * An event from a game device (joystick, joypad ...) - */ -class CGameDeviceEvent : public CEvent -{ -public: - /// the game device this event come from - IGameDevice *GameDevice; -public: - CGameDeviceEvent( - IGameDevice *gameDevice, - IEventEmitter *emitter, - const CClassId &classId - ) - : CEvent(emitter, classId), - GameDevice(gameDevice) - {} -}; - - -//========================================================================================== -/** A button state has changed - */ -class CGDButton : public CGameDeviceEvent -{ -public: - // index of the buttons that has been pushed - uint ButtonIndex; - bool Pushed; -public: - /// - CGDButton( - uint buttonIndex, - bool pushed, - IGameDevice *gameDevice, - IEventEmitter *emitter, - const CClassId &classId - ) - : CGameDeviceEvent(gameDevice, emitter, classId), - ButtonIndex(buttonIndex), - Pushed(pushed) - {} -}; - - -//========================================================================================== -/** A button has been pushed - */ -class CGDButtonDown : public CGDButton -{ -public: - /// - CGDButtonDown(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter) - : CGDButton(buttonIndex, true, gameDevice, emitter, EventGDButtonDownId) - {} - - virtual CEvent *clone() const {return new CGDButtonDown(*this);} -}; - -//========================================================================================== -/** A button has been released - */ -class CGDButtonUp : public CGDButton -{ -public: - /// - CGDButtonUp(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter) - : CGDButton(buttonIndex, false, gameDevice, emitter, EventGDButtonUpId) - {} - - virtual CEvent *clone() const {return new CGDButtonUp(*this);} -}; - -//========================================================================================== -/// An axis has moved -class CGDAxisMoved : public CGameDeviceEvent -{ -public: - IGameDevice::TAxis Axis; - // current position of the axis, ranges from -1.f to 1.f - float Value; -public: - CGDAxisMoved( - IGameDevice::TAxis axis, - float value, - IGameDevice *gameDevice, - IEventEmitter *emitter - ) - : CGameDeviceEvent(gameDevice, emitter, EventGDAxisMovedId), - Axis(axis), - Value(value) - {} - - virtual CEvent *clone() const {return new CGDAxisMoved(*this);} -}; - - -//========================================================================================== -/// A slider position has changed -class CGDSliderMoved : public CGameDeviceEvent -{ -public: - uint SliderIndex; - // current position of the slider, ranges from 0.f to 1.f - float SliderPos; -public: - CGDSliderMoved( - float sliderPos, - uint sliderIndex, - IGameDevice *gameDevice, - IEventEmitter *emitter - ) - : CGameDeviceEvent(gameDevice, emitter, EventGDSliderMovedId), - SliderIndex(sliderIndex), - SliderPos(sliderPos) - {} - - virtual CEvent *clone() const {return new CGDSliderMoved(*this);} -}; - -//========================================================================================== -/// A point of view control changed -class CGDPOVChanged : public CGameDeviceEvent -{ -public: - uint POVIndex; - bool Centered; - // The POV angle, in degrees (CW) - float POVAngle; -public: - CGDPOVChanged( - bool centered, - float povAngle, - uint povIndex, - IGameDevice *gameDevice, - IEventEmitter *emitter - ) - : CGameDeviceEvent(gameDevice, emitter, EventGDPOVChanged), - POVIndex(povIndex), - Centered(centered), - POVAngle(povAngle) - {} - - virtual CEvent *clone() const {return new CGDPOVChanged(*this);} -}; - - -} // NLMISC - - -#endif // NL_GAME_DEVICE_EVENT_H - -/* End of game_device_event.h */ diff --git a/code/nel/include/nel/misc/input_device.h b/code/nel/include/nel/misc/input_device.h deleted file mode 100644 index b07a0128e..000000000 --- a/code/nel/include/nel/misc/input_device.h +++ /dev/null @@ -1,84 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_INPUT_DEVICE_H -#define NL_INPUT_DEVICE_H - -#include "types_nl.h" - - -namespace NLMISC -{ - - -class CEventServer; -class CInputDeviceServer; -struct IInputDeviceEvent; - - -/** - * Base class that wrap to a device - * \author Nicolas Vizerie - * \author Nevrax France - * \date 2002 - */ - -struct IInputDevice -{ - /** Set the buffer size for this device (the number of samples it can retains). - * This return true if the size could be set - */ - virtual bool setBufferSize(uint size) = 0; - /// Get the buffer size for this device - virtual uint getBufferSize() const = 0; - - ///\name Device server specifics. You usually don't want to call these - //@{ - /** For device server usage : - * Called at the beginning of each events retrieval. - * If a device doesn't support buffered datas, the state changes can be directly send to the event server. - * The default does nothing. - */ - virtual void begin(CEventServer * /* server */) {} - - /** For device server usage : - * Poll all events from that device, and notify them to the given device server, so that they can be sorted between devices. - * This retrieves messages, but do not process them. - */ - virtual void poll(CInputDeviceServer *dev) = 0; - /** For device server usage : - * Process an event (eventually update this device state), and translate the message to a IEventServerMessage - */ - virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server) = 0; - /** For device server usage : - * Says that the next message is for another device, or that it is the last message that will be received. - * This allow to pack several messages in one (for example, to sum up mouse moves until a click occurs) - * The default does nothing. - * The next message can be used to get a time stamp for example. It may be NULL is no next message is available - */ - virtual void transitionOccured(CEventServer * /* server */, const IInputDeviceEvent * /* nextMessage */) {} - //@} - - // dtor - virtual ~IInputDevice() {} -}; - -} // NLMISC - - -#endif // NL_INPUT_DEVICE_H - -/* End of input_device.h */ diff --git a/code/nel/include/nel/misc/input_device_manager.h b/code/nel/include/nel/misc/input_device_manager.h deleted file mode 100644 index a23437696..000000000 --- a/code/nel/include/nel/misc/input_device_manager.h +++ /dev/null @@ -1,69 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_INPUT_DEVICE_MANAGER_H -#define NL_INPUT_DEVICE_MANAGER_H - -#include "types_nl.h" -#include "game_device.h" -#include "common.h" - -namespace NLMISC -{ - - -struct IMouseDevice; -struct IKeyboardDevice; - - - -struct EInputDevice : public Exception -{ - EInputDevice(const char *reason) : Exception(reason) {} -}; - - -/** Interface for objects that give low level access to devices (mouse, keyboard, joypads and joysticks). - * Generally an object implementing this interface will send the appropriate events when a device is 'created'. - * (Example of implementation : a direct input event emitter) - */ -struct IInputDeviceManager -{ - // Test if a mouse has been created (by a call to getMouseDeivce) - virtual bool isMouseCreated() = 0; - /// Create the low level mouse device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained. - virtual IMouseDevice *getMouseDevice(bool hardware) throw(EInputDevice) = 0; - /// remove the low level mouse - virtual void releaseMouse() = 0; - /// Create the low level keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained. - virtual IKeyboardDevice *getKeyboardDevice() throw(EInputDevice) = 0; - /// remove the low level keyboard - virtual void releaseKeyboard() = 0; - // Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector - virtual void enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice) = 0; - // Create the given game device interface from its instance name. It also means that it will begin to sends events. - virtual IGameDevice *createGameDevice(const std::string &instanceName) throw(EInputDevice) = 0; - // Release the given game device. - virtual void releaseGameDevice(IGameDevice *gd) = 0; -}; - - -} // NLMISC - - -#endif // NL_INPUT_DEVICE_MANAGER_H - -/* End of device_manager.h */ diff --git a/code/nel/include/nel/misc/input_device_server.h b/code/nel/include/nel/misc/input_device_server.h deleted file mode 100644 index 45c3db77d..000000000 --- a/code/nel/include/nel/misc/input_device_server.h +++ /dev/null @@ -1,84 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_INPUT_DEVICE_SERVER_H -#define NL_INPUT_DEVICE_SERVER_H - -#include "types_nl.h" -#include - - -namespace NLMISC -{ - -class CEventServer; -struct IInputDevice; -struct IInputDeviceEvent; - - -/** Base class for an input device server. Unlike an event server, it manages several devices, and can sort their events (by date for example). - * It keeps a list of active devices. - * It can poll datas from every active device. - * It can sort devices messages to submit them in correct order to a CEventServer. - */ - -class CInputDeviceServer -{ -public: - /// register a device into this device server. - void registerDevice(IInputDevice *device); - /// remove a device from this server (but does not delete it). - void removeDevice(IInputDevice *device); - // returns the number of registered devices - uint getNumDevices() const { return (uint)_Devices.size(); } - // return a device - IInputDevice *getDevice(uint index) { return _Devices[index]; } - /// Test whether the given device is handled by this server. - bool isDevice(IInputDevice *device) const; - /// Retrieve datas from the devices, and submit them to the given CEventServer. - void poll(CEventServer *server); - /// Allow an input device to register an event. The event will then be deleted by this server - void submitEvent(IInputDeviceEvent *deviceEvent); - // dtor - virtual ~CInputDeviceServer() {} -private: - typedef std::vector TDeviceCont; - typedef std::vector TEventCont; -private: - TDeviceCont _Devices; - TEventCont _Events; -}; - - - - -/** An event from an input device. - */ -struct IInputDeviceEvent -{ - IInputDevice *Emitter; // the input device that emitted that event - // Used to sort events by time stamp. - virtual bool operator < (const IInputDeviceEvent &IInputDeviceEvent) const = 0; - virtual ~IInputDeviceEvent() {} -}; - - -} // NLMISC - - -#endif // NL_INPUT_DEVICE_SERVER_H - -/* End of input_device_server.h */ diff --git a/code/nel/include/nel/misc/keyboard_device.h b/code/nel/include/nel/misc/keyboard_device.h deleted file mode 100644 index bf3b2af8d..000000000 --- a/code/nel/include/nel/misc/keyboard_device.h +++ /dev/null @@ -1,63 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_KEYBOARD_DEVICE_H -#define NL_KEYBOARD_DEVICE_H - -#include "types_nl.h" -#include "events.h" -#include "input_device.h" - - - -namespace NLMISC -{ - -/** Gives access to low level keyboard parameters - * - 'Shift' messages are replaced by RShift and LShift msg. - * - 'Control' messages are replaced by 'RControl' and 'LControl' msg. - * - 'Menu' (alternate) messages are replaced by 'RMenu' and 'LMenu' msg. - */ -struct IKeyboardDevice : public IInputDevice -{ - /// Max number of supported keys - enum { NumKeys = 256 }; - /// Get the delay before key repeat, in milliseconds - virtual uint getKeyRepeatDelay() const = 0; - /// Get the delay before key repeat, in milliseconds - virtual void setKeyRepeatDelay(uint delay) = 0; - /// Get the period before key repeat, in milliseconds - virtual uint getKeyRepeatPeriod() const = 0; - /// Get the period before key repeat, in milliseconds - virtual void setKeyRepeatPeriod(uint period) = 0; - /// Set a set of keys for which repetition is disabled - virtual void disableRepetition(const TKey *keyTab, uint numKey) = 0; - /// Get the number of disabled keys - virtual uint getNumDisabledRepetition() const = 0; - /** Get the disabled keys and stores in the given tab. - * NB: must ensure the destination table has the right size - * \see getNumDisabledKeys() - */ - virtual void getDisabledRepetitions(TKey *destTab) const = 0; -}; - - -} // NLMISC - - -#endif // NL_KEYBOARD_DEVICE_H - -/* End of keyboard_device.h */ diff --git a/code/nel/include/nel/misc/mouse_device.h b/code/nel/include/nel/misc/mouse_device.h deleted file mode 100644 index 8ae181cdd..000000000 --- a/code/nel/include/nel/misc/mouse_device.h +++ /dev/null @@ -1,130 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_MOUSE_DEVICE_H -#define NL_MOUSE_DEVICE_H - -#include "types_nl.h" -#include "input_device.h" - - - -namespace NLMISC -{ - -class CRect; - -/// An interface to a low level mouse device -struct IMouseDevice : public IInputDevice -{ - enum TAxisMode { Raw, Clamped, AxisModeLast }; - enum TAxis { XAxis = 0, YAxis = 1, AxisLast }; - enum TMessageMode { NormalMode, RawMode, MessageModeLast }; - - ///\name Messages - //@{ - /** Tells what messages should be sent : - * DEFAULT is 'raw' messages - * Raw messages : - no clamping nor frames applied - * - no speed applied - * - no factor applied - * - CGDMouseMove messages are sent - * - Move expressed in mickeys - * Normal messages : - CEventMouseMove messages are sent - * - A frame may clamp one or both axis - * - The mouse speed can be changed - */ - virtual void setMessagesMode(TMessageMode mode) = 0; - /// retrieve what kinds of messages are sent - virtual TMessageMode getMessagesMode() const = 0; - //@} - - ///\name Mouse MOVE, valid only - //@{ - /** Set the mode of axis of the mouse. This can be raw, or clamped. In clamped mode, a frame is used to limit the move. - * NB : invalid in raw message mode - * \see setMouseFrame(const CRect &rect) - */ - virtual void setMouseMode(TAxis axis, TAxisMode axisMode) = 0; - /** returns the mode of the mouse for the given axis. - * NB : invalid in raw message mode - */ - virtual TAxisMode getMouseMode(TAxis axis) const = 0; - /** Set the mouse speed. It must be in the ]0, +inf] range, 1 gives the natural mouse speed. - * NB : invalid in raw message mode - */ - virtual void setMouseSpeed(float speed) = 0; - /** Get the mouse speed. - * NB : invalid in raw message mode - */ - virtual float getMouseSpeed() const = 0; - /** Set the mouse acceleration. It is the threshold in mickey, when start the acceleration. 0 means not acceleration. - */ - virtual void setMouseAcceleration(uint speed) = 0; - /** Get the mouse acceleration. - */ - virtual uint getMouseAcceleration() const = 0; - /** Set the current frame in which the mouse can move, expressed in pixels. - * NB do not forget to call setMouseFactors if you want the results to be reported in the 0-1 range. - * NB : invalid in raw message mode. - * \see setMouseFactors - */ - virtual void setMouseFrame(const CRect &rect) = 0; - /** Gives factor by which the mouse coordinates must be multiplied before an event is sent. - * The default factor is 1. - * NB : invalid in raw message mode. - * - * Example : this set a frame of 800x600 and reports event in the [0, 1] range. - * \code - * mouse->setMouseFrame(800, 600); - * mouse->setMouseMode(XAxis, IMouseDevice::Clamped); - * mouse->setMouseMode(YAxis, IMouseDevice::Clamped); - * mouse->setFactors(1.f / 800, 1.f / 600); - * \endcode - */ - virtual void setFactors(float xFactor, float yFactor) = 0; - /** Get the x factor, use to multiply the mouse position before an event is sent. - * NB : invalid in raw message mode. - * \see setFactors() - */ - virtual float getXFactor() const = 0; - /** Get the y factor, use to multiply the mouse position before an event is sent. - * NB : invalid in raw message mode. - * \see setFactors() - */ - virtual float getYFactor() const = 0; - //@} - - // Get the current frame used for limiting mouse movements - virtual const CRect &getMouseFrame() const = 0; - // Set the maximum delay for a double click to be taken in account (in ms). - virtual void setDoubleClickDelay(uint ms) = 0; - // Get the maximum delay for double click (in ms) - virtual uint getDoubleClickDelay() const = 0; - // Force the position of the mouse, expressed in pixels - virtual void setMousePos(float x, float y) = 0; - - /// From a delta of a mouse position input (eg from CEventMouseMove), deduce delta in mickeys (eg: like received from a CGDMouseMove) - virtual void convertStdMouseMoveInMickeys(float &dx, float &dy) const = 0; -}; - - -} // NLMISC - - -#endif // NL_MOUSE_DEVICE_H - -/* End of u_mouse_device.h */ diff --git a/code/nel/include/nel/misc/win_event_emitter.h b/code/nel/include/nel/misc/win_event_emitter.h index 756dfbaee..1b361485f 100644 --- a/code/nel/include/nel/misc/win_event_emitter.h +++ b/code/nel/include/nel/misc/win_event_emitter.h @@ -100,8 +100,6 @@ public: */ bool processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server=NULL); - void emulateMouseRawMode(bool enable); - private: CWinEventServer _InternalServer; HWND _HWnd; diff --git a/code/nel/samples/misc/CMakeLists.txt b/code/nel/samples/misc/CMakeLists.txt index 753b418ae..d00a54952 100644 --- a/code/nel/samples/misc/CMakeLists.txt +++ b/code/nel/samples/misc/CMakeLists.txt @@ -1,3 +1,4 @@ +ADD_SUBDIRECTORY(callback) ADD_SUBDIRECTORY(command) ADD_SUBDIRECTORY(configfile) ADD_SUBDIRECTORY(debug) diff --git a/code/nel/samples/misc/callback/CMakeLists.txt b/code/nel/samples/misc/callback/CMakeLists.txt new file mode 100644 index 000000000..62626b0a7 --- /dev/null +++ b/code/nel/samples/misc/callback/CMakeLists.txt @@ -0,0 +1,9 @@ +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(nl_sample_callback ${SRC}) + +TARGET_LINK_LIBRARIES(nl_sample_callback nelmisc) +NL_DEFAULT_PROPS(nl_sample_callback "NeL, Samples, Misc: Callback") +NL_ADD_RUNTIME_FLAGS(nl_sample_callback) + +INSTALL(TARGETS nl_sample_callback RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) diff --git a/code/nel/samples/misc/callback/main.cpp b/code/nel/samples/misc/callback/main.cpp new file mode 100644 index 000000000..157f3b259 --- /dev/null +++ b/code/nel/samples/misc/callback/main.cpp @@ -0,0 +1,62 @@ +/* + +Copyright (c) 2014, Jan BOON +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include + +class CTestClass +{ +public: + void helloWorld(int y) + { + nldebug("Method call: %i, %i", y, x); + } + int x; +}; + +void functionCall(int i) +{ + nldebug("Function call: %i", i); +} + +typedef NLMISC::CCallback TCallbackType; + +int main(int argc, char **argv) +{ + CTestClass tc; + tc.x = 42; + + TCallbackType cbMethod = TCallbackType(&tc, &CTestClass::helloWorld); + TCallbackType cbFunction = TCallbackType(functionCall); + cbMethod(100); + cbFunction(99); + + getchar(); + + return EXIT_SUCCESS; +} diff --git a/code/nel/src/3d/CMakeLists.txt b/code/nel/src/3d/CMakeLists.txt index fff343915..21184eb12 100644 --- a/code/nel/src/3d/CMakeLists.txt +++ b/code/nel/src/3d/CMakeLists.txt @@ -562,8 +562,13 @@ SOURCE_GROUP(Fx\\Particles\\lights FILES ps_light.cpp ../../include/nel/3d/ps_light.h) SOURCE_GROUP(Fx\\2d FILES + render_target_manager.cpp + ../../include/nel/3d/render_target_manager.h bloom_effect.cpp ../../include/nel/3d/bloom_effect.h + fxaa.cpp + fxaa_program.h + ../../include/nel/3d/fxaa.h deform_2d.cpp ../../include/nel/3d/deform_2d.h heat_haze.cpp @@ -700,6 +705,9 @@ SOURCE_GROUP(Stereo FILES stereo_ovr.cpp stereo_ovr_fp.cpp ../../include/nel/3d/stereo_ovr.h + stereo_ovr_04.cpp + stereo_ovr_04_program.h + ../../include/nel/3d/stereo_ovr_04.h stereo_libvr.cpp ../../include/nel/3d/stereo_libvr.h stereo_debugger.cpp diff --git a/code/nel/src/3d/bloom_effect.cpp b/code/nel/src/3d/bloom_effect.cpp index 7809aba2c..c468349ac 100644 --- a/code/nel/src/3d/bloom_effect.cpp +++ b/code/nel/src/3d/bloom_effect.cpp @@ -72,79 +72,47 @@ CBloomEffect::CBloomEffect() _SquareBloom = true; _DensityBloom = 128; _Init = false; - _InitBloomEffect = false; + + _BlurFinalTex = NULL; + _BlurHorizontalTex = NULL; } //----------------------------------------------------------------------------------------------------------- CBloomEffect::~CBloomEffect() { - if(_Init) + if (_Init) { - if(!_DisplayInitMat.empty()) + if (!_DisplayBlurMat.empty()) { - _DisplayInitMat.getObjectPtr()->setTexture(0, NULL); - if (_Driver) _Driver->deleteMaterial(_DisplayInitMat); - } - _InitText = NULL; - - if(!_DisplayBlurMat.empty()) - { - _DisplayBlurMat.getObjectPtr()->setTexture(0, NULL); if (_Driver) _Driver->deleteMaterial(_DisplayBlurMat); } - if(!_DisplaySquareBlurMat.empty()) + + if (!_DisplaySquareBlurMat.empty()) { - _DisplaySquareBlurMat.getObjectPtr()->setTexture(0, NULL); - _DisplaySquareBlurMat.getObjectPtr()->setTexture(1, NULL); if (_Driver) _Driver->deleteMaterial(_DisplaySquareBlurMat); } - if(!_BlurMat.empty()) + if (!_BlurMat.empty()) { - _BlurMat.getObjectPtr()->setTexture(0, NULL); - _BlurMat.getObjectPtr()->setTexture(1, NULL); - _BlurMat.getObjectPtr()->setTexture(2, NULL); - _BlurMat.getObjectPtr()->setTexture(3, NULL); if (_Driver) _Driver->deleteMaterial(_BlurMat); } - - _BlurHorizontalTex = NULL; - _BlurFinalTex = NULL; } } //----------------------------------------------------------------------------------------------------------- -void CBloomEffect::init(bool initBloomEffect) -{ - _InitBloomEffect = initBloomEffect; - - if(((CDriverUser *)_Driver)->getDriver()->supportBloomEffect()) - init(); -} - -//----------------------------------------------------------------------------------------------------------- - void CBloomEffect::init() { - _WndWidth = _Driver->getWindowWidth(); - _WndHeight = _Driver->getWindowHeight(); + if (!((CDriverUser *)_Driver)->getDriver()->supportBloomEffect()) + return; + + CDriverUser *dru = static_cast(_Driver); + IDriver *drv = dru->getDriver(); _BlurWidth = 256; _BlurHeight = 256; - // initialize textures - _InitText = NULL; - _BlurHorizontalTex = NULL; - _BlurFinalTex = NULL; - if(_InitBloomEffect) - { - initTexture(_InitText, false, _WndWidth, _WndHeight); - } - initTexture(_BlurFinalTex, true, _BlurWidth, _BlurHeight); - initTexture(_BlurHorizontalTex, true, _BlurWidth, _BlurHeight); - // initialize blur material _BlurMat = _Driver->createMaterial(); CMaterial * matObject = _BlurMat.getObjectPtr(); @@ -187,22 +155,6 @@ void CBloomEffect::init() matObject->texEnvArg1RGB(3, CMaterial::Constant, CMaterial::SrcColor); matObject->texEnvArg2RGB(3, CMaterial::Previous, CMaterial::SrcColor); - // initialize display materials - if(_InitBloomEffect) - { - _DisplayInitMat = _Driver->createMaterial(); - CMaterial * matObjectInit = _DisplayInitMat.getObjectPtr(); - _DisplayInitMat.initUnlit(); - _DisplayInitMat.setColor(CRGBA::White); - _DisplayInitMat.setBlend (false); - _DisplayInitMat.setAlphaTest (false); - matObjectInit->setBlendFunc (CMaterial::one, CMaterial::zero); - matObjectInit->setZWrite(false); - matObjectInit->setZFunc(CMaterial::always); - matObjectInit->setDoubleSided(true); - matObjectInit->setTexture(0, _InitText); - } - // initialize linear blur material _DisplayBlurMat = _Driver->createMaterial(); CMaterial * matObjectFinal = _DisplayBlurMat.getObjectPtr(); @@ -214,7 +166,7 @@ void CBloomEffect::init() matObjectFinal->setZFunc(CMaterial::always); matObjectFinal->setDoubleSided(true); - matObjectFinal->setTexture(0, _BlurFinalTex); + // matObjectFinal->setTexture(0, _BlurFinalTex); matObjectFinal->texEnvOpRGB(0, CMaterial::Modulate); matObjectFinal->texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor); matObjectFinal->texEnvArg1RGB(0, CMaterial::Constant, CMaterial::SrcColor); @@ -230,163 +182,93 @@ void CBloomEffect::init() matObjectFinal->setZFunc(CMaterial::always); matObjectFinal->setDoubleSided(true); - matObjectFinal->setTexture(0, _BlurFinalTex); matObjectFinal->texEnvOpRGB(0, CMaterial::Modulate); matObjectFinal->texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor); matObjectFinal->texEnvArg1RGB(0, CMaterial::Constant, CMaterial::SrcColor); - matObjectFinal->setTexture(1, _BlurFinalTex); matObjectFinal->texEnvOpRGB(1, CMaterial::Modulate); matObjectFinal->texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor); matObjectFinal->texEnvArg1RGB(1, CMaterial::Previous, CMaterial::SrcColor); // initialize quads - _DisplayQuad.V0 = CVector(0.f, 0.f, 0.5f); - _DisplayQuad.V1 = CVector(1.f, 0.f, 0.5f); - _DisplayQuad.V2 = CVector(1.f, 1.f, 0.5f); - _DisplayQuad.V3 = CVector(0.f, 1.f, 0.5f); - _BlurQuad.V0 = CVector(-1.f, -1.f, 0.5f); _BlurQuad.V1 = CVector(1.f, -1.f, 0.5f); _BlurQuad.V2 = CVector(1.f, 1.f, 0.5f); _BlurQuad.V3 = CVector(-1.f, 1.f, 0.5f); + if (drv->textureCoordinateAlternativeMode()) + { + _BlurQuad.Uv0 = CUV(0.f, 1.f); + _BlurQuad.Uv1 = CUV(1.f, 1.f); + _BlurQuad.Uv2 = CUV(1.f, 0.f); + _BlurQuad.Uv3 = CUV(0.f, 0.f); + } + else + { + _BlurQuad.Uv0 = CUV(0.f, 0.f); + _BlurQuad.Uv1 = CUV(1.f, 0.f); + _BlurQuad.Uv2 = CUV(1.f, 1.f); + _BlurQuad.Uv3 = CUV(0.f, 1.f); + } _Init = true; } //----------------------------------------------------------------------------------------------------------- -void CBloomEffect::initTexture(CSmartPtr & tex, bool isMode2D, uint32 width, uint32 height) +void CBloomEffect::applyBloom() { - NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); - - tex = new CTextureBloom(); - tex->setReleasable(false); - tex->resize(width, height); - tex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); - tex->setWrapS(ITexture::Clamp); - tex->setWrapT(ITexture::Clamp); - ((CTextureBloom *)tex.getPtr())->mode2D(isMode2D); - if(tex->TextureDrvShare==NULL || tex->TextureDrvShare->DrvTexture.getPtr()==NULL) - { - tex->setRenderTarget(true); - drvInternal->setupTexture(*tex); - } -} - -//----------------------------------------------------------------------------------------------------------- - -void CBloomEffect::initBloom() // clientcfg -{ - if(!((CDriverUser *)_Driver)->getDriver()->supportBloomEffect()) + if (!((CDriverUser *)_Driver)->getDriver()->supportBloomEffect()) return; // don't activate bloom when PolygonMode is different from Filled if (_Driver->getPolygonMode() != UDriver::Filled) return; - if(_Driver->getWindowWidth()==0 || _Driver->getWindowHeight()==0) + if (_Driver->getWindowWidth()==0 || _Driver->getWindowHeight()==0) return; - if(!_Init) + if (!_Init) init(); - _OriginalRenderTarget = static_cast(_Driver)->getDriver()->getRenderTarget(); + CDriverUser *dru = static_cast(_Driver); + IDriver *drv = dru->getDriver(); - // if window resize, reinitialize textures - if(_WndWidth!=_Driver->getWindowWidth() || _WndHeight!=_Driver->getWindowHeight()) - { - _WndWidth = _Driver->getWindowWidth(); - _WndHeight = _Driver->getWindowHeight(); + // backup + bool fogEnabled = _Driver->fogEnabled(); + _Driver->enableFog(false); - if(_InitBloomEffect) - { - // release old SmartPtr - _DisplayInitMat.getObjectPtr()->setTexture(0, NULL); - _InitText = NULL; + NL3D::ITexture *renderTarget = drv->getRenderTarget(); + nlassert(renderTarget); + nlassert(renderTarget->isBloomTexture()); - initTexture(_InitText, false, _WndWidth, _WndHeight); + uint width = renderTarget->getWidth(); + uint height = renderTarget->getHeight(); + bool mode2D = static_cast(renderTarget)->isMode2D(); + nlassert(renderTarget->getUploadFormat() == ITexture::Auto); - _DisplayInitMat.getObjectPtr()->setTexture(0, _InitText); - } + if (width >= 256) _BlurWidth = 256; + else _BlurWidth = raiseToNextPowerOf2(width) / 2; + if (height >= 256) _BlurHeight = 256; + else _BlurHeight = raiseToNextPowerOf2(height) / 2; - bool reinitBlurTextures = false; - if(_WndWidth<_BlurWidth || _WndHeight<_BlurHeight) - { - _BlurWidth = raiseToNextPowerOf2(_WndWidth)/2; - _BlurHeight = raiseToNextPowerOf2(_WndHeight)/2; + nlassert(!_BlurFinalTex); + _BlurFinalTex = _Driver->getRenderTargetManager().getRenderTarget(_BlurWidth, _BlurHeight, true); + nlassert(!_BlurHorizontalTex); + _BlurHorizontalTex = _Driver->getRenderTargetManager().getRenderTarget(_BlurWidth, _BlurHeight, true); - reinitBlurTextures = true; - } + _DisplayBlurMat.getObjectPtr()->setTexture(0, _BlurFinalTex->getITexture()); + _DisplaySquareBlurMat.getObjectPtr()->setTexture(0, _BlurFinalTex->getITexture()); + _DisplaySquareBlurMat.getObjectPtr()->setTexture(1, _BlurFinalTex->getITexture()); - if(_WndWidth>256 && _BlurWidth!=256) - { - _BlurWidth = 256; - reinitBlurTextures = true; - } + CTextureUser texNull; + dru->setRenderTarget(texNull); - if(_WndHeight>256 && _BlurHeight!=256) - { - _BlurHeight = 256; - reinitBlurTextures = true; - } - - if(reinitBlurTextures) - { - // release old SmartPtr - _DisplayBlurMat.getObjectPtr()->setTexture(0, NULL); - - _DisplaySquareBlurMat.getObjectPtr()->setTexture(0, NULL); - _DisplaySquareBlurMat.getObjectPtr()->setTexture(1, NULL); - - _BlurMat.getObjectPtr()->setTexture(0, NULL); - _BlurMat.getObjectPtr()->setTexture(1, NULL); - _BlurMat.getObjectPtr()->setTexture(2, NULL); - _BlurMat.getObjectPtr()->setTexture(3, NULL); - - _BlurHorizontalTex = NULL; - _BlurFinalTex = NULL; - - initTexture(_BlurFinalTex, true, _BlurWidth, _BlurHeight); - initTexture(_BlurHorizontalTex, true, _BlurWidth, _BlurHeight); - - _DisplayBlurMat.getObjectPtr()->setTexture(0, _BlurFinalTex); - - _DisplaySquareBlurMat.getObjectPtr()->setTexture(0, _BlurFinalTex); - _DisplaySquareBlurMat.getObjectPtr()->setTexture(1, _BlurFinalTex); - } - } - - if (!_OriginalRenderTarget) - { - NL3D::CTextureUser txt = (_InitBloomEffect) ? (CTextureUser(_InitText)) : (CTextureUser()); - if(!(static_cast(_Driver)->setRenderTarget(txt, 0, 0, _WndWidth, _WndHeight))) - { - nlwarning("setRenderTarget return false with initial texture for bloom effect\n"); - return; - } - } -} - -//----------------------------------------------------------------------------------------------------------- - -void CBloomEffect::endBloom() // clientcfg -{ - if(!_Driver->supportBloomEffect() || !_Init) - return; - - // don't activate bloom when PolygonMode is different from Filled - if (_Driver->getPolygonMode() != UDriver::Filled) return; - - if(_Driver->getWindowWidth()==0 || _Driver->getWindowHeight()==0) - return; - - CTextureUser txt1 = _OriginalRenderTarget ? CTextureUser(_OriginalRenderTarget) : ((_InitBloomEffect) ? (CTextureUser(_InitText)) : (CTextureUser())); - CTextureUser txt2(_BlurFinalTex); - CRect rect1(0, 0, _WndWidth, _WndHeight); + // Stretch original render target into blur texture + CTextureUser txt1(renderTarget); + CTextureUser txt2(_BlurFinalTex->getITexture()); + CRect rect1(0, 0, width, height); CRect rect2(0, 0, _BlurWidth, _BlurHeight); - // stretch rect - ((CDriverUser *) _Driver)->stretchRect(_Scene, txt1 , rect1, - txt2, rect2); + dru->stretchRect(_Scene, txt1, rect1, txt2, rect2); + _Driver->setMatrixMode2D11(); // horizontal blur pass doBlur(true); @@ -395,7 +277,27 @@ void CBloomEffect::endBloom() // clientcfg doBlur(false); // apply blur with a blend operation + drv->setRenderTarget(renderTarget); + _Driver->setMatrixMode2D11(); applyBlur(); + + // cleanup material texture references + _DisplayBlurMat.getObjectPtr()->setTexture(0, NULL); + _DisplaySquareBlurMat.getObjectPtr()->setTexture(0, NULL); + _DisplaySquareBlurMat.getObjectPtr()->setTexture(1, NULL); + _BlurMat.getObjectPtr()->setTexture(0, NULL); + _BlurMat.getObjectPtr()->setTexture(1, NULL); + _BlurMat.getObjectPtr()->setTexture(2, NULL); + _BlurMat.getObjectPtr()->setTexture(3, NULL); + + // restore + _Driver->enableFog(fogEnabled); + + // recycle render targets + _Driver->getRenderTargetManager().recycleRenderTarget(_BlurFinalTex); + _BlurFinalTex = NULL; + _Driver->getRenderTargetManager().recycleRenderTarget(_BlurHorizontalTex); + _BlurHorizontalTex = NULL; } //----------------------------------------------------------------------------------------------------------- @@ -404,49 +306,6 @@ void CBloomEffect::applyBlur() { NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); - /*if (_OriginalRenderTarget) - { - CTextureUser txt(_OriginalRenderTarget); - if(!(static_cast(_Driver)->setRenderTarget(txt, 0, 0, _WndWidth, _WndHeight))) - { - nlwarning("setRenderTarget return false with original render target for bloom effect\n"); - return; - } - } - // in opengl, display in init texture - else if(_InitBloomEffect) - { - CTextureUser txt(_InitText); - if(!(static_cast(_Driver)->setRenderTarget(txt, 0, 0, _WndWidth, _WndHeight))) - { - nlwarning("setRenderTarget return false with initial texture for bloom effect\n"); - return; - } - }*/ - CTextureUser txtApply = _OriginalRenderTarget ? CTextureUser(_OriginalRenderTarget) : ((_InitBloomEffect) ? (CTextureUser(_InitText)) : (CTextureUser())); - if(!(static_cast(_Driver)->setRenderTarget(txtApply, 0, 0, _WndWidth, _WndHeight))) - { - nlwarning("setRenderTarget return false with initial texture for bloom effect\n"); - return; - } - - // display blur texture - // initialize blur texture coordinates - if(_InitBloomEffect) - { - _BlurQuad.Uv0 = CUV(0.f, 0.f); - _BlurQuad.Uv1 = CUV(1.f, 0.f); - _BlurQuad.Uv2 = CUV(1.f, 1.f); - _BlurQuad.Uv3 = CUV(0.f, 1.f); - } - else - { - _BlurQuad.Uv0 = CUV(0.f, 1.f); - _BlurQuad.Uv1 = CUV(1.f, 1.f); - _BlurQuad.Uv2 = CUV(1.f, 0.f); - _BlurQuad.Uv3 = CUV(0.f, 0.f); - } - // initialize vertex program drvInternal->activeVertexProgram(TextureOffsetVertexProgram); drvInternal->setUniform4f(IDriver::VertexProgram, 8, 255.f, 255.f, 255.f, 255.f); @@ -469,59 +328,12 @@ void CBloomEffect::applyBlur() matObjectFinal->texConstantColor(0, constCoeff); // display quad - UCamera pCam = _Scene->getCam(); - _Driver->setMatrixMode2D11(); _Driver->drawQuad(_BlurQuad, displayBlurMat); - _Driver->setMatrixMode3D(pCam); // disable vertex program drvInternal->activeVertexProgram(NULL); } -//----------------------------------------------------------------------------------------------------------- - -void CBloomEffect::endInterfacesDisplayBloom() // clientcfg -{ - // Render from render target to screen if necessary. - // Don't do this when the blend was done to the screen or when rendering to a user provided rendertarget. - if ((_OriginalRenderTarget.getPtr() == NULL) && _InitBloomEffect) - { - if(!_Driver->supportBloomEffect() || !_Init) - return; - - // don't activate bloom when PolygonMode is different from Filled - if (_Driver->getPolygonMode() != UDriver::Filled) return; - - if(_Driver->getWindowWidth()==0 || _Driver->getWindowHeight()==0) - return; - - NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); - CTextureUser txtNull; - ((CDriverUser *)_Driver)->setRenderTarget(txtNull, 0, 0, 0, 0); - - // initialize texture coordinates - float newU = drvInternal->isTextureRectangle(_InitText) ? (float)_WndWidth : 1.f; - float newV = drvInternal->isTextureRectangle(_InitText) ? (float)_WndHeight : 1.f; - - _DisplayQuad.Uv0 = CUV(0.f, 0.f); - _DisplayQuad.Uv1 = CUV(newU, 0.f); - _DisplayQuad.Uv2 = CUV(newU, newV); - _DisplayQuad.Uv3 = CUV(0.f, newV); - - // init material texture -// CMaterial * matObjectInit = _DisplayInitMat.getObjectPtr(); - - // display - UCamera pCam = _Scene->getCam(); - _Driver->setMatrixMode2D11(); - _Driver->drawQuad(_DisplayQuad, _DisplayInitMat); - _Driver->setMatrixMode3D(pCam); - } - - _OriginalRenderTarget = NULL; -} - - //----------------------------------------------------------------------------------------------------------- void CBloomEffect::doBlur(bool horizontalBlur) @@ -531,17 +343,17 @@ void CBloomEffect::doBlur(bool horizontalBlur) ITexture * endTexture; // set displayed texture and render target texture of the pass - if(horizontalBlur) + if (horizontalBlur) { blurVec = CVector2f(1.f, 0.f); - startTexture = _BlurFinalTex; - endTexture = _BlurHorizontalTex; + startTexture = _BlurFinalTex->getITexture(); + endTexture = _BlurHorizontalTex->getITexture(); } else { blurVec = CVector2f(0.f, 1.f); - startTexture = _BlurHorizontalTex; - endTexture = _BlurFinalTex; + startTexture = _BlurHorizontalTex->getITexture(); + endTexture = _BlurFinalTex->getITexture(); } NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); @@ -552,6 +364,7 @@ void CBloomEffect::doBlur(bool horizontalBlur) nlwarning("setRenderTarget return false with blur texture for bloom effect\n"); return; } + _Driver->setMatrixMode2D11(); // initialize vertex program drvInternal->activeVertexProgram(TextureOffsetVertexProgram); @@ -561,20 +374,30 @@ void CBloomEffect::doBlur(bool horizontalBlur) // set several decal constants in order to obtain in the render target texture a mix of color // of a texel and its neighbored texels on the axe of the pass. float decalL, decal2L, decalR, decal2R; - if(_InitBloomEffect) + if (drvInternal->textureCoordinateAlternativeMode()) + { + if (horizontalBlur) + { + decalL = 0.5f; + decal2L = -0.5f; + decalR = 1.5f; + decal2R = 2.5f; + } + else + { + decalL = 0.0f; + decal2L = -1.0f; + decalR = 1.0f; + decal2R = 2.0f; + } + } + else { decalL = -0.5f; decal2L = -1.5f; decalR = 0.5f; decal2R = 1.5f; } - else - { - decalL = 0.f; - decal2L = -1.f; - decalR = 1.f; - decal2R = 2.f; - } drvInternal->setUniform2f(IDriver::VertexProgram, 10, (decalR/(float)_BlurWidth)*blurVec.x, (decalR/(float)_BlurHeight)*blurVec.y); drvInternal->setUniform2f(IDriver::VertexProgram, 11, (decal2R/(float)_BlurWidth)*blurVec.x, (decal2R/(float)_BlurHeight)*blurVec.y); drvInternal->setUniform2f(IDriver::VertexProgram, 12, (decalL/(float)_BlurWidth)*blurVec.x, (decalL/(float)_BlurHeight)*blurVec.y); @@ -587,22 +410,13 @@ void CBloomEffect::doBlur(bool horizontalBlur) matObject->setTexture(2, startTexture); matObject->setTexture(3, startTexture); - // initialize quad - _BlurQuad.Uv0 = CUV(0.0f, 0.0f); - _BlurQuad.Uv1 = CUV(1.f, 0.0f); - _BlurQuad.Uv2 = CUV(1.f, 1.f); - _BlurQuad.Uv3 = CUV(0.0f, 1.f); - // display - UCamera pCam = _Scene->getCam(); - _Driver->setMatrixMode2D11(); _Driver->drawQuad(_BlurQuad, _BlurMat); // disable render target and vertex program drvInternal->activeVertexProgram(NULL); CTextureUser cu; ((CDriverUser *)_Driver)->setRenderTarget(cu, 0, 0, 0, 0); - _Driver->setMatrixMode3D(pCam); } }; // NL3D diff --git a/code/nel/src/3d/driver.cpp b/code/nel/src/3d/driver.cpp index 2bfb0ea1f..791172700 100644 --- a/code/nel/src/3d/driver.cpp +++ b/code/nel/src/3d/driver.cpp @@ -32,7 +32,7 @@ namespace NL3D { // *************************************************************************** -const uint32 IDriver::InterfaceVersion = 0x6d; // gpu program interface +const uint32 IDriver::InterfaceVersion = 0x6e; // gpu program interface // *************************************************************************** IDriver::IDriver() : _SyncTexDrvInfos( "IDriver::_SyncTexDrvInfos" ) @@ -123,8 +123,9 @@ bool IDriver::release(void) // *************************************************************************** -GfxMode::GfxMode(uint16 w, uint16 h, uint8 d, bool windowed, bool offscreen, uint frequency, sint8 aa) +GfxMode::GfxMode(uint16 w, uint16 h, uint8 d, bool windowed, bool offscreen, uint frequency, sint8 aa, const std::string &displayDevice) { + DisplayDevice = displayDevice; Windowed = windowed; Width = w; Height = h; diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp index c7fd65a99..916cafe49 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp @@ -25,8 +25,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/misc/dynloadlib.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" @@ -1478,7 +1476,7 @@ bool CDriverD3D::setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool r D3DADAPTER_IDENTIFIER9 Identifier; HRESULT Res; Res = _D3D->GetAdapterIdentifier(gAdapter,0,&Identifier); - + if (strstr(Identifier.Description,"PerfHUD") != 0) { nlinfo ("Setting up with PerfHUD"); @@ -1511,6 +1509,7 @@ bool CDriverD3D::setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool r } } + // _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶meters, &_DeviceInterface); // Check some caps @@ -1637,20 +1636,6 @@ bool CDriverD3D::setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool r // Setup the event emitter, and try to retrieve a direct input interface _EventEmitter.addEmitter(we, true /*must delete*/); // the main emitter - // Try to get direct input - try - { - NLMISC::CDIEventEmitter *diee = NLMISC::CDIEventEmitter::create(GetModuleHandle(NULL), _HWnd, we); - if (diee) - { - _EventEmitter.addEmitter(diee, true); - } - } - catch(const EDirectInput &e) - { - nlinfo(e.what()); - } - // Init some variables _ForceDXTCCompression = false; _AnisotropicFilter = 0; @@ -2010,13 +1995,6 @@ bool CDriverD3D::swapBuffers() // todo hulud volatile //_DeviceInterface->SetStreamSource(0, _VolatileVertexBufferRAM[1]->VertexBuffer, 0, 12); - // Is direct input running ? - if (_EventEmitter.getNumEmitters() > 1) - { - // flush direct input messages if any - NLMISC::safe_cast(_EventEmitter.getEmitter(1))->poll(); - } - // End now if (!endScene()) { diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d.h b/code/nel/src/3d/driver/direct3d/driver_direct3d.h index 254b21871..039b6f3ed 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d.h +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d.h @@ -944,6 +944,7 @@ public: virtual ITexture *getRenderTarget() const; virtual bool copyTargetToTexture (ITexture *tex, uint32 offsetx, uint32 offsety, uint32 x, uint32 y, uint32 width, uint32 height, uint32 mipmapLevel); + virtual bool textureCoordinateAlternativeMode() const { return true; }; virtual bool getRenderTargetSize (uint32 &width, uint32 &height); virtual bool fillBuffer (CBitmap &bitmap); @@ -1033,11 +1034,6 @@ public: // Change default scale for all cursors virtual void setCursorScale(float scale); - virtual NLMISC::IMouseDevice *enableLowLevelMouse(bool enable, bool exclusive); - virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable); - virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager(); - virtual uint getDoubleClickDelay(bool hardwareMouse); - // Lights virtual uint getMaxLight () const; virtual void setLight (uint8 num, const CLight& light); diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_index.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_index.cpp index 20d59725c..b75a21d9d 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_index.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_index.cpp @@ -19,8 +19,6 @@ #include "nel/3d/index_buffer.h" #include "nel/3d/light.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/u_driver.h" diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_inputs.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_inputs.cpp index 4949e2fd8..f754b6357 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_inputs.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_inputs.cpp @@ -17,9 +17,6 @@ #include "stddirect3d.h" #include "driver_direct3d.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" - using namespace std; using namespace NLMISC; @@ -466,121 +463,6 @@ bool CDriverD3D::isSystemCursorCaptured() return GetCapture() == _HWnd; } -// *************************************************************************** -NLMISC::IMouseDevice* CDriverD3D::enableLowLevelMouse(bool enable, bool exclusive) -{ - H_AUTO_D3D(CDriverD3D_enableLowLevelMouse); - - NLMISC::IMouseDevice *res = NULL; - - NLMISC::CDIEventEmitter *diee = NULL; - - if (_EventEmitter.getNumEmitters() > 1) - diee = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - - if (enable) - { - try - { - if (diee) - res = diee->getMouseDevice(exclusive); - } - catch (const EDirectInput &) - { - } - } - else - { - if (diee) - diee->releaseMouse(); - } - - return res; -} - -// *************************************************************************** -NLMISC::IKeyboardDevice* CDriverD3D::enableLowLevelKeyboard(bool enable) -{ - H_AUTO_D3D(CDriverD3D_enableLowLevelKeyboard); - - NLMISC::IKeyboardDevice *res = NULL; - - NLMISC::CDIEventEmitter *diee = NULL; - - if (_EventEmitter.getNumEmitters() > 1) - diee = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - - if (enable) - { - try - { - if (diee) - res = diee->getKeyboardDevice(); - } - catch (const EDirectInput &) - { - } - } - else - { - if (diee) - diee->releaseKeyboard(); - } - - return res; -} - -// *************************************************************************** -NLMISC::IInputDeviceManager* CDriverD3D::getLowLevelInputDeviceManager() -{ - H_AUTO_D3D(CDriverD3D_getLowLevelInputDeviceManager); - - NLMISC::IInputDeviceManager *res = NULL; - - if (_EventEmitter.getNumEmitters() > 1) - res = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - - return res; -} - -// *************************************************************************** -uint CDriverD3D::getDoubleClickDelay(bool hardwareMouse) -{ - H_AUTO_D3D(CDriverD3D_getDoubleClickDelay); - - uint res = 250; - - NLMISC::IMouseDevice *md = NULL; - - if (_EventEmitter.getNumEmitters() >= 2) - { - NLMISC::CDIEventEmitter *diee = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - if (diee->isMouseCreated()) - { - try - { - md = diee->getMouseDevice(hardwareMouse); - } - catch (const EDirectInput &) - { - // could not get device .. - } - } - } - - if (md) - { - res = md->getDoubleClickDelay(); - } - else - { - // try to read the good value from windows - res = ::GetDoubleClickTime(); - } - - return res; -} - bool CDriverD3D::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY) { return convertBitmapToIcon(bitmap, cursor, iconWidth, iconHeight, iconDepth, col, hotSpotX, hotSpotY, true); diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_light.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_light.cpp index 4ad5b46c0..d3bb62e64 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_light.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_light.cpp @@ -20,8 +20,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/u_driver.h" diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp index 40d01039b..f22cba111 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp @@ -21,8 +21,6 @@ #include "nel/3d/index_buffer.h" #include "nel/3d/texture_bump.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/u_driver.h" @@ -648,7 +646,7 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) // Must separate texture setup and texture activation in 2 "for"... // because setupTexture() may disable all stage. - if (matShader == CMaterial::Normal + if (matShader == CMaterial::Normal || ((matShader == CMaterial::Program) && (_PixelProgramUser->features().MaterialFlags & CProgramFeatures::TextureStages)) ) { @@ -670,7 +668,7 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) // Don't do it also for Specular because the EnvFunction and the TexGen may be special. { H_AUTO_D3D(CDriverD3D_setupMaterial_normalShaderActivateTextures) - if (matShader == CMaterial::Normal + if (matShader == CMaterial::Normal || ((matShader == CMaterial::Program) && (_PixelProgramUser->features().MaterialFlags & CProgramFeatures::TextureStages)) ) { diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_matrix.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_matrix.cpp index 87b047476..c5b479de0 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_matrix.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_matrix.cpp @@ -20,8 +20,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/u_driver.h" diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_render.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_render.cpp index 313fb2344..939dc1dc9 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_render.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_render.cpp @@ -20,8 +20,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/misc/fast_mem.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp index 2995c5b4c..ad5de53c1 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp @@ -20,8 +20,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/u_driver.h" diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex.cpp index b798acb26..d37c272a2 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex.cpp @@ -20,8 +20,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/u_driver.h" diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.cpp b/code/nel/src/3d/driver/opengl/driver_opengl.cpp index 6dae9f4fe..ce60d7f42 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl.cpp @@ -28,8 +28,6 @@ #include "nel/3d/light.h" #include "nel/3d/index_buffer.h" #include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/mouse_device.h" #include "nel/misc/hierarchical_timer.h" #include "nel/misc/dynloadlib.h" #include "driver_opengl_vertex_buffer_hard.h" @@ -483,7 +481,7 @@ bool CDriverGL::setupDisplay() glLightModeli((GLenum)GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT); #endif } - + if (_Extensions.ARBFragmentShader) { _ForceNativeFragmentPrograms = false; @@ -936,14 +934,6 @@ bool CDriverGL::swapBuffers() } #endif -#ifdef NL_OS_WINDOWS - if (_EventEmitter.getNumEmitters() > 1) // is direct input running ? - { - // flush direct input messages if any - NLMISC::safe_cast(_EventEmitter.getEmitter(1))->poll(); - } -#endif - if (!_WndActive) { if (_AGPVertexArrayRange) _AGPVertexArrayRange->updateLostBuffers(); @@ -1042,6 +1032,8 @@ bool CDriverGL::release() // Call IDriver::release() before, to destroy textures, shaders and VBs... IDriver::release(); + nlassert(_DepthStencilFBOs.empty()); + _SwapBufferCounter = 0; // delete querries @@ -1085,7 +1077,7 @@ void CDriverGL::setupViewport (const class CViewport& viewport) // Setup gl viewport uint32 clientWidth, clientHeight; - getWindowSize(clientWidth, clientHeight); + getRenderTargetSize(clientWidth, clientHeight); // Backup the viewport _CurrViewport = viewport; @@ -1140,7 +1132,7 @@ void CDriverGL::setupScissor (const class CScissor& scissor) // Setup gl viewport uint32 clientWidth, clientHeight; - getWindowSize(clientWidth, clientHeight); + getRenderTargetSize(clientWidth, clientHeight); // Backup the scissor _CurrScissor= scissor; @@ -1509,7 +1501,7 @@ void CDriverGL::enableUsedTextureMemorySum (bool enable) H_AUTO_OGL(CDriverGL_enableUsedTextureMemorySum ) if (enable) - { + { nlinfo ("3D: PERFORMANCE INFO: enableUsedTextureMemorySum has been set to true in CDriverGL"); _TextureUsed.reserve(512); } diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.h b/code/nel/src/3d/driver/opengl/driver_opengl.h index 241b3bb95..c4540b9da 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl.h @@ -146,6 +146,23 @@ public: virtual uint getVisibleCount(); }; +// *************************************************************************** +class CDepthStencilFBO : public NLMISC::CRefCount +{ +public: + CDepthStencilFBO(CDriverGL *driver, uint width, uint height); + ~CDepthStencilFBO(); + + uint Width; + uint Height; + + GLuint DepthFBOId; + GLuint StencilFBOId; + +private: + CDriverGL *m_Driver; +}; + // *************************************************************************** class CTextureDrvInfosGL : public ITextureDrvInfos { @@ -173,12 +190,9 @@ public: GLuint FBOId; // depth stencil FBO id - GLuint DepthFBOId; - GLuint StencilFBOId; - - bool InitFBO; bool AttachDepthStencil; - bool UsePackedDepthStencil; + NLMISC::CSmartPtr DepthStencilFBO; + bool InitFBO; // The current wrap modes assigned to the texture. ITexture::TWrapMode WrapS; @@ -527,14 +541,6 @@ public: // Change default scale for all cursors virtual void setCursorScale(float scale); - virtual NLMISC::IMouseDevice *enableLowLevelMouse(bool enable, bool exclusive); - - virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable); - - virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager(); - - virtual uint getDoubleClickDelay(bool hardwareMouse); - virtual void getWindowSize (uint32 &width, uint32 &height); virtual void getWindowPos (sint32 &x, sint32 &y); @@ -566,6 +572,8 @@ public: virtual bool copyTargetToTexture (ITexture *tex, uint32 offsetx, uint32 offsety, uint32 x, uint32 y, uint32 width, uint32 height, uint32 mipmapLevel); + virtual bool textureCoordinateAlternativeMode() const { return false; }; + virtual bool getRenderTargetSize (uint32 &width, uint32 &height); @@ -693,6 +701,7 @@ private: friend class CTextureDrvInfosGL; friend class CVertexProgamDrvInfosGL; friend class CPixelProgamDrvInfosGL; + friend class CDepthStencilFBO; private: // Version of the driver. Not the interface version!! Increment when implementation of the driver change. @@ -888,8 +897,11 @@ private: // viewport before call to setRenderTarget, if BFO extension is supported CViewport _OldViewport; + // Current FBO render target CSmartPtr _RenderTargetFBO; + // Share the same backbuffer for FBO render targets with window size + std::vector _DepthStencilFBOs; // Num lights return by GL_MAX_LIGHTS uint _MaxDriverLight; diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_inputs.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_inputs.cpp index d1cd1fb60..cbd1bcd9a 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_inputs.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_inputs.cpp @@ -27,8 +27,6 @@ # endif // HAVE_XCURSOR #endif // defined(NL_OS_UNIX) && !defined(NL_OS_MAC) -#include "nel/misc/mouse_device.h" -#include "nel/misc/di_event_emitter.h" #include "nel/3d/u_driver.h" #include "nel/misc/file.h" @@ -666,149 +664,6 @@ bool CDriverGL::isSystemCursorCaptured() #endif } -// *************************************************************************** -NLMISC::IMouseDevice* CDriverGL::enableLowLevelMouse(bool enable, bool exclusive) -{ - H_AUTO_OGL(CDriverGL_enableLowLevelMouse); - - NLMISC::IMouseDevice *res = NULL; - -#ifdef NL_OS_WINDOWS - - NLMISC::CDIEventEmitter *diee = NULL; - - if (_EventEmitter.getNumEmitters() > 1) - diee = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - - if (enable) - { - try - { - if (diee) - res = diee->getMouseDevice(exclusive); - } - catch (const EDirectInput &) - { - } - } - else - { - if (diee) - diee->releaseMouse(); - } - -#elif defined(NL_OS_MAC) -#elif defined (NL_OS_UNIX) -#endif - - return res; -} - -// *************************************************************************** -NLMISC::IKeyboardDevice* CDriverGL::enableLowLevelKeyboard(bool enable) -{ - H_AUTO_OGL(CDriverGL_enableLowLevelKeyboard); - - NLMISC::IKeyboardDevice *res = NULL; - -#ifdef NL_OS_WINDOWS - - NLMISC::CDIEventEmitter *diee = NULL; - - if (_EventEmitter.getNumEmitters() > 1) - diee = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - - if (enable) - { - try - { - if (diee) - res = diee->getKeyboardDevice(); - } - catch (const EDirectInput &) - { - } - } - else - { - if (diee) - diee->releaseKeyboard(); - } - -#elif defined(NL_OS_MAC) -#elif defined (NL_OS_UNIX) -#endif - - return res; -} - -// *************************************************************************** -NLMISC::IInputDeviceManager* CDriverGL::getLowLevelInputDeviceManager() -{ - H_AUTO_OGL(CDriverGL_getLowLevelInputDeviceManager); - - NLMISC::IInputDeviceManager *res = NULL; - -#ifdef NL_OS_WINDOWS - - if (_EventEmitter.getNumEmitters() > 1) - res = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - -#elif defined(NL_OS_MAC) -#elif defined (NL_OS_UNIX) -#endif - - return res; -} - -// *************************************************************************** -uint CDriverGL::getDoubleClickDelay(bool hardwareMouse) -{ - H_AUTO_OGL(CDriverGL_getDoubleClickDelay); - - uint res = 250; - -#ifdef NL_OS_WINDOWS - - NLMISC::IMouseDevice *md = NULL; - - if (_EventEmitter.getNumEmitters() >= 2) - { - NLMISC::CDIEventEmitter *diee = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); - if (diee->isMouseCreated()) - { - try - { - md = diee->getMouseDevice(hardwareMouse); - } - catch (const EDirectInput &) - { - // could not get device .. - } - } - } - - if (md) - { - res = md->getDoubleClickDelay(); - } - else - { - // try to read the good value from windows - res = ::GetDoubleClickTime(); - } - -#elif defined(NL_OS_MAC) - // TODO: Missing Mac Implementation for getDoubleClickDelay -#elif defined (NL_OS_UNIX) - - // TODO for Linux - -#endif - - return res; -} - bool CDriverGL::getBestCursorSize(uint srcWidth, uint srcHeight, uint &dstWidth, uint &dstHeight) { #ifdef NL_OS_WINDOWS diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_material.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_material.cpp index ed43fe8c3..986dd6303 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_material.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_material.cpp @@ -2087,14 +2087,16 @@ void CDriverGL::setupCloudPass (uint /* pass */) glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA); activateTexEnvColor (1, mat.getColor()); } - else + else if (ATICloudShaderHandle) { // TODO : for now the state is not cached in _CurrentTexEnvSpecial nglBindFragmentShaderATI(ATICloudShaderHandle); glEnable(GL_FRAGMENT_SHADER_ATI); float cst[4] = { 0.f, 0.f, 0.f, mat.getColor().A / 255.f }; nglSetFragmentShaderConstantATI(GL_CON_0_ATI, cst); - /* + } + else + { _DriverGLStates.activeTextureARB(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); // Operator. @@ -2130,7 +2132,6 @@ void CDriverGL::setupCloudPass (uint /* pass */) glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_CONSTANT_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - */ } #endif } diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp index f26b53254..9b798ae51 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp @@ -73,12 +73,8 @@ CTextureDrvInfosGL::CTextureDrvInfosGL(IDriver *drv, ItTexDrvInfoPtrMap it, CDri #endif FBOId = 0; - DepthFBOId = 0; - StencilFBOId = 0; - InitFBO = false; AttachDepthStencil = true; - UsePackedDepthStencil = drvGl->supportPackedDepthStencil(); TextureUsedIdx = 0; } @@ -98,9 +94,9 @@ CTextureDrvInfosGL::~CTextureDrvInfosGL() _Driver->_TextureUsed[TextureUsedIdx] = NULL; } - if(InitFBO) - { #ifdef USE_OPENGLES + if (InitFBO) + { nglDeleteFramebuffersOES(1, &FBOId); if(AttachDepthStencil) { @@ -108,24 +104,73 @@ CTextureDrvInfosGL::~CTextureDrvInfosGL() if(!UsePackedDepthStencil) nglDeleteRenderbuffersOES(1, &StencilFBOId); } -#else - nglDeleteFramebuffersEXT(1, &FBOId); - if(AttachDepthStencil) - { - nglDeleteRenderbuffersEXT(1, &DepthFBOId); - if(!UsePackedDepthStencil) - nglDeleteRenderbuffersEXT(1, &StencilFBOId); - } + } #endif +} + +CDepthStencilFBO::CDepthStencilFBO(CDriverGL *driver, uint width, uint height) +{ + nldebug("3D: Init shared FBO"); + + m_Driver = driver; + Width = width; + Height = height; + + bool packedDepthStencil = driver->supportPackedDepthStencil(); + nglGenRenderbuffersEXT(1, &DepthFBOId); + if (packedDepthStencil) + StencilFBOId = DepthFBOId; + else + nglGenRenderbuffersEXT(1, &StencilFBOId); + + if (packedDepthStencil) + { + //nldebug("3D: using packed depth stencil"); + nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilFBOId); + nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, width, height); + } + else + { + nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthFBOId); + nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height); + /* + nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilFBOId); + nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, width, height); + */ + } + + nlassert(DepthFBOId); + nlassert(StencilFBOId); + + driver->_DepthStencilFBOs.push_back(this); +} + +CDepthStencilFBO::~CDepthStencilFBO() +{ + // driver remove + m_Driver->_DepthStencilFBOs.erase(std::find(m_Driver->_DepthStencilFBOs.begin(), m_Driver->_DepthStencilFBOs.end(), this)); + + if (DepthFBOId) + { + nldebug("3D: Release shared FBO"); + nglDeleteRenderbuffersEXT(1, &DepthFBOId); + if (StencilFBOId == DepthFBOId) + StencilFBOId = 0; + DepthFBOId = 0; + } + if (StencilFBOId) + { + nglDeleteRenderbuffersEXT(1, &StencilFBOId); + StencilFBOId = 0; } } // *************************************************************************** bool CTextureDrvInfosGL::initFrameBufferObject(ITexture * tex) { - if(!InitFBO) + if (!InitFBO) { - if(tex->isBloomTexture()) + if (tex->isBloomTexture()) { AttachDepthStencil = !((CTextureBloom*)tex)->isMode2D(); } @@ -179,49 +224,33 @@ bool CTextureDrvInfosGL::initFrameBufferObject(ITexture * tex) #else // generate IDs nglGenFramebuffersEXT(1, &FBOId); - if(AttachDepthStencil) - { - nglGenRenderbuffersEXT(1, &DepthFBOId); - if(UsePackedDepthStencil) - StencilFBOId = DepthFBOId; - else - nglGenRenderbuffersEXT(1, &StencilFBOId); - } - + //nldebug("3D: using depth %d and stencil %d", DepthFBOId, StencilFBOId); // initialize FBO nglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId); nglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, TextureMode, ID, 0); - // attach depth/stencil render to FBO - // note: for some still unkown reason it's impossible to add - // a stencil buffer as shown in the respective docs (see - // opengl.org extension registry). Until a safe approach to add - // them is found, there will be no attached stencil for the time - // being, aside of using packed depth+stencil buffers. - if(AttachDepthStencil) + // attach depth stencil + if (AttachDepthStencil) { - if(UsePackedDepthStencil) + for (std::vector::iterator it(_Driver->_DepthStencilFBOs.begin()), end(_Driver->_DepthStencilFBOs.end()); it != end; ++it) { - //nldebug("3D: using packed depth stencil"); - nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilFBOId); - nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, tex->getWidth(), tex->getHeight()); + if ((*it)->Width == tex->getWidth() && (*it)->Height == tex->getHeight()) + { + DepthStencilFBO = (*it); + break; + } } - else + if (!DepthStencilFBO) { - nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthFBOId); - nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, tex->getWidth(), tex->getHeight()); - /* - nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilFBOId); - nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, tex->getWidth(), tex->getHeight()); - */ + DepthStencilFBO = new CDepthStencilFBO(_Driver, tex->getWidth(), tex->getHeight()); } nglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, DepthFBOId); + GL_RENDERBUFFER_EXT, DepthStencilFBO->DepthFBOId); nldebug("3D: glFramebufferRenderbufferExt(depth:24) = %X", nglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); nglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, StencilFBOId); + GL_RENDERBUFFER_EXT, DepthStencilFBO->StencilFBOId); nldebug("3D: glFramebufferRenderbufferExt(stencil:8) = %X", nglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); } #endif @@ -339,17 +368,7 @@ bool CTextureDrvInfosGL::initFrameBufferObject(ITexture * tex) #endif if (AttachDepthStencil) { -#ifdef USE_OPENGLES - nglDeleteRenderbuffersOES(1, &DepthFBOId); -#else - nglDeleteRenderbuffersEXT(1, &DepthFBOId); -#endif - if(!UsePackedDepthStencil) -#ifdef USE_OPENGLES - nglDeleteRenderbuffersOES(1, &StencilFBOId); -#else - nglDeleteRenderbuffersEXT(1, &StencilFBOId); -#endif + DepthStencilFBO = NULL; } } @@ -2260,11 +2279,8 @@ void CDriverGL::swapTextureHandle(ITexture &tex0, ITexture &tex1) swap(t0->MinFilter, t1->MinFilter); swap(t0->TextureMode, t1->TextureMode); swap(t0->FBOId, t1->FBOId); - swap(t0->DepthFBOId, t1->DepthFBOId); - swap(t0->StencilFBOId, t1->StencilFBOId); + swap(t0->DepthStencilFBO, t1->DepthStencilFBO); swap(t0->InitFBO, t1->InitFBO); - swap(t0->AttachDepthStencil, t1->AttachDepthStencil); - swap(t0->UsePackedDepthStencil, t1->UsePackedDepthStencil); } @@ -2314,11 +2330,16 @@ bool CDriverGL::setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width if(tex->isBloomTexture() && supportBloomEffect()) { + // NOTE: No support for mip map level here! + uint32 w, h; getWindowSize(w, h); getViewport(_OldViewport); + if (!width) width = tex->getWidth(); + if (!height) height = tex->getHeight(); + CViewport newVP; newVP.init(0, 0, ((float)width/(float)w), ((float)height/(float)h)); setupViewport(newVP); @@ -2401,10 +2422,11 @@ bool CDriverGL::copyTargetToTexture (ITexture *tex, bool CDriverGL::getRenderTargetSize (uint32 &width, uint32 &height) { H_AUTO_OGL(CDriverGL_getRenderTargetSize) - if (_TextureTarget) + NLMISC::CSmartPtr tex = _RenderTargetFBO ? _RenderTargetFBO : (_TextureTarget ? _TextureTarget : NULL); + if (tex) { - width = _TextureTarget->getWidth(); - height = _TextureTarget->getHeight(); + width = tex->getWidth(); + height = tex->getHeight(); } else { diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp index 2fea530cf..5bea65771 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp @@ -38,8 +38,6 @@ # define _NET_WM_STATE_ADD 1 #endif // NL_OS_UNIX -#include "nel/misc/mouse_device.h" -#include "nel/misc/di_event_emitter.h" #include "nel/3d/u_driver.h" #include "nel/misc/file.h" @@ -255,7 +253,7 @@ bool GlWndProc(CDriverGL *driver, XEvent &e) unsigned long nitems_return = 0; unsigned long bytes_after_return = 0; long *data = NULL; - + int status = XGetWindowProperty(driver->_dpy, driver->_win, XA_FRAME_EXTENTS, 0, 4, False, XA_CARDINAL, &type_return, &format_return, &nitems_return, &bytes_after_return, (unsigned char**)&data); // succeeded to retrieve decoration size @@ -270,7 +268,7 @@ bool GlWndProc(CDriverGL *driver, XEvent &e) driver->_DecorationWidth = e.xconfigure.x - driver->_WindowX; driver->_DecorationHeight = e.xconfigure.y - driver->_WindowY; } - + // don't allow negative decoration sizes if (driver->_DecorationWidth < 0) driver->_DecorationWidth = 0; if (driver->_DecorationHeight < 0) driver->_DecorationHeight = 0; @@ -940,20 +938,6 @@ bool CDriverGL::setDisplay(nlWindow wnd, const GfxMode &mode, bool show, bool re // setup the event emitter, and try to retrieve a direct input interface _EventEmitter.addEmitter(we, true /*must delete*/); // the main emitter - /// try to get direct input - try - { - NLMISC::CDIEventEmitter *diee = NLMISC::CDIEventEmitter::create(GetModuleHandle(NULL), _win, we); - if (diee) - { - _EventEmitter.addEmitter(diee, true); - } - } - catch(const EDirectInput &e) - { - nlinfo(e.what()); - } - #elif defined(NL_OS_MAC) if (wnd == EmptyWindow) @@ -1864,6 +1848,19 @@ bool CDriverGL::setMode(const GfxMode& mode) if (!_DestroyWindow) return true; +#if defined(NL_OS_WINDOWS) + // save relative cursor + POINT cursorPos; + cursorPos.x = 0; + cursorPos.y = 0; + + BOOL cursorPosOk = isSystemCursorInClientArea() + && GetCursorPos(&cursorPos) + && ScreenToClient(_win, &cursorPos); + sint curX = (sint)cursorPos.x * (sint)mode.Width; + sint curY = (sint)cursorPos.y * (sint)mode.Height; +#endif + if (!setScreenMode(mode)) return false; @@ -1883,6 +1880,17 @@ bool CDriverGL::setMode(const GfxMode& mode) case 32: _ColorDepth = ColorDepth32; break; } +#if defined(NL_OS_WINDOWS) + // restore relative cursor + if (cursorPosOk) + { + cursorPos.x = curX / (sint)mode.Width; + cursorPos.y = curY / (sint)mode.Height; + ClientToScreen(_win, &cursorPos); + SetCursorPos(cursorPos.x, cursorPos.y); + } +#endif + // set color depth for custom cursor updateCursor(true); @@ -2298,7 +2306,19 @@ void CDriverGL::setWindowPos(sint32 x, sint32 y) #ifdef NL_OS_WINDOWS - SetWindowPos(_win, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); + // save relative cursor + POINT cursorPos; + BOOL cursorPosOk = isSystemCursorInClientArea() + && GetCursorPos(&cursorPos) + && ScreenToClient(_win, &cursorPos); + + SetWindowPos(_win, NULL, x, y, 0, 0, /*SWP_NOZORDER | SWP_NOACTIVATE |*/ SWP_NOSIZE); + + if (cursorPosOk) + { + ClientToScreen(_win, &cursorPos); + SetCursorPos(cursorPos.x, cursorPos.y); + } #elif defined(NL_OS_MAC) // get the rect (position, size) of the screen with menu bar @@ -2469,7 +2489,7 @@ bool CDriverGL::createContext() if (_EglContext == EGL_NO_CONTEXT) { return false; - } + } // Make the context current if (!eglMakeCurrent(_EglDisplay, _EglSurface, _EglSurface, _EglContext)) diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h index 7e46fc6de..aa7d591fd 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h @@ -20,14 +20,13 @@ #include "nel/misc/event_emitter.h" #include "nel/misc/event_server.h" #include "nel/misc/events.h" -#include "nel/misc/game_device_events.h" #include "nel/3d/driver.h" #import "cocoa_opengl_view.h" #include #import -namespace NLMISC +namespace NLMISC { class CCocoaEventEmitter : public IEventEmitter @@ -42,8 +41,8 @@ class CCocoaEventEmitter : public IEventEmitter CEventServer* _server; public: - CCocoaEventEmitter() : - _emulateRawMode(false), + CCocoaEventEmitter() : + _emulateRawMode(false), _setToEmulateRawMode(false), _driver(NULL), _glView(nil), @@ -52,7 +51,6 @@ public: void init(NL3D::IDriver*, CocoaOpenGLView*, bool eventLoop); bool processMessage(NSEvent* event, CEventServer* server = NULL); virtual void submitEvents(CEventServer& server, bool allWindows); - virtual void emulateMouseRawMode(bool enable); bool handleQuitRequest(); virtual bool copyTextToClipboard(const ucstring &text); diff --git a/code/nel/src/3d/driver/opengl/stdopengl.h b/code/nel/src/3d/driver/opengl/stdopengl.h index 9773b0048..ab4eb8316 100644 --- a/code/nel/src/3d/driver/opengl/stdopengl.h +++ b/code/nel/src/3d/driver/opengl/stdopengl.h @@ -83,7 +83,6 @@ #include "nel/misc/event_emitter_multi.h" #include "nel/misc/time_nl.h" #include "nel/misc/rect.h" -#include "nel/misc/mouse_device.h" #include "nel/misc/dynloadlib.h" #include "nel/misc/file.h" diff --git a/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp b/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp index c3a8552ac..be0736bae 100644 --- a/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp +++ b/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "nel/misc/debug.h" @@ -37,7 +37,7 @@ static Atom XA_WM_DELETE_WINDOW = 0; namespace NLMISC { -CUnixEventEmitter::CUnixEventEmitter ():_dpy(NULL), _win(0), _emulateRawMode(false), _driver(NULL) +CUnixEventEmitter::CUnixEventEmitter ():_dpy(NULL), _win(0), _driver(NULL) { _im = 0; _ic = 0; @@ -158,25 +158,6 @@ static Bool isMouseMoveEvent(Display *display, XEvent *event, XPointer arg) return (event->type == MotionNotify); } -void CUnixEventEmitter::emulateMouseRawMode(bool enable) -{ - _emulateRawMode = enable; - - if(_emulateRawMode) - { - XWindowAttributes xwa; - XGetWindowAttributes(_dpy, _win, &xwa); - XWarpPointer(_dpy, None, _win, None, None, None, None, - (xwa.width / 2), (xwa.height / 2)); - - // remove all outstanding mouse move events, they happened before the mouse - // was pulled back to 0.5 / 0.5, so a wrong movement delta would be - // reported otherwise - XEvent event; - while(XCheckIfEvent(_dpy, &event, &isMouseMoveEvent, NULL)) { }; - } -} - #ifndef AltMask # ifdef NL_OS_MAC # define AltMask (8192) @@ -512,33 +493,13 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server) { TMouseButton button=getMouseButton (event.xbutton.state); - // if raw mode should be emulated - if(_emulateRawMode) - { - // when we just wrapped back the pointer to 0.5 / 0.5, ignore event - if(event.xbutton.x == xwa.width / 2 && event.xbutton.y == xwa.height / 2) - break; + // get the relative mouse position + float fX = (float) event.xbutton.x / (float) xwa.width; + float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height; - // post a CGDMouseMove with the movement delta to the event server - server->postEvent( - new CGDMouseMove(this, NULL /* no mouse device */, - event.xbutton.x - (xwa.width / 2), - (xwa.height / 2) - event.xbutton.y)); + // post a normal mouse move event to the event server + server->postEvent (new CEventMouseMove (fX, fY, button, this)); - // move the pointer back to the center of the window - XWarpPointer(_dpy, None, _win, None, None, None, None, - (xwa.width / 2), (xwa.height / 2)); - } - // if in normal mouse mode - else - { - // get the relative mouse position - float fX = (float) event.xbutton.x / (float) xwa.width; - float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height; - - // post a normal mouse move event to the event server - server->postEvent (new CEventMouseMove (fX, fY, button, this)); - } break; } case KeyPress: diff --git a/code/nel/src/3d/driver/opengl/unix_event_emitter.h b/code/nel/src/3d/driver/opengl/unix_event_emitter.h index 362ed2086..7eeef970e 100644 --- a/code/nel/src/3d/driver/opengl/unix_event_emitter.h +++ b/code/nel/src/3d/driver/opengl/unix_event_emitter.h @@ -20,7 +20,6 @@ #include "nel/misc/types_nl.h" #include "nel/misc/event_emitter.h" #include "nel/misc/events.h" -#include "nel/misc/game_device_events.h" #include "nel/3d/driver.h" @@ -56,11 +55,6 @@ public: */ virtual void submitEvents(CEventServer & server, bool allWindows); - /** - * enable or disable mouse raw mode - */ - virtual void emulateMouseRawMode(bool emulate); - /** * process input-related events (mouse and keyboard) */ diff --git a/code/nel/src/3d/driver_user.cpp b/code/nel/src/3d/driver_user.cpp index 7ccf4cfce..c4dc97655 100644 --- a/code/nel/src/3d/driver_user.cpp +++ b/code/nel/src/3d/driver_user.cpp @@ -192,8 +192,11 @@ CDriverUser::CDriverUser (uintptr_t windowIcon, TDriver driver, emptyProc exitFu _PBTri.lock (iba); iba.setTri(0, 0, 1, 2); + _RenderTargetManager.m_Driver = this; _ShapeBank._DriverUser = this; + _EffectRenderTarget = NULL; + NL_SET_IB_NAME(_PBLine, "CDriverUser::_PBLine"); NL_SET_IB_NAME(_PBTri, "CDriverUser::_PBTri"); } @@ -246,7 +249,7 @@ bool CDriverUser::setDisplay(nlWindow wnd, const CMode &mode, bool show, bool NL3D_HAUTO_UI_DRIVER; // window init. - if (_Driver->setDisplay(wnd, GfxMode(mode.Width, mode.Height, mode.Depth, mode.Windowed, false, mode.Frequency, mode.AntiAlias), show, resizeable)) + if (_Driver->setDisplay(wnd, GfxMode(mode.Width, mode.Height, mode.Depth, mode.Windowed, false, mode.Frequency, mode.AntiAlias, mode.DisplayDevice), show, resizeable)) { // Always true nlverify (activate()); @@ -290,7 +293,7 @@ bool CDriverUser::setDisplay(nlWindow wnd, const CMode &mode, bool show, bool // *************************************************************************** bool CDriverUser::setMode(const CMode& mode) { - return _Driver->setMode(GfxMode(mode.Width, mode.Height, mode.Depth, mode.Windowed, false, mode.Frequency, mode.AntiAlias)); + return _Driver->setMode(GfxMode(mode.Width, mode.Height, mode.Depth, mode.Windowed, false, mode.Frequency, mode.AntiAlias, mode.DisplayDevice)); } // ---------------------------------------------------------------------------- @@ -316,7 +319,7 @@ bool CDriverUser::getModes(std::vector &modes) bool res = _Driver->getModes(vTmp); modes.clear(); for (uint i = 0; i < vTmp.size(); ++i) - modes.push_back(CMode(vTmp[i].Width, vTmp[i].Height, vTmp[i].Depth, vTmp[i].Windowed, vTmp[i].Frequency, vTmp[i].AntiAlias)); + modes.push_back(CMode(vTmp[i].Width, vTmp[i].Height, vTmp[i].Depth, vTmp[i].Windowed, vTmp[i].Frequency, vTmp[i].AntiAlias, vTmp[i].DisplayDevice)); std::sort(modes.begin(), modes.end(), CModeSorter()); @@ -1357,6 +1360,7 @@ void CDriverUser::swapBuffers() NL3D_HAUTO_SWAP_DRIVER; _Driver->swapBuffers(); + _RenderTargetManager.cleanup(); } // *************************************************************************** @@ -1609,36 +1613,6 @@ bool CDriverUser::fillBuffer (CBitmap &bitmap) // *************************************************************************** // *************************************************************************** -NLMISC::IMouseDevice *CDriverUser::enableLowLevelMouse(bool enable, bool exclusive) -{ - NL3D_HAUTO_UI_DRIVER; - - return _Driver->enableLowLevelMouse(enable, exclusive); -} -NLMISC::IKeyboardDevice *CDriverUser::enableLowLevelKeyboard(bool enable) -{ - NL3D_HAUTO_UI_DRIVER; - - return _Driver->enableLowLevelKeyboard(enable); -} - -void CDriverUser::emulateMouseRawMode(bool enable) -{ - _Driver->getEventEmitter()->emulateMouseRawMode(enable); -} - -uint CDriverUser::getDoubleClickDelay(bool hardwareMouse) -{ - NL3D_HAUTO_UI_DRIVER; - return _Driver->getDoubleClickDelay(hardwareMouse); -} - -NLMISC::IInputDeviceManager *CDriverUser::getLowLevelInputDeviceManager() -{ - NL3D_HAUTO_UI_DRIVER; - - return _Driver->getLowLevelInputDeviceManager(); -} void CDriverUser::showCursor (bool b) { NL3D_HAUTO_UI_DRIVER; @@ -1974,9 +1948,7 @@ bool CDriverUser::setRenderTarget(class UTexture & uTex, uint32 x, uint32 y, uin bool result = _Driver->setRenderTarget(tex, x, y, width, height, mipmapLevel, cubeFace); - CViewport currentViewport; - _Driver->getViewport(currentViewport); - setViewport(currentViewport); + setupMatrixContext(); return result; } diff --git a/code/nel/src/3d/driver_user2.cpp b/code/nel/src/3d/driver_user2.cpp index 990175dd4..1b46ab607 100644 --- a/code/nel/src/3d/driver_user2.cpp +++ b/code/nel/src/3d/driver_user2.cpp @@ -73,6 +73,77 @@ void CDriverUser::deleteScene(UScene *scene) _Scenes.erase((CSceneUser*)scene, "deleteScene(): Bad scene ptr"); } +// *************************************************************************** + +void CDriverUser::beginDefaultRenderTarget(uint32 width, uint32 height) +{ + if (_MatRenderTarget.empty()) + { + _MatRenderTarget.attach(&_MatRenderTargetInt); + UMaterial &umat = _MatRenderTarget; + CMaterial &mat = _MatRenderTargetInt; + umat.initUnlit(); + umat.setColor(CRGBA::White); + umat.setBlend(false); + umat.setAlphaTest(false); + mat.setBlendFunc(CMaterial::one, CMaterial::zero); + mat.setZWrite(false); + mat.setZFunc(CMaterial::always); + mat.setDoubleSided(true); + + _RenderTargetQuad.V0 = CVector(0.f, 0.f, 0.5f); + _RenderTargetQuad.V1 = CVector(1.f, 0.f, 0.5f); + _RenderTargetQuad.V2 = CVector(1.f, 1.f, 0.5f); + _RenderTargetQuad.V3 = CVector(0.f, 1.f, 0.5f); + _RenderTargetQuad.Uv0 = CUV(0.f, 0.f); + _RenderTargetQuad.Uv1 = CUV(1.f, 0.f); + _RenderTargetQuad.Uv2 = CUV(1.f, 1.f); + _RenderTargetQuad.Uv3 = CUV(0.f, 1.f); + } + + nlassert(!_EffectRenderTarget); + if (width == 0 || height == 0) + getWindowSize(width, height); + _EffectRenderTarget = getRenderTargetManager().getRenderTarget(width, height); + setRenderTarget(*_EffectRenderTarget); +} + +// *************************************************************************** + +void CDriverUser::endDefaultRenderTarget(UScene *scene) +{ + nlassert(_EffectRenderTarget); + + CTextureUser texNull; + setRenderTarget(texNull); + + _MatRenderTarget.getObjectPtr()->setTexture(0, _EffectRenderTarget->getITexture()); + + UCamera pCam; + if (scene) + { + pCam = scene->getCam(); + } + CViewport oldVp = getViewport(); + CViewport vp = CViewport(); + setViewport(vp); + setMatrixMode2D11(); + bool fog = fogEnabled(); + enableFog(false); + drawQuad(_RenderTargetQuad, _MatRenderTarget); + enableFog(fog); + setViewport(oldVp); + if (scene) + { + setMatrixMode3D(pCam); + } + + _MatRenderTarget.getObjectPtr()->setTexture(0, NULL); + + getRenderTargetManager().recycleRenderTarget(_EffectRenderTarget); + _EffectRenderTarget = NULL; +} + // *************************************************************************** UTextContext *CDriverUser::createTextContext(const std::string fontFileName, const std::string fontExFileName) { diff --git a/code/nel/src/3d/fxaa.cpp b/code/nel/src/3d/fxaa.cpp new file mode 100644 index 000000000..89d1c59cd --- /dev/null +++ b/code/nel/src/3d/fxaa.cpp @@ -0,0 +1,291 @@ +/** + * \file fxaa.cpp + * \brief CFXAA + * \date 2014-08-03 21:41GMT + * \author Jan Boon (Kaetemi) + * CFXAA + */ + +/* + * Copyright (C) 2014 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +namespace { + +#include "fxaa_program.h" + +} /* anonymous namespace */ + +CFXAA::CFXAA(NL3D::UDriver *driver) : m_Driver(driver), m_PP(NULL), m_VP(NULL), m_Width(~0), m_Height(~0) +{ + nldebug("3D: Create FXAA"); + + CDriverUser *dru = static_cast(driver); + NL3D::IDriver *drv = (dru)->getDriver(); + + if (drv->supportBloomEffect() && drv->supportNonPowerOfTwoTextures()) + { + m_PP = new CPixelProgram(); + // arbfp1 + { + IProgram::CSource *source = new IProgram::CSource(); + source->Features.MaterialFlags = CProgramFeatures::TextureStages; + source->Profile = IProgram::arbfp1; + source->setSourcePtr(a_arbfp1); + m_PP->addSource(source); + } + // ps_2_0 + { + IProgram::CSource *source = new IProgram::CSource(); + source->Features.MaterialFlags = CProgramFeatures::TextureStages; + source->Profile = IProgram::ps_2_0; + source->setSourcePtr(a_ps_2_0); + m_PP->addSource(source); + } + if (!drv->compilePixelProgram(m_PP)) + { + nlwarning("3D: No supported pixel program for FXAA effect"); + + delete m_PP; + m_PP = NULL; + } + else + { + nldebug("3D: FXAA pixel program available"); + } + } + + if (!m_PP) + { + return; + } + + // create vp + { + m_VP = new CVertexProgram(); + // nelvp + { + IProgram::CSource *source = new IProgram::CSource(); + source->Features.MaterialFlags = CProgramFeatures::TextureStages; + source->Profile = IProgram::nelvp; + source->setSourcePtr(a_nelvp); + m_VP->addSource(source); + } + if (!drv->compileVertexProgram(m_VP)) + { + nlwarning("3D: No supported vertex program for FXAA effect"); + + delete m_VP; + m_VP = NULL; + delete m_PP; + m_PP = NULL; + } + else + { + nldebug("3D: FXAA vertex program available"); + } + } + + if (!m_VP) + { + return; + } + + // create material and vb + { + m_Mat = m_Driver->createMaterial(); + m_Mat.initUnlit(); + m_Mat.setColor(CRGBA::White); + m_Mat.setBlend (false); + m_Mat.setAlphaTest (false); + NL3D::CMaterial *mat = m_Mat.getObjectPtr(); + mat->setShader(NL3D::CMaterial::Normal); + mat->setBlendFunc(CMaterial::one, CMaterial::zero); + mat->setZWrite(false); + mat->setZFunc(CMaterial::always); + mat->setDoubleSided(true); + + m_QuadUV.V0 = CVector(0.f, 0.f, 0.5f); + m_QuadUV.V1 = CVector(1.f, 0.f, 0.5f); + m_QuadUV.V2 = CVector(1.f, 1.f, 0.5f); + m_QuadUV.V3 = CVector(0.f, 1.f, 0.5f); + + /*if (drv->textureCoordinateAlternativeMode()) + { + m_QuadUV.Uv0 = CUV(0.f, 1.f); + m_QuadUV.Uv1 = CUV(1.f, 1.f); + m_QuadUV.Uv2 = CUV(1.f, 0.f); + m_QuadUV.Uv3 = CUV(0.f, 0.f); + } + else + {*/ + m_QuadUV.Uv0 = CUV(0.f, 0.f); + m_QuadUV.Uv1 = CUV(1.f, 0.f); + m_QuadUV.Uv2 = CUV(1.f, 1.f); + m_QuadUV.Uv3 = CUV(0.f, 1.f); + /*}*/ + + /*CVertexBuffer &vb = m_VB; + vb.clearValueEx(); + vb.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3); + vb.addValueEx(CVertexBuffer::TexCoord0, CVertexBuffer::Float2); + vb.addValueEx(CVertexBuffer::TexCoord1, CVertexBuffer::Float4); + vb.initEx(); + vb.setPreferredMemory(CVertexBuffer::RAMVolatile, false); + vb.setNumVertices(4);*/ + } +} + +CFXAA::~CFXAA() +{ + nldebug("3D: Destroy FXAA"); + + if (!m_Mat.empty()) + { + m_Driver->deleteMaterial(m_Mat); + } + + delete m_VP; + m_VP = NULL; + delete m_PP; + m_PP = NULL; + + m_Driver = NULL; +} + +void CFXAA::applyEffect() +{ + if (!m_PP) + return; + + CDriverUser *dru = static_cast(m_Driver); + IDriver *drv = dru->getDriver(); + + // backup + bool fogEnabled = m_Driver->fogEnabled(); + m_Driver->enableFog(false); + + NL3D::ITexture *renderTarget = drv->getRenderTarget(); + nlassert(renderTarget); + nlassert(renderTarget->isBloomTexture()); + + uint width = renderTarget->getWidth(); + uint height = renderTarget->getHeight(); + bool mode2D = static_cast(renderTarget)->isMode2D(); + nlassert(renderTarget->getUploadFormat() == ITexture::Auto); + + float fwidth = (float)width; + float fheight = (float)height; + float pwidth = 1.0f / fwidth; + float pheight = 1.0f / fheight; + float hpwidth = pwidth * 0.5f; + float hpheight = pheight * 0.5f; + float n = 0.5f; + + //if (width != m_Width || height != m_Height) + /*{ + // Build VB + m_Width = width; + m_Height = height; + CVertexBufferReadWrite vba; + m_VB.lock(vba); + vba.setValueFloat3Ex(CVertexBuffer::Position, 0, 0.f, 0.f, 0.5f); // BL + vba.setValueFloat3Ex(CVertexBuffer::Position, 1, 1.f, 0.f, 0.5f); // BR + vba.setValueFloat3Ex(CVertexBuffer::Position, 2, 1.f, 1.f, 0.5f); // TR + vba.setValueFloat3Ex(CVertexBuffer::Position, 3, 0.f, 1.f, 0.5f); // TL + vba.setValueFloat2Ex(CVertexBuffer::TexCoord0, 0, 0.f, 0.f); + vba.setValueFloat2Ex(CVertexBuffer::TexCoord0, 1, 1.f, 0.f); + vba.setValueFloat2Ex(CVertexBuffer::TexCoord0, 2, 1.f, 1.f); + vba.setValueFloat2Ex(CVertexBuffer::TexCoord0, 3, 0.f, 1.f); + vba.setValueFloat4Ex(CVertexBuffer::TexCoord1, 0, 0.f - hpwidth, 0.f - hpheight, 0.f + hpwidth, 0.f + hpheight); + vba.setValueFloat4Ex(CVertexBuffer::TexCoord1, 1, 1.f - hpwidth, 0.f - hpheight, 1.f + hpwidth, 0.f + hpheight); + vba.setValueFloat4Ex(CVertexBuffer::TexCoord1, 2, 1.f - hpwidth, 1.f - hpheight, 1.f + hpwidth, 1.f + hpheight); + vba.setValueFloat4Ex(CVertexBuffer::TexCoord1, 3, 0.f - hpwidth, 1.f - hpheight, 0.f + hpwidth, 1.f + hpheight); + }*/ + + // create render target + CTextureUser *otherRenderTarget = m_Driver->getRenderTargetManager().getRenderTarget(width, height, mode2D); + + // swap render target + CTextureUser texNull; + dru->setRenderTarget(texNull); + drv->swapTextureHandle(*renderTarget, *otherRenderTarget->getITexture()); + drv->setRenderTarget(renderTarget); + m_Driver->setMatrixMode2D11(); + + // debug + // m_Driver->clearBuffers(CRGBA(128, 128, 128, 128)); + + // activate program + bool vpok = drv->activeVertexProgram(m_VP); + nlassert(vpok); + bool ppok = drv->activePixelProgram(m_PP); + nlassert(ppok); + /*drv->setUniform4f(IDriver::PixelProgram, 0, -n / fwidth, -n / fheight, n / fwidth, n / fheight); // fxaaConsoleRcpFrameOpt + drv->setUniform4f(IDriver::PixelProgram, 1, -2.0f / fwidth, -2.0f / fheight, 2.0f / fwidth, 2.0f / fheight); // fxaaConsoleRcpFrameOpt2*/ + drv->setUniform2f(IDriver::PixelProgram, 0, 1.0f / fwidth, 1.0f / fheight); // fxaaQualityRcpFrame + drv->setUniform1f(IDriver::PixelProgram, 1, 0.75f); // fxaaQualitySubpix + drv->setUniform1f(IDriver::PixelProgram, 2, 0.166f); // fxaaQualityEdgeThreshold + drv->setUniform1f(IDriver::PixelProgram, 3, 0.0833f); // fxaaQualityEdgeThresholdMin + drv->setUniformMatrix(IDriver::VertexProgram, 0, IDriver::ModelViewProjection, IDriver::Identity); + // drv->setUniform4f(IDriver::VertexProgram, 9, -hpwidth, -hpheight, hpwidth, hpheight); + + // render effect + m_Mat.getObjectPtr()->setTexture(0, otherRenderTarget->getITexture()); + /*drv->activeVertexBuffer(m_VB); + drv->renderRawQuads(*m_Mat.getObjectPtr(), 0, 1);*/ + m_Driver->drawQuad(m_QuadUV, m_Mat); + m_Mat.getObjectPtr()->setTexture(0, NULL); + + // deactivate program + drv->activeVertexProgram(NULL); + drv->activePixelProgram(NULL); + + // restore + m_Driver->enableFog(fogEnabled); + + // recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(otherRenderTarget); +} + +} /* namespace NL3D */ + +/* end of file */ diff --git a/code/nel/src/3d/fxaa_program.h b/code/nel/src/3d/fxaa_program.h new file mode 100644 index 000000000..a6bf847ef --- /dev/null +++ b/code/nel/src/3d/fxaa_program.h @@ -0,0 +1,994 @@ + +const char *a_nelvp = + "!!VP1.0\n" + "DP4 o[HPOS].x, c[0], v[OPOS];\n" + "DP4 o[HPOS].y, c[1], v[OPOS];\n" + "DP4 o[HPOS].z, c[2], v[OPOS];\n" + "DP4 o[HPOS].w, c[3], v[OPOS];\n" + "MOV o[TEX0].xy, v[TEX0];\n" + // "ADD o[TEX1], v[TEX0].xyxy, c[9];\n" + "END\n"; + +const char *a_arbfp1_test = + "!!ARBfp1.0\n" + "OPTION ARB_precision_hint_fastest;\n" + "TEX result.color, fragment.texcoord[1].zwzw, texture[0], 2D;\n" + "END\n"; + +const char *a_arbfp1 = + "!!ARBfp1.0\n" + "OPTION ARB_precision_hint_fastest;\n" + /*"# cgc version 3.1.0013, build date Apr 18 2012\n" + "# command line args: -profile arbfp1 -O3 -fastmath -fastprecision\n" + "# source file: fxaa_pp.cg\n" + "#vendor NVIDIA Corporation\n" + "#version 3.1.0.13\n" + "#profile arbfp1\n" + "#program fxaa_pp\n" + "#semantic fxaa_pp.fxaaQualityRcpFrame\n" + "#semantic fxaa_pp.fxaaQualitySubpix\n" + "#semantic fxaa_pp.fxaaQualityEdgeThreshold\n" + "#semantic fxaa_pp.fxaaQualityEdgeThresholdMin\n" + "#semantic fxaa_pp.nlTex0 : TEX0\n" + "#var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1\n" + "#var float2 fxaaQualityRcpFrame : : c[0] : 2 : 1\n" + "#var float fxaaQualitySubpix : : c[1] : 3 : 1\n" + "#var float fxaaQualityEdgeThreshold : : c[2] : 4 : 1\n" + "#var float fxaaQualityEdgeThresholdMin : : c[3] : 5 : 1\n" + "#var sampler2D nlTex0 : TEX0 : texunit 0 : 6 : 1\n" + "#var float4 oCol : $vout.COLOR : COL : 7 : 1\n" + "#const c[4] = 0 -1 1 -2\n" + "#const c[5] = 2 0.5 0.25 1.5\n" + "#const c[6] = 4 12 0.083333336 3\n"*/ + "PARAM c[7] = { program.env[0..3],\n" + " { 0, -1, 1, -2 },\n" + " { 2, 0.5, 0.25, 1.5 },\n" + " { 4, 12, 0.083333336, 3 } };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "TEMP R2;\n" + "TEMP R3;\n" + "TEMP R4;\n" + "TEMP R5;\n" + "TEMP R6;\n" + "TEMP R7;\n" + "TEMP R8;\n" + "TEMP R9;\n" + "MOV R3.xyz, c[4];\n" + "MAD R2.zw, R3.xyyz, c[0].xyxy, fragment.texcoord[0].xyxy;\n" + "MAD R0.xy, R3, c[0], fragment.texcoord[0];\n" + "MAD R1.xy, R3.zyzw, c[0], fragment.texcoord[0];\n" + "TEX R5.y, R1, texture[0], 2D;\n" + "MAD R1.xy, R3.zxzw, c[0], fragment.texcoord[0];\n" + "ADD R0.zw, fragment.texcoord[0].xyxy, -c[0].xyxy;\n" + "TEX R4.y, R0.zwzw, texture[0], 2D;\n" + "TEX R6.y, R2.zwzw, texture[0], 2D;\n" + "TEX R8, fragment.texcoord[0], texture[0], 2D;\n" + "TEX R1.y, R1, texture[0], 2D;\n" + "TEX R0.y, R0, texture[0], 2D;\n" + "ADD R0.z, R4.y, R5.y;\n" + "MAD R1.z, R0.y, c[4].w, R0;\n" + "MAD R0.zw, R3.xyyx, c[0].xyxy, fragment.texcoord[0].xyxy;\n" + "TEX R2.y, R0.zwzw, texture[0], 2D;\n" + "ADD R0.x, R2.y, R1.y;\n" + "ABS R0.w, R1.z;\n" + "ADD R1.zw, fragment.texcoord[0].xyxy, c[0].xyxy;\n" + "TEX R7.y, R1.zwzw, texture[0], 2D;\n" + "MAD R0.z, R8.y, c[4].w, R0.x;\n" + "ABS R0.z, R0;\n" + "MAD R2.x, R0.z, c[5], R0.w;\n" + "MAD R0.zw, R3.xyxz, c[0].xyxy, fragment.texcoord[0].xyxy;\n" + "TEX R3.y, R0.zwzw, texture[0], 2D;\n" + "ADD R0.z, R0.y, R3.y;\n" + "ADD R1.x, R6.y, R7.y;\n" + "MAD R0.w, R3.y, c[4], R1.x;\n" + "MAD R1.x, R8.y, c[4].w, R0.z;\n" + "ABS R0.w, R0;\n" + "ADD R2.x, R0.w, R2;\n" + "ADD R2.w, R4.y, R6.y;\n" + "ADD R0.w, R5.y, R7.y;\n" + "ABS R1.z, R1.x;\n" + "MAD R1.x, R1.y, c[4].w, R0.w;\n" + "ABS R1.w, R1.x;\n" + "MAD R1.x, R2.y, c[4].w, R2.w;\n" + "MAD R1.z, R1, c[5].x, R1.w;\n" + "ABS R1.x, R1;\n" + "ADD R1.x, R1, R1.z;\n" + "SGE R4.x, R1, R2;\n" + "MAX R1.x, R3.y, R8.y;\n" + "MAX R1.z, R1.y, R1.x;\n" + "MAX R1.x, R0.y, R2.y;\n" + "MAX R1.x, R1, R1.z;\n" + "MIN R1.z, R3.y, R8.y;\n" + "MIN R1.w, R1.y, R1.z;\n" + "MIN R1.z, R0.y, R2.y;\n" + "MIN R1.z, R1, R1.w;\n" + "MUL R2.x, R1, c[2];\n" + "ADD R3.z, R1.x, -R1;\n" + "ABS R3.w, R4.x;\n" + "MAX R1.w, R2.x, c[3].x;\n" + "ADD R2.z, R3, -R1.w;\n" + "CMP R2.x, R2.z, c[4], c[4].z;\n" + "CMP R1.x, -R3.w, c[4], c[4].z;\n" + "MUL R3.w, R2.x, R1.x;\n" + "CMP R1.z, -R3.w, R1.y, R3.y;\n" + "ADD R1.y, -R8, R1.z;\n" + "CMP R1.w, -R3, R2.y, R0.y;\n" + "ADD R0.y, -R8, R1.w;\n" + "MUL R4.x, R2, R4;\n" + "CMP R3.y, -R3.w, c[0], R3.x;\n" + "ABS R4.w, R1.y;\n" + "ABS R4.z, R0.y;\n" + "SGE R0.y, R4.z, R4.w;\n" + "MUL R1.y, R2.x, R0;\n" + "ABS R0.y, R0;\n" + "CMP R4.y, -R0, c[4].x, c[4].z;\n" + "ABS R0.y, R1.x;\n" + "CMP R0.y, -R0, c[4].x, c[4].z;\n" + "MUL R1.x, R2, R0.y;\n" + "CMP R2.y, -R4.x, c[0], c[0].x;\n" + "CMP R2.y, -R1, -R2, R2;\n" + "MAD R1.y, R2, c[5], fragment.texcoord[0];\n" + "CMP R5.z, -R4.x, R1.y, fragment.texcoord[0].y;\n" + "ADD R5.y, R5.z, -R3;\n" + "MAD R0.y, R2, c[5], fragment.texcoord[0].x;\n" + "CMP R3.x, -R1, c[0], R3;\n" + "CMP R6.x, -R3.w, R0.y, fragment.texcoord[0];\n" + "ADD R5.w, R5.z, R3.y;\n" + "ADD R1.x, R6, -R3;\n" + "MOV R1.y, R5;\n" + "TEX R0.y, R1, texture[0], 2D;\n" + "MUL R1.y, R2.x, R4;\n" + "ADD R0.x, R0.z, R0;\n" + "ADD R0.w, R2, R0;\n" + "MAD R0.z, R0.x, c[5].x, R0.w;\n" + "ADD R1.w, R8.y, R1;\n" + "ADD R1.z, R8.y, R1;\n" + "CMP R4.y, -R1, R1.z, R1.w;\n" + "ADD R1.z, R6.x, R3.x;\n" + "MAD R5.x, -R4.y, c[5].y, R0.y;\n" + "MOV R1.w, R5;\n" + "TEX R0.y, R1.zwzw, texture[0], 2D;\n" + "MAX R1.w, R4.z, R4;\n" + "MAD R1.y, -R4, c[5], R0;\n" + "MUL R4.z, R1.w, c[5];\n" + "ABS R0.y, R1;\n" + "SGE R1.w, R0.y, R4.z;\n" + "ABS R6.y, R5.x;\n" + "SGE R0.y, R6, R4.z;\n" + "ABS R1.w, R1;\n" + "CMP R6.y, -R1.w, c[4].x, c[4].z;\n" + "ABS R0.y, R0;\n" + "CMP R5.z, -R0.y, c[4].x, c[4];\n" + "ADD_SAT R0.y, R5.z, R6;\n" + "MUL R4.w, R2.x, R0.y;\n" + "MUL R0.y, R2.x, R6;\n" + "MAD R1.w, R3.y, c[5], R5;\n" + "CMP R6.x, -R0.y, R1.w, R5.w;\n" + "MAD R6.z, R3.x, c[5].w, R1;\n" + "CMP R1.z, -R0.y, R6, R1;\n" + "MOV R1.w, R6.x;\n" + "TEX R0.y, R1.zwzw, texture[0], 2D;\n" + "MUL R1.w, R4, R6.y;\n" + "CMP R6.y, -R1.w, R0, R1;\n" + "MUL R0.y, R2.x, R5.z;\n" + "MAD R1.y, -R3, c[5].w, R5;\n" + "CMP R5.w, -R0.y, R1.y, R5.y;\n" + "MAD R6.z, -R3.x, c[5].w, R1.x;\n" + "CMP R1.x, -R0.y, R6.z, R1;\n" + "MOV R1.y, R5.w;\n" + "TEX R0.y, R1, texture[0], 2D;\n" + "MUL R5.y, R4.w, R5.z;\n" + "CMP R0.y, -R5, R0, R5.x;\n" + "MAD R5.x, -R4.y, c[5].y, R0.y;\n" + "CMP R5.z, -R5.y, R5.x, R0.y;\n" + "MAD R1.y, -R4, c[5], R6;\n" + "CMP R1.y, -R1.w, R1, R6;\n" + "ABS R1.w, R1.y;\n" + "SGE R1.w, R1, R4.z;\n" + "ABS R0.y, R5.z;\n" + "SGE R0.y, R0, R4.z;\n" + "ABS R1.w, R1;\n" + "CMP R6.y, -R1.w, c[4].x, c[4].z;\n" + "ABS R0.y, R0;\n" + "CMP R5.y, -R0, c[4].x, c[4].z;\n" + "ADD_SAT R0.y, R5, R6;\n" + "MUL R5.x, R4.w, R0.y;\n" + "MUL R0.y, R4.w, R6;\n" + "MAD R1.w, R3.y, c[5].x, R6.x;\n" + "CMP R6.x, -R0.y, R1.w, R6;\n" + "MAD R6.z, R3.x, c[5].x, R1;\n" + "CMP R1.z, -R0.y, R6, R1;\n" + "MOV R1.w, R6.x;\n" + "TEX R0.y, R1.zwzw, texture[0], 2D;\n" + "MUL R1.w, R5.x, R6.y;\n" + "CMP R6.y, -R1.w, R0, R1;\n" + "MUL R0.y, R4.w, R5;\n" + "MAD R1.y, -R3, c[5].x, R5.w;\n" + "CMP R4.w, -R0.y, R1.y, R5;\n" + "MAD R6.z, -R3.x, c[5].x, R1.x;\n" + "CMP R1.x, -R0.y, R6.z, R1;\n" + "MOV R1.y, R4.w;\n" + "TEX R0.y, R1, texture[0], 2D;\n" + "MUL R5.y, R5.x, R5;\n" + "CMP R0.y, -R5, R0, R5.z;\n" + "MAD R5.z, -R4.y, c[5].y, R0.y;\n" + "CMP R5.w, -R5.y, R5.z, R0.y;\n" + "MAD R1.y, -R4, c[5], R6;\n" + "CMP R1.y, -R1.w, R1, R6;\n" + "ABS R1.w, R1.y;\n" + "SGE R1.w, R1, R4.z;\n" + "ABS R1.w, R1;\n" + "CMP R6.y, -R1.w, c[4].x, c[4].z;\n" + "ABS R0.y, R5.w;\n" + "SGE R0.y, R0, R4.z;\n" + "ABS R0.y, R0;\n" + "CMP R5.y, -R0, c[4].x, c[4].z;\n" + "ADD_SAT R0.y, R5, R6;\n" + "MUL R5.z, R5.x, R0.y;\n" + "MUL R0.y, R5.x, R6;\n" + "MAD R1.w, R3.y, c[6].x, R6.x;\n" + "CMP R6.x, -R0.y, R1.w, R6;\n" + "MAD R6.z, R3.x, c[6].x, R1;\n" + "CMP R1.z, -R0.y, R6, R1;\n" + "MOV R1.w, R6.x;\n" + "TEX R0.y, R1.zwzw, texture[0], 2D;\n" + "MUL R1.w, R5.z, R6.y;\n" + "CMP R6.y, -R1.w, R0, R1;\n" + "MUL R0.y, R5.x, R5;\n" + "MAD R1.y, -R3, c[6].x, R4.w;\n" + "CMP R4.w, -R0.y, R1.y, R4;\n" + "MAD R5.x, -R3, c[6], R1;\n" + "CMP R1.x, -R0.y, R5, R1;\n" + "MOV R1.y, R4.w;\n" + "TEX R0.y, R1, texture[0], 2D;\n" + "MUL R1.y, R5.z, R5;\n" + "CMP R5.x, -R1.y, R0.y, R5.w;\n" + "MAD R5.y, -R4, c[5], R5.x;\n" + "CMP R1.y, -R1, R5, R5.x;\n" + "MAD R0.y, -R4, c[5], R6;\n" + "CMP R0.y, -R1.w, R0, R6;\n" + "ABS R5.x, R0.y;\n" + "ABS R1.w, R1.y;\n" + "SGE R1.w, R1, R4.z;\n" + "SGE R5.x, R5, R4.z;\n" + "ABS R4.z, R5.x;\n" + "ABS R1.w, R1;\n" + "CMP R4.z, -R4, c[4].x, c[4];\n" + "CMP R1.w, -R1, c[4].x, c[4].z;\n" + "MUL R4.z, R5, R4;\n" + "MAD R5.y, R3.x, c[6], R1.z;\n" + "CMP R5.y, -R4.z, R5, R1.z;\n" + "MAD R5.x, R3.y, c[6].y, R6;\n" + "CMP R1.z, -R4, R5.x, R6.x;\n" + "MUL R1.w, R5.z, R1;\n" + "ADD R4.z, -fragment.texcoord[0].x, R5.y;\n" + "ADD R1.z, -fragment.texcoord[0].y, R1;\n" + "CMP R1.z, -R3.w, R1, R4;\n" + "MAD R4.z, -R3.x, c[6].y, R1.x;\n" + "MAD R3.x, -R3.y, c[6].y, R4.w;\n" + "CMP R3.y, -R1.w, R4.z, R1.x;\n" + "CMP R1.x, -R1.w, R3, R4.w;\n" + "ADD R1.w, fragment.texcoord[0].x, -R3.y;\n" + "ADD R1.x, fragment.texcoord[0].y, -R1;\n" + "CMP R1.x, -R3.w, R1, R1.w;\n" + "SLT R1.w, R1.x, R1.z;\n" + "ADD R3.x, R1, R1.z;\n" + "ABS R1.w, R1;\n" + "MIN R1.x, R1, R1.z;\n" + "CMP R1.w, -R1, c[4].x, c[4].z;\n" + "MUL R1.z, R2.x, R1.w;\n" + "RCP R3.x, R3.x;\n" + "MAD R1.x, R1, -R3, c[5].y;\n" + "MUL R1.w, R4.y, c[5].y;\n" + "SLT R3.x, R1.y, c[4];\n" + "SLT R1.y, R8, R1.w;\n" + "SLT R0.y, R0, c[4].x;\n" + "ADD R0.y, R0, -R1;\n" + "ADD R1.y, -R1, R3.x;\n" + "ABS R0.y, R0;\n" + "ABS R1.y, R1;\n" + "CMP R0.y, -R0, c[4].z, c[4].x;\n" + "CMP R1.y, -R1, c[4].z, c[4].x;\n" + "CMP R0.x, -R1.z, R0.y, R1.y;\n" + "MAD R0.y, R0.z, c[6].z, -R8;\n" + "ABS R0.x, R0;\n" + "CMP R0.x, -R0, c[4], c[4].z;\n" + "MUL R0.x, R2, R0;\n" + "CMP R0.x, -R0, c[4], R1;\n" + "RCP R0.z, R3.z;\n" + "ABS R0.y, R0;\n" + "MUL_SAT R0.y, R0, R0.z;\n" + "MUL R0.z, R0.y, c[4].w;\n" + "ADD R0.z, R0, c[6].w;\n" + "MUL R0.y, R0, R0;\n" + "MUL R0.y, R0.z, R0;\n" + "MUL R0.y, R0, R0;\n" + "MUL R0.y, R0, c[1].x;\n" + "MAX R0.x, R0, R0.y;\n" + "MAD R0.y, R0.x, R2, fragment.texcoord[0];\n" + "MAD R0.z, R0.x, R2.y, fragment.texcoord[0].x;\n" + "CMP R0.x, -R3.w, R0.z, fragment.texcoord[0];\n" + "CMP R0.y, -R4.x, R0, fragment.texcoord[0];\n" + "TEX R0.xyz, R0, texture[0], 2D;\n" + "CMP R1, R2.z, R8, R9;\n" + "MOV R0.w, R8.y;\n" + "CMP result.color, -R2.x, R0, R1;\n" + "END\n"; + /*"# 260 instructions, 10 R-regs\n" + "\n"*/ + +const char *a_arbfp1_ps3 = + "!!ARBfp1.0\n" + "OPTION ARB_precision_hint_fastest;\n" + //# cgc version 3.1.0013, build date Apr 18 2012 + //# command line args: -profile arbfp1 -O3 -fastmath -fastprecision + //# source file: fxaa_fp.cg + //#vendor NVIDIA Corporation + //#version 3.1.0.13 + //#profile arbfp1 + //#program fxaa_fp + //#semantic fxaa_fp.fxaaConsoleRcpFrameOpt + //#semantic fxaa_fp.fxaaConsoleRcpFrameOpt2 + //#semantic fxaa_fp.nlTex0 : TEX0 + //#var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1 + //#var float4 fxaaConsolePosPos : $vin.TEXCOORD1 : TEX1 : 1 : 1 + //#var float4 fxaaConsoleRcpFrameOpt : : c[0] : 2 : 1 + //#var float4 fxaaConsoleRcpFrameOpt2 : : c[1] : 3 : 1 + //#var sampler2D nlTex0 : TEX0 : texunit 0 : 4 : 1 + //#var float4 oCol : $vout.COLOR : COL : 5 : 1 + //#const c[2] = 0.125 0 -2 2 + //#const c[3] = 0.001953125 0.5 + "PARAM c[4] = { program.env[0..1],\n" + " { 0.125, 0, -2, 2 },\n" + " { 0.001953125, 0.5 } };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "TEMP R2;\n" + "TEMP R3;\n" + "TEMP R4;\n" + "TEMP R5;\n" + "TEX R1.w, fragment.texcoord[1].zyzw, texture[0], 2D;\n" + "ADD R0.x, R1.w, c[3];\n" + "TEX R0.w, fragment.texcoord[1].xwzw, texture[0], 2D;\n" + "TEX R1.w, fragment.texcoord[1], texture[0], 2D;\n" + "ADD R0.y, -R0.x, R0.w;\n" + "ADD R0.z, R1.w, R0.y;\n" + "TEX R2.w, fragment.texcoord[1].zwzw, texture[0], 2D;\n" + "ADD R0.y, -R1.w, R0;\n" + "ADD R1.x, R2.w, R0.y;\n" + "ADD R1.y, R0.z, -R2.w;\n" + "MUL R2.xy, R1, R1;\n" + "ADD R0.y, R2.x, R2;\n" + "RSQ R0.y, R0.y;\n" + "MUL R2.xy, R0.y, R1;\n" + "MAD R3.xy, R2, c[0].zwzw, fragment.texcoord[0];\n" + "ABS R0.z, R2.y;\n" + "ABS R0.y, R2.x;\n" + "MIN R0.y, R0, R0.z;\n" + "RCP R0.y, R0.y;\n" + "MUL R1.xy, R0.y, R2;\n" + "MUL R1.xy, R1, c[2].x;\n" + "MIN R1.xy, R1, c[2].w;\n" + "TEX R4, R3, texture[0], 2D;\n" + "MAD R2.xy, -R2, c[0].zwzw, fragment.texcoord[0];\n" + "TEX R3, R2, texture[0], 2D;\n" + "ADD R3, R3, R4;\n" + "MAX R1.xy, R1, c[2].z;\n" + "MAD R2.xy, R1, c[1].zwzw, fragment.texcoord[0];\n" + "MUL R5, R3, c[3].y;\n" + "MAD R1.xy, -R1, c[1].zwzw, fragment.texcoord[0];\n" + "MIN R0.z, R0.x, R2.w;\n" + "MIN R0.y, R0.w, R1.w;\n" + "MIN R0.y, R0, R0.z;\n" + "MAX R0.z, R0.x, R2.w;\n" + "MAX R0.x, R0.w, R1.w;\n" + "MAX R0.x, R0, R0.z;\n" + "TEX R4, R2, texture[0], 2D;\n" + "TEX R3, R1, texture[0], 2D;\n" + "ADD R3, R3, R4;\n" + "MAD R3, R3, c[3].y, R5;\n" + "MUL R3, R3, c[3].y;\n" + "SLT R0.z, R0.x, R3.w;\n" + "SLT R0.x, R3.w, R0.y;\n" + "ADD_SAT R0.x, R0, R0.z;\n" + "CMP result.color, -R0.x, R5, R3;\n" + "END\n"; + //# 45 instructions, 6 R-regs + +const char *a_arbfp1_earlyexit = + "!!ARBfp1.0\n" + "OPTION ARB_precision_hint_fastest;\n" + //"# cgc version 3.1.0013, build date Apr 18 2012\n" + //"# command line args: -profile arbfp1\n" + //"# source file: fxaa_fp.cg\n" + //"#vendor NVIDIA Corporation\n" + //"#version 3.1.0.13\n" + //"#profile arbfp1\n" + //"#program fxaa_fp\n" + //"#semantic fxaa_fp.fxaaConsoleRcpFrameOpt\n" + //"#semantic fxaa_fp.fxaaConsoleRcpFrameOpt2\n" + //"#semantic fxaa_fp.nlTex0 : TEX0\n" + //"#var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1\n" + //"#var float4 fxaaConsolePosPos : $vin.TEXCOORD1 : TEX1 : 1 : 1\n" + //"#var float4 fxaaConsoleRcpFrameOpt : : c[0] : 2 : 1\n" + //"#var float4 fxaaConsoleRcpFrameOpt2 : : c[1] : 3 : 1\n" + //"#var sampler2D nlTex0 : TEX0 : texunit 0 : 4 : 1\n" + //"#var float4 oCol : $vout.COLOR : COL : 5 : 1\n" + //"#const c[2] = 0.125 0 8 0.001953125\n" + //"#const c[3] = -2 2 0.5\n" + "PARAM c[4] = { program.env[0..1],\n" + " { 0.125, 0, 8, 0.001953125 },\n" + " { -2, 2, 0.5 } };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "TEMP R2;\n" + "TEMP R3;\n" + "TEMP R4;\n" + "TEMP R5;\n" + "TEX R0.w, fragment.texcoord[1].zyzw, texture[0], 2D;\n" + "ADD R0.x, R0.w, c[2].w;\n" + "TEX R1.w, fragment.texcoord[1].xwzw, texture[0], 2D;\n" + "TEX R0.w, fragment.texcoord[1], texture[0], 2D;\n" + "ADD R0.y, R1.w, -R0.x;\n" + "ADD R0.z, R0.w, R0.y;\n" + "TEX R2.w, fragment.texcoord[1].zwzw, texture[0], 2D;\n" + "ADD R0.y, -R0.w, R0;\n" + "ADD R1.z, -R2.w, R0;\n" + "ADD R1.x, R2.w, R0.y;\n" + "MOV R1.y, c[2];\n" + "DP3 R0.y, R1, R1;\n" + "RSQ R0.y, R0.y;\n" + "MUL R2.xy, R0.y, R1.xzzw;\n" + "MAD R3.xy, R2, c[0].zwzw, fragment.texcoord[0];\n" + "ABS R0.z, R2.y;\n" + "ABS R0.y, R2.x;\n" + "MIN R0.y, R0, R0.z;\n" + "RCP R0.y, R0.y;\n" + "MUL R1.xy, R0.y, R2;\n" + "MUL R1.xy, R1, c[2].x;\n" + "MIN R1.xy, R1, c[3].y;\n" + "MIN R0.y, R0.w, R1.w;\n" + "TEX R4, R3, texture[0], 2D;\n" + "MAD R2.xy, -R2, c[0].zwzw, fragment.texcoord[0];\n" + "TEX R3, R2, texture[0], 2D;\n" + "ADD R3, R3, R4;\n" + "MAX R1.xy, R1, c[3].x;\n" + "MAD R2.xy, R1, c[1].zwzw, fragment.texcoord[0];\n" + "MAD R1.xy, -R1, c[1].zwzw, fragment.texcoord[0];\n" + "MUL R5, R3, c[3].z;\n" + "TEX R4, R2, texture[0], 2D;\n" + "TEX R3, R1, texture[0], 2D;\n" + "MIN R0.z, R0.x, R2.w;\n" + "MIN R1.x, R0.y, R0.z;\n" + "MAX R0.y, R0.x, R2.w;\n" + "MAX R0.x, R0.w, R1.w;\n" + "MAX R2.x, R0, R0.y;\n" + "ADD R3, R3, R4;\n" + "MAD R3, R3, c[3].z, R5;\n" + "MUL R3, R3, c[3].z;\n" + "SLT R1.z, R2.x, R3.w;\n" + "SLT R1.y, R3.w, R1.x;\n" + "TEX R0, fragment.texcoord[0], texture[0], 2D;\n" + "ADD_SAT R1.y, R1, R1.z;\n" + "MIN R1.z, R0.w, R1.x;\n" + "MAX R1.x, R2, R0.w;\n" + "ADD R2.y, R1.x, -R1.z;\n" + "CMP R1, -R1.y, R5, R3;\n" + "MAD R2.x, R2.y, c[2].z, -R2;\n" + "CMP result.color, R2.x, R0, R1;\n" + "END\n"; + //"# 51 instructions, 6 R-regs\n" + +const char *a_ps_2_0_test_t0 = + "ps_2_x\n" + "dcl_2d s0\n" + "dcl t0.xyz\n" + "mov r0.xy, t0.xy\n" + "texld r0, r0, s0\n" + "mov oC0, r0\n"; + +const char *a_ps_2_0_test_avg = + "ps_2_x\n" + "dcl_2d s0\n" + "def c0, 0.25000000, 0, 0, 0\n" + "dcl t1\n" + "mov r0.xy, t1.xwzw\n" + "mov r1.xy, t1.zyzw\n" + "texld r0, r0, s0\n" + "texld r1, r1, s0\n" + "add r2, r1, r0\n" + "mov r0.xy, t1.zwzw\n" + "texld r1, t1, s0\n" + "texld r0, r0, s0\n" + "add r1, r2, r1\n" + "add r0, r1, r0\n" + "mul r0, r0, c0.x\n" + "mov oC0, r0\n"; + +const char *a_ps_2_0 = + "ps_2_x\n" + /*"// cgc version 3.1.0013, build date Apr 18 2012\n" + "// command line args: -profile ps_2_x -O3 -fastmath -fastprecision\n" + "// source file: fxaa_pp.cg\n" + "//vendor NVIDIA Corporation\n" + "//version 3.1.0.13\n" + "//profile ps_2_x\n" + "//program fxaa_pp\n" + "//semantic fxaa_pp.fxaaQualityRcpFrame\n" + "//semantic fxaa_pp.fxaaQualitySubpix\n" + "//semantic fxaa_pp.fxaaQualityEdgeThreshold\n" + "//semantic fxaa_pp.fxaaQualityEdgeThresholdMin\n" + "//semantic fxaa_pp.nlTex0 : TEX0\n" + "//var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1\n" + "//var float2 fxaaQualityRcpFrame : : c[0] : 2 : 1\n" + "//var float fxaaQualitySubpix : : c[1] : 3 : 1\n" + "//var float fxaaQualityEdgeThreshold : : c[2] : 4 : 1\n" + "//var float fxaaQualityEdgeThresholdMin : : c[3] : 5 : 1\n" + "//var sampler2D nlTex0 : TEX0 : texunit 0 : 6 : 1\n" + "//var float4 oCol : $vout.COLOR : COL : 7 : 1\n" + "//const c[4] = 0 -1 1 -2\n" + "//const c[5] = 2 0.5 0.25 1.5\n" + "//const c[6] = 4 12 0.083333336\n" + "//const c[7] = -2 3\n"*/ + "dcl_2d s0\n" + "def c4, 0.00000000, -1.00000000, 1.00000000, -2.00000000\n" + "def c5, 2.00000000, 0.50000000, 0.25000000, 1.50000000\n" + "def c6, 4.00000000, 12.00000000, 0.08333334, 0\n" + "def c7, -2.00000000, 3.00000000, 0, 0\n" + "dcl t0.xy\n" + "mov r0.zw, c0.xyxy\n" + "mad r3.xy, c4.zxzw, r0.zwzw, t0\n" + "texld r7, r3, s0\n" + "texld r1, t0, s0\n" + "mov r0.xy, c0\n" + "mad r0.xy, c4.yxzw, r0, t0\n" + "texld r8, r0, s0\n" + "mov r0.xy, c0\n" + "mad r0.xy, c4, r0, t0\n" + "texld r9, r0, s0\n" + "add r0.xy, t0, -c0\n" + "texld r5, r0, s0\n" + "mov r3.xy, c0\n" + "mad r3.xy, c4.zyzw, r3, t0\n" + "texld r3, r3, s0\n" + "add r7.x, r8.y, r7.y\n" + "mad r0.z, r1.y, c4.w, r7.x\n" + "add r0.x, r5.y, r3.y\n" + "mad r0.w, r9.y, c4, r0.x\n" + "mov r0.xy, c0\n" + "mad r0.xy, c4.xzzw, r0, t0\n" + "texld r6, r0, s0\n" + "add r5.x, r9.y, r6.y\n" + "abs r0.z, r0\n" + "abs r0.w, r0\n" + "mad r3.x, r0.z, c5, r0.w\n" + "mov r0.zw, c0.xyxy\n" + "mad r4.xy, c4.yzzw, r0.zwzw, t0\n" + "texld r4, r4, s0\n" + "add r0.xy, t0, c0\n" + "texld r0, r0, s0\n" + "add r4.x, r5.y, r4.y\n" + "add r5.y, r3, r0\n" + "add r0.x, r4.y, r0.y\n" + "mad r0.x, r6.y, c4.w, r0\n" + "abs r0.x, r0\n" + "add r0.w, r0.x, r3.x\n" + "mad r0.x, r8.y, c4.w, r4\n" + "mad r0.z, r7.y, c4.w, r5.y\n" + "mad r0.y, r1, c4.w, r5.x\n" + "abs r0.z, r0\n" + "abs r0.y, r0\n" + "mad r0.y, r0, c5.x, r0.z\n" + "abs r0.x, r0\n" + "add r0.x, r0, r0.y\n" + "add r0.x, r0, -r0.w\n" + "cmp r3.y, r0.x, c4.z, c4.x\n" + "max r0.y, r6, r1\n" + "max r0.z, r7.y, r0.y\n" + "max r0.y, r9, r8\n" + "max r0.y, r0, r0.z\n" + "min r0.z, r6.y, r1.y\n" + "min r0.w, r7.y, r0.z\n" + "min r0.z, r9.y, r8.y\n" + "min r0.z, r0, r0.w\n" + "mul r3.x, r0.y, c2\n" + "abs_pp r0.x, r3.y\n" + "add r4.y, r0, -r0.z\n" + "max r0.w, r3.x, c3.x\n" + "add r4.z, r4.y, -r0.w\n" + "cmp_pp r4.w, r4.z, c4.z, c4.x\n" + "mul_pp r5.w, r4, r3.y\n" + "cmp_pp r0.y, -r0.x, c4.z, c4.x\n" + "mul_pp r5.z, r4.w, r0.y\n" + "cmp_pp r3.x, -r0, c4, c4.z\n" + "cmp r6.w, -r5.z, r6.y, r7.y\n" + "cmp r7.w, -r5.z, r9.y, r8.y\n" + "add r0.z, -r1.y, r6.w\n" + "add r0.y, -r1, r7.w\n" + "abs r9.z, r0\n" + "abs r7.y, r0\n" + "add r0.y, r7, -r9.z\n" + "cmp r0.y, r0, c4.z, c4.x\n" + "max r7.y, r7, r9.z\n" + "mul_pp r0.z, r4.w, r0.y\n" + "cmp r0.w, -r5, c0.x, c0.y\n" + "cmp r6.x, -r0.z, r0.w, -r0.w\n" + "mov r0.z, c0.y\n" + "cmp r6.y, -r5.z, c4.x, r0.z\n" + "mad r0.w, r6.x, c5.y, t0.y\n" + "cmp r0.z, -r5.w, t0.y, r0.w\n" + "add r8.z, r0, r6.y\n" + "add r7.z, r0, -r6.y\n" + "mov r9.y, r7.z\n" + "mov r8.y, r8.z\n" + "mad r0.w, r6.x, c5.y, t0.x\n" + "mov r0.x, c0\n" + "mul_pp r3.x, r4.w, r3\n" + "cmp r6.z, -r3.x, c4.x, r0.x\n" + "cmp r0.x, -r5.z, t0, r0.w\n" + "add r9.x, r0, -r6.z\n" + "texld r3, r9, s0\n" + "add r8.x, r0, r6.z\n" + "abs_pp r3.x, r0.y\n" + "texld r0, r8, s0\n" + "cmp_pp r0.x, -r3, c4.z, c4\n" + "add r0.w, r1.y, r6\n" + "add r0.z, r1.y, r7.w\n" + "mul_pp r0.x, r4.w, r0\n" + "cmp r6.w, -r0.x, r0.z, r0\n" + "mad r7.w, -r6, c5.y, r0.y\n" + "mad r8.w, -r6, c5.y, r3.y\n" + "abs r0.y, r7.w\n" + "abs r0.x, r8.w\n" + "mad r0.x, -r7.y, c5.z, r0\n" + "mad r0.y, -r7, c5.z, r0\n" + "cmp r0.x, r0, c4.z, c4\n" + "abs_pp r0.x, r0\n" + "cmp_pp r9.z, -r0.x, c4, c4.x\n" + "cmp r0.y, r0, c4.z, c4.x\n" + "abs_pp r0.y, r0\n" + "cmp_pp r9.w, -r0.y, c4.z, c4.x\n" + "mul_pp r0.x, r4.w, r9.z\n" + "mad r0.y, -r6, c5.w, r7.z\n" + "cmp r7.z, -r0.x, r7, r0.y\n" + "mad r0.z, -r6, c5.w, r9.x\n" + "cmp r9.x, -r0, r9, r0.z\n" + "mov r9.y, r7.z\n" + "texld r3, r9, s0\n" + "add_pp_sat r3.z, r9, r9.w\n" + "mul_pp r0.x, r4.w, r9.w\n" + "mad r0.y, r6, c5.w, r8.z\n" + "cmp r3.x, -r0, r8.z, r0.y\n" + "mad r0.z, r6, c5.w, r8.x\n" + "mul_pp r8.z, r4.w, r3\n" + "cmp r8.x, -r0, r8, r0.z\n" + "mov r8.y, r3.x\n" + "texld r0, r8, s0\n" + "mul_pp r0.w, r8.z, r9\n" + "cmp r3.z, -r0.w, r7.w, r0.y\n" + "mul_pp r0.x, r8.z, r9.z\n" + "cmp r0.y, -r0.x, r8.w, r3\n" + "mad r0.z, -r6.w, c5.y, r0.y\n" + "cmp r8.w, -r0.x, r0.y, r0.z\n" + "mad r3.y, -r6.w, c5, r3.z\n" + "cmp r9.w, -r0, r3.z, r3.y\n" + "abs r0.y, r9.w\n" + "abs r0.x, r8.w\n" + "mad r0.y, -r7, c5.z, r0\n" + "mad r0.x, -r7.y, c5.z, r0\n" + "cmp r0.y, r0, c4.z, c4.x\n" + "abs_pp r0.y, r0\n" + "cmp_pp r10.x, -r0.y, c4.z, c4\n" + "cmp r0.x, r0, c4.z, c4\n" + "abs_pp r0.x, r0\n" + "cmp_pp r9.z, -r0.x, c4, c4.x\n" + "mul_pp r0.x, r8.z, r10\n" + "mad r0.y, r6, c5.x, r3.x\n" + "cmp r7.w, -r0.x, r3.x, r0.y\n" + "mad r0.z, r6, c5.x, r8.x\n" + "cmp r8.x, -r0, r8, r0.z\n" + "mov r8.y, r7.w\n" + "texld r0, r8, s0\n" + "mul_pp r0.w, r8.z, r9.z\n" + "mad r3.x, -r6.z, c5, r9\n" + "mad r0.x, -r6.y, c5, r7.z\n" + "cmp r0.x, -r0.w, r7.z, r0\n" + "add_pp_sat r0.z, r9, r10.x\n" + "mul_pp r7.z, r8, r0\n" + "cmp r9.x, -r0.w, r9, r3\n" + "mov r9.y, r0.x\n" + "texld r3, r9, s0\n" + "mul_pp r0.z, r7, r9\n" + "cmp r0.w, -r0.z, r8, r3.y\n" + "mul_pp r3.x, r7.z, r10\n" + "cmp r3.y, -r3.x, r9.w, r0\n" + "mad r0.y, -r6.w, c5, r0.w\n" + "cmp r8.z, -r0, r0.w, r0.y\n" + "mad r3.z, -r6.w, c5.y, r3.y\n" + "cmp r9.z, -r3.x, r3.y, r3\n" + "abs r0.y, r8.z\n" + "abs r0.z, r9\n" + "mad r0.y, -r7, c5.z, r0\n" + "mad r0.z, -r7.y, c5, r0\n" + "cmp r0.y, r0, c4.z, c4.x\n" + "abs_pp r0.y, r0\n" + "cmp_pp r8.w, -r0.y, c4.z, c4.x\n" + "cmp r0.z, r0, c4, c4.x\n" + "abs_pp r0.z, r0\n" + "cmp_pp r9.w, -r0.z, c4.z, c4.x\n" + "mul_pp r0.y, r7.z, r8.w\n" + "mad r0.z, -r6.y, c6.x, r0.x\n" + "cmp r10.x, -r0.y, r0, r0.z\n" + "mad r0.w, -r6.z, c6.x, r9.x\n" + "cmp r9.x, -r0.y, r9, r0.w\n" + "mov r9.y, r10.x\n" + "texld r3, r9, s0\n" + "mul_pp r0.x, r7.z, r9.w\n" + "mad r0.z, r6, c6.x, r8.x\n" + "mad r0.y, r6, c6.x, r7.w\n" + "cmp r3.x, -r0, r7.w, r0.y\n" + "cmp r8.x, -r0, r8, r0.z\n" + "mov r8.y, r3.x\n" + "texld r0, r8, s0\n" + "add_pp_sat r3.z, r8.w, r9.w\n" + "mul_pp r0.x, r7.z, r3.z\n" + "mul_pp r3.z, r0.x, r9.w\n" + "cmp r0.y, -r3.z, r9.z, r0\n" + "mul_pp r0.z, r0.x, r8.w\n" + "cmp r0.w, -r0.z, r8.z, r3.y\n" + "mad r3.w, -r6, c5.y, r0.y\n" + "cmp r0.y, -r3.z, r0, r3.w\n" + "mad r3.y, -r6.w, c5, r0.w\n" + "cmp r0.z, -r0, r0.w, r3.y\n" + "abs r3.y, r0\n" + "abs r0.w, r0.z\n" + "mad r3.y, -r7, c5.z, r3\n" + "mad r0.w, -r7.y, c5.z, r0\n" + "cmp r3.y, r3, c4.z, c4.x\n" + "abs_pp r3.y, r3\n" + "cmp r0.w, r0, c4.z, c4.x\n" + "cmp_pp r3.z, -r3.y, c4, c4.x\n" + "abs_pp r0.w, r0\n" + "cmp_pp r3.y, -r0.w, c4.z, c4.x\n" + "mul_pp r0.w, r0.x, r3.z\n" + "mul_pp r0.x, r0, r3.y\n" + "mad r3.w, r6.y, c6.y, r3.x\n" + "cmp r3.x, -r0.w, r3, r3.w\n" + "mad r3.z, r6, c6.y, r8.x\n" + "cmp r0.w, -r0, r8.x, r3.z\n" + "mad r3.y, -r6, c6, r10.x\n" + "cmp r3.y, -r0.x, r10.x, r3\n" + "add r3.x, -t0.y, r3\n" + "add r0.w, -t0.x, r0\n" + "cmp r0.w, -r5.z, r0, r3.x\n" + "mad r3.x, -r6.z, c6.y, r9\n" + "cmp r0.x, -r0, r9, r3\n" + "add r3.x, t0.y, -r3.y\n" + "add r0.x, t0, -r0\n" + "cmp r0.x, -r5.z, r0, r3\n" + "add r3.x, r0, -r0.w\n" + "add r3.y, r0.x, r0.w\n" + "cmp r3.x, r3, c4, c4.z\n" + "abs_pp r3.x, r3\n" + "min r0.x, r0, r0.w\n" + "cmp_pp r3.x, -r3, c4.z, c4\n" + "mul_pp r0.w, r4, r3.x\n" + "rcp r3.y, r3.y\n" + "mad r0.x, r0, -r3.y, c5.y\n" + "cmp r3.y, r0, c4.x, c4.z\n" + "mad r3.x, -r6.w, c5.y, r1.y\n" + "cmp r3.x, r3, c4, c4.z\n" + "cmp r0.y, r0.z, c4.x, c4.z\n" + "add_pp r0.z, -r3.x, r3.y\n" + "add_pp r0.y, r0, -r3.x\n" + "abs_pp r0.y, r0\n" + "abs_pp r0.z, r0\n" + "cmp_pp r0.z, -r0, c4.x, c4\n" + "cmp_pp r0.y, -r0, c4.x, c4.z\n" + "cmp_pp r0.y, -r0.w, r0, r0.z\n" + "abs_pp r0.y, r0\n" + "cmp_pp r0.y, -r0, c4.z, c4.x\n" + "mul_pp r0.y, r4.w, r0\n" + "rcp r0.w, r4.y\n" + "cmp r0.x, -r0.y, r0, c4\n" + "add r3.y, r4.x, r5\n" + "add r3.x, r5, r7\n" + "mad r3.x, r3, c5, r3.y\n" + "mad r0.z, r3.x, c6, -r1.y\n" + "abs r0.z, r0\n" + "mul_sat r0.z, r0, r0.w\n" + "mul r0.w, r0.z, r0.z\n" + "mad r0.z, r0, c7.x, c7.y\n" + "mul r0.z, r0, r0.w\n" + "mul r0.z, r0, r0\n" + "mul r0.z, r0, c1.x\n" + "max r0.x, r0, r0.z\n" + "mad r0.y, r0.x, r6.x, t0\n" + "mad r0.z, r0.x, r6.x, t0.x\n" + "cmp r0.x, -r5.z, t0, r0.z\n" + "cmp r0.y, -r5.w, t0, r0\n" + "texld r0, r0, s0\n" + "mov r0.w, r1.y\n" + "cmp r1, r4.z, r2, r1\n" + "cmp r0, -r4.w, r1, r0\n" + "mov oC0, r0\n"; + +const char *a_ps_2_0_ps3 = + "ps_2_0\n" + // cgc version 3.1.0013, build date Apr 18 2012 + // command line args: -profile ps_2_0 -O3 -fastmath -fastprecision + // source file: fxaa_pp.cg + //vendor NVIDIA Corporation + //version 3.1.0.13 + //profile ps_2_0 + //program fxaa_pp + //semantic fxaa_pp.fxaaConsoleRcpFrameOpt + //semantic fxaa_pp.fxaaConsoleRcpFrameOpt2 + //semantic fxaa_pp.nlTex0 : TEX0 + //var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1 + //var float4 fxaaConsolePosPos : $vin.TEXCOORD1 : TEX1 : 1 : 1 + //var float4 fxaaConsoleRcpFrameOpt : : c[0] : 2 : 1 + //var float4 fxaaConsoleRcpFrameOpt2 : : c[1] : 3 : 1 + //var sampler2D nlTex0 : TEX0 : texunit 0 : 4 : 1 + //var float4 oCol : $vout.COLOR : COL : 5 : 1 + //const c[2] = 0.001953125 0.125 2 -2 + //const c[3] = 0.5 0 1 + "dcl_2d s0\n" + "def c2, 0.00195313, 0.12500000, 2.00000000, -2.00000000\n" + "def c3, 0.50000000, 0.00000000, 1.00000000, 0\n" + "dcl t1\n" + "dcl t0.xy\n" + "texld r5, t1, s0\n" + "mov r1.y, t1.w\n" + "mov r1.x, t1.z\n" + "mov r2.xy, r1\n" + "mov r0.y, t1.w\n" + "mov r0.x, t1\n" + "mov r1.y, t1\n" + "mov r1.x, t1.z\n" + "texld r1, r1, s0\n" + "texld r0, r0, s0\n" + "texld r6, r2, s0\n" + "add r0.x, r1.w, c2\n" + "add r2.x, -r0, r0.w\n" + "add r1.x, r5.w, r2\n" + "add r2.z, r1.x, -r6.w\n" + "add r2.x, -r5.w, r2\n" + "add r2.x, r6.w, r2\n" + "mov r3.x, r2\n" + "mov r3.y, r2.z\n" + "mov r2.y, r2.z\n" + "mov r1.y, r2.z\n" + "mov r1.x, r2\n" + "mul r1.xy, r3, r1\n" + "add r1.x, r1, r1.y\n" + "rsq r1.x, r1.x\n" + "mul r4.xy, r1.x, r2\n" + "abs r2.x, r4.y\n" + "abs r1.x, r4\n" + "min r1.x, r1, r2\n" + "rcp r1.x, r1.x\n" + "mul r1.xy, r1.x, r4\n" + "mul r1.xy, r1, c2.y\n" + "min r1.xy, r1, c2.z\n" + "max r2.xy, r1, c2.w\n" + "mov r1.y, c1.w\n" + "mov r1.x, c1.z\n" + "mad r3.xy, r2, r1, t0\n" + "mov r1.y, c1.w\n" + "mov r1.x, c1.z\n" + "mad r5.xy, -r2, r1, t0\n" + "mov r1.y, c0.w\n" + "mov r1.x, c0.z\n" + "mad r2.xy, -r4, r1, t0\n" + "mov r1.y, c0.w\n" + "mov r1.x, c0.z\n" + "mad r1.xy, r4, r1, t0\n" + "texld r4, r5, s0\n" + "texld r3, r3, s0\n" + "texld r1, r1, s0\n" + "texld r2, r2, s0\n" + "add r1, r2, r1\n" + "mul r2, r1, c3.x\n" + "add r1, r4, r3\n" + "max r3.x, r0, r6.w\n" + "mad r1, r1, c3.x, r2\n" + "mul r4, r1, c3.x\n" + "max r1.x, r0.w, r5.w\n" + "max r1.x, r1, r3\n" + "add r1.x, -r4.w, r1\n" + "min r3.x, r0.w, r5.w\n" + "min r0.x, r0, r6.w\n" + "min r0.x, r3, r0\n" + "add r0.x, r4.w, -r0\n" + "cmp r1.x, r1, c3.y, c3.z\n" + "cmp r0.x, r0, c3.y, c3.z\n" + "add_pp_sat r0.x, r0, r1\n" + "cmp r0, -r0.x, r4, r2\n" + "mov oC0, r0\n"; + +const char *a_ps_2_0_earlyexit = + "ps_2_x\n" + // cgc version 3.1.0013, build date Apr 18 2012 + // command line args: -profile ps_2_x + // source file: fxaa_fp.cg + //vendor NVIDIA Corporation + //version 3.1.0.13 + //profile ps_2_x + //program fxaa_fp + //semantic fxaa_fp.fxaaConsoleRcpFrameOpt + //semantic fxaa_fp.fxaaConsoleRcpFrameOpt2 + //semantic fxaa_fp.nlTex0 : TEX0 + //var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1 + //var float4 fxaaConsolePosPos : $vin.TEXCOORD1 : TEX1 : 1 : 1 + //var float4 fxaaConsoleRcpFrameOpt : : c[0] : 2 : 1 + //var float4 fxaaConsoleRcpFrameOpt2 : : c[1] : 3 : 1 + //var sampler2D nlTex0 : TEX0 : texunit 0 : 4 : 1 + //var float4 oCol : $vout.COLOR : COL : 5 : 1 + //const c[2] = 0.001953125 0 0.125 2 + //const c[3] = -2 0.5 0 1 + //const c[4] = 8 + "dcl_2d s0\n" + "def c2, 0.00195313, 0.00000000, 0.12500000, 2.00000000\n" + "def c3, -2.00000000, 0.50000000, 0.00000000, 1.00000000\n" + "def c4, 8.00000000, 0, 0, 0\n" + "dcl t1\n" + "dcl t0.xy\n" + "mov r0.xy, t1.zyzw\n" + "texld r0, r0, s0\n" + "mov r0.xy, t1.xwzw\n" + "texld r5, t1, s0\n" + "texld r4, r0, s0\n" + "add r4.x, r0.w, c2\n" + "mov r0.xy, t1.zwzw\n" + "texld r3, r0, s0\n" + "add r0.w, r4, -r4.x\n" + "add r0.x, r5.w, r0.w\n" + "add r0.z, -r3.w, r0.x\n" + "add r0.x, -r5.w, r0.w\n" + "add r0.x, r3.w, r0\n" + "mov r0.y, c2\n" + "dp3 r0.y, r0, r0\n" + "rsq r0.y, r0.y\n" + "mul r0.zw, r0.y, r0.xyxz\n" + "mad r1.xy, -r0.zwzw, c0.zwzw, t0\n" + "texld r1, r1, s0\n" + "abs r0.y, r0.w\n" + "abs r0.x, r0.z\n" + "min r0.x, r0, r0.y\n" + "rcp r0.x, r0.x\n" + "mul r0.xy, r0.x, r0.zwzw\n" + "mul r0.xy, r0, c2.z\n" + "min r2.xy, r0, c2.w\n" + "mad r0.xy, r0.zwzw, c0.zwzw, t0\n" + "texld r0, r0, s0\n" + "add r0, r1, r0\n" + "max r1.xy, r2, c3.x\n" + "mul r2, r0, c3.y\n" + "mad r0.xy, r1, c1.zwzw, t0\n" + "mad r1.xy, -r1, c1.zwzw, t0\n" + "texld r0, r0, s0\n" + "texld r1, r1, s0\n" + "add r0, r1, r0\n" + "mad r0, r0, c3.y, r2\n" + "mul r1, r0, c3.y\n" + "min r0.y, r4.x, r3.w\n" + "min r0.x, r5.w, r4.w\n" + "min r3.y, r0.x, r0\n" + "add r0.x, -r3.y, r1.w\n" + "max r0.z, r4.x, r3.w\n" + "max r0.y, r5.w, r4.w\n" + "max r3.x, r0.y, r0.z\n" + "cmp r3.z, r0.x, c3, c3.w\n" + "add r3.w, r3.x, -r1\n" + "cmp r3.w, r3, c3.z, c3\n" + "add_pp_sat r3.z, r3, r3.w\n" + "texld r0, t0, s0\n" + "min r3.w, r0, r3.y\n" + "max r3.y, r3.x, r0.w\n" + "cmp r1, -r3.z, r1, r2\n" + "add r3.y, r3, -r3.w\n" + "mad r2.x, r3.y, c4, -r3\n" + "cmp r0, r2.x, r1, r0\n" + "mov oC0, r0\n"; diff --git a/code/nel/src/3d/particle_system.cpp b/code/nel/src/3d/particle_system.cpp index 3b25c3e1e..f6060640b 100644 --- a/code/nel/src/3d/particle_system.cpp +++ b/code/nel/src/3d/particle_system.cpp @@ -422,6 +422,11 @@ void CParticleSystem::step(TPass pass, TAnimationTime ellapsedTime, CParticleSys NL_PS_FUNC_MAIN(CParticleSystem_step) CHECK_INTEGRITY OwnerModel = &model; + if (!_CoordSystemInfo.Matrix) + { + nlwarning("3D: BUG: CParticleSystem::step -> !_CoordSystemInfo.Matrix"); + return; + } nlassert(_CoordSystemInfo.Matrix); // matrix not set for position of system if (_UserCoordSystemInfo) { diff --git a/code/nel/src/3d/render_target_manager.cpp b/code/nel/src/3d/render_target_manager.cpp new file mode 100644 index 000000000..0c4daa507 --- /dev/null +++ b/code/nel/src/3d/render_target_manager.cpp @@ -0,0 +1,162 @@ +/** + * \file render_target_manager.cpp + * \brief CRenderTargetManager + * \date 2014-07-30 21:30GMT + * \author Jan Boon (Kaetemi) + * CRenderTargetManager + */ + +/* + * Copyright (C) 2014 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#include +#include + +// STL includes +#include + +// NeL includes +// #include +#include +#include +#include +#include +#include +#include +#include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +struct CRenderTargetDescInt +{ +public: + // Options + uint Width; + uint Height; + bool Mode2D; + UTexture::TUploadFormat Format; + + // Data + NL3D::CTextureUser *TextureUser; + NLMISC::CSmartPtr TextureInterface; + bool InUse; + bool Used; +}; + +CRenderTargetManager::CRenderTargetManager() : m_Driver(NULL) +{ + +} + +CRenderTargetManager::~CRenderTargetManager() +{ + // Call twice to reset counters and cleanup + cleanup(); + cleanup(); +} + +NL3D::CTextureUser *CRenderTargetManager::getRenderTarget(uint width, uint height, bool mode2D, UTexture::TUploadFormat format) +{ + // Find or create a render target, short loop so no real optimization + for (std::vector::iterator it(m_RenderTargets.begin()), end(m_RenderTargets.end()); it != end; ++it) + { + CRenderTargetDescInt *desc = *it; + if (!desc->InUse && desc->Width == width && desc->Height == height && desc->Mode2D == mode2D && desc->Format == format) + { + desc->InUse = true; + desc->Used = true; + return desc->TextureUser; + } + } + + nldebug("3D: Create new render target (%u x %u)", width, height); + NL3D::IDriver *drvInternal = (static_cast(m_Driver))->getDriver(); + CRenderTargetDescInt *desc = new CRenderTargetDescInt(); + CTextureBloom *tex = new CTextureBloom(); // LOL + tex->mode2D(mode2D); + desc->TextureInterface = tex; + desc->TextureInterface->setRenderTarget(true); + desc->TextureInterface->setReleasable(false); + desc->TextureInterface->setUploadFormat((ITexture::TUploadFormat)(uint32)format); + desc->TextureInterface->resize(width, height); + desc->TextureInterface->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); + desc->TextureInterface->setWrapS(ITexture::Clamp); + desc->TextureInterface->setWrapT(ITexture::Clamp); + drvInternal->setupTexture(*desc->TextureInterface); + desc->TextureUser = new CTextureUser(desc->TextureInterface); + nlassert(!drvInternal->isTextureRectangle(desc->TextureInterface)); // Not allowed, we only support NPOT for render targets now. + desc->Width = width; + desc->Height = height; + desc->Mode2D = mode2D; + desc->Format = format; + desc->Used = true; + desc->InUse = true; + m_RenderTargets.push_back(desc); + return desc->TextureUser; +} + +void CRenderTargetManager::recycleRenderTarget(NL3D::CTextureUser *renderTarget) +{ + for (std::vector::iterator it(m_RenderTargets.begin()), end(m_RenderTargets.end()); it != end; ++it) + { + CRenderTargetDescInt *desc = *it; + if (desc->TextureUser == renderTarget) + { + desc->InUse = false; + return; + } + } + nlerror("3D: Render target not found"); +} + +void CRenderTargetManager::cleanup() +{ + for (sint i = 0; i < (sint)m_RenderTargets.size(); ++i) + { + CRenderTargetDescInt *desc = m_RenderTargets[i]; + nlassert(!desc->InUse); // Assert for debugging, to not allow textures being carried over between frames. Optional assert + if (!desc->InUse) + { + if (!desc->Used) + { + // No longer in use + nldebug("3D: Release render target (%u x %u)", desc->Width, desc->Height); + delete desc->TextureUser; + desc->TextureUser = NULL; + desc->TextureInterface = NULL; // CSmartPtr + m_RenderTargets.erase(m_RenderTargets.begin() + i); + --i; + } + else + { + // Flag for next round + desc->Used = false; + } + } + } +} + +} /* namespace NL3D */ + +/* end of file */ diff --git a/code/nel/src/3d/render_trav.cpp b/code/nel/src/3d/render_trav.cpp index e7dfe89b1..026e80e9c 100644 --- a/code/nel/src/3d/render_trav.cpp +++ b/code/nel/src/3d/render_trav.cpp @@ -92,7 +92,7 @@ CRenderTrav::CRenderTrav() // *************************************************************************** -void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender) +void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender, bool generateShadows) { #ifdef NL_DEBUG_RENDER_TRAV nlwarning("Render trave begin"); @@ -279,7 +279,8 @@ void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender) */ // Generate ShadowMaps - _ShadowMapManager.renderGenerate(Scene); + if (generateShadows) + _ShadowMapManager.renderGenerate(Scene); // Render the Landscape renderLandscapes(); diff --git a/code/nel/src/3d/scene.cpp b/code/nel/src/3d/scene.cpp index fb2d476ac..67465eb8c 100644 --- a/code/nel/src/3d/scene.cpp +++ b/code/nel/src/3d/scene.cpp @@ -353,28 +353,31 @@ void CScene::beginPartRender() // *************************************************************************** -void CScene::endPartRender() +void CScene::endPartRender(bool keepTrav) { nlassert(_IsRendering); - - // Delete model deleted during the rendering _IsRendering = false; - uint i; - for (i=0; i<_ToDelete.size(); i++) - deleteModel (_ToDelete[i]); - _ToDelete.clear (); - // Special for SkeletonSpawnScript animation. create models spawned now - flushSSSModelRequests(); + if (!keepTrav) + { + // Delete model deleted during the rendering + uint i; + for (i=0; i<_ToDelete.size(); i++) + deleteModel (_ToDelete[i]); + _ToDelete.clear (); - // Particle system handling (remove the resources of those which are too far, as their clusters may not have been parsed). - // Note that only a few of them are tested at each call - _ParticleSystemManager.refreshModels(ClipTrav.WorldFrustumPyramid, ClipTrav.CamPos); + // Special for SkeletonSpawnScript animation. create models spawned now + flushSSSModelRequests(); - // Waiting Instance handling - double deltaT = _DeltaSystemTimeBetweenRender; - clamp (deltaT, 0.01, 0.1); - updateWaitingInstances(deltaT); + // Particle system handling (remove the resources of those which are too far, as their clusters may not have been parsed). + // Note that only a few of them are tested at each call + _ParticleSystemManager.refreshModels(ClipTrav.WorldFrustumPyramid, ClipTrav.CamPos); + + // Waiting Instance handling + double deltaT = _DeltaSystemTimeBetweenRender; + clamp (deltaT, 0.01, 0.1); + updateWaitingInstances(deltaT); + } // Reset profiling _NextRenderProfile= false; @@ -555,7 +558,7 @@ void CScene::endPartRender() // *************************************************************************** -void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass) +void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass, bool doTrav, bool keepTrav) { nlassert(_IsRendering); @@ -569,25 +572,31 @@ void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass) // if first part to be rendered, do the start stuff if (_RenderedPart == UScene::RenderNothing) { - // update water envmap - //updateWaterEnvmap(); RenderTrav.clearWaterModelList(); - _FirstFlare = NULL; - double fNewGlobalSystemTime = NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()); - if(_GlobalSystemTime==0) - _DeltaSystemTimeBetweenRender= 0.020; - else - _DeltaSystemTimeBetweenRender= fNewGlobalSystemTime - _GlobalSystemTime; - _GlobalSystemTime = fNewGlobalSystemTime; + if (doTrav) + { + // update water envmap + //updateWaterEnvmap(); + _FirstFlare = NULL; + + double fNewGlobalSystemTime = NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()); + if(_GlobalSystemTime==0) + _DeltaSystemTimeBetweenRender= 0.020; + else + _DeltaSystemTimeBetweenRender= fNewGlobalSystemTime - _GlobalSystemTime; + _GlobalSystemTime = fNewGlobalSystemTime; + } // ++ _NumRender; // nlassert(CurrentCamera); + // update models. updateModels(); + // Use the camera to setup Clip / Render pass. float left, right, bottom, top, znear, zfar; CurrentCamera->getFrustum(left, right, bottom, top, znear, zfar); @@ -609,49 +618,67 @@ void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass) // **** For all render traversals, traverse them (except the Hrc one), in ascending order. if( doHrcPass ) HrcTrav.traverse(); + else + HrcTrav._MovingObjects.clear(); // Set Cam World Matrix for all trav that need it ClipTrav.setCamMatrix(CurrentCamera->getWorldMatrix()); RenderTrav.setCamMatrix (CurrentCamera->getWorldMatrix()); LoadBalancingTrav.setCamMatrix (CurrentCamera->getWorldMatrix()); - // clip ClipTrav.traverse(); + // animDetail AnimDetailTrav.traverse(); + // loadBalance LoadBalancingTrav.traverse(); - // - if (_RequestParticlesAnimate) + + if (doTrav) { - _ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems - _RequestParticlesAnimate = false; + // + if (_RequestParticlesAnimate) + { + _ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems + _RequestParticlesAnimate = false; + } } + // Light LightTrav.traverse(); } // render - RenderTrav.traverse(rp, _RenderedPart == UScene::RenderNothing); - // Always must clear shadow caster (if render did not work because of IDriver::isLost()) - RenderTrav.getShadowMapManager().clearAllShadowCasters(); + RenderTrav.traverse(rp, (_RenderedPart == UScene::RenderNothing), doTrav); + if (!keepTrav) + { + // Always must clear shadow caster (if render did not work because of IDriver::isLost()) + RenderTrav.getShadowMapManager().clearAllShadowCasters(); + } // render flare if (rp & UScene::RenderFlare) { - if (_FirstFlare) + if (doTrav) { - IDriver *drv = getDriver(); - CFlareModel::updateOcclusionQueryBegin(drv); - CFlareModel *currFlare = _FirstFlare; - do + if (_FirstFlare) { - currFlare->updateOcclusionQuery(drv); - currFlare = currFlare->Next; + IDriver *drv = getDriver(); + CFlareModel::updateOcclusionQueryBegin(drv); + CFlareModel *currFlare = _FirstFlare; + do + { + currFlare->updateOcclusionQuery(drv); + currFlare = currFlare->Next; + } + while(currFlare); + CFlareModel::updateOcclusionQueryEnd(drv); } - while(currFlare); - CFlareModel::updateOcclusionQueryEnd(drv); + } + else + { + _FirstFlare = NULL; } } _RenderedPart = (UScene::TRenderPart) (_RenderedPart | rp); diff --git a/code/nel/src/3d/scene_user.cpp b/code/nel/src/3d/scene_user.cpp index 908e6a090..0df2439de 100644 --- a/code/nel/src/3d/scene_user.cpp +++ b/code/nel/src/3d/scene_user.cpp @@ -517,7 +517,7 @@ void CSceneUser::beginPartRender() } // *************************************************************************** -void CSceneUser::renderPart(TRenderPart rp) +void CSceneUser::renderPart(TRenderPart rp, bool doHrcPass, bool doTrav, bool keepTrav) { // render the scene. @@ -526,18 +526,18 @@ void CSceneUser::renderPart(TRenderPart rp) if(_Scene.getCam() == NULL) nlerror("render(): try to render with no camera linked (may have been deleted)"); - _Scene.renderPart(rp, true); + _Scene.renderPart(rp, doHrcPass, doTrav, keepTrav); } } // *************************************************************************** -void CSceneUser::endPartRender(bool updateWaitingInstancesFlag, bool restoreMatrixContextAfterRender) +void CSceneUser::endPartRender(bool updateWaitingInstancesFlag, bool restoreMatrixContextAfterRender, bool keepTrav) { // render the scene. { NL3D_HAUTO_RENDER_SCENE_END - _Scene.endPartRender(); + _Scene.endPartRender(keepTrav); } if (updateWaitingInstancesFlag) updateWaitingInstances(); diff --git a/code/nel/src/3d/shaders/compile.bat b/code/nel/src/3d/shaders/compile.bat new file mode 100644 index 000000000..06306a0da --- /dev/null +++ b/code/nel/src/3d/shaders/compile.bat @@ -0,0 +1,3 @@ +cgc -entry fxaa_pp fxaa_pp.cg -profile arbfp1 -O3 -fastmath -fastprecision -o fxaa_pp_arbfp1.txt +cgc -entry fxaa_pp fxaa_pp.cg -profile ps_2_x -O3 -fastmath -fastprecision -o fxaa_pp_ps_2_0.txt +cgc -entry fxaa_vp fxaa_vp.cg -profile arbvp1 -fastmath -fastprecision -o fxaa_vp_arbvp1.txt \ No newline at end of file diff --git a/code/nel/src/3d/shaders/fxaa3_11.h b/code/nel/src/3d/shaders/fxaa3_11.h new file mode 100644 index 000000000..7cdc32c70 --- /dev/null +++ b/code/nel/src/3d/shaders/fxaa3_11.h @@ -0,0 +1,2046 @@ +/*============================================================================ + + +NVIDIA FXAA 3.11 by TIMOTHY LOTTES + + +------------------------------------------------------------------------------ +COPYRIGHT (C) 2010, 2011 NVIDIA CORPORATION. ALL RIGHTS RESERVED. +------------------------------------------------------------------------------ +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED +*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA +OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, +OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE +THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +------------------------------------------------------------------------------ +INTEGRATION CHECKLIST +------------------------------------------------------------------------------ +(1.) +In the shader source, setup defines for the desired configuration. +When providing multiple shaders (for different presets), +simply setup the defines differently in multiple files. +Example, + +#define FXAA_PC 1 +#define FXAA_HLSL_5 1 +#define FXAA_QUALITY__PRESET 12 + +Or, + +#define FXAA_360 1 +Or, + +#define FXAA_PS3 1 +Etc. + +(2.) +Then include this file, + +#include "Fxaa3_11.h" + +(3.) +Then call the FXAA pixel shader from within your desired shader. +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. +As for FXAA 3.11 all inputs for all shaders are the same +to enable easy porting between platforms. + +return FxaaPixelShader(...); + +(4.) +Insure pass prior to FXAA outputs RGBL (see next section). +Or use, + +#define FXAA_GREEN_AS_LUMA 1 + +(5.) +Setup engine to provide the following constants +which are used in the FxaaPixelShader() inputs, + +FxaaFloat2 fxaaQualityRcpFrame, +FxaaFloat4 fxaaConsoleRcpFrameOpt, +FxaaFloat4 fxaaConsoleRcpFrameOpt2, +FxaaFloat4 fxaaConsole360RcpFrameOpt2, +FxaaFloat fxaaQualitySubpix, +FxaaFloat fxaaQualityEdgeThreshold, +FxaaFloat fxaaQualityEdgeThresholdMin, +FxaaFloat fxaaConsoleEdgeSharpness, +FxaaFloat fxaaConsoleEdgeThreshold, +FxaaFloat fxaaConsoleEdgeThresholdMin, +FxaaFloat4 fxaaConsole360ConstDir + +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. + +(6.) +Have FXAA vertex shader run as a full screen triangle, +and output "pos" and "fxaaConsolePosPos" +such that inputs in the pixel shader provide, + +// {xy} = center of pixel +FxaaFloat2 pos, + +// {xy__} = upper left of pixel +// {__zw} = lower right of pixel +FxaaFloat4 fxaaConsolePosPos, + +(7.) +Insure the texture sampler(s) used by FXAA are set to bilinear filtering. + + +------------------------------------------------------------------------------ +INTEGRATION - RGBL AND COLORSPACE +------------------------------------------------------------------------------ +FXAA3 requires RGBL as input unless the following is set, + +#define FXAA_GREEN_AS_LUMA 1 + +In which case the engine uses green in place of luma, +and requires RGB input is in a non-linear colorspace. + +RGB should be LDR (low dynamic range). +Specifically do FXAA after tonemapping. + +RGB data as returned by a texture fetch can be non-linear, +or linear when FXAA_GREEN_AS_LUMA is not set. +Note an "sRGB format" texture counts as linear, +because the result of a texture fetch is linear data. +Regular "RGBA8" textures in the sRGB colorspace are non-linear. + +If FXAA_GREEN_AS_LUMA is not set, +luma must be stored in the alpha channel prior to running FXAA. +This luma should be in a perceptual space (could be gamma 2.0). +Example pass before FXAA where output is gamma 2.0 encoded, + +color.rgb = ToneMap(color.rgb); // linear color output +color.rgb = sqrt(color.rgb); // gamma 2.0 color output +return color; + +To use FXAA, + +color.rgb = ToneMap(color.rgb); // linear color output +color.rgb = sqrt(color.rgb); // gamma 2.0 color output +color.a = dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114)); // compute luma +return color; + +Another example where output is linear encoded, +say for instance writing to an sRGB formated render target, +where the render target does the conversion back to sRGB after blending, + +color.rgb = ToneMap(color.rgb); // linear color output +return color; + +To use FXAA, + +color.rgb = ToneMap(color.rgb); // linear color output +color.a = sqrt(dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114))); // compute luma +return color; + +Getting luma correct is required for the algorithm to work correctly. + + +------------------------------------------------------------------------------ +BEING LINEARLY CORRECT? +------------------------------------------------------------------------------ +Applying FXAA to a framebuffer with linear RGB color will look worse. +This is very counter intuitive, but happends to be true in this case. +The reason is because dithering artifacts will be more visiable +in a linear colorspace. + + +------------------------------------------------------------------------------ +COMPLEX INTEGRATION +------------------------------------------------------------------------------ +Q. What if the engine is blending into RGB before wanting to run FXAA? + +A. In the last opaque pass prior to FXAA, +have the pass write out luma into alpha. +Then blend into RGB only. +FXAA should be able to run ok +assuming the blending pass did not any add aliasing. +This should be the common case for particles and common blending passes. + +A. Or use FXAA_GREEN_AS_LUMA. + +============================================================================*/ + +/*============================================================================ + +INTEGRATION KNOBS + +============================================================================*/ +// +// FXAA_PS3 and FXAA_360 choose the console algorithm (FXAA3 CONSOLE). +// FXAA_360_OPT is a prototype for the new optimized 360 version. +// +// 1 = Use API. +// 0 = Don't use API. +// +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PS3 +#define FXAA_PS3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360 +#define FXAA_360 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360_OPT +#define FXAA_360_OPT 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_PC +// +// FXAA Quality +// The high quality PC algorithm. +// +#define FXAA_PC 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PC_CONSOLE +// +// The console algorithm for PC is included +// for developers targeting really low spec machines. +// Likely better to just run FXAA_PC, and use a really low preset. +// +#define FXAA_PC_CONSOLE 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_120 +#define FXAA_GLSL_120 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_130 +#define FXAA_GLSL_130 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_3 +#define FXAA_HLSL_3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_4 +#define FXAA_HLSL_4 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_5 +#define FXAA_HLSL_5 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_GREEN_AS_LUMA +// +// For those using non-linear color, +// and either not able to get luma in alpha, or not wanting to, +// this enables FXAA to run using green as a proxy for luma. +// So with this enabled, no need to pack luma in alpha. +// +// This will turn off AA on anything which lacks some amount of green. +// Pure red and blue or combination of only R and B, will get no AA. +// +// Might want to lower the settings for both, +// fxaaConsoleEdgeThresholdMin +// fxaaQualityEdgeThresholdMin +// In order to insure AA does not get turned off on colors +// which contain a minor amount of green. +// +// 1 = On. +// 0 = Off. +// +#define FXAA_GREEN_AS_LUMA 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_EARLY_EXIT +// +// Controls algorithm's early exit path. +// On PS3 turning this ON adds 2 cycles to the shader. +// On 360 turning this OFF adds 10ths of a millisecond to the shader. +// Turning this off on console will result in a more blurry image. +// So this defaults to on. +// +// 1 = On. +// 0 = Off. +// +#define FXAA_EARLY_EXIT 1 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_DISCARD +// +// Only valid for PC OpenGL currently. +// Probably will not work when FXAA_GREEN_AS_LUMA = 1. +// +// 1 = Use discard on pixels which don't need AA. +// For APIs which enable concurrent TEX+ROP from same surface. +// 0 = Return unchanged color on pixels which don't need AA. +// +#define FXAA_DISCARD 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_FAST_PIXEL_OFFSET +// +// Used for GLSL 120 only. +// +// 1 = GL API supports fast pixel offsets +// 0 = do not use fast pixel offsets +// +#ifdef GL_EXT_gpu_shader4 +#define FXAA_FAST_PIXEL_OFFSET 1 +#endif +#ifdef GL_NV_gpu_shader5 +#define FXAA_FAST_PIXEL_OFFSET 1 +#endif +#ifdef GL_ARB_gpu_shader5 +#define FXAA_FAST_PIXEL_OFFSET 1 +#endif +#ifndef FXAA_FAST_PIXEL_OFFSET +#define FXAA_FAST_PIXEL_OFFSET 0 +#endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GATHER4_ALPHA +// +// 1 = API supports gather4 on alpha channel. +// 0 = API does not support gather4 on alpha channel. +// +#if (FXAA_HLSL_5 == 1) +#define FXAA_GATHER4_ALPHA 1 +#endif +#ifdef GL_ARB_gpu_shader5 +#define FXAA_GATHER4_ALPHA 1 +#endif +#ifdef GL_NV_gpu_shader5 +#define FXAA_GATHER4_ALPHA 1 +#endif +#ifndef FXAA_GATHER4_ALPHA +#define FXAA_GATHER4_ALPHA 0 +#endif +#endif + +/*============================================================================ +FXAA CONSOLE PS3 - TUNING KNOBS +============================================================================*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_SHARPNESS +// +// Consoles the sharpness of edges on PS3 only. +// Non-PS3 tuning is done with shader input. +// +// Due to the PS3 being ALU bound, +// there are only two safe values here: 4 and 8. +// These options use the shaders ability to a free *|/ by 2|4|8. +// +// 8.0 is sharper +// 4.0 is softer +// 2.0 is really soft (good for vector graphics inputs) +// +#if 1 +#define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 8.0 +#endif +#if 0 +#define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 4.0 +#endif +#if 0 +#define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 2.0 +#endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_THRESHOLD +// +// Only effects PS3. +// Non-PS3 tuning is done with shader input. +// +// The minimum amount of local contrast required to apply algorithm. +// The console setting has a different mapping than the quality setting. +// +// This only applies when FXAA_EARLY_EXIT is 1. +// +// Due to the PS3 being ALU bound, +// there are only two safe values here: 0.25 and 0.125. +// These options use the shaders ability to a free *|/ by 2|4|8. +// +// 0.125 leaves less aliasing, but is softer +// 0.25 leaves more aliasing, and is sharper +// +#if 1 +#define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.125 +#else +#define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.25 +#endif +#endif + +/*============================================================================ +FXAA QUALITY - TUNING KNOBS +------------------------------------------------------------------------------ +NOTE the other tuning knobs are now in the shader function inputs! +============================================================================*/ +#ifndef FXAA_QUALITY__PRESET +// +// Choose the quality preset. +// This needs to be compiled into the shader as it effects code. +// Best option to include multiple presets is to +// in each shader define the preset, then include this file. +// +// OPTIONS +// ----------------------------------------------------------------------- +// 10 to 15 - default medium dither (10=fastest, 15=highest quality) +// 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) +// 39 - no dither, very expensive +// +// NOTES +// ----------------------------------------------------------------------- +// 12 = slightly faster then FXAA 3.9 and higher edge quality (default) +// 13 = about same speed as FXAA 3.9 and better than 12 +// 23 = closest to FXAA 3.9 visually and performance wise +// _ = the lowest digit is directly related to performance +// _ = the highest digit is directly related to style +// +#define FXAA_QUALITY__PRESET 12 +#endif + + +/*============================================================================ + +FXAA QUALITY - PRESETS + +============================================================================*/ + +/*============================================================================ +FXAA QUALITY - MEDIUM DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 10) +#define FXAA_QUALITY__PS 3 +#define FXAA_QUALITY__P0 1.5 +#define FXAA_QUALITY__P1 3.0 +#define FXAA_QUALITY__P2 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 11) +#define FXAA_QUALITY__PS 4 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 3.0 +#define FXAA_QUALITY__P3 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 12) +#define FXAA_QUALITY__PS 5 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 4.0 +#define FXAA_QUALITY__P4 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 13) +#define FXAA_QUALITY__PS 6 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 4.0 +#define FXAA_QUALITY__P5 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 14) +#define FXAA_QUALITY__PS 7 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 4.0 +#define FXAA_QUALITY__P6 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 15) +#define FXAA_QUALITY__PS 8 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 2.0 +#define FXAA_QUALITY__P6 4.0 +#define FXAA_QUALITY__P7 12.0 +#endif + +/*============================================================================ +FXAA QUALITY - LOW DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 20) +#define FXAA_QUALITY__PS 3 +#define FXAA_QUALITY__P0 1.5 +#define FXAA_QUALITY__P1 2.0 +#define FXAA_QUALITY__P2 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 21) +#define FXAA_QUALITY__PS 4 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 22) +#define FXAA_QUALITY__PS 5 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 23) +#define FXAA_QUALITY__PS 6 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 24) +#define FXAA_QUALITY__PS 7 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 3.0 +#define FXAA_QUALITY__P6 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 25) +#define FXAA_QUALITY__PS 8 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 2.0 +#define FXAA_QUALITY__P6 4.0 +#define FXAA_QUALITY__P7 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 26) +#define FXAA_QUALITY__PS 9 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 2.0 +#define FXAA_QUALITY__P6 2.0 +#define FXAA_QUALITY__P7 4.0 +#define FXAA_QUALITY__P8 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 27) +#define FXAA_QUALITY__PS 10 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 2.0 +#define FXAA_QUALITY__P6 2.0 +#define FXAA_QUALITY__P7 2.0 +#define FXAA_QUALITY__P8 4.0 +#define FXAA_QUALITY__P9 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 28) +#define FXAA_QUALITY__PS 11 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 2.0 +#define FXAA_QUALITY__P6 2.0 +#define FXAA_QUALITY__P7 2.0 +#define FXAA_QUALITY__P8 2.0 +#define FXAA_QUALITY__P9 4.0 +#define FXAA_QUALITY__P10 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 29) +#define FXAA_QUALITY__PS 12 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.5 +#define FXAA_QUALITY__P2 2.0 +#define FXAA_QUALITY__P3 2.0 +#define FXAA_QUALITY__P4 2.0 +#define FXAA_QUALITY__P5 2.0 +#define FXAA_QUALITY__P6 2.0 +#define FXAA_QUALITY__P7 2.0 +#define FXAA_QUALITY__P8 2.0 +#define FXAA_QUALITY__P9 2.0 +#define FXAA_QUALITY__P10 4.0 +#define FXAA_QUALITY__P11 8.0 +#endif + +/*============================================================================ +FXAA QUALITY - EXTREME QUALITY +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 39) +#define FXAA_QUALITY__PS 12 +#define FXAA_QUALITY__P0 1.0 +#define FXAA_QUALITY__P1 1.0 +#define FXAA_QUALITY__P2 1.0 +#define FXAA_QUALITY__P3 1.0 +#define FXAA_QUALITY__P4 1.0 +#define FXAA_QUALITY__P5 1.5 +#define FXAA_QUALITY__P6 2.0 +#define FXAA_QUALITY__P7 2.0 +#define FXAA_QUALITY__P8 2.0 +#define FXAA_QUALITY__P9 2.0 +#define FXAA_QUALITY__P10 4.0 +#define FXAA_QUALITY__P11 8.0 +#endif + + + +/*============================================================================ + +API PORTING + +============================================================================*/ +#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) +#define FxaaBool bool +#define FxaaDiscard discard +#define FxaaFloat float +#define FxaaFloat2 vec2 +#define FxaaFloat3 vec3 +#define FxaaFloat4 vec4 +#define FxaaHalf float +#define FxaaHalf2 vec2 +#define FxaaHalf3 vec3 +#define FxaaHalf4 vec4 +#define FxaaInt2 ivec2 +#define FxaaSat(x) clamp(x, 0.0, 1.0) +#define FxaaTex sampler2D +#else +#define FxaaBool bool +#define FxaaDiscard clip(-1) +#define FxaaFloat float +#define FxaaFloat2 float2 +#define FxaaFloat3 float3 +#define FxaaFloat4 float4 +#define FxaaHalf half +#define FxaaHalf2 half2 +#define FxaaHalf3 half3 +#define FxaaHalf4 half4 +#define FxaaSat(x) saturate(x) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_120 == 1) +// Requires, +// #version 120 +// And at least, +// #extension GL_EXT_gpu_shader4 : enable +// (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9) +#define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) +#if (FXAA_FAST_PIXEL_OFFSET == 1) +#define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o) +#else +#define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) +#endif +#if (FXAA_GATHER4_ALPHA == 1) +// use #extension GL_ARB_gpu_shader5 : enable +#define FxaaTexAlpha4(t, p) textureGather(t, p, 3) +#define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) +#define FxaaTexGreen4(t, p) textureGather(t, p, 1) +#define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) +#endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_130 == 1) +// Requires "#version 130" or better +#define FxaaTexTop(t, p) textureLod(t, p, 0.0) +#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) +#if (FXAA_GATHER4_ALPHA == 1) +// use #extension GL_ARB_gpu_shader5 : enable +#define FxaaTexAlpha4(t, p) textureGather(t, p, 3) +#define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) +#define FxaaTexGreen4(t, p) textureGather(t, p, 1) +#define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) +#endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_3 == 1) || (FXAA_360 == 1) || (FXAA_PS3 == 1) +#define FxaaInt2 float2 +#define FxaaTex sampler2D +#define FxaaTexTop(t, p) tex2Dlod(t, float4(p, 0.0, 0.0)) +#define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p + (o * r), 0, 0)) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_4 == 1) +#define FxaaInt2 int2 +struct FxaaTex { SamplerState smpl; Texture2D tex; }; +#define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) +#define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_5 == 1) +#define FxaaInt2 int2 +struct FxaaTex { SamplerState smpl; Texture2D tex; }; +#define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) +#define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) +#define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p) +#define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o) +#define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p) +#define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o) +#endif + +#undef FxaaTexTop +#define FxaaTexTop(t, p) tex2D(t, p) +#undef FxaaTexOff +#define FxaaTexOff(t, p, o, r) tex2D(t, p + (o * r)) + +/*============================================================================ +GREEN AS LUMA OPTION SUPPORT FUNCTION +============================================================================*/ +#if (FXAA_GREEN_AS_LUMA == 0) +FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } +#else +FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } +#endif + + + + +/*============================================================================ + +FXAA3 QUALITY - PC + +============================================================================*/ +#if (FXAA_PC == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( +// +// Use noperspective interpolation here (turn off perspective interpolation). +// {xy} = center of pixel +FxaaFloat2 pos, +// +// Used only for FXAA Console, and not used on the 360 version. +// Use noperspective interpolation here (turn off perspective interpolation). +// {xy__} = upper left of pixel +// {__zw} = lower right of pixel +//FxaaFloat4 fxaaConsolePosPos, +// +// Input color texture. +// {rgb_} = color in linear or perceptual color space +// if (FXAA_GREEN_AS_LUMA == 0) +// {___a} = luma in perceptual color space (not linear) +FxaaTex tex, +// +// Only used on the optimized 360 version of FXAA Console. +// For everything but 360, just use the same input here as for "tex". +// For 360, same texture, just alias with a 2nd sampler. +// This sampler needs to have an exponent bias of -1. +//FxaaTex fxaaConsole360TexExpBiasNegOne, +// +// Only used on the optimized 360 version of FXAA Console. +// For everything but 360, just use the same input here as for "tex". +// For 360, same texture, just alias with a 3nd sampler. +// This sampler needs to have an exponent bias of -2. +//FxaaTex fxaaConsole360TexExpBiasNegTwo, +// +// Only used on FXAA Quality. +// This must be from a constant/uniform. +// {x_} = 1.0/screenWidthInPixels +// {_y} = 1.0/screenHeightInPixels +FxaaFloat2 fxaaQualityRcpFrame, +// +// Only used on FXAA Console. +// This must be from a constant/uniform. +// This effects sub-pixel AA quality and inversely sharpness. +// Where N ranges between, +// N = 0.50 (default) +// N = 0.33 (sharper) +// {x___} = -N/screenWidthInPixels +// {_y__} = -N/screenHeightInPixels +// {__z_} = N/screenWidthInPixels +// {___w} = N/screenHeightInPixels +//FxaaFloat4 fxaaConsoleRcpFrameOpt, +// +// Only used on FXAA Console. +// Not used on 360, but used on PS3 and PC. +// This must be from a constant/uniform. +// {x___} = -2.0/screenWidthInPixels +// {_y__} = -2.0/screenHeightInPixels +// {__z_} = 2.0/screenWidthInPixels +// {___w} = 2.0/screenHeightInPixels +//FxaaFloat4 fxaaConsoleRcpFrameOpt2, +// +// Only used on FXAA Console. +// Only used on 360 in place of fxaaConsoleRcpFrameOpt2. +// This must be from a constant/uniform. +// {x___} = 8.0/screenWidthInPixels +// {_y__} = 8.0/screenHeightInPixels +// {__z_} = -4.0/screenWidthInPixels +// {___w} = -4.0/screenHeightInPixels +//FxaaFloat4 fxaaConsole360RcpFrameOpt2, +// +// Only used on FXAA Quality. +// This used to be the FXAA_QUALITY__SUBPIX define. +// It is here now to allow easier tuning. +// Choose the amount of sub-pixel aliasing removal. +// This can effect sharpness. +// 1.00 - upper limit (softer) +// 0.75 - default amount of filtering +// 0.50 - lower limit (sharper, less sub-pixel aliasing removal) +// 0.25 - almost off +// 0.00 - completely off +FxaaFloat fxaaQualitySubpix, +// +// Only used on FXAA Quality. +// This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. +// It is here now to allow easier tuning. +// The minimum amount of local contrast required to apply algorithm. +// 0.333 - too little (faster) +// 0.250 - low quality +// 0.166 - default +// 0.125 - high quality +// 0.063 - overkill (slower) +FxaaFloat fxaaQualityEdgeThreshold, +// +// Only used on FXAA Quality. +// This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. +// It is here now to allow easier tuning. +// Trims the algorithm from processing darks. +// 0.0833 - upper limit (default, the start of visible unfiltered edges) +// 0.0625 - high quality (faster) +// 0.0312 - visible limit (slower) +// Special notes when using FXAA_GREEN_AS_LUMA, +// Likely want to set this to zero. +// As colors that are mostly not-green +// will appear very dark in the green channel! +// Tune by looking at mostly non-green content, +// then start at zero and increase until aliasing is a problem. +FxaaFloat fxaaQualityEdgeThresholdMin +// +// Only used on FXAA Console. +// This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. +// It is here now to allow easier tuning. +// This does not effect PS3, as this needs to be compiled in. +// Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. +// Due to the PS3 being ALU bound, +// there are only three safe values here: 2 and 4 and 8. +// These options use the shaders ability to a free *|/ by 2|4|8. +// For all other platforms can be a non-power of two. +// 8.0 is sharper (default!!!) +// 4.0 is softer +// 2.0 is really soft (good only for vector graphics inputs) +//FxaaFloat fxaaConsoleEdgeSharpness, +// +// Only used on FXAA Console. +// This used to be the FXAA_CONSOLE__EDGE_THRESHOLD define. +// It is here now to allow easier tuning. +// This does not effect PS3, as this needs to be compiled in. +// Use FXAA_CONSOLE__PS3_EDGE_THRESHOLD for PS3. +// Due to the PS3 being ALU bound, +// there are only two safe values here: 1/4 and 1/8. +// These options use the shaders ability to a free *|/ by 2|4|8. +// The console setting has a different mapping than the quality setting. +// Other platforms can use other values. +// 0.125 leaves less aliasing, but is softer (default!!!) +// 0.25 leaves more aliasing, and is sharper +//FxaaFloat fxaaConsoleEdgeThreshold, +// +// Only used on FXAA Console. +// This used to be the FXAA_CONSOLE__EDGE_THRESHOLD_MIN define. +// It is here now to allow easier tuning. +// Trims the algorithm from processing darks. +// The console setting has a different mapping than the quality setting. +// This only applies when FXAA_EARLY_EXIT is 1. +// This does not apply to PS3, +// PS3 was simplified to avoid more shader instructions. +// 0.06 - faster but more aliasing in darks +// 0.05 - default +// 0.04 - slower and less aliasing in darks +// Special notes when using FXAA_GREEN_AS_LUMA, +// Likely want to set this to zero. +// As colors that are mostly not-green +// will appear very dark in the green channel! +// Tune by looking at mostly non-green content, +// then start at zero and increase until aliasing is a problem. +//FxaaFloat fxaaConsoleEdgeThresholdMin, +// +// Extra constants for 360 FXAA Console only. +// Use zeros or anything else for other platforms. +// These must be in physical constant registers and NOT immedates. +// Immedates will result in compiler un-optimizing. +// {xyzw} = float4(1.0, -1.0, 0.25, -0.25) +//FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +FxaaFloat2 posM; +posM.x = pos.x; +posM.y = pos.y; +#if (FXAA_GATHER4_ALPHA == 1) +#if (FXAA_DISCARD == 0) +FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); +#if (FXAA_GREEN_AS_LUMA == 0) +#define lumaM rgbyM.w +#else +#define lumaM rgbyM.y +#endif +#endif +#if (FXAA_GREEN_AS_LUMA == 0) +FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); +FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); +#else +FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); +FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); +#endif +#if (FXAA_DISCARD == 1) +#define lumaM luma4A.w +#endif +#define lumaE luma4A.z +#define lumaS luma4A.x +#define lumaSE luma4A.y +#define lumaNW luma4B.w +#define lumaN luma4B.z +#define lumaW luma4B.x +#else +FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); +#if (FXAA_GREEN_AS_LUMA == 0) +#define lumaM rgbyM.w +#else +#define lumaM rgbyM.y +#endif +FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); +#endif +/*--------------------------------------------------------------------------*/ +FxaaFloat maxSM = max(lumaS, lumaM); +FxaaFloat minSM = min(lumaS, lumaM); +FxaaFloat maxESM = max(lumaE, maxSM); +FxaaFloat minESM = min(lumaE, minSM); +FxaaFloat maxWN = max(lumaN, lumaW); +FxaaFloat minWN = min(lumaN, lumaW); +FxaaFloat rangeMax = max(maxWN, maxESM); +FxaaFloat rangeMin = min(minWN, minESM); +FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; +FxaaFloat range = rangeMax - rangeMin; +FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); +FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ +if(earlyExit) +#if (FXAA_DISCARD == 1) +FxaaDiscard; +#else +return rgbyM; +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GATHER4_ALPHA == 0) +FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); +#else +FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); +FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); +#endif +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaNS = lumaN + lumaS; +FxaaFloat lumaWE = lumaW + lumaE; +FxaaFloat subpixRcpRange = 1.0/range; +FxaaFloat subpixNSWE = lumaNS + lumaWE; +FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; +FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaNESE = lumaNE + lumaSE; +FxaaFloat lumaNWNE = lumaNW + lumaNE; +FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; +FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaNWSW = lumaNW + lumaSW; +FxaaFloat lumaSWSE = lumaSW + lumaSE; +FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); +FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); +FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; +FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; +FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; +FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ +FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; +FxaaFloat lengthSign = fxaaQualityRcpFrame.x; +FxaaBool horzSpan = edgeHorz >= edgeVert; +FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ +if(!horzSpan) lumaN = lumaW; +if(!horzSpan) lumaS = lumaE; +if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; +FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ +FxaaFloat gradientN = lumaN - lumaM; +FxaaFloat gradientS = lumaS - lumaM; +FxaaFloat lumaNN = lumaN + lumaM; +FxaaFloat lumaSS = lumaS + lumaM; +FxaaBool pairN = abs(gradientN) >= abs(gradientS); +FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); +if(pairN) lengthSign = -lengthSign; +FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ +FxaaFloat2 posB; +posB.x = posM.x; +posB.y = posM.y; +FxaaFloat2 offNP; +offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; +offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; +if(!horzSpan) posB.x += lengthSign * 0.5; +if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ +FxaaFloat2 posN; +posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; +posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; +FxaaFloat2 posP; +posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; +posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; +FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; +FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); +FxaaFloat subpixE = subpixC * subpixC; +FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ +if(!pairN) lumaNN = lumaSS; +FxaaFloat gradientScaled = gradient * 1.0/4.0; +FxaaFloat lumaMM = lumaM - lumaNN * 0.5; +FxaaFloat subpixF = subpixD * subpixE; +FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ +lumaEndN -= lumaNN * 0.5; +lumaEndP -= lumaNN * 0.5; +FxaaBool doneN = abs(lumaEndN) >= gradientScaled; +FxaaBool doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; +FxaaBool doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 3) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 4) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 5) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 6) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 7) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 8) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 9) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 10) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 11) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PS > 12) +if(doneNP) { +if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); +if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); +if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; +if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; +doneN = abs(lumaEndN) >= gradientScaled; +doneP = abs(lumaEndP) >= gradientScaled; +if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; +if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; +doneNP = (!doneN) || (!doneP); +if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; +if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +#endif +/*--------------------------------------------------------------------------*/ +} +/*--------------------------------------------------------------------------*/ +FxaaFloat dstN = posM.x - posN.x; +FxaaFloat dstP = posP.x - posM.x; +if(!horzSpan) dstN = posM.y - posN.y; +if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ +FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; +FxaaFloat spanLength = (dstP + dstN); +FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; +FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ +FxaaBool directionN = dstN < dstP; +FxaaFloat dst = min(dstN, dstP); +FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; +FxaaFloat subpixG = subpixF * subpixF; +FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; +FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ +FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; +FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); +if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; +if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; +#if (FXAA_DISCARD == 1) +return FxaaTexTop(tex, posM); +#else +return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); +#endif +} +/*==========================================================================*/ +#endif + + + + +/*============================================================================ + +FXAA3 CONSOLE - PC VERSION +------------------------------------------------------------------------------ +Instead of using this on PC, I'd suggest just using FXAA Quality with +#define FXAA_QUALITY__PRESET 10 +Or +#define FXAA_QUALITY__PRESET 20 +Either are higher qualilty and almost as fast as this on modern PC GPUs. +============================================================================*/ +#if (FXAA_PC_CONSOLE == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( +// See FXAA Quality FxaaPixelShader() source for docs on Inputs! +FxaaFloat2 pos, +FxaaFloat4 fxaaConsolePosPos, +FxaaTex tex, +FxaaTex fxaaConsole360TexExpBiasNegOne, +FxaaTex fxaaConsole360TexExpBiasNegTwo, +FxaaFloat2 fxaaQualityRcpFrame, +FxaaFloat4 fxaaConsoleRcpFrameOpt, +FxaaFloat4 fxaaConsoleRcpFrameOpt2, +FxaaFloat4 fxaaConsole360RcpFrameOpt2, +FxaaFloat fxaaQualitySubpix, +FxaaFloat fxaaQualityEdgeThreshold, +FxaaFloat fxaaQualityEdgeThresholdMin, +FxaaFloat fxaaConsoleEdgeSharpness, +FxaaFloat fxaaConsoleEdgeThreshold, +FxaaFloat fxaaConsoleEdgeThresholdMin, +FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaNw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xy)); +FxaaFloat lumaSw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xw)); +FxaaFloat lumaNe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zy)); +FxaaFloat lumaSe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zw)); +/*--------------------------------------------------------------------------*/ +FxaaFloat4 rgbyM = FxaaTexTop(tex, pos.xy); +#if (FXAA_GREEN_AS_LUMA == 0) +FxaaFloat lumaM = rgbyM.w; +#else +FxaaFloat lumaM = rgbyM.y; +#endif +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaMaxNwSw = max(lumaNw, lumaSw); +lumaNe += 1.0/384.0; +FxaaFloat lumaMinNwSw = min(lumaNw, lumaSw); +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaMaxNeSe = max(lumaNe, lumaSe); +FxaaFloat lumaMinNeSe = min(lumaNe, lumaSe); +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaMax = max(lumaMaxNeSe, lumaMaxNwSw); +FxaaFloat lumaMin = min(lumaMinNeSe, lumaMinNwSw); +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaMaxScaled = lumaMax * fxaaConsoleEdgeThreshold; +/*--------------------------------------------------------------------------*/ +FxaaFloat lumaMinM = min(lumaMin, lumaM); +FxaaFloat lumaMaxScaledClamped = max(fxaaConsoleEdgeThresholdMin, lumaMaxScaled); +FxaaFloat lumaMaxM = max(lumaMax, lumaM); +FxaaFloat dirSwMinusNe = lumaSw - lumaNe; +FxaaFloat lumaMaxSubMinM = lumaMaxM - lumaMinM; +FxaaFloat dirSeMinusNw = lumaSe - lumaNw; +if(lumaMaxSubMinM < lumaMaxScaledClamped) return rgbyM; +/*--------------------------------------------------------------------------*/ +FxaaFloat2 dir; +dir.x = dirSwMinusNe + dirSeMinusNw; +dir.y = dirSwMinusNe - dirSeMinusNw; +/*--------------------------------------------------------------------------*/ +FxaaFloat2 dir1 = normalize(dir.xy); +FxaaFloat4 rgbyN1 = FxaaTexTop(tex, pos.xy - dir1 * fxaaConsoleRcpFrameOpt.zw); +FxaaFloat4 rgbyP1 = FxaaTexTop(tex, pos.xy + dir1 * fxaaConsoleRcpFrameOpt.zw); +/*--------------------------------------------------------------------------*/ +FxaaFloat dirAbsMinTimesC = min(abs(dir1.x), abs(dir1.y)) * fxaaConsoleEdgeSharpness; +FxaaFloat2 dir2 = clamp(dir1.xy / dirAbsMinTimesC, -2.0, 2.0); +/*--------------------------------------------------------------------------*/ +FxaaFloat4 rgbyN2 = FxaaTexTop(tex, pos.xy - dir2 * fxaaConsoleRcpFrameOpt2.zw); +FxaaFloat4 rgbyP2 = FxaaTexTop(tex, pos.xy + dir2 * fxaaConsoleRcpFrameOpt2.zw); +/*--------------------------------------------------------------------------*/ +FxaaFloat4 rgbyA = rgbyN1 + rgbyP1; +FxaaFloat4 rgbyB = ((rgbyN2 + rgbyP2) * 0.25) + (rgbyA * 0.25); +/*--------------------------------------------------------------------------*/ +#if (FXAA_GREEN_AS_LUMA == 0) +FxaaBool twoTap = (rgbyB.w < lumaMin) || (rgbyB.w > lumaMax); +#else +FxaaBool twoTap = (rgbyB.y < lumaMin) || (rgbyB.y > lumaMax); +#endif +if(twoTap) rgbyB.xyz = rgbyA.xyz * 0.5; +return rgbyB; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + +FXAA3 CONSOLE - 360 PIXEL SHADER + +------------------------------------------------------------------------------ +This optimized version thanks to suggestions from Andy Luedke. +Should be fully tex bound in all cases. +As of the FXAA 3.11 release, I have still not tested this code, +however I fixed a bug which was in both FXAA 3.9 and FXAA 3.10. +And note this is replacing the old unoptimized version. +If it does not work, please let me know so I can fix it. +============================================================================*/ +#if (FXAA_360 == 1) +/*--------------------------------------------------------------------------*/ +[reduceTempRegUsage(4)] +float4 FxaaPixelShader( +// See FXAA Quality FxaaPixelShader() source for docs on Inputs! +FxaaFloat2 pos, +FxaaFloat4 fxaaConsolePosPos, +FxaaTex tex, +FxaaTex fxaaConsole360TexExpBiasNegOne, +FxaaTex fxaaConsole360TexExpBiasNegTwo, +FxaaFloat2 fxaaQualityRcpFrame, +FxaaFloat4 fxaaConsoleRcpFrameOpt, +FxaaFloat4 fxaaConsoleRcpFrameOpt2, +FxaaFloat4 fxaaConsole360RcpFrameOpt2, +FxaaFloat fxaaQualitySubpix, +FxaaFloat fxaaQualityEdgeThreshold, +FxaaFloat fxaaQualityEdgeThresholdMin, +FxaaFloat fxaaConsoleEdgeSharpness, +FxaaFloat fxaaConsoleEdgeThreshold, +FxaaFloat fxaaConsoleEdgeThresholdMin, +FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +float4 lumaNwNeSwSe; +#if (FXAA_GREEN_AS_LUMA == 0) +asm { +tfetch2D lumaNwNeSwSe.w___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false +tfetch2D lumaNwNeSwSe._w__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false +tfetch2D lumaNwNeSwSe.__w_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false +tfetch2D lumaNwNeSwSe.___w, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false +}; +#else +asm { +tfetch2D lumaNwNeSwSe.y___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false +tfetch2D lumaNwNeSwSe._y__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false +tfetch2D lumaNwNeSwSe.__y_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false +tfetch2D lumaNwNeSwSe.___y, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false +}; +#endif +/*--------------------------------------------------------------------------*/ +lumaNwNeSwSe.y += 1.0/384.0; +float2 lumaMinTemp = min(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); +float2 lumaMaxTemp = max(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); +float lumaMin = min(lumaMinTemp.x, lumaMinTemp.y); +float lumaMax = max(lumaMaxTemp.x, lumaMaxTemp.y); +/*--------------------------------------------------------------------------*/ +float4 rgbyM = tex2Dlod(tex, float4(pos.xy, 0.0, 0.0)); +#if (FXAA_GREEN_AS_LUMA == 0) +float lumaMinM = min(lumaMin, rgbyM.w); +float lumaMaxM = max(lumaMax, rgbyM.w); +#else +float lumaMinM = min(lumaMin, rgbyM.y); +float lumaMaxM = max(lumaMax, rgbyM.y); +#endif +if((lumaMaxM - lumaMinM) < max(fxaaConsoleEdgeThresholdMin, lumaMax * fxaaConsoleEdgeThreshold)) return rgbyM; +/*--------------------------------------------------------------------------*/ +float2 dir; +dir.x = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.yyxx); +dir.y = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.xyxy); +dir = normalize(dir); +/*--------------------------------------------------------------------------*/ +float4 dir1 = dir.xyxy * fxaaConsoleRcpFrameOpt.xyzw; +/*--------------------------------------------------------------------------*/ +float4 dir2; +float dirAbsMinTimesC = min(abs(dir.x), abs(dir.y)) * fxaaConsoleEdgeSharpness; +dir2 = saturate(fxaaConsole360ConstDir.zzww * dir.xyxy / dirAbsMinTimesC + 0.5); +dir2 = dir2 * fxaaConsole360RcpFrameOpt2.xyxy + fxaaConsole360RcpFrameOpt2.zwzw; +/*--------------------------------------------------------------------------*/ +float4 rgbyN1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.xy, 0.0, 0.0)); +float4 rgbyP1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.zw, 0.0, 0.0)); +float4 rgbyN2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.xy, 0.0, 0.0)); +float4 rgbyP2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.zw, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ +float4 rgbyA = rgbyN1 + rgbyP1; +float4 rgbyB = rgbyN2 + rgbyP2 + rgbyA * 0.5; +/*--------------------------------------------------------------------------*/ +float4 rgbyR = ((FxaaLuma(rgbyB) - lumaMax) > 0.0) ? rgbyA : rgbyB; +rgbyR = ((FxaaLuma(rgbyB) - lumaMin) > 0.0) ? rgbyR : rgbyA; +return rgbyR; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + +FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (NO EARLY EXIT) + +============================================================================== +The code below does not exactly match the assembly. +I have a feeling that 12 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + +--fenable-bx2 --fastmath --fastprecision --nofloatbindings + +------------------------------------------------------------------------------ +NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: +0: texpkb h0.w(TRUE), v5.zyxx, #0 +2: addh h2.z(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x +4: texpkb h0.w(TRUE), v5.xwxx, #0 +6: addh h0.z(TRUE), -h2, h0.w +7: texpkb h1.w(TRUE), v5, #0 +9: addh h0.x(TRUE), h0.z, -h1.w +10: addh h3.w(TRUE), h0.z, h1 +11: texpkb h2.w(TRUE), v5.zwzz, #0 +13: addh h0.z(TRUE), h3.w, -h2.w +14: addh h0.x(TRUE), h2.w, h0 +15: nrmh h1.xz(TRUE), h0_n +16: minh_m8 h0.x(TRUE), |h1|, |h1.z| +17: maxh h4.w(TRUE), h0, h1 +18: divx h2.xy(TRUE), h1_n.xzzw, h0_n +19: movr r1.zw(TRUE), v4.xxxy +20: madr r2.xz(TRUE), -h1, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zzww, r1.zzww +22: minh h5.w(TRUE), h0, h1 +23: texpkb h0(TRUE), r2.xzxx, #0 +25: madr r0.zw(TRUE), h1.xzxz, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w), r1 +27: maxh h4.x(TRUE), h2.z, h2.w +28: texpkb h1(TRUE), r0.zwzz, #0 +30: addh_d2 h1(TRUE), h0, h1 +31: madr r0.xy(TRUE), -h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz +33: texpkb h0(TRUE), r0, #0 +35: minh h4.z(TRUE), h2, h2.w +36: fenct TRUE +37: madr r1.xy(TRUE), h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz +39: texpkb h2(TRUE), r1, #0 +41: addh_d2 h0(TRUE), h0, h2 +42: maxh h2.w(TRUE), h4, h4.x +43: minh h2.x(TRUE), h5.w, h4.z +44: addh_d2 h0(TRUE), h0, h1 +45: slth h2.x(TRUE), h0.w, h2 +46: sgth h2.w(TRUE), h0, h2 +47: movh h0(TRUE), h0 +48: addx.c0 rc(TRUE), h2, h2.w +49: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- +1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; +| TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; +| SCB1 | add | 2: ADDh h2.z, h0.--w-, const.--x-; +| | | +2 | SCT0/1 | mov | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; +| TEX | txl | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; +| SCB1 | add | 6: ADDh h0.z,-h2, h0.--w-; +| | | +3 | SCT0/1 | mov | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; +| TEX | txl | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; +| SCB0 | add | 9: ADDh h0.x, h0.z---,-h1.w---; +| SCB1 | add | 10: ADDh h3.w, h0.---z, h1; +| | | +4 | SCT0/1 | mov | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; +| TEX | txl | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; +| SCB0 | add | 14: ADDh h0.x, h2.w---, h0; +| SCB1 | add | 13: ADDh h0.z, h3.--w-,-h2.--w-; +| | | +5 | SCT1 | mov | 15: NRMh h1.xz, h0; +| SRB | nrm | 15: NRMh h1.xz, h0; +| SCB0 | min | 16: MINh*8 h0.x, |h1|, |h1.z---|; +| SCB1 | max | 17: MAXh h4.w, h0, h1; +| | | +6 | SCT0 | div | 18: DIVx h2.xy, h1.xz--, h0; +| SCT1 | mov | 19: MOVr r1.zw, g[TEX0].--xy; +| SCB0 | mad | 20: MADr r2.xz,-h1, const.z-w-, r1.z-w-; +| SCB1 | min | 22: MINh h5.w, h0, h1; +| | | +7 | SCT0/1 | mov | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; +| TEX | txl | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; +| SCB0 | max | 27: MAXh h4.x, h2.z---, h2.w---; +| SCB1 | mad | 25: MADr r0.zw, h1.--xz, const, r1; +| | | +8 | SCT0/1 | mov | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; +| TEX | txl | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; +| SCB0/1 | add | 30: ADDh/2 h1, h0, h1; +| | | +9 | SCT0 | mad | 31: MADr r0.xy,-h2, const.xy--, r1.zw--; +| SCT1 | mov | 33: TXLr h0, r0, const.zzzz, TEX0; +| TEX | txl | 33: TXLr h0, r0, const.zzzz, TEX0; +| SCB1 | min | 35: MINh h4.z, h2, h2.--w-; +| | | +10 | SCT0 | mad | 37: MADr r1.xy, h2, const.xy--, r1.zw--; +| SCT1 | mov | 39: TXLr h2, r1, const.zzzz, TEX0; +| TEX | txl | 39: TXLr h2, r1, const.zzzz, TEX0; +| SCB0/1 | add | 41: ADDh/2 h0, h0, h2; +| | | +11 | SCT0 | min | 43: MINh h2.x, h5.w---, h4.z---; +| SCT1 | max | 42: MAXh h2.w, h4, h4.---x; +| SCB0/1 | add | 44: ADDh/2 h0, h0, h1; +| | | +12 | SCT0 | set | 45: SLTh h2.x, h0.w---, h2; +| SCT1 | set | 46: SGTh h2.w, h0, h2; +| SCB0/1 | mul | 47: MOVh h0, h0; +| | | +13 | SCT0 | mad | 48: ADDxc0_s rc, h2, h2.w---; +| SCB0/1 | mul | 49: MOVh h0(NE0.xxxx), h1; +Pass SCT TEX SCB +1: 0% 100% 25% +2: 0% 100% 25% +3: 0% 100% 50% +4: 0% 100% 50% +5: 0% 0% 50% +6: 100% 0% 75% +7: 0% 100% 75% +8: 0% 100% 100% +9: 0% 100% 25% +10: 0% 100% 100% +11: 50% 0% 100% +12: 50% 0% 100% +13: 25% 0% 100% + +MEAN: 17% 61% 67% + +Pass SCT0 SCT1 TEX SCB0 SCB1 +1: 0% 0% 100% 0% 100% +2: 0% 0% 100% 0% 100% +3: 0% 0% 100% 100% 100% +4: 0% 0% 100% 100% 100% +5: 0% 0% 0% 100% 100% +6: 100% 100% 0% 100% 100% +7: 0% 0% 100% 100% 100% +8: 0% 0% 100% 100% 100% +9: 0% 0% 100% 0% 100% +10: 0% 0% 100% 100% 100% +11: 100% 100% 0% 100% 100% +12: 100% 100% 0% 100% 100% +13: 100% 0% 0% 100% 100% + +MEAN: 30% 23% 61% 76% 100% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 13 cycles, 3 r regs, 923,076,923 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 0) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +//#pragma option O3 +//#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( +// See FXAA Quality FxaaPixelShader() source for docs on Inputs! +FxaaFloat2 pos, +FxaaFloat4 fxaaConsolePosPos, +FxaaTex tex, +//FxaaTex fxaaConsole360TexExpBiasNegOne, +//FxaaTex fxaaConsole360TexExpBiasNegTwo, +//FxaaFloat2 fxaaQualityRcpFrame, +FxaaFloat4 fxaaConsoleRcpFrameOpt, +FxaaFloat4 fxaaConsoleRcpFrameOpt2 +//FxaaFloat4 fxaaConsole360RcpFrameOpt2, +//FxaaFloat fxaaQualitySubpix, +//FxaaFloat fxaaQualityEdgeThreshold, +//FxaaFloat fxaaQualityEdgeThresholdMin, +//FxaaFloat fxaaConsoleEdgeSharpness, +//FxaaFloat fxaaConsoleEdgeThreshold, +//FxaaFloat fxaaConsoleEdgeThresholdMin, +//FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) +half4 dir; +half4 lumaNe = tex2D(tex, fxaaConsolePosPos.zy); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +lumaNe.w += half(1.0/512.0); +dir.x = -lumaNe.w; +dir.z = -lumaNe.w; +#else +lumaNe.y += half(1.0/512.0); +dir.x = -lumaNe.y; +dir.z = -lumaNe.y; +#endif +/*--------------------------------------------------------------------------*/ +// (2) +half4 lumaSw = tex2D(tex, fxaaConsolePosPos.xw); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +dir.x += lumaSw.w; +dir.z += lumaSw.w; +#else +dir.x += lumaSw.y; +dir.z += lumaSw.y; +#endif +/*--------------------------------------------------------------------------*/ +// (3) +half4 lumaNw = tex2D(tex, fxaaConsolePosPos.xy); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +dir.x -= lumaNw.w; +dir.z += lumaNw.w; +#else +dir.x -= lumaNw.y; +dir.z += lumaNw.y; +#endif +/*--------------------------------------------------------------------------*/ +// (4) +half4 lumaSe = tex2D(tex, fxaaConsolePosPos.zw); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +dir.x += lumaSe.w; +dir.z -= lumaSe.w; +#else +dir.x += lumaSe.y; +dir.z -= lumaSe.y; +#endif +/*--------------------------------------------------------------------------*/ +// (5) +half4 dir1_pos; +dir1_pos.xy = normalize(dir.xz); +half dirAbsMinTimesC = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (6) +half4 dir2_pos; +dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimesC, half(-2.0), half(2.0)); +dir1_pos.zw = pos.xy; +dir2_pos.zw = pos.xy; +half4 temp1N; +temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (7) +temp1N = tex2D(tex, temp1N.xy); // h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); +half4 rgby1; +rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (8) +rgby1 = tex2D(tex, rgby1.xy); // h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); +rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (9) +half4 temp2N; +temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; +temp2N = tex2D(tex, temp2N.xy); // h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ +// (10) +half4 rgby2; +rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; +rgby2 = tex2D(tex, rgby2.xy); // h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); +rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (11) +// compilier moves these scalar ops up to other cycles +#if (FXAA_GREEN_AS_LUMA == 0) +half lumaMin = min(min(lumaNw.w, lumaSw.w), min(lumaNe.w, lumaSe.w)); +half lumaMax = max(max(lumaNw.w, lumaSw.w), max(lumaNe.w, lumaSe.w)); +#else +half lumaMin = min(min(lumaNw.y, lumaSw.y), min(lumaNe.y, lumaSe.y)); +half lumaMax = max(max(lumaNw.y, lumaSw.y), max(lumaNe.y, lumaSe.y)); +#endif +rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (12) +#if (FXAA_GREEN_AS_LUMA == 0) +bool twoTapLt = rgby2.w < lumaMin; +bool twoTapGt = rgby2.w > lumaMax; +#else +bool twoTapLt = rgby2.y < lumaMin; +bool twoTapGt = rgby2.y > lumaMax; +#endif +/*--------------------------------------------------------------------------*/ +// (13) +if(twoTapLt || twoTapGt) rgby2 = rgby1; +/*--------------------------------------------------------------------------*/ +return rgby2; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + +FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (WITH EARLY EXIT) + +============================================================================== +The code mostly matches the assembly. +I have a feeling that 14 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + +--fenable-bx2 --fastmath --fastprecision --nofloatbindings + +Use of FXAA_GREEN_AS_LUMA currently adds a cycle (16 clks). +Will look at fixing this for FXAA 3.12. +------------------------------------------------------------------------------ +NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: +0: texpkb h0.w(TRUE), v5.zyxx, #0 +2: addh h2.y(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x +4: texpkb h1.w(TRUE), v5.xwxx, #0 +6: addh h0.x(TRUE), h1.w, -h2.y +7: texpkb h2.w(TRUE), v5.zwzz, #0 +9: minh h4.w(TRUE), h2.y, h2 +10: maxh h5.x(TRUE), h2.y, h2.w +11: texpkb h0.w(TRUE), v5, #0 +13: addh h3.w(TRUE), -h0, h0.x +14: addh h0.x(TRUE), h0.w, h0 +15: addh h0.z(TRUE), -h2.w, h0.x +16: addh h0.x(TRUE), h2.w, h3.w +17: minh h5.y(TRUE), h0.w, h1.w +18: nrmh h2.xz(TRUE), h0_n +19: minh_m8 h2.w(TRUE), |h2.x|, |h2.z| +20: divx h4.xy(TRUE), h2_n.xzzw, h2_n.w +21: movr r1.zw(TRUE), v4.xxxy +22: maxh h2.w(TRUE), h0, h1 +23: fenct TRUE +24: madr r0.xy(TRUE), -h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz +26: texpkb h0(TRUE), r0, #0 +28: maxh h5.x(TRUE), h2.w, h5 +29: minh h5.w(TRUE), h5.y, h4 +30: madr r1.xy(TRUE), h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz +32: texpkb h2(TRUE), r1, #0 +34: addh_d2 h2(TRUE), h0, h2 +35: texpkb h1(TRUE), v4, #0 +37: maxh h5.y(TRUE), h5.x, h1.w +38: minh h4.w(TRUE), h1, h5 +39: madr r0.xy(TRUE), -h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz +41: texpkb h0(TRUE), r0, #0 +43: addh_m8 h5.z(TRUE), h5.y, -h4.w +44: madr r2.xy(TRUE), h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz +46: texpkb h3(TRUE), r2, #0 +48: addh_d2 h0(TRUE), h0, h3 +49: addh_d2 h3(TRUE), h0, h2 +50: movh h0(TRUE), h3 +51: slth h3.x(TRUE), h3.w, h5.w +52: sgth h3.w(TRUE), h3, h5.x +53: addx.c0 rc(TRUE), h3.x, h3 +54: slth.c0 rc(TRUE), h5.z, h5 +55: movh h0(c0.NE.w), h2 +56: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- +1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; +| TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; +| SCB0 | add | 2: ADDh h2.y, h0.-w--, const.-x--; +| | | +2 | SCT0/1 | mov | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; +| TEX | txl | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; +| SCB0 | add | 6: ADDh h0.x, h1.w---,-h2.y---; +| | | +3 | SCT0/1 | mov | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; +| TEX | txl | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; +| SCB0 | max | 10: MAXh h5.x, h2.y---, h2.w---; +| SCB1 | min | 9: MINh h4.w, h2.---y, h2; +| | | +4 | SCT0/1 | mov | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; +| TEX | txl | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; +| SCB0 | add | 14: ADDh h0.x, h0.w---, h0; +| SCB1 | add | 13: ADDh h3.w,-h0, h0.---x; +| | | +5 | SCT0 | mad | 16: ADDh h0.x, h2.w---, h3.w---; +| SCT1 | mad | 15: ADDh h0.z,-h2.--w-, h0.--x-; +| SCB0 | min | 17: MINh h5.y, h0.-w--, h1.-w--; +| | | +6 | SCT1 | mov | 18: NRMh h2.xz, h0; +| SRB | nrm | 18: NRMh h2.xz, h0; +| SCB1 | min | 19: MINh*8 h2.w, |h2.---x|, |h2.---z|; +| | | +7 | SCT0 | div | 20: DIVx h4.xy, h2.xz--, h2.ww--; +| SCT1 | mov | 21: MOVr r1.zw, g[TEX0].--xy; +| SCB1 | max | 22: MAXh h2.w, h0, h1; +| | | +8 | SCT0 | mad | 24: MADr r0.xy,-h2.xz--, const.zw--, r1.zw--; +| SCT1 | mov | 26: TXLr h0, r0, const.xxxx, TEX0; +| TEX | txl | 26: TXLr h0, r0, const.xxxx, TEX0; +| SCB0 | max | 28: MAXh h5.x, h2.w---, h5; +| SCB1 | min | 29: MINh h5.w, h5.---y, h4; +| | | +9 | SCT0 | mad | 30: MADr r1.xy, h2.xz--, const.zw--, r1.zw--; +| SCT1 | mov | 32: TXLr h2, r1, const.xxxx, TEX0; +| TEX | txl | 32: TXLr h2, r1, const.xxxx, TEX0; +| SCB0/1 | add | 34: ADDh/2 h2, h0, h2; +| | | +10 | SCT0/1 | mov | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; +| TEX | txl | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; +| SCB0 | max | 37: MAXh h5.y, h5.-x--, h1.-w--; +| SCB1 | min | 38: MINh h4.w, h1, h5; +| | | +11 | SCT0 | mad | 39: MADr r0.xy,-h4, const.xy--, r1.zw--; +| SCT1 | mov | 41: TXLr h0, r0, const.zzzz, TEX0; +| TEX | txl | 41: TXLr h0, r0, const.zzzz, TEX0; +| SCB0 | mad | 44: MADr r2.xy, h4, const.xy--, r1.zw--; +| SCB1 | add | 43: ADDh*8 h5.z, h5.--y-,-h4.--w-; +| | | +12 | SCT0/1 | mov | 46: TXLr h3, r2, const.xxxx, TEX0; +| TEX | txl | 46: TXLr h3, r2, const.xxxx, TEX0; +| SCB0/1 | add | 48: ADDh/2 h0, h0, h3; +| | | +13 | SCT0/1 | mad | 49: ADDh/2 h3, h0, h2; +| SCB0/1 | mul | 50: MOVh h0, h3; +| | | +14 | SCT0 | set | 51: SLTh h3.x, h3.w---, h5.w---; +| SCT1 | set | 52: SGTh h3.w, h3, h5.---x; +| SCB0 | set | 54: SLThc0 rc, h5.z---, h5; +| SCB1 | add | 53: ADDxc0_s rc, h3.---x, h3; +| | | +15 | SCT0/1 | mul | 55: MOVh h0(NE0.wwww), h2; +| SCB0/1 | mul | 56: MOVh h0(NE0.xxxx), h1; +Pass SCT TEX SCB +1: 0% 100% 25% +2: 0% 100% 25% +3: 0% 100% 50% +4: 0% 100% 50% +5: 50% 0% 25% +6: 0% 0% 25% +7: 100% 0% 25% +8: 0% 100% 50% +9: 0% 100% 100% +10: 0% 100% 50% +11: 0% 100% 75% +12: 0% 100% 100% +13: 100% 0% 100% +14: 50% 0% 50% +15: 100% 0% 100% + +MEAN: 26% 60% 56% + +Pass SCT0 SCT1 TEX SCB0 SCB1 +1: 0% 0% 100% 100% 0% +2: 0% 0% 100% 100% 0% +3: 0% 0% 100% 100% 100% +4: 0% 0% 100% 100% 100% +5: 100% 100% 0% 100% 0% +6: 0% 0% 0% 0% 100% +7: 100% 100% 0% 0% 100% +8: 0% 0% 100% 100% 100% +9: 0% 0% 100% 100% 100% +10: 0% 0% 100% 100% 100% +11: 0% 0% 100% 100% 100% +12: 0% 0% 100% 100% 100% +13: 100% 100% 0% 100% 100% +14: 100% 100% 0% 100% 100% +15: 100% 100% 0% 100% 100% + +MEAN: 33% 33% 60% 86% 80% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 15 cycles, 3 r regs, 800,000,000 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 1) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +//#pragma option O2 +//#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( +// See FXAA Quality FxaaPixelShader() source for docs on Inputs! +FxaaFloat2 pos, +FxaaFloat4 fxaaConsolePosPos, +FxaaTex tex, +//FxaaTex fxaaConsole360TexExpBiasNegOne, +//FxaaTex fxaaConsole360TexExpBiasNegTwo, +//FxaaFloat2 fxaaQualityRcpFrame, +FxaaFloat4 fxaaConsoleRcpFrameOpt, +FxaaFloat4 fxaaConsoleRcpFrameOpt2 +//FxaaFloat4 fxaaConsole360RcpFrameOpt, +//FxaaFloat fxaaQualitySubpix, +//FxaaFloat fxaaQualityEdgeThreshold, +//FxaaFloat fxaaQualityEdgeThresholdMin, +//FxaaFloat fxaaConsoleEdgeSharpness, +//FxaaFloat fxaaConsoleEdgeThreshold, +//FxaaFloat fxaaConsoleEdgeThresholdMin, +//FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) +half4 rgbyNe = tex2D(tex, fxaaConsolePosPos.zy); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +half lumaNe = rgbyNe.w + half(1.0/512.0); +#else +half lumaNe = rgbyNe.y + half(1.0/512.0); +#endif +/*--------------------------------------------------------------------------*/ +// (2) +half4 lumaSw = tex2D(tex, fxaaConsolePosPos.xw); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +half lumaSwNegNe = lumaSw.w - lumaNe; +#else +half lumaSwNegNe = lumaSw.y - lumaNe; +#endif +/*--------------------------------------------------------------------------*/ +// (3) +half4 lumaNw = tex2D(tex, fxaaConsolePosPos.xy); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +half lumaMaxNwSw = max(lumaNw.w, lumaSw.w); +half lumaMinNwSw = min(lumaNw.w, lumaSw.w); +#else +half lumaMaxNwSw = max(lumaNw.y, lumaSw.y); +half lumaMinNwSw = min(lumaNw.y, lumaSw.y); +#endif +/*--------------------------------------------------------------------------*/ +// (4) +half4 lumaSe = tex2D(tex, fxaaConsolePosPos.zw); // h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); +#if (FXAA_GREEN_AS_LUMA == 0) +half dirZ = lumaNw.w + lumaSwNegNe; +half dirX = -lumaNw.w + lumaSwNegNe; +#else +half dirZ = lumaNw.y + lumaSwNegNe; +half dirX = -lumaNw.y + lumaSwNegNe; +#endif +/*--------------------------------------------------------------------------*/ +// (5) +half3 dir; +dir.y = 0.0; +#if (FXAA_GREEN_AS_LUMA == 0) +dir.x = lumaSe.w + dirX; +dir.z = -lumaSe.w + dirZ; +half lumaMinNeSe = min(lumaNe, lumaSe.w); +#else +dir.x = lumaSe.y + dirX; +dir.z = -lumaSe.y + dirZ; +half lumaMinNeSe = min(lumaNe, lumaSe.y); +#endif +/*--------------------------------------------------------------------------*/ +// (6) +half4 dir1_pos; +dir1_pos.xy = normalize(dir).xz; +half dirAbsMinTimes8 = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (7) +half4 dir2_pos; +dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimes8, half(-2.0), half(2.0)); +dir1_pos.zw = pos.xy; +dir2_pos.zw = pos.xy; +#if (FXAA_GREEN_AS_LUMA == 0) +half lumaMaxNeSe = max(lumaNe, lumaSe.w); +#else +half lumaMaxNeSe = max(lumaNe, lumaSe.y); +#endif +/*--------------------------------------------------------------------------*/ +// (8) +half4 temp1N; +temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +temp1N = tex2D(tex, temp1N.xy); // h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); +half lumaMax = max(lumaMaxNwSw, lumaMaxNeSe); +half lumaMin = min(lumaMinNwSw, lumaMinNeSe); +/*--------------------------------------------------------------------------*/ +// (9) +half4 rgby1; +rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +rgby1 = tex2D(tex, rgby1.xy); // h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); +rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (10) +half4 rgbyM = tex2D(tex, pos.xy); // h4tex2Dlod(tex, half4(pos.xy, 0.0, 0.0)); +#if (FXAA_GREEN_AS_LUMA == 0) +half lumaMaxM = max(lumaMax, rgbyM.w); +half lumaMinM = min(lumaMin, rgbyM.w); +#else +half lumaMaxM = max(lumaMax, rgbyM.y); +half lumaMinM = min(lumaMin, rgbyM.y); +#endif +/*--------------------------------------------------------------------------*/ +// (11) +half4 temp2N; +temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; +temp2N = tex2D(tex, temp2N.xy); // h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); +half4 rgby2; +rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; +half lumaRangeM = (lumaMaxM - lumaMinM) / FXAA_CONSOLE__PS3_EDGE_THRESHOLD; +/*--------------------------------------------------------------------------*/ +// (12) +rgby2 = tex2D(tex, rgby2.xy); // h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); +rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (13) +rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (14) +#if (FXAA_GREEN_AS_LUMA == 0) +bool twoTapLt = rgby2.w < lumaMin; +bool twoTapGt = rgby2.w > lumaMax; +#else +bool twoTapLt = rgby2.y < lumaMin; +bool twoTapGt = rgby2.y > lumaMax; +#endif +bool earlyExit = lumaRangeM < lumaMax; +bool twoTap = twoTapLt || twoTapGt; +/*--------------------------------------------------------------------------*/ +// (15) +if(twoTap) rgby2 = rgby1; +if(earlyExit) rgby2 = rgbyM; +/*--------------------------------------------------------------------------*/ +return rgby2; } +/*==========================================================================*/ +#endif \ No newline at end of file diff --git a/code/nel/src/3d/shaders/fxaa_pp.cg b/code/nel/src/3d/shaders/fxaa_pp.cg new file mode 100644 index 000000000..49622f206 --- /dev/null +++ b/code/nel/src/3d/shaders/fxaa_pp.cg @@ -0,0 +1,91 @@ + +#define FXAA_PC 1 +#define FXAA_HLSL_3 1 +#define FXAA_QUALITY__PRESET 12 +#define FXAA_EARLY_EXIT 0 +#define FXAA_GREEN_AS_LUMA 1 + +#define h4tex2Dlod tex2Dlod +#define half4 float4 +#define half3 float3 +#define half2 float2 +#define half float + +#include "fxaa3_11.h" + +void fxaa_pp( + // Per fragment parameters + float2 pos : TEXCOORD0, +#if (FXAA_PS3 == 1) + float4 fxaaConsolePosPos : TEXCOORD1, +#endif + + // Fragment program constants +#if (FXAA_PC == 1) + uniform float2 fxaaQualityRcpFrame, + uniform float fxaaQualitySubpix, + uniform float fxaaQualityEdgeThreshold, + uniform float fxaaQualityEdgeThresholdMin, +#else + uniform float4 fxaaConsoleRcpFrameOpt, + uniform float4 fxaaConsoleRcpFrameOpt2, +#endif + uniform sampler2D nlTex0 : TEX0, + + // Output color + out float4 oCol : COLOR +) +{ +#if (FXAA_PC == 1) + oCol = FxaaPixelShader( + pos, + nlTex0, + fxaaQualityRcpFrame, + fxaaQualitySubpix, + fxaaQualityEdgeThreshold, + fxaaQualityEdgeThresholdMin + ); +#else + oCol = FxaaPixelShader( + pos, + fxaaConsolePosPos, + nlTex0, + fxaaConsoleRcpFrameOpt, + fxaaConsoleRcpFrameOpt2 + ); +#endif +} + +/* +Have FXAA vertex shader run as a full screen triangle, +and output "pos" and "fxaaConsolePosPos" +such that inputs in the pixel shader provide, + +// {xy} = center of pixel +FxaaFloat2 pos, + +// {xy__} = upper left of pixel +// {__zw} = lower right of pixel +FxaaFloat4 fxaaConsolePosPos, +*/ + +// fxaaConsoleRcpFrameOpt: +// Only used on FXAA Console. +// This must be from a constant/uniform. +// This effects sub-pixel AA quality and inversely sharpness. +// Where N ranges between, +// N = 0.50 (default) +// N = 0.33 (sharper) +// {x___} = -N/screenWidthInPixels +// {_y__} = -N/screenHeightInPixels +// {__z_} = N/screenWidthInPixels +// {___w} = N/screenHeightInPixels + +// fxaaConsoleRcpFrameOpt2: +// Only used on FXAA Console. +// Not used on 360, but used on PS3 and PC. +// This must be from a constant/uniform. +// {x___} = -2.0/screenWidthInPixels +// {_y__} = -2.0/screenHeightInPixels +// {__z_} = 2.0/screenWidthInPixels +// {___w} = 2.0/screenHeightInPixels diff --git a/code/nel/src/3d/shaders/fxaa_pp_arbfp1.txt b/code/nel/src/3d/shaders/fxaa_pp_arbfp1.txt new file mode 100644 index 000000000..5a498ed61 --- /dev/null +++ b/code/nel/src/3d/shaders/fxaa_pp_arbfp1.txt @@ -0,0 +1,300 @@ +!!ARBfp1.0 +OPTION ARB_precision_hint_fastest; +# cgc version 3.1.0013, build date Apr 18 2012 +# command line args: -profile arbfp1 -O3 -fastmath -fastprecision +# source file: fxaa_pp.cg +#vendor NVIDIA Corporation +#version 3.1.0.13 +#profile arbfp1 +#program fxaa_pp +#semantic fxaa_pp.fxaaQualityRcpFrame +#semantic fxaa_pp.fxaaQualitySubpix +#semantic fxaa_pp.fxaaQualityEdgeThreshold +#semantic fxaa_pp.fxaaQualityEdgeThresholdMin +#semantic fxaa_pp.nlTex0 : TEX0 +#var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1 +#var float2 fxaaQualityRcpFrame : : c[0] : 1 : 1 +#var float fxaaQualitySubpix : : c[1] : 2 : 1 +#var float fxaaQualityEdgeThreshold : : c[2] : 3 : 1 +#var float fxaaQualityEdgeThresholdMin : : c[3] : 4 : 1 +#var sampler2D nlTex0 : TEX0 : texunit 0 : 5 : 1 +#var float4 oCol : $vout.COLOR : COL : 6 : 1 +#const c[4] = 0 -1 1 -2 +#const c[5] = 2 0.5 0.25 1.5 +#const c[6] = 4 12 0.083333336 3 +PARAM c[7] = { program.local[0..3], + { 0, -1, 1, -2 }, + { 2, 0.5, 0.25, 1.5 }, + { 4, 12, 0.083333336, 3 } }; +TEMP R0; +TEMP R1; +TEMP R2; +TEMP R3; +TEMP R4; +TEMP R5; +TEMP R6; +TEMP R7; +TEMP R8; +TEMP R9; +MOV R3.xyz, c[4]; +MAD R2.zw, R3.xyyz, c[0].xyxy, fragment.texcoord[0].xyxy; +MAD R0.xy, R3, c[0], fragment.texcoord[0]; +MAD R1.xy, R3.zyzw, c[0], fragment.texcoord[0]; +TEX R5.y, R1, texture[0], 2D; +MAD R1.xy, R3.zxzw, c[0], fragment.texcoord[0]; +ADD R0.zw, fragment.texcoord[0].xyxy, -c[0].xyxy; +TEX R4.y, R0.zwzw, texture[0], 2D; +TEX R6.y, R2.zwzw, texture[0], 2D; +TEX R8, fragment.texcoord[0], texture[0], 2D; +TEX R1.y, R1, texture[0], 2D; +TEX R0.y, R0, texture[0], 2D; +ADD R0.z, R4.y, R5.y; +MAD R1.z, R0.y, c[4].w, R0; +MAD R0.zw, R3.xyyx, c[0].xyxy, fragment.texcoord[0].xyxy; +TEX R2.y, R0.zwzw, texture[0], 2D; +ADD R0.x, R2.y, R1.y; +ABS R0.w, R1.z; +ADD R1.zw, fragment.texcoord[0].xyxy, c[0].xyxy; +TEX R7.y, R1.zwzw, texture[0], 2D; +MAD R0.z, R8.y, c[4].w, R0.x; +ABS R0.z, R0; +MAD R2.x, R0.z, c[5], R0.w; +MAD R0.zw, R3.xyxz, c[0].xyxy, fragment.texcoord[0].xyxy; +TEX R3.y, R0.zwzw, texture[0], 2D; +ADD R0.z, R0.y, R3.y; +ADD R1.x, R6.y, R7.y; +MAD R0.w, R3.y, c[4], R1.x; +MAD R1.x, R8.y, c[4].w, R0.z; +ABS R0.w, R0; +ADD R2.x, R0.w, R2; +ADD R2.w, R4.y, R6.y; +ADD R0.w, R5.y, R7.y; +ABS R1.z, R1.x; +MAD R1.x, R1.y, c[4].w, R0.w; +ABS R1.w, R1.x; +MAD R1.x, R2.y, c[4].w, R2.w; +MAD R1.z, R1, c[5].x, R1.w; +ABS R1.x, R1; +ADD R1.x, R1, R1.z; +SGE R4.x, R1, R2; +MAX R1.x, R3.y, R8.y; +MAX R1.z, R1.y, R1.x; +MAX R1.x, R0.y, R2.y; +MAX R1.x, R1, R1.z; +MIN R1.z, R3.y, R8.y; +MIN R1.w, R1.y, R1.z; +MIN R1.z, R0.y, R2.y; +MIN R1.z, R1, R1.w; +MUL R2.x, R1, c[2]; +ADD R3.z, R1.x, -R1; +ABS R3.w, R4.x; +MAX R1.w, R2.x, c[3].x; +ADD R2.z, R3, -R1.w; +CMP R2.x, R2.z, c[4], c[4].z; +CMP R1.x, -R3.w, c[4], c[4].z; +MUL R3.w, R2.x, R1.x; +CMP R1.z, -R3.w, R1.y, R3.y; +ADD R1.y, -R8, R1.z; +CMP R1.w, -R3, R2.y, R0.y; +ADD R0.y, -R8, R1.w; +MUL R4.x, R2, R4; +CMP R3.y, -R3.w, c[0], R3.x; +ABS R4.w, R1.y; +ABS R4.z, R0.y; +SGE R0.y, R4.z, R4.w; +MUL R1.y, R2.x, R0; +ABS R0.y, R0; +CMP R4.y, -R0, c[4].x, c[4].z; +ABS R0.y, R1.x; +CMP R0.y, -R0, c[4].x, c[4].z; +MUL R1.x, R2, R0.y; +CMP R2.y, -R4.x, c[0], c[0].x; +CMP R2.y, -R1, -R2, R2; +MAD R1.y, R2, c[5], fragment.texcoord[0]; +CMP R5.z, -R4.x, R1.y, fragment.texcoord[0].y; +ADD R5.y, R5.z, -R3; +MAD R0.y, R2, c[5], fragment.texcoord[0].x; +CMP R3.x, -R1, c[0], R3; +CMP R6.x, -R3.w, R0.y, fragment.texcoord[0]; +ADD R5.w, R5.z, R3.y; +ADD R1.x, R6, -R3; +MOV R1.y, R5; +TEX R0.y, R1, texture[0], 2D; +MUL R1.y, R2.x, R4; +ADD R0.x, R0.z, R0; +ADD R0.w, R2, R0; +MAD R0.z, R0.x, c[5].x, R0.w; +ADD R1.w, R8.y, R1; +ADD R1.z, R8.y, R1; +CMP R4.y, -R1, R1.z, R1.w; +ADD R1.z, R6.x, R3.x; +MAD R5.x, -R4.y, c[5].y, R0.y; +MOV R1.w, R5; +TEX R0.y, R1.zwzw, texture[0], 2D; +MAX R1.w, R4.z, R4; +MAD R1.y, -R4, c[5], R0; +MUL R4.z, R1.w, c[5]; +ABS R0.y, R1; +SGE R1.w, R0.y, R4.z; +ABS R6.y, R5.x; +SGE R0.y, R6, R4.z; +ABS R1.w, R1; +CMP R6.y, -R1.w, c[4].x, c[4].z; +ABS R0.y, R0; +CMP R5.z, -R0.y, c[4].x, c[4]; +ADD_SAT R0.y, R5.z, R6; +MUL R4.w, R2.x, R0.y; +MUL R0.y, R2.x, R6; +MAD R1.w, R3.y, c[5], R5; +CMP R6.x, -R0.y, R1.w, R5.w; +MAD R6.z, R3.x, c[5].w, R1; +CMP R1.z, -R0.y, R6, R1; +MOV R1.w, R6.x; +TEX R0.y, R1.zwzw, texture[0], 2D; +MUL R1.w, R4, R6.y; +CMP R6.y, -R1.w, R0, R1; +MUL R0.y, R2.x, R5.z; +MAD R1.y, -R3, c[5].w, R5; +CMP R5.w, -R0.y, R1.y, R5.y; +MAD R6.z, -R3.x, c[5].w, R1.x; +CMP R1.x, -R0.y, R6.z, R1; +MOV R1.y, R5.w; +TEX R0.y, R1, texture[0], 2D; +MUL R5.y, R4.w, R5.z; +CMP R0.y, -R5, R0, R5.x; +MAD R5.x, -R4.y, c[5].y, R0.y; +CMP R5.z, -R5.y, R5.x, R0.y; +MAD R1.y, -R4, c[5], R6; +CMP R1.y, -R1.w, R1, R6; +ABS R1.w, R1.y; +SGE R1.w, R1, R4.z; +ABS R0.y, R5.z; +SGE R0.y, R0, R4.z; +ABS R1.w, R1; +CMP R6.y, -R1.w, c[4].x, c[4].z; +ABS R0.y, R0; +CMP R5.y, -R0, c[4].x, c[4].z; +ADD_SAT R0.y, R5, R6; +MUL R5.x, R4.w, R0.y; +MUL R0.y, R4.w, R6; +MAD R1.w, R3.y, c[5].x, R6.x; +CMP R6.x, -R0.y, R1.w, R6; +MAD R6.z, R3.x, c[5].x, R1; +CMP R1.z, -R0.y, R6, R1; +MOV R1.w, R6.x; +TEX R0.y, R1.zwzw, texture[0], 2D; +MUL R1.w, R5.x, R6.y; +CMP R6.y, -R1.w, R0, R1; +MUL R0.y, R4.w, R5; +MAD R1.y, -R3, c[5].x, R5.w; +CMP R4.w, -R0.y, R1.y, R5; +MAD R6.z, -R3.x, c[5].x, R1.x; +CMP R1.x, -R0.y, R6.z, R1; +MOV R1.y, R4.w; +TEX R0.y, R1, texture[0], 2D; +MUL R5.y, R5.x, R5; +CMP R0.y, -R5, R0, R5.z; +MAD R5.z, -R4.y, c[5].y, R0.y; +CMP R5.w, -R5.y, R5.z, R0.y; +MAD R1.y, -R4, c[5], R6; +CMP R1.y, -R1.w, R1, R6; +ABS R1.w, R1.y; +SGE R1.w, R1, R4.z; +ABS R1.w, R1; +CMP R6.y, -R1.w, c[4].x, c[4].z; +ABS R0.y, R5.w; +SGE R0.y, R0, R4.z; +ABS R0.y, R0; +CMP R5.y, -R0, c[4].x, c[4].z; +ADD_SAT R0.y, R5, R6; +MUL R5.z, R5.x, R0.y; +MUL R0.y, R5.x, R6; +MAD R1.w, R3.y, c[6].x, R6.x; +CMP R6.x, -R0.y, R1.w, R6; +MAD R6.z, R3.x, c[6].x, R1; +CMP R1.z, -R0.y, R6, R1; +MOV R1.w, R6.x; +TEX R0.y, R1.zwzw, texture[0], 2D; +MUL R1.w, R5.z, R6.y; +CMP R6.y, -R1.w, R0, R1; +MUL R0.y, R5.x, R5; +MAD R1.y, -R3, c[6].x, R4.w; +CMP R4.w, -R0.y, R1.y, R4; +MAD R5.x, -R3, c[6], R1; +CMP R1.x, -R0.y, R5, R1; +MOV R1.y, R4.w; +TEX R0.y, R1, texture[0], 2D; +MUL R1.y, R5.z, R5; +CMP R5.x, -R1.y, R0.y, R5.w; +MAD R5.y, -R4, c[5], R5.x; +CMP R1.y, -R1, R5, R5.x; +MAD R0.y, -R4, c[5], R6; +CMP R0.y, -R1.w, R0, R6; +ABS R5.x, R0.y; +ABS R1.w, R1.y; +SGE R1.w, R1, R4.z; +SGE R5.x, R5, R4.z; +ABS R4.z, R5.x; +ABS R1.w, R1; +CMP R4.z, -R4, c[4].x, c[4]; +CMP R1.w, -R1, c[4].x, c[4].z; +MUL R4.z, R5, R4; +MAD R5.y, R3.x, c[6], R1.z; +CMP R5.y, -R4.z, R5, R1.z; +MAD R5.x, R3.y, c[6].y, R6; +CMP R1.z, -R4, R5.x, R6.x; +MUL R1.w, R5.z, R1; +ADD R4.z, -fragment.texcoord[0].x, R5.y; +ADD R1.z, -fragment.texcoord[0].y, R1; +CMP R1.z, -R3.w, R1, R4; +MAD R4.z, -R3.x, c[6].y, R1.x; +MAD R3.x, -R3.y, c[6].y, R4.w; +CMP R3.y, -R1.w, R4.z, R1.x; +CMP R1.x, -R1.w, R3, R4.w; +ADD R1.w, fragment.texcoord[0].x, -R3.y; +ADD R1.x, fragment.texcoord[0].y, -R1; +CMP R1.x, -R3.w, R1, R1.w; +SLT R1.w, R1.x, R1.z; +ADD R3.x, R1, R1.z; +ABS R1.w, R1; +MIN R1.x, R1, R1.z; +CMP R1.w, -R1, c[4].x, c[4].z; +MUL R1.z, R2.x, R1.w; +RCP R3.x, R3.x; +MAD R1.x, R1, -R3, c[5].y; +MUL R1.w, R4.y, c[5].y; +SLT R3.x, R1.y, c[4]; +SLT R1.y, R8, R1.w; +SLT R0.y, R0, c[4].x; +ADD R0.y, R0, -R1; +ADD R1.y, -R1, R3.x; +ABS R0.y, R0; +ABS R1.y, R1; +CMP R0.y, -R0, c[4].z, c[4].x; +CMP R1.y, -R1, c[4].z, c[4].x; +CMP R0.x, -R1.z, R0.y, R1.y; +MAD R0.y, R0.z, c[6].z, -R8; +ABS R0.x, R0; +CMP R0.x, -R0, c[4], c[4].z; +MUL R0.x, R2, R0; +CMP R0.x, -R0, c[4], R1; +RCP R0.z, R3.z; +ABS R0.y, R0; +MUL_SAT R0.y, R0, R0.z; +MUL R0.z, R0.y, c[4].w; +ADD R0.z, R0, c[6].w; +MUL R0.y, R0, R0; +MUL R0.y, R0.z, R0; +MUL R0.y, R0, R0; +MUL R0.y, R0, c[1].x; +MAX R0.x, R0, R0.y; +MAD R0.y, R0.x, R2, fragment.texcoord[0]; +MAD R0.z, R0.x, R2.y, fragment.texcoord[0].x; +CMP R0.x, -R3.w, R0.z, fragment.texcoord[0]; +CMP R0.y, -R4.x, R0, fragment.texcoord[0]; +TEX R0.xyz, R0, texture[0], 2D; +CMP R1, R2.z, R8, R9; +MOV R0.w, R8.y; +CMP result.color, -R2.x, R0, R1; +END +# 260 instructions, 10 R-regs diff --git a/code/nel/src/3d/shaders/fxaa_pp_ps_2_0.txt b/code/nel/src/3d/shaders/fxaa_pp_ps_2_0.txt new file mode 100644 index 000000000..de51eba42 --- /dev/null +++ b/code/nel/src/3d/shaders/fxaa_pp_ps_2_0.txt @@ -0,0 +1,306 @@ +ps_2_x +// cgc version 3.1.0013, build date Apr 18 2012 +// command line args: -profile ps_2_x -O3 -fastmath -fastprecision +// source file: fxaa_pp.cg +//vendor NVIDIA Corporation +//version 3.1.0.13 +//profile ps_2_x +//program fxaa_pp +//semantic fxaa_pp.fxaaQualityRcpFrame +//semantic fxaa_pp.fxaaQualitySubpix +//semantic fxaa_pp.fxaaQualityEdgeThreshold +//semantic fxaa_pp.fxaaQualityEdgeThresholdMin +//semantic fxaa_pp.nlTex0 : TEX0 +//var float2 pos : $vin.TEXCOORD0 : TEX0 : 0 : 1 +//var float2 fxaaQualityRcpFrame : : c[0] : 1 : 1 +//var float fxaaQualitySubpix : : c[1] : 2 : 1 +//var float fxaaQualityEdgeThreshold : : c[2] : 3 : 1 +//var float fxaaQualityEdgeThresholdMin : : c[3] : 4 : 1 +//var sampler2D nlTex0 : TEX0 : texunit 0 : 5 : 1 +//var float4 oCol : $vout.COLOR : COL : 6 : 1 +//const c[4] = 0 -1 1 -2 +//const c[5] = 2 0.5 0.25 1.5 +//const c[6] = 4 12 0.083333336 +//const c[7] = -2 3 +dcl_2d s0 +def c4, 0.00000000, -1.00000000, 1.00000000, -2.00000000 +def c5, 2.00000000, 0.50000000, 0.25000000, 1.50000000 +def c6, 4.00000000, 12.00000000, 0.08333334, 0 +def c7, -2.00000000, 3.00000000, 0, 0 +dcl t0.xy +mov r0.zw, c0.xyxy +mad r3.xy, c4.zxzw, r0.zwzw, t0 +texld r7, r3, s0 +texld r1, t0, s0 +mov r0.xy, c0 +mad r0.xy, c4.yxzw, r0, t0 +texld r8, r0, s0 +mov r0.xy, c0 +mad r0.xy, c4, r0, t0 +texld r9, r0, s0 +add r0.xy, t0, -c0 +texld r5, r0, s0 +mov r3.xy, c0 +mad r3.xy, c4.zyzw, r3, t0 +texld r3, r3, s0 +add r7.x, r8.y, r7.y +mad r0.z, r1.y, c4.w, r7.x +add r0.x, r5.y, r3.y +mad r0.w, r9.y, c4, r0.x +mov r0.xy, c0 +mad r0.xy, c4.xzzw, r0, t0 +texld r6, r0, s0 +add r5.x, r9.y, r6.y +abs r0.z, r0 +abs r0.w, r0 +mad r3.x, r0.z, c5, r0.w +mov r0.zw, c0.xyxy +mad r4.xy, c4.yzzw, r0.zwzw, t0 +texld r4, r4, s0 +add r0.xy, t0, c0 +texld r0, r0, s0 +add r4.x, r5.y, r4.y +add r5.y, r3, r0 +add r0.x, r4.y, r0.y +mad r0.x, r6.y, c4.w, r0 +abs r0.x, r0 +add r0.w, r0.x, r3.x +mad r0.x, r8.y, c4.w, r4 +mad r0.z, r7.y, c4.w, r5.y +mad r0.y, r1, c4.w, r5.x +abs r0.z, r0 +abs r0.y, r0 +mad r0.y, r0, c5.x, r0.z +abs r0.x, r0 +add r0.x, r0, r0.y +add r0.x, r0, -r0.w +cmp r3.y, r0.x, c4.z, c4.x +max r0.y, r6, r1 +max r0.z, r7.y, r0.y +max r0.y, r9, r8 +max r0.y, r0, r0.z +min r0.z, r6.y, r1.y +min r0.w, r7.y, r0.z +min r0.z, r9.y, r8.y +min r0.z, r0, r0.w +mul r3.x, r0.y, c2 +abs_pp r0.x, r3.y +add r4.y, r0, -r0.z +max r0.w, r3.x, c3.x +add r4.z, r4.y, -r0.w +cmp_pp r4.w, r4.z, c4.z, c4.x +mul_pp r5.w, r4, r3.y +cmp_pp r0.y, -r0.x, c4.z, c4.x +mul_pp r5.z, r4.w, r0.y +cmp_pp r3.x, -r0, c4, c4.z +cmp r6.w, -r5.z, r6.y, r7.y +cmp r7.w, -r5.z, r9.y, r8.y +add r0.z, -r1.y, r6.w +add r0.y, -r1, r7.w +abs r9.z, r0 +abs r7.y, r0 +add r0.y, r7, -r9.z +cmp r0.y, r0, c4.z, c4.x +max r7.y, r7, r9.z +mul_pp r0.z, r4.w, r0.y +cmp r0.w, -r5, c0.x, c0.y +cmp r6.x, -r0.z, r0.w, -r0.w +mov r0.z, c0.y +cmp r6.y, -r5.z, c4.x, r0.z +mad r0.w, r6.x, c5.y, t0.y +cmp r0.z, -r5.w, t0.y, r0.w +add r8.z, r0, r6.y +add r7.z, r0, -r6.y +mov r9.y, r7.z +mov r8.y, r8.z +mad r0.w, r6.x, c5.y, t0.x +mov r0.x, c0 +mul_pp r3.x, r4.w, r3 +cmp r6.z, -r3.x, c4.x, r0.x +cmp r0.x, -r5.z, t0, r0.w +add r9.x, r0, -r6.z +texld r3, r9, s0 +add r8.x, r0, r6.z +abs_pp r3.x, r0.y +texld r0, r8, s0 +cmp_pp r0.x, -r3, c4.z, c4 +add r0.w, r1.y, r6 +add r0.z, r1.y, r7.w +mul_pp r0.x, r4.w, r0 +cmp r6.w, -r0.x, r0.z, r0 +mad r7.w, -r6, c5.y, r0.y +mad r8.w, -r6, c5.y, r3.y +abs r0.y, r7.w +abs r0.x, r8.w +mad r0.x, -r7.y, c5.z, r0 +mad r0.y, -r7, c5.z, r0 +cmp r0.x, r0, c4.z, c4 +abs_pp r0.x, r0 +cmp_pp r9.z, -r0.x, c4, c4.x +cmp r0.y, r0, c4.z, c4.x +abs_pp r0.y, r0 +cmp_pp r9.w, -r0.y, c4.z, c4.x +mul_pp r0.x, r4.w, r9.z +mad r0.y, -r6, c5.w, r7.z +cmp r7.z, -r0.x, r7, r0.y +mad r0.z, -r6, c5.w, r9.x +cmp r9.x, -r0, r9, r0.z +mov r9.y, r7.z +texld r3, r9, s0 +add_pp_sat r3.z, r9, r9.w +mul_pp r0.x, r4.w, r9.w +mad r0.y, r6, c5.w, r8.z +cmp r3.x, -r0, r8.z, r0.y +mad r0.z, r6, c5.w, r8.x +mul_pp r8.z, r4.w, r3 +cmp r8.x, -r0, r8, r0.z +mov r8.y, r3.x +texld r0, r8, s0 +mul_pp r0.w, r8.z, r9 +cmp r3.z, -r0.w, r7.w, r0.y +mul_pp r0.x, r8.z, r9.z +cmp r0.y, -r0.x, r8.w, r3 +mad r0.z, -r6.w, c5.y, r0.y +cmp r8.w, -r0.x, r0.y, r0.z +mad r3.y, -r6.w, c5, r3.z +cmp r9.w, -r0, r3.z, r3.y +abs r0.y, r9.w +abs r0.x, r8.w +mad r0.y, -r7, c5.z, r0 +mad r0.x, -r7.y, c5.z, r0 +cmp r0.y, r0, c4.z, c4.x +abs_pp r0.y, r0 +cmp_pp r10.x, -r0.y, c4.z, c4 +cmp r0.x, r0, c4.z, c4 +abs_pp r0.x, r0 +cmp_pp r9.z, -r0.x, c4, c4.x +mul_pp r0.x, r8.z, r10 +mad r0.y, r6, c5.x, r3.x +cmp r7.w, -r0.x, r3.x, r0.y +mad r0.z, r6, c5.x, r8.x +cmp r8.x, -r0, r8, r0.z +mov r8.y, r7.w +texld r0, r8, s0 +mul_pp r0.w, r8.z, r9.z +mad r3.x, -r6.z, c5, r9 +mad r0.x, -r6.y, c5, r7.z +cmp r0.x, -r0.w, r7.z, r0 +add_pp_sat r0.z, r9, r10.x +mul_pp r7.z, r8, r0 +cmp r9.x, -r0.w, r9, r3 +mov r9.y, r0.x +texld r3, r9, s0 +mul_pp r0.z, r7, r9 +cmp r0.w, -r0.z, r8, r3.y +mul_pp r3.x, r7.z, r10 +cmp r3.y, -r3.x, r9.w, r0 +mad r0.y, -r6.w, c5, r0.w +cmp r8.z, -r0, r0.w, r0.y +mad r3.z, -r6.w, c5.y, r3.y +cmp r9.z, -r3.x, r3.y, r3 +abs r0.y, r8.z +abs r0.z, r9 +mad r0.y, -r7, c5.z, r0 +mad r0.z, -r7.y, c5, r0 +cmp r0.y, r0, c4.z, c4.x +abs_pp r0.y, r0 +cmp_pp r8.w, -r0.y, c4.z, c4.x +cmp r0.z, r0, c4, c4.x +abs_pp r0.z, r0 +cmp_pp r9.w, -r0.z, c4.z, c4.x +mul_pp r0.y, r7.z, r8.w +mad r0.z, -r6.y, c6.x, r0.x +cmp r10.x, -r0.y, r0, r0.z +mad r0.w, -r6.z, c6.x, r9.x +cmp r9.x, -r0.y, r9, r0.w +mov r9.y, r10.x +texld r3, r9, s0 +mul_pp r0.x, r7.z, r9.w +mad r0.z, r6, c6.x, r8.x +mad r0.y, r6, c6.x, r7.w +cmp r3.x, -r0, r7.w, r0.y +cmp r8.x, -r0, r8, r0.z +mov r8.y, r3.x +texld r0, r8, s0 +add_pp_sat r3.z, r8.w, r9.w +mul_pp r0.x, r7.z, r3.z +mul_pp r3.z, r0.x, r9.w +cmp r0.y, -r3.z, r9.z, r0 +mul_pp r0.z, r0.x, r8.w +cmp r0.w, -r0.z, r8.z, r3.y +mad r3.w, -r6, c5.y, r0.y +cmp r0.y, -r3.z, r0, r3.w +mad r3.y, -r6.w, c5, r0.w +cmp r0.z, -r0, r0.w, r3.y +abs r3.y, r0 +abs r0.w, r0.z +mad r3.y, -r7, c5.z, r3 +mad r0.w, -r7.y, c5.z, r0 +cmp r3.y, r3, c4.z, c4.x +abs_pp r3.y, r3 +cmp r0.w, r0, c4.z, c4.x +cmp_pp r3.z, -r3.y, c4, c4.x +abs_pp r0.w, r0 +cmp_pp r3.y, -r0.w, c4.z, c4.x +mul_pp r0.w, r0.x, r3.z +mul_pp r0.x, r0, r3.y +mad r3.w, r6.y, c6.y, r3.x +cmp r3.x, -r0.w, r3, r3.w +mad r3.z, r6, c6.y, r8.x +cmp r0.w, -r0, r8.x, r3.z +mad r3.y, -r6, c6, r10.x +cmp r3.y, -r0.x, r10.x, r3 +add r3.x, -t0.y, r3 +add r0.w, -t0.x, r0 +cmp r0.w, -r5.z, r0, r3.x +mad r3.x, -r6.z, c6.y, r9 +cmp r0.x, -r0, r9, r3 +add r3.x, t0.y, -r3.y +add r0.x, t0, -r0 +cmp r0.x, -r5.z, r0, r3 +add r3.x, r0, -r0.w +add r3.y, r0.x, r0.w +cmp r3.x, r3, c4, c4.z +abs_pp r3.x, r3 +min r0.x, r0, r0.w +cmp_pp r3.x, -r3, c4.z, c4 +mul_pp r0.w, r4, r3.x +rcp r3.y, r3.y +mad r0.x, r0, -r3.y, c5.y +cmp r3.y, r0, c4.x, c4.z +mad r3.x, -r6.w, c5.y, r1.y +cmp r3.x, r3, c4, c4.z +cmp r0.y, r0.z, c4.x, c4.z +add_pp r0.z, -r3.x, r3.y +add_pp r0.y, r0, -r3.x +abs_pp r0.y, r0 +abs_pp r0.z, r0 +cmp_pp r0.z, -r0, c4.x, c4 +cmp_pp r0.y, -r0, c4.x, c4.z +cmp_pp r0.y, -r0.w, r0, r0.z +abs_pp r0.y, r0 +cmp_pp r0.y, -r0, c4.z, c4.x +mul_pp r0.y, r4.w, r0 +rcp r0.w, r4.y +cmp r0.x, -r0.y, r0, c4 +add r3.y, r4.x, r5 +add r3.x, r5, r7 +mad r3.x, r3, c5, r3.y +mad r0.z, r3.x, c6, -r1.y +abs r0.z, r0 +mul_sat r0.z, r0, r0.w +mul r0.w, r0.z, r0.z +mad r0.z, r0, c7.x, c7.y +mul r0.z, r0, r0.w +mul r0.z, r0, r0 +mul r0.z, r0, c1.x +max r0.x, r0, r0.z +mad r0.y, r0.x, r6.x, t0 +mad r0.z, r0.x, r6.x, t0.x +cmp r0.x, -r5.z, t0, r0.z +cmp r0.y, -r5.w, t0, r0 +texld r0, r0, s0 +mov r0.w, r1.y +cmp r1, r4.z, r2, r1 +cmp r0, -r4.w, r1, r0 +mov oC0, r0 diff --git a/code/nel/src/3d/shaders/fxaa_vp.cg b/code/nel/src/3d/shaders/fxaa_vp.cg new file mode 100644 index 000000000..13c9c9bcb --- /dev/null +++ b/code/nel/src/3d/shaders/fxaa_vp.cg @@ -0,0 +1,20 @@ + +void fxaa_vp( + // Per vertex parameters + float3 position : POSITION, + float2 texCoord0 : TEXCOORD0, + + // Vertex program constants + uniform float4x4 modelViewProjection, + uniform float4 fxaaConsolePosPos, + + // Output position + out float4 oPosition : POSITION, + out float2 oTexCoord0 : TEXCOORD0, + out float4 oTexCoord1 : TEXCOORD1 +) +{ + oPosition = mul(modelViewProjection, float4(position, 0.0)); + oTexCoord0 = texCoord0; + oTexCoord1 = texCoord0.xyxy + fxaaConsolePosPos; +} diff --git a/code/nel/src/3d/shaders/fxaa_vp_arbvp1.txt b/code/nel/src/3d/shaders/fxaa_vp_arbvp1.txt new file mode 100644 index 000000000..6c8530ae0 --- /dev/null +++ b/code/nel/src/3d/shaders/fxaa_vp_arbvp1.txt @@ -0,0 +1,31 @@ +!!ARBvp1.0 +# cgc version 3.1.0013, build date Apr 18 2012 +# command line args: -profile arbvp1 -fastmath -fastprecision +# source file: fxaa_vp.cg +#vendor NVIDIA Corporation +#version 3.1.0.13 +#profile arbvp1 +#program fxaa_vp +#semantic fxaa_vp.modelViewProjection +#semantic fxaa_vp.fxaaConsolePosPos +#var float3 position : $vin.POSITION : POSITION : 0 : 1 +#var float2 texCoord0 : $vin.TEXCOORD0 : TEXCOORD0 : 1 : 1 +#var float4x4 modelViewProjection : : c[1], 4 : 2 : 1 +#var float4 fxaaConsolePosPos : : c[5] : 3 : 1 +#var float4 oPosition : $vout.POSITION : HPOS : 4 : 1 +#var float2 oTexCoord0 : $vout.TEXCOORD0 : TEX0 : 5 : 1 +#var float4 oTexCoord1 : $vout.TEXCOORD1 : TEX1 : 6 : 1 +#const c[0] = 0 +PARAM c[6] = { { 0 }, + program.local[1..5] }; +TEMP R0; +MOV R0.w, c[0].x; +MOV R0.xyz, vertex.position; +DP4 result.position.w, R0, c[4]; +DP4 result.position.z, R0, c[3]; +DP4 result.position.y, R0, c[2]; +DP4 result.position.x, R0, c[1]; +ADD result.texcoord[1], vertex.texcoord[0].xyxy, c[5]; +MOV result.texcoord[0].xy, vertex.texcoord[0]; +END +# 8 instructions, 1 R-regs diff --git a/code/nel/src/3d/shaders/readme.txt b/code/nel/src/3d/shaders/readme.txt new file mode 100644 index 000000000..fe657f6e5 --- /dev/null +++ b/code/nel/src/3d/shaders/readme.txt @@ -0,0 +1,4 @@ +Compiled shaders are embedded in the source. +Must compile and re-embed manually. + +FXAA is in public domain. \ No newline at end of file diff --git a/code/nel/src/3d/stereo_debugger.cpp b/code/nel/src/3d/stereo_debugger.cpp index 34a348c80..6650e1c2b 100644 --- a/code/nel/src/3d/stereo_debugger.cpp +++ b/code/nel/src/3d/stereo_debugger.cpp @@ -26,7 +26,7 @@ */ #if !FINAL_VERSION -#include +#include "std3d.h" #include // STL includes @@ -42,6 +42,7 @@ #include #include #include +#include using namespace std; // using namespace NLMISC; @@ -137,8 +138,6 @@ CStereoDebugger::CStereoDebugger() : m_Driver(NULL), m_Stage(0), m_SubStage(0), CStereoDebugger::~CStereoDebugger() { - releaseTextures(); - if (!m_Mat.empty()) { m_Driver->deleteMaterial(m_Mat); @@ -188,8 +187,6 @@ void CStereoDebugger::setDriver(NL3D::UDriver *driver) if (m_PixelProgram) { - initTextures(); - m_Mat = m_Driver->createMaterial(); m_Mat.initUnlit(); m_Mat.setColor(CRGBA::White); @@ -202,8 +199,6 @@ void CStereoDebugger::setDriver(NL3D::UDriver *driver) mat->setZFunc(CMaterial::always); mat->setDoubleSided(true); - setTextures(); - m_QuadUV.V0 = CVector(0.f, 0.f, 0.5f); m_QuadUV.V1 = CVector(1.f, 0.f, 0.5f); m_QuadUV.V2 = CVector(1.f, 1.f, 0.5f); @@ -216,6 +211,42 @@ void CStereoDebugger::setDriver(NL3D::UDriver *driver) } } +bool CStereoDebugger::attachToDisplay() +{ + return false; +} + +void CStereoDebugger::detachFromDisplay() +{ + +} + +void CStereoDebugger::getTextures() +{ + nlassert(!m_LeftTexU); + nlassert(!m_RightTexU); + uint32 width, height; + m_Driver->getWindowSize(width, height); + m_LeftTexU = m_Driver->getRenderTargetManager().getRenderTarget(width, height); + m_RightTexU = m_Driver->getRenderTargetManager().getRenderTarget(width, height); + NL3D::CMaterial *mat = m_Mat.getObjectPtr(); + mat->setTexture(0, m_LeftTexU->getITexture()); + mat->setTexture(1, m_RightTexU->getITexture()); +} + +void CStereoDebugger::recycleTextures() +{ + nlassert(m_LeftTexU); + nlassert(m_RightTexU); + m_Mat.getObjectPtr()->setTexture(0, NULL); + m_Mat.getObjectPtr()->setTexture(1, NULL); + m_Driver->getRenderTargetManager().recycleRenderTarget(m_LeftTexU); + m_Driver->getRenderTargetManager().recycleRenderTarget(m_RightTexU); + m_LeftTexU = NULL; + m_RightTexU = NULL; +} + +/* void CStereoDebugger::releaseTextures() { if (!m_Mat.empty()) @@ -233,7 +264,7 @@ void CStereoDebugger::releaseTextures() m_RightTexU = NULL; m_RightTex = NULL; // CSmartPtr } - +*//* void CStereoDebugger::initTextures() { uint32 width, height; @@ -261,15 +292,15 @@ void CStereoDebugger::initTextures() drvInternal->setupTexture(*m_RightTex); m_RightTexU = new CTextureUser(m_RightTex); nlassert(!drvInternal->isTextureRectangle(m_RightTex)); // not allowed -} - +}*/ +/* void CStereoDebugger::setTextures() { NL3D::CMaterial *mat = m_Mat.getObjectPtr(); mat->setTexture(0, m_LeftTex); mat->setTexture(1, m_RightTex); -} - +}*/ +/* void CStereoDebugger::verifyTextures() { if (m_Driver) @@ -287,7 +318,7 @@ void CStereoDebugger::verifyTextures() setTextures(); } } -} +}*/ /// Gets the required screen resolution for this device bool CStereoDebugger::getScreenResolution(uint &width, uint &height) @@ -307,6 +338,12 @@ void CStereoDebugger::getClippingFrustum(uint cid, NL3D::UCamera *camera) const // do nothing } +/// Get the original frustum of the camera +void CStereoDebugger::getOriginalFrustum(uint cid, NL3D::UCamera *camera) const +{ + // do nothing, as we never modified it +} + /// Is there a next pass bool CStereoDebugger::nextPass() { @@ -388,6 +425,12 @@ bool CStereoDebugger::wantScene() return m_Stage != 3; } +/// The 3D scene end (after multiple wantScene) +bool CStereoDebugger::wantSceneEffects() +{ + return m_Stage != 3; +} + /// Interface within the 3D scene bool CStereoDebugger::wantInterface3D() { @@ -402,11 +445,22 @@ bool CStereoDebugger::wantInterface2D() return m_Stage == 3; } +bool CStereoDebugger::isSceneFirst() +{ + return m_Stage != 3; +} + +bool CStereoDebugger::isSceneLast() +{ + return m_Stage != 3; +} + /// Returns true if a new render target was set, always fase if not using render targets bool CStereoDebugger::beginRenderTarget() { if (m_Stage != 3 && m_Driver && (m_Driver->getPolygonMode() == UDriver::Filled)) { + if (!m_LeftTexU) getTextures(); if (m_Stage % 2) static_cast(m_Driver)->setRenderTarget(*m_RightTexU, 0, 0, 0, 0); else static_cast(m_Driver)->setRenderTarget(*m_LeftTexU, 0, 0, 0, 0); return true; @@ -430,14 +484,15 @@ bool CStereoDebugger::endRenderTarget() uint32 width, height; NL3D::IDriver *drvInternal = (static_cast(m_Driver))->getDriver(); NL3D::CMaterial *mat = m_Mat.getObjectPtr(); - mat->setTexture(0, m_LeftTex); - mat->setTexture(1, m_RightTex); + mat->setTexture(0, m_LeftTexU->getITexture()); + mat->setTexture(1, m_RightTexU->getITexture()); drvInternal->activePixelProgram(m_PixelProgram); m_Driver->drawQuad(m_QuadUV, m_Mat); drvInternal->activePixelProgram(NULL); m_Driver->enableFog(fogEnabled); + recycleTextures(); return true; } diff --git a/code/nel/src/3d/stereo_display.cpp b/code/nel/src/3d/stereo_display.cpp index eace867fc..2a79c1039 100644 --- a/code/nel/src/3d/stereo_display.cpp +++ b/code/nel/src/3d/stereo_display.cpp @@ -25,7 +25,7 @@ * . */ -#include +#include "std3d.h" #include // STL includes @@ -35,6 +35,7 @@ // Project includes #include +#include #include #include diff --git a/code/nel/src/3d/stereo_hmd.cpp b/code/nel/src/3d/stereo_hmd.cpp index d28017482..25249e2b4 100644 --- a/code/nel/src/3d/stereo_hmd.cpp +++ b/code/nel/src/3d/stereo_hmd.cpp @@ -25,7 +25,7 @@ * . */ -#include +#include "std3d.h" #include // STL includes diff --git a/code/nel/src/3d/stereo_libvr.cpp b/code/nel/src/3d/stereo_libvr.cpp index 44a5a0a5a..c655f959c 100644 --- a/code/nel/src/3d/stereo_libvr.cpp +++ b/code/nel/src/3d/stereo_libvr.cpp @@ -27,7 +27,7 @@ #ifdef HAVE_LIBVR -#include +#include "std3d.h" #include #include diff --git a/code/nel/src/3d/stereo_ovr.cpp b/code/nel/src/3d/stereo_ovr.cpp index 402d9b2d0..073490dc0 100644 --- a/code/nel/src/3d/stereo_ovr.cpp +++ b/code/nel/src/3d/stereo_ovr.cpp @@ -41,15 +41,16 @@ * so, delete this exception statement from your version. */ -#ifdef HAVE_LIBOVR +#ifdef HAVE_LIBOVR_02 -#include +#include "std3d.h" #include // STL includes #include // External includes +#define OVR_NO_STDINT #include // NeL includes @@ -169,7 +170,7 @@ public: OVR::HMDInfo HMDInfo; }; -CStereoOVR::CStereoOVR(const CStereoOVRDeviceHandle *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), m_BarrelTexU(NULL), m_PixelProgram(NULL), m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f) +CStereoOVR::CStereoOVR(const CStereoOVRDeviceHandle *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), m_SceneTexture(NULL), m_GUITexture(NULL), m_PixelProgram(NULL), m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f) { ++s_DeviceCounter; m_DevicePtr = new CStereoOVRDevicePtr(); @@ -213,9 +214,6 @@ CStereoOVR::~CStereoOVR() m_BarrelMat.getObjectPtr()->setTexture(0, NULL); m_Driver->deleteMaterial(m_BarrelMat); } - delete m_BarrelTexU; - m_BarrelTexU = NULL; - m_BarrelTex = NULL; // CSmartPtr delete m_PixelProgram; m_PixelProgram = NULL; @@ -340,7 +338,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) { m_Driver = driver; - m_BarrelTex = new CTextureBloom(); // lol bloom + /*m_BarrelTex = new CTextureBloom(); // lol bloom m_BarrelTex->setRenderTarget(true); m_BarrelTex->setReleasable(false); m_BarrelTex->resize(m_DevicePtr->HMDInfo.HResolution, m_DevicePtr->HMDInfo.VResolution); @@ -348,7 +346,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) m_BarrelTex->setWrapS(ITexture::Clamp); m_BarrelTex->setWrapT(ITexture::Clamp); drvInternal->setupTexture(*m_BarrelTex); - m_BarrelTexU = new CTextureUser(m_BarrelTex); + m_BarrelTexU = new CTextureUser(m_BarrelTex);*/ m_BarrelMat = m_Driver->createMaterial(); m_BarrelMat.initUnlit(); @@ -361,7 +359,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) barrelMat->setZWrite(false); barrelMat->setZFunc(CMaterial::always); barrelMat->setDoubleSided(true); - barrelMat->setTexture(0, m_BarrelTex); + // barrelMat->setTexture(0, m_BarrelTex); m_BarrelQuadLeft.V0 = CVector(0.f, 0.f, 0.5f); m_BarrelQuadLeft.V1 = CVector(0.5f, 0.f, 0.5f); @@ -373,7 +371,7 @@ void CStereoOVR::setDriver(NL3D::UDriver *driver) m_BarrelQuadRight.V2 = CVector(1.f, 1.f, 0.5f); m_BarrelQuadRight.V3 = CVector(0.5f, 1.f, 0.5f); - nlassert(!drvInternal->isTextureRectangle(m_BarrelTex)); // not allowed + // nlassert(!drvInternal->isTextureRectangle(m_BarrelTex)); // not allowed m_BarrelQuadLeft.Uv0 = CUV(0.f, 0.f); m_BarrelQuadLeft.Uv1 = CUV(0.5f, 0.f); @@ -400,6 +398,8 @@ bool CStereoOVR::getScreenResolution(uint &width, uint &height) void CStereoOVR::initCamera(uint cid, const NL3D::UCamera *camera) { + m_OriginalFrustum[cid] = camera->getFrustum(); + float ar = (float)m_DevicePtr->HMDInfo.HResolution / ((float)m_DevicePtr->HMDInfo.VResolution * 2.0f); float fov = 2.0f * atanf((m_DevicePtr->HMDInfo.HScreenSize * 0.5f * 0.5f) / (m_DevicePtr->HMDInfo.EyeToScreenDistance)); //(float)NLMISC::Pi/2.f; // 2.0f * atanf(m_DevicePtr->HMDInfo.VScreenSize / 2.0f * m_DevicePtr->HMDInfo.EyeToScreenDistance); m_LeftFrustum[cid].initPerspective(fov, ar, camera->getFrustum().Near, camera->getFrustum().Far); @@ -427,6 +427,12 @@ void CStereoOVR::getClippingFrustum(uint cid, NL3D::UCamera *camera) const camera->setFrustum(m_ClippingFrustum[cid]); } +/// Get the original frustum of the camera +void CStereoOVR::getOriginalFrustum(uint cid, NL3D::UCamera *camera) const +{ + camera->setFrustum(m_OriginalFrustum[cid]); +} + void CStereoOVR::updateCamera(uint cid, const NL3D::UCamera *camera) { if (camera->getFrustum().Near != m_LeftFrustum[cid].Near @@ -440,53 +446,59 @@ bool CStereoOVR::nextPass() // Do not allow weird stuff. uint32 width, height; m_Driver->getWindowSize(width, height); - nlassert(width == m_DevicePtr->HMDInfo.HResolution); - nlassert(height == m_DevicePtr->HMDInfo.VResolution); + // nlassert(width == m_DevicePtr->HMDInfo.HResolution); + // nlassert(height == m_DevicePtr->HMDInfo.VResolution); if (m_Driver->getPolygonMode() == UDriver::Filled) { - switch (m_Stage) + switch (m_Stage) // Previous stage { case 0: - ++m_Stage; - m_SubStage = 0; - // stage 1: - // (initBloom) - // clear buffer - // draw scene left - return true; - case 1: - ++m_Stage; + m_Stage += 2; m_SubStage = 0; // stage 2: - // draw scene right + // draw interface 2d (onto render target) return true; case 2: ++m_Stage; m_SubStage = 0; // stage 3: - // (endBloom) - // draw interface 3d left + // (initBloom) + // clear buffer + // draw scene left return true; case 3: ++m_Stage; m_SubStage = 0; // stage 4: - // draw interface 3d right + // draw scene right return true; case 4: ++m_Stage; m_SubStage = 0; // stage 5: - // (endInterfacesDisplayBloom) - // draw interface 2d left + // (endBloom) + // draw interface 3d left return true; case 5: ++m_Stage; m_SubStage = 0; // stage 6: - // draw interface 2d right + // draw interface 3d right return true; + /*case 6: + ++m_Stage; + m_SubStage = 0; + // stage 7: + // (endInterfacesDisplayBloom) + // draw interface 2d left + return true; + case 7: + ++m_Stage; + m_SubStage = 0; + // stage 8: + // draw interface 2d right + return true;*/ case 6: m_Stage = 0; m_SubStage = 0; @@ -518,26 +530,30 @@ bool CStereoOVR::nextPass() const NL3D::CViewport &CStereoOVR::getCurrentViewport() const { - if (m_Stage % 2) return m_LeftViewport; + if (m_Stage == 2) return m_RegularViewport; + else if (m_Stage % 2) return m_LeftViewport; else return m_RightViewport; } const NL3D::CFrustum &CStereoOVR::getCurrentFrustum(uint cid) const { - if (m_Stage % 2) return m_LeftFrustum[cid]; + if (m_Stage == 2) return m_OriginalFrustum[cid]; + else if (m_Stage % 2) return m_LeftFrustum[cid]; else return m_RightFrustum[cid]; } void CStereoOVR::getCurrentFrustum(uint cid, NL3D::UCamera *camera) const { - if (m_Stage % 2) camera->setFrustum(m_LeftFrustum[cid]); + if (m_Stage == 2) camera->setFrustum(m_OriginalFrustum[cid]); + else if (m_Stage % 2) camera->setFrustum(m_LeftFrustum[cid]); else camera->setFrustum(m_RightFrustum[cid]); } void CStereoOVR::getCurrentMatrix(uint cid, NL3D::UCamera *camera) const { CMatrix translate; - if (m_Stage % 2) translate.translate(CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f)); + if (m_Stage == 2) { } + else if (m_Stage % 2) translate.translate(CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f)); else translate.translate(CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * 0.5f, 0.f, 0.f)); CMatrix mat = m_CameraMatrix[cid] * translate; if (camera->getTransformMode() == NL3D::UTransformable::RotQuat) @@ -556,7 +572,7 @@ bool CStereoOVR::wantClear() { switch (m_Stage) { - case 1: + case 3: m_SubStage = 1; return true; } @@ -567,8 +583,8 @@ bool CStereoOVR::wantScene() { switch (m_Stage) { - case 1: - case 2: + case 3: + case 4: m_SubStage = 2; return true; } @@ -579,8 +595,8 @@ bool CStereoOVR::wantInterface3D() { switch (m_Stage) { - case 3: - case 4: + case 5: + case 6: m_SubStage = 3; return true; } @@ -591,37 +607,225 @@ bool CStereoOVR::wantInterface2D() { switch (m_Stage) { - case 5: - case 6: + case 2: m_SubStage = 4; return true; } return m_Driver->getPolygonMode() != UDriver::Filled; } - /// Returns non-NULL if a new render target was set bool CStereoOVR::beginRenderTarget() { // render target always set before driver clear // nlassert(m_SubStage <= 1); - if (m_Driver && m_Stage == 1 && (m_Driver->getPolygonMode() == UDriver::Filled)) + + // Set GUI render target + if (m_Driver && m_Stage == 2 && (m_Driver->getPolygonMode() == UDriver::Filled)) { - static_cast(m_Driver)->setRenderTarget(*m_BarrelTexU, 0, 0, 0, 0); + nlassert(!m_GUITexture); + uint32 width, height; + m_Driver->getWindowSize(width, height); + m_GUITexture = m_Driver->getRenderTargetManager().getRenderTarget(width, height, true, UTexture::RGBA8888); + static_cast(m_Driver)->setRenderTarget(*m_GUITexture); + m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 0, 0)); return true; } + + // Begin 3D scene render target + if (m_Driver && m_Stage == 3 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + nlassert(!m_SceneTexture); + uint32 width, height; + m_Driver->getWindowSize(width, height); // Temporary limitation, TODO: scaling! + m_SceneTexture = m_Driver->getRenderTargetManager().getRenderTarget(width, height); + static_cast(m_Driver)->setRenderTarget(*m_SceneTexture); + return true; + } + return false; } +void CStereoOVR::setInterfaceMatrix(const NL3D::CMatrix &matrix) +{ + m_InterfaceCameraMatrix = matrix; +} + +void CStereoOVR::renderGUI() +{ + + /*CMatrix mat; + mat.translate(m_InterfaceCameraMatrix.getPos()); + CVector dir = m_InterfaceCameraMatrix.getJ(); + dir.z = 0; + dir.normalize(); + if (dir.y < 0) + mat.rotateZ(float(NLMISC::Pi+asin(dir.x))); + else + mat.rotateZ(float(NLMISC::Pi+NLMISC::Pi-asin(dir.x))); + m_Driver->setModelMatrix(mat);*/ + m_Driver->setModelMatrix(m_InterfaceCameraMatrix); + + { + NLMISC::CLine line(NLMISC::CVector(0, 5, 2), NLMISC::CVector(0, 5, 3)); + + NL3D::UMaterial mat = m_Driver->createMaterial(); + mat.setZWrite(false); + // mat.setZFunc(UMaterial::always); // Not nice! + mat.setDoubleSided(true); + mat.setColor(NLMISC::CRGBA::Red); + mat.setBlend(false); + + m_Driver->drawLine(line, mat); + + m_Driver->deleteMaterial(mat); + } + + { + nlassert(m_GUITexture); + + NLMISC::CQuadUV quad; + + NL3D::UMaterial umat = m_Driver->createMaterial(); + umat.initUnlit(); + umat.setColor(NLMISC::CRGBA::White); + umat.setDoubleSided(true); + umat.setBlend(true); + umat.setAlphaTest(false); + NL3D::CMaterial *mat = umat.getObjectPtr(); + mat->setShader(NL3D::CMaterial::Normal); + mat->setBlendFunc(CMaterial::one, CMaterial::TBlend::invsrcalpha); + mat->setZWrite(false); + // mat->setZFunc(CMaterial::always); // Not nice + mat->setDoubleSided(true); + mat->setTexture(0, m_GUITexture->getITexture()); + + // user options + float scale = 1.0f; + float distance = 1.5f; + float offcenter = 0.75f; + + float height = scale * distance * 2.0f; + + uint32 winw, winh; + m_Driver->getWindowSize(winw, winh); + float width = height * (float)winw / (float)winh; + + float bottom = -(height * 0.5f); + float top = (height * 0.5f); + + NLMISC::CQuadUV quadUV; + quadUV.V0 = CVector(-(width * 0.5f), distance, -(height * 0.5f)); + quadUV.V1 = CVector((width * 0.5f), distance, -(height * 0.5f)); + quadUV.V2 = CVector((width * 0.5f), distance, (height * 0.5f)); + quadUV.V3 = CVector(-(width * 0.5f), distance, (height * 0.5f)); + quadUV.Uv0 = CUV(0.f, 0.f); + quadUV.Uv1 = CUV(1.f, 0.f); + quadUV.Uv2 = CUV(1.f, 1.f); + quadUV.Uv3 = CUV(0.f, 1.f); + + const uint nbQuads = 128; + static CVertexBuffer vb; + static CIndexBuffer ib; + + vb.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag); + vb.setPreferredMemory(CVertexBuffer::RAMVolatile, false); + vb.setNumVertices((nbQuads + 1) * 2); + + { + CVertexBufferReadWrite vba; + vb.lock(vba); + float radius = distance + offcenter; + float relWidth = width / radius; + float quadWidth = relWidth / (float)nbQuads; + for (uint i = 0; i < nbQuads + 1; ++i) + { + uint vi0 = i * 2; + uint vi1 = vi0 + 1; + float lineH = -(relWidth * 0.5f) + quadWidth * (float)i; + float lineUV = (float)i / (float)(nbQuads); + float left = sin(lineH) * radius; + float forward = cos(lineH) * radius; + vba.setVertexCoord(vi0, left, forward - offcenter, bottom); + vba.setTexCoord(vi0, 0, lineUV, 0.0f); + vba.setVertexCoord(vi1, left, forward - offcenter, top); + vba.setTexCoord(vi1, 0, lineUV, 1.0f); + } + } + + ib.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT); + ib.setPreferredMemory(CIndexBuffer::RAMVolatile, false); + ib.setNumIndexes(nbQuads * 6); + + { + CIndexBufferReadWrite iba; + ib.lock(iba); + for (uint i = 0; i < nbQuads; ++i) + { + uint ti0 = i * 2; + uint ti1 = ti0 + 1; + uint bl = ti0; + uint tl = ti0 + 1; + uint br = ti0 + 2; + uint tr = ti0 + 3; + iba.setTri(ti0 * 3, bl, tl, br); + iba.setTri(ti1 * 3, br, tl, tr); + } + } + + IDriver *driver = static_cast(m_Driver)->getDriver(); + // m_Driver->setPolygonMode(UDriver::Line); + driver->activeVertexBuffer(vb); + driver->activeIndexBuffer(ib); + driver->renderTriangles(*umat.getObjectPtr(), 0, nbQuads * 2); //renderRawQuads(umat, 0, 128); + // m_Driver->setPolygonMode(UDriver::Filled); + + // m_Driver->drawQuad(quadUV, umat); + + m_Driver->deleteMaterial(umat); + } +} + /// Returns true if a render target was fully drawn bool CStereoOVR::endRenderTarget() { // after rendering of course // nlassert(m_SubStage > 1); + + // End GUI render target + if (m_Driver && m_Stage == 2 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // End GUI render target + nlassert(m_GUITexture); + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); + } + + // End of 3D Interface pass left + if (m_Driver && m_Stage == 5 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // Render 2D GUI in 3D space, assume existing camera is OK + renderGUI(); + } + + // End of 3D Interface pass right + if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // Render 2D GUI in 3D space, assume existing camera is OK + renderGUI(); + + // Recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_GUITexture); + m_GUITexture = NULL; + } + + // End 3D scene render target if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) // set to 4 to turn off distortion of 2d gui { - CTextureUser cu; - (static_cast(m_Driver))->setRenderTarget(cu); + nlassert(m_SceneTexture); + + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); bool fogEnabled = m_Driver->fogEnabled(); m_Driver->enableFog(false); @@ -632,7 +836,7 @@ bool CStereoOVR::endRenderTarget() m_Driver->getWindowSize(width, height); NL3D::IDriver *drvInternal = (static_cast(m_Driver))->getDriver(); NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr(); - barrelMat->setTexture(0, m_BarrelTex); + barrelMat->setTexture(0, m_SceneTexture->getITexture()); drvInternal->activePixelProgram(m_PixelProgram); @@ -697,8 +901,13 @@ bool CStereoOVR::endRenderTarget() drvInternal->activePixelProgram(NULL); m_Driver->enableFog(fogEnabled); + // Recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_SceneTexture); + m_SceneTexture = NULL; + return true; } + return false; } diff --git a/code/nel/src/3d/stereo_ovr_04.cpp b/code/nel/src/3d/stereo_ovr_04.cpp new file mode 100644 index 000000000..121855fb8 --- /dev/null +++ b/code/nel/src/3d/stereo_ovr_04.cpp @@ -0,0 +1,1312 @@ +/** + * \file stereo_ovr.cpp + * \brief CStereoOVR + * \date 2014-08-04 16:21GMT + * \author Jan Boon (Kaetemi) + * CStereoOVR + */ + +/* + * Copyright (C) 2014 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + * + * Linking this library statically or dynamically with other modules + * is making a combined work based on this library. Thus, the terms + * and conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with the Oculus SDK to produce + * an executable, regardless of the license terms of the Oculus SDK, + * and distribute linked combinations including the two, provided that + * you also meet the terms and conditions of the license of the Oculus + * SDK. You must obey the GNU General Public License in all respects + * for all of the code used other than the Oculus SDK. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. + */ + +#ifdef HAVE_LIBOVR + +#include "std3d.h" +#include + +// STL includes +#include + +// External includes +#define OVR_NO_STDINT +#include + +// NeL includes +// #include +#include +#include +#include +#include +#include +#include +#include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +namespace { + +#include "stereo_ovr_04_program.h" + +class CStereoOVRSystem +{ +public: + CStereoOVRSystem() : m_InitOk(false) + { + + } + + ~CStereoOVRSystem() + { + if (m_InitOk) + { + nlwarning("OVR: Not all resources were released before exit"); + Release(); + } + } + + bool Init() + { + if (!m_InitOk) + { + nldebug("OVR: Initialize"); + m_InitOk = ovr_Initialize(); + nlassert(m_InitOk); + } + + return m_InitOk; + } + + void Release() + { + if (m_InitOk) + { + nldebug("OVR: Release"); + ovr_Shutdown(); + m_InitOk = false; + } + } + +private: + bool m_InitOk; + +}; + +CStereoOVRSystem s_StereoOVRSystem; + +sint s_DeviceCounter = 0; +uint s_DetectId = 0; + +} + +class CStereoOVRDeviceFactory : public IStereoDeviceFactory +{ +public: + uint DeviceIndex; + uint DetectId; + + bool DebugDevice; + ovrHmdType DebugDeviceType; + + IStereoDisplay *createDevice() const + { + CStereoOVR *stereo = new CStereoOVR(this); + if (stereo->isDeviceCreated()) + return stereo; + delete stereo; + return NULL; + } +}; + +static NLMISC::CVector2f toTex(NLMISC::CVector2f texCoord, NLMISC::CVector2f uvScaleOffset[2]) +{ + // return(EyeToSourceUVScale * flattened + EyeToSourceUVOffset); + NLMISC::CVector2f vec = NLMISC::CVector2f(texCoord.x * uvScaleOffset[0].x, texCoord.y * uvScaleOffset[0].y) + uvScaleOffset[1]; + // some trial and error voodoo, sorry + vec = (vec + NLMISC::CVector2f(1, 1)) * 0.5f; + vec.y = 1.0f - vec.y; + vec.x = 1.0f - vec.x; + vec.x += 0.5f; + vec.y *= 2.0f; + + vec.x = 1.0f - vec.x; + + return vec; +} + +static float lerp(float f0, float f1, float factor) +{ + return (f1 * factor) + (f0 * (1.0f - factor)); +} + +CStereoOVR::CStereoOVR(const CStereoOVRDeviceFactory *factory) : m_DevicePtr(NULL), m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), m_SceneTexture(NULL), m_GUITexture(NULL), m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f), m_AttachedDisplay(false) +{ + nlctassert(NL_OVR_EYE_COUNT == ovrEye_Count); + + if (factory->DetectId != s_DetectId) + { + nlwarning("OVR: Previous device info structures become invalid after listing devices"); + return; + } + + m_DebugDevice = factory->DebugDevice; + if (factory->DebugDevice) m_DevicePtr = ovrHmd_CreateDebug(factory->DebugDeviceType); + else m_DevicePtr = ovrHmd_Create(factory->DeviceIndex); + + if (!m_DevicePtr) + { + nlwarning("OVR: Device not created"); + return; + } + + ++s_DeviceCounter; + + // nldebug("OVR: HScreenSize: %f, VScreenSize: %f", m_DevicePtr->HMDInfo.HScreenSize, m_DevicePtr->HMDInfo.VScreenSize); // No more support for physically non-square pixels? + // nldebug("OVR: VScreenCenter: %f", m_DevicePtr->HMDInfo.VScreenCenter); + // nldebug("OVR: EyeToScreenDistance: %f", m_DevicePtr->HMDInfo.EyeToScreenDistance); + // nldebug("OVR: LensSeparationDistance: %f", m_DevicePtr->HMDInfo.LensSeparationDistance); + // nldebug("OVR: InterpupillaryDistance: %f", m_DevicePtr->HMDInfo.InterpupillaryDistance); + nldebug("OVR: Resolution.w: %i, Resolution.h: %i", m_DevicePtr->Resolution.w, m_DevicePtr->Resolution.h); + // nldebug("OVR: DistortionK[0]: %f, DistortionK[1]: %f", m_DevicePtr->HMDInfo.DistortionK[0], m_DevicePtr->HMDInfo.DistortionK[1]); + // nldebug("OVR: DistortionK[2]: %f, DistortionK[3]: %f", m_DevicePtr->HMDInfo.DistortionK[2], m_DevicePtr->HMDInfo.DistortionK[3]); + + if (!ovrHmd_ConfigureTracking(m_DevicePtr, + ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection, // | ovrTrackingCap_Position + ovrTrackingCap_Orientation)) + { + nlwarning("OVR: Cannot configure tracking"); + ovrHmd_Destroy(m_DevicePtr); + m_DevicePtr = NULL; + --s_DeviceCounter; + return; + } + + float nativeWidth = m_DevicePtr->Resolution.w; + float nativeHeight = m_DevicePtr->Resolution.h; + + // get render descriptions for default fov + ovrEyeRenderDesc eyeRenderDesc[ovrEye_Count]; + eyeRenderDesc[ovrEye_Left] = ovrHmd_GetRenderDesc(m_DevicePtr, ovrEye_Left, m_DevicePtr->DefaultEyeFov[ovrEye_Left]); + eyeRenderDesc[ovrEye_Right] = ovrHmd_GetRenderDesc(m_DevicePtr, ovrEye_Right, m_DevicePtr->DefaultEyeFov[ovrEye_Right]); + nldebug("OVR: LEFT DistortedViewport: x: %i, y: %i, w: %i, h: %i", eyeRenderDesc[0].DistortedViewport.Pos.x, eyeRenderDesc[0].DistortedViewport.Pos.y, eyeRenderDesc[0].DistortedViewport.Size.w, eyeRenderDesc[0].DistortedViewport.Size.h); + nldebug("OVR: LEFT PixelsPerTanAngleAtCenter: x: %f, y: %f ", eyeRenderDesc[0].PixelsPerTanAngleAtCenter.x, eyeRenderDesc[0].PixelsPerTanAngleAtCenter.y); + nldebug("OVR: LEFT ViewAdjust: x: %f, y: %f, z: %f ", eyeRenderDesc[0].ViewAdjust.x, eyeRenderDesc[0].ViewAdjust.y, eyeRenderDesc[0].ViewAdjust.z); + nldebug("OVR: RIGHT DistortedViewport: x: %i, y: %i, w: %i, h: %i", eyeRenderDesc[1].DistortedViewport.Pos.x, eyeRenderDesc[1].DistortedViewport.Pos.y, eyeRenderDesc[1].DistortedViewport.Size.w, eyeRenderDesc[1].DistortedViewport.Size.h); + nldebug("OVR: RIGHT PixelsPerTanAngleAtCenter: x: %f, y: %f ", eyeRenderDesc[1].PixelsPerTanAngleAtCenter.x, eyeRenderDesc[1].PixelsPerTanAngleAtCenter.y); + nldebug("OVR: RIGHT ViewAdjust: x: %f, y: %f, z: %f ", eyeRenderDesc[1].ViewAdjust.x, eyeRenderDesc[1].ViewAdjust.y, eyeRenderDesc[1].ViewAdjust.z); + + // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 171 NL3D::CStereoOVR::CStereoOVR : OVR: Resolution.w: 1280, Resolution.h: 800 + // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 189 NL3D::CStereoOVR::CStereoOVR : OVR: LEFT DistortedViewport: x: 0, y: 0, w: 640, h: 800 + // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 190 NL3D::CStereoOVR::CStereoOVR : OVR: LEFT PixelsPerTanAngleAtCenter: x: 363.247864, y: 363.247864 + // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 191 NL3D::CStereoOVR::CStereoOVR : OVR: LEFT ViewAdjust: x: 0.031800, y: 0.000000, z: 0.000000 + // 2014/08/04 19:55:46 DBG 2e18 snowballs_client.exe stereo_ovr_04.cpp 192 NL3D::CStereoOVR::CStereoOVR : OVR: RIGHT DistortedViewport: x: 640, y: 0, w: 640, h: 800 + // 2014/08/04 19:55:46 DBG 2e18 snowballs_client.exe stereo_ovr_04.cpp 193 NL3D::CStereoOVR::CStereoOVR : OVR: RIGHT PixelsPerTanAngleAtCenter: x: 363.247864, y: 363.247864 + // 2014/08/04 19:55:46 DBG 2e18 snowballs_client.exe stereo_ovr_04.cpp 194 NL3D::CStereoOVR::CStereoOVR : OVR: RIGHT ViewAdjust: x: -0.031868, y: 0.000000, z: 0.000000 + + // find out the recommended render target size + ovrSizei fovTextureSize[ovrEye_Count]; + fovTextureSize[ovrEye_Left] = ovrHmd_GetFovTextureSize(m_DevicePtr, ovrEye_Left, eyeRenderDesc[ovrEye_Left].Fov, 1.0f); + fovTextureSize[ovrEye_Right] = ovrHmd_GetFovTextureSize(m_DevicePtr, ovrEye_Right, eyeRenderDesc[ovrEye_Right].Fov, 1.0f); + m_RenderTargetWidth = fovTextureSize[ovrEye_Left].w + fovTextureSize[ovrEye_Right].w; + m_RenderTargetHeight = max(fovTextureSize[ovrEye_Left].h, fovTextureSize[ovrEye_Right].h); + nldebug("OVR: RenderTarget: w: %u, h: %u", m_RenderTargetWidth, m_RenderTargetHeight); + + // 2014/08/04 20:22:03 DBG 30e4 snowballs_client.exe stereo_ovr_04.cpp 213 NL3D::CStereoOVR::CStereoOVR : OVR: RenderTarget: w: 2414, h: 1870 // That looks a bit excessive... + + for (uint eye = 0; eye < ovrEye_Count; ++eye) + { + ovrFovPort &fov = eyeRenderDesc[eye].Fov; + + // store data + m_EyeViewAdjustX[eye] = -eyeRenderDesc[eye].ViewAdjust.x; + + // setup viewport + m_EyeViewport[eye].init( + (float)eyeRenderDesc[eye].DistortedViewport.Pos.x / nativeWidth, + (float)eyeRenderDesc[eye].DistortedViewport.Pos.y / nativeHeight, + (float)eyeRenderDesc[eye].DistortedViewport.Size.w / nativeWidth, + (float)eyeRenderDesc[eye].DistortedViewport.Size.h / nativeHeight); + nldebug("OVR: EyeViewport: x: %f, y: %f, w: %f, h: %f", m_EyeViewport[eye].getX(), m_EyeViewport[eye].getY(), m_EyeViewport[eye].getWidth(), m_EyeViewport[eye].getHeight()); + ovrRecti eyeViewport; + eyeViewport.Pos.x = (eyeRenderDesc[eye].DistortedViewport.Pos.x * m_RenderTargetWidth) / m_DevicePtr->Resolution.w; + eyeViewport.Pos.y = (eyeRenderDesc[eye].DistortedViewport.Pos.y * m_RenderTargetHeight) / m_DevicePtr->Resolution.h; + eyeViewport.Size.w = (eyeRenderDesc[eye].DistortedViewport.Size.w * m_RenderTargetWidth) / m_DevicePtr->Resolution.w; + eyeViewport.Size.h = (eyeRenderDesc[eye].DistortedViewport.Size.h * m_RenderTargetHeight) / m_DevicePtr->Resolution.h; + + // calculate hfov and ar + /*float combinedTanHalfFovHorizontal = max(fov.LeftTan, fov.RightTan); + float combinedTanHalfFovVertical = max(fov.UpTan, fov.DownTan); + float horizontalFullFovInRadians = 2.0f * atanf (combinedTanHalfFovHorizontal); + float aspectRatio = combinedTanHalfFovHorizontal / combinedTanHalfFovVertical; + float m_EyeHFov[NL_OVR_EYE_COUNT]; + float m_EyeAR[NL_OVR_EYE_COUNT]; + m_EyeHFov[eye] = horizontalFullFovInRadians; + m_EyeAR[eye] = aspectRatio; + nldebug("OVR: HFOV: %f, AR: %f", horizontalFullFovInRadians, aspectRatio); + m_EyeFrustumBase[eye].initPerspective(m_EyeHFov[eye], m_EyeAR[eye], 1.0f, 100.f); + nldebug("OVR: FOV: Left: %f, Right: %f, Down: %f, Up: %f", // DOUBLE CHECK + m_EyeFrustumBase[eye].Left, m_EyeFrustumBase[eye].Right, m_EyeFrustumBase[eye].Bottom, m_EyeFrustumBase[eye].Top);*/ + m_EyeFrustumBase[eye].init( + -fov.LeftTan, // OVR provides positive values + fov.RightTan, // DEBUG: If renders shifted left and right, swap left and right + -fov.DownTan, + fov.UpTan, // DEBUG: If renders shifted up or down, swap down and up + 1.0f, // dummy + 100.f, // dummy + true); + nldebug("OVR: FOV: Left: %f, Right: %f, Down: %f, Up: %f", + m_EyeFrustumBase[eye].Left, m_EyeFrustumBase[eye].Right, m_EyeFrustumBase[eye].Bottom, m_EyeFrustumBase[eye].Top); + + // get distortion mesh + ovrDistortionMesh meshData; + ovrHmd_CreateDistortionMesh(m_DevicePtr, (ovrEyeType)eye, fov, + ovrDistortionCap_Chromatic /*| ovrDistortionCap_TimeWarp*/ | ovrDistortionCap_Vignette, // I believe the timewarp gimmick screws with parallax + &meshData); + ovrVector2f uvScaleOffset[2]; + + // get parameters for programs + ovrHmd_GetRenderScaleAndOffset(fov, + fovTextureSize[eye], eyeViewport, + (ovrVector2f *)uvScaleOffset); + m_EyeUVScaleOffset[eye][0] = NLMISC::CVector2f(uvScaleOffset[0].x, uvScaleOffset[0].y); + m_EyeUVScaleOffset[eye][1] = NLMISC::CVector2f(uvScaleOffset[1].x, uvScaleOffset[1].y); + + // chroma bugfix + float chromaFactor = 1.00f; + if (m_DevicePtr->Type == ovrHmd_DK2) + chromaFactor = 0.75f; + + // create distortion mesh vertex buffer + m_VB[eye].setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag | CVertexBuffer::TexCoord1Flag | CVertexBuffer::TexCoord2Flag | CVertexBuffer::PrimaryColorFlag); + m_VB[eye].setPreferredMemory(CVertexBuffer::StaticPreferred, true); + m_VB[eye].setNumVertices(meshData.VertexCount); + { + CVertexBufferReadWrite vba; + m_VB[eye].lock(vba); + for (uint i = 0; i < meshData.VertexCount; ++i) + { + ovrDistortionVertex &ov = meshData.pVertexData[i]; + vba.setVertexCoord(i, (ov.ScreenPosNDC.x + 1.0f) * 0.5f, (ov.ScreenPosNDC.y + 1.0f) * 0.5f, 0.5f); + NLMISC::CVector2f texR( + lerp(ov.TanEyeAnglesG.x, ov.TanEyeAnglesR.x, chromaFactor), + lerp(ov.TanEyeAnglesG.y, ov.TanEyeAnglesR.y, chromaFactor)); + NLMISC::CVector2f texG(ov.TanEyeAnglesG.x, ov.TanEyeAnglesG.y); + NLMISC::CVector2f texB( + lerp(ov.TanEyeAnglesG.x, ov.TanEyeAnglesB.x, chromaFactor), + lerp(ov.TanEyeAnglesG.y, ov.TanEyeAnglesB.y, chromaFactor)); + texR = toTex(texR, m_EyeUVScaleOffset[eye]); + texG = toTex(texG, m_EyeUVScaleOffset[eye]); + texB = toTex(texB, m_EyeUVScaleOffset[eye]); + vba.setTexCoord(i, 0, texR.x, texR.y); + vba.setTexCoord(i, 1, texG.x, texG.y); + vba.setTexCoord(i, 2, texB.x, texB.y); + NLMISC::CRGBA color; + color.R = color.G = color.B = (uint8)(ov.VignetteFactor * 255.99f); + color.A = 255; // (uint8)(ov.TimeWarpFactor * 255.99f); + vba.setColor(i, color); + } + } + + // create distortion mesh index buffer + m_IB[eye].setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT); + m_IB[eye].setPreferredMemory(CIndexBuffer::StaticPreferred, true); + m_IB[eye].setNumIndexes(meshData.IndexCount); + { + CIndexBufferReadWrite iba; + m_IB[eye].lock(iba); + for (uint i = 0; i + 2 < meshData.IndexCount; i += 3) + { + nlassert(meshData.pIndexData[i] < meshData.VertexCount); + nlassert(meshData.pIndexData[i + 1] < meshData.VertexCount); + nlassert(meshData.pIndexData[i + 2] < meshData.VertexCount); + iba.setTri(i, meshData.pIndexData[i], meshData.pIndexData[i + 1], meshData.pIndexData[i + 2]); + } + } + + // set tri count + m_NbTris[eye] = meshData.IndexCount / 3; + + // destroy ovr distortion mesh + ovrHmd_DestroyDistortionMesh(&meshData); + } + + // 2014/08/04 20:22:03 DBG 30e4 snowballs_client.exe stereo_ovr_04.cpp 222 NL3D::CStereoOVR::CStereoOVR : OVR: EyeViewport: x: 0.000000, y: 0.000000, w: 0.500000, h: 1.000000 + // 2014/08/04 22:28:39 DBG 3040 snowballs_client.exe stereo_ovr_04.cpp 235 NL3D::CStereoOVR::CStereoOVR : OVR: HFOV: 2.339905, AR: 0.916641 + // 2014/08/04 20:22:03 DBG 30e4 snowballs_client.exe stereo_ovr_04.cpp 222 NL3D::CStereoOVR::CStereoOVR : OVR: EyeViewport: x: 0.500000, y: 0.000000, w: 0.500000, h: 1.000000 + // 2014/08/04 22:28:39 DBG 3040 snowballs_client.exe stereo_ovr_04.cpp 235 NL3D::CStereoOVR::CStereoOVR : OVR: HFOV: 2.339905, AR: 0.916641 + + ovrHmd_RecenterPose(m_DevicePtr); + + // DEBUG EARLY EXIT + /*nldebug("OVR: Early exit"); + ovrHmd_Destroy(m_DevicePtr); + m_DevicePtr = NULL; + --s_DeviceCounter;*/ +} + +CStereoOVR::~CStereoOVR() +{ + if (m_AttachedDisplay) + { + detachFromDisplay(); + } + + if (!m_UnlitMat.empty()) + { + m_Driver->deleteMaterial(m_UnlitMat); + } + + m_Driver = NULL; + + if (m_DevicePtr) + { + ovrHmd_Destroy(m_DevicePtr); + m_DevicePtr = NULL; + --s_DeviceCounter; + } +} + +void CStereoOVR::setDriver(NL3D::UDriver *driver) +{ + m_Driver = driver; + + CDriverUser *dru = static_cast(driver); + IDriver *drv = dru->getDriver(); + + m_UnlitMat = m_Driver->createMaterial(); + m_UnlitMat.initUnlit(); + m_UnlitMat.setColor(CRGBA::White); + m_UnlitMat.setBlend (false); + m_UnlitMat.setAlphaTest (false); + NL3D::CMaterial *unlitMat = m_UnlitMat.getObjectPtr(); + unlitMat->setShader(NL3D::CMaterial::Normal); + unlitMat->setBlendFunc(CMaterial::one, CMaterial::zero); + unlitMat->setZWrite(false); + unlitMat->setZFunc(CMaterial::always); + unlitMat->setDoubleSided(true); + + unlitMat->texConstantColor(0, NLMISC::CRGBA(255, 0, 0, 0)); + unlitMat->texConstantColor(1, NLMISC::CRGBA(0, 255, 0, 0)); + unlitMat->texConstantColor(2, NLMISC::CRGBA(0, 0, 255, 0)); + + m_UnlitMat.texEnvArg0RGB(0, UMaterial::Texture, UMaterial::SrcColor); + m_UnlitMat.texEnvArg1RGB(0, UMaterial::Constant, UMaterial::SrcColor); + m_UnlitMat.texEnvOpRGB(0, UMaterial::Modulate); + + m_UnlitMat.texEnvArg0RGB(1, UMaterial::Texture, UMaterial::SrcColor); + m_UnlitMat.texEnvArg1RGB(1, UMaterial::Constant, UMaterial::SrcColor); + m_UnlitMat.texEnvArg2RGB(1, UMaterial::Previous, UMaterial::SrcColor); + m_UnlitMat.texEnvOpRGB(1, UMaterial::Mad); + + m_UnlitMat.texEnvArg0RGB(2, UMaterial::Texture, UMaterial::SrcColor); + m_UnlitMat.texEnvArg1RGB(2, UMaterial::Constant, UMaterial::SrcColor); + m_UnlitMat.texEnvArg2RGB(2, UMaterial::Previous, UMaterial::SrcColor); + m_UnlitMat.texEnvOpRGB(2, UMaterial::Mad); + + m_UnlitMat.texEnvArg0RGB(3, UMaterial::Previous, UMaterial::SrcColor); + m_UnlitMat.texEnvArg1RGB(3, UMaterial::Diffuse, UMaterial::SrcColor); + m_UnlitMat.texEnvOpRGB(3, UMaterial::Modulate); +} + +bool CStereoOVR::getScreenResolution(uint &width, uint &height) +{ + if (m_DevicePtr) + { + width = m_DevicePtr->Resolution.w; + height = m_DevicePtr->Resolution.h; + return true; + } + return false; +} + +bool CStereoOVR::attachToDisplay() +{ + nldebug("OVR: Attach to display '%s'", m_DevicePtr->DisplayDeviceName); + + if (m_DebugDevice) + return false; + + if (!m_AttachedDisplay) + { + m_Driver->getCurrentScreenMode(m_OriginalMode); + m_Driver->getWindowPos(m_OriginalWinPosX, m_OriginalWinPosY); + } + +#if defined(NL_OS_WINDOWS) + if ((m_DevicePtr->HmdCaps & ovrHmdCap_ExtendDesktop) != ovrHmdCap_ExtendDesktop) + { + nldebug("OVR: Direct Rift"); + CDriverUser *dru = static_cast(m_Driver); + IDriver *drv = dru->getDriver(); + m_AttachedDisplay = ovrHmd_AttachToWindow(m_DevicePtr, (void *)drv->getDisplay(), NULL, NULL); + if (!m_AttachedDisplay) + nlwarning("OVR: Direct Rift failed!"); + } + else +#endif + { + nldebug("OVR: Extended Rift"); + UDriver::CMode mode; + mode.DisplayDevice = m_DevicePtr->DisplayDeviceName; + mode.Windowed = false; + mode.Width = m_DevicePtr->Resolution.w; + mode.Height = m_DevicePtr->Resolution.h; + m_Driver->setMode(mode); + m_AttachedDisplay = true; + } + + return m_AttachedDisplay; +} + +void CStereoOVR::detachFromDisplay() +{ + /*if (!m_OriginalMode.Windowed) + { + m_OriginalMode.Windowed = true; + m_Driver->setMode(m_OriginalMode); + m_OriginalMode.Windowed = false; + }*/ + m_Driver->setMode(m_OriginalMode); + m_Driver->setWindowPos(m_OriginalWinPosX, m_OriginalWinPosY); + m_AttachedDisplay = false; +} + +void CStereoOVR::initCamera(uint cid, const NL3D::UCamera *camera) +{ + m_OriginalFrustum[cid] = camera->getFrustum(); + + /*m_LeftFrustum[cid] = m_OriginalFrustum[cid]; + m_RightFrustum[cid] = m_OriginalFrustum[cid]; + m_ClippingFrustum[cid] = m_OriginalFrustum[cid]; + return;*/ + + m_LeftFrustum[cid].init( + m_EyeFrustumBase[ovrEye_Left].Left * camera->getFrustum().Near, + m_EyeFrustumBase[ovrEye_Left].Right * camera->getFrustum().Near, + m_EyeFrustumBase[ovrEye_Left].Bottom * camera->getFrustum().Near, + m_EyeFrustumBase[ovrEye_Left].Top * camera->getFrustum().Near, + camera->getFrustum().Near, + camera->getFrustum().Far, + true); + + m_RightFrustum[cid].init( + m_EyeFrustumBase[ovrEye_Right].Left * camera->getFrustum().Near, + m_EyeFrustumBase[ovrEye_Right].Right * camera->getFrustum().Near, + m_EyeFrustumBase[ovrEye_Right].Bottom * camera->getFrustum().Near, + m_EyeFrustumBase[ovrEye_Right].Top * camera->getFrustum().Near, + camera->getFrustum().Near, + camera->getFrustum().Far, + true); + + m_ClippingFrustum[cid].init( + min(m_EyeFrustumBase[ovrEye_Left].Left, m_EyeFrustumBase[ovrEye_Right].Left) * camera->getFrustum().Near, + max(m_EyeFrustumBase[ovrEye_Left].Right, m_EyeFrustumBase[ovrEye_Right].Right) * camera->getFrustum().Near, + min(m_EyeFrustumBase[ovrEye_Left].Bottom, m_EyeFrustumBase[ovrEye_Right].Bottom) * camera->getFrustum().Near, + max(m_EyeFrustumBase[ovrEye_Left].Top, m_EyeFrustumBase[ovrEye_Right].Top) * camera->getFrustum().Near, + camera->getFrustum().Near, + camera->getFrustum().Far, + true); +} + +/// Get the frustum to use for clipping +void CStereoOVR::getClippingFrustum(uint cid, NL3D::UCamera *camera) const +{ + camera->setFrustum(m_ClippingFrustum[cid]); +} + +/// Get the original frustum of the camera +void CStereoOVR::getOriginalFrustum(uint cid, NL3D::UCamera *camera) const +{ + camera->setFrustum(m_OriginalFrustum[cid]); +} + +void CStereoOVR::updateCamera(uint cid, const NL3D::UCamera *camera) +{ + if (camera->getFrustum().Near != m_LeftFrustum[cid].Near + || camera->getFrustum().Far != m_LeftFrustum[cid].Far) + CStereoOVR::initCamera(cid, camera); + m_CameraMatrix[cid] = camera->getMatrix(); +} + +bool CStereoOVR::nextPass() +{ + if (m_Driver->getPolygonMode() == UDriver::Filled) + { + switch (m_Stage) // Previous stage + { + case 0: + m_Stage += 2; + m_SubStage = 0; + // stage 2: + // draw interface 2d (onto render target) + return true; + case 2: + ++m_Stage; + m_SubStage = 0; + // stage 3: + // (initBloom) + // clear buffer + // draw scene left + return true; + case 3: + ++m_Stage; + m_SubStage = 0; + // stage 4: + // draw scene right + return true; + case 4: + ++m_Stage; + m_SubStage = 0; + // stage 5: + // (endBloom) + // draw interface 3d left + return true; + case 5: + ++m_Stage; + m_SubStage = 0; + // stage 6: + // draw interface 3d right + return true; + /*case 6: + ++m_Stage; + m_SubStage = 0; + // stage 7: + // (endInterfacesDisplayBloom) + // draw interface 2d left + return true; + case 7: + ++m_Stage; + m_SubStage = 0; + // stage 8: + // draw interface 2d right + return true;*/ + case 6: + m_Stage = 0; + m_SubStage = 0; + // present + m_OrientationCached = false; + return false; + } + } + else + { + switch (m_Stage) + { + case 0: + ++m_Stage; + m_SubStage = 0; + return true; + case 1: + m_Stage = 0; + m_SubStage = 0; + return false; + } + } + nlerror("Invalid stage"); + m_Stage = 0; + m_SubStage = 0; + m_OrientationCached = false; + return false; +} + +const NL3D::CViewport &CStereoOVR::getCurrentViewport() const +{ + if (m_Stage == 2) return m_RegularViewport; + else if (m_Stage % 2) return m_EyeViewport[ovrEye_Left]; + else return m_EyeViewport[ovrEye_Right]; +} + +const NL3D::CFrustum &CStereoOVR::getCurrentFrustum(uint cid) const +{ + if (m_Stage == 2) return m_OriginalFrustum[cid]; + else if (m_Stage % 2) return m_LeftFrustum[cid]; + else return m_RightFrustum[cid]; +} + +void CStereoOVR::getCurrentFrustum(uint cid, NL3D::UCamera *camera) const +{ + if (m_Stage == 2) camera->setFrustum(m_OriginalFrustum[cid]); + else if (m_Stage % 2) camera->setFrustum(m_LeftFrustum[cid]); + else camera->setFrustum(m_RightFrustum[cid]); +} + +void CStereoOVR::getCurrentMatrix(uint cid, NL3D::UCamera *camera) const +{ + CMatrix translate; + if (m_Stage == 2) { } + else if (m_Stage % 2) translate.translate(CVector(m_EyeViewAdjustX[ovrEye_Left] * m_Scale, 0.f, 0.f)); // ok + else translate.translate(CVector(m_EyeViewAdjustX[ovrEye_Right] * m_Scale, 0.f, 0.f)); // ok + CMatrix mat = m_CameraMatrix[cid] * translate; + if (camera->getTransformMode() == NL3D::UTransformable::RotQuat) + { + camera->setPos(mat.getPos()); + camera->setRotQuat(mat.getRot()); + } + else + { + // camera->setTransformMode(NL3D::UTransformable::DirectMatrix); + camera->setMatrix(mat); + } +} + +bool CStereoOVR::wantClear() +{ + switch (m_Stage) + { + case 3: + m_SubStage = 1; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantScene() +{ + switch (m_Stage) + { + case 3: + case 4: + m_SubStage = 2; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantSceneEffects() +{ + switch (m_Stage) + { + case 4: + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantInterface3D() +{ + switch (m_Stage) + { + case 5: + case 6: + m_SubStage = 3; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantInterface2D() +{ + switch (m_Stage) + { + case 2: + m_SubStage = 4; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::isSceneFirst() +{ + switch (m_Stage) + { + case 3: + return true; + case 4: + return false; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::isSceneLast() +{ + switch (m_Stage) + { + case 3: + return false; + case 4: + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +/// Returns non-NULL if a new render target was set +bool CStereoOVR::beginRenderTarget() +{ + // render target always set before driver clear + // nlassert(m_SubStage <= 1); + + // Set GUI render target + if (m_Driver && m_Stage == 2 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + nlassert(!m_GUITexture); + uint32 width, height; + m_Driver->getWindowSize(width, height); + m_GUITexture = m_Driver->getRenderTargetManager().getRenderTarget(width, height, true, UTexture::RGBA8888); + static_cast(m_Driver)->setRenderTarget(*m_GUITexture); + m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 0, 0)); + return true; + } + + // Begin 3D scene render target + if (m_Driver && m_Stage == 3 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + nlassert(!m_SceneTexture); + m_SceneTexture = m_Driver->getRenderTargetManager().getRenderTarget(m_RenderTargetWidth, m_RenderTargetHeight); + static_cast(m_Driver)->setRenderTarget(*m_SceneTexture); + return true; + /*nldebug("OVR: Begin render target");*/ + //m_Driver->beginDefaultRenderTarget(m_RenderTargetWidth, m_RenderTargetHeight); // DEBUG + //return true; + } + + return false; +} + +void CStereoOVR::setInterfaceMatrix(const NL3D::CMatrix &matrix) +{ + m_InterfaceCameraMatrix = matrix; +} + +void CStereoOVR::renderGUI() +{ + m_Driver->setModelMatrix(m_InterfaceCameraMatrix); +/* + { + NLMISC::CLine line(NLMISC::CVector(0, 5, 2), NLMISC::CVector(0, 5, 3)); + + NL3D::UMaterial mat = m_Driver->createMaterial(); + mat.setZWrite(false); + // mat.setZFunc(UMaterial::always); // Not nice! + mat.setDoubleSided(true); + mat.setColor(NLMISC::CRGBA::Red); + mat.setBlend(false); + + m_Driver->drawLine(line, mat); + + m_Driver->deleteMaterial(mat); + } + + { + NL3D::UMaterial mat = m_Driver->createMaterial(); + mat.setZWrite(false); + mat.setZFunc(UMaterial::always); // Not nice! + mat.setDoubleSided(true); + mat.setBlend(false); + NLMISC::CLine line; + + mat.setColor(NLMISC::CRGBA::Red); + line = NLMISC::CLine(NLMISC::CVector(0, 3, -3), NLMISC::CVector(0, 3, 3)); // YPos + m_Driver->drawLine(line, mat); + + mat.setColor(NLMISC::CRGBA::Green); + line = NLMISC::CLine(NLMISC::CVector(3, 0, -3), NLMISC::CVector(3, 0, 3)); // XPos + m_Driver->drawLine(line, mat); + + mat.setColor(NLMISC::CRGBA::Magenta); + line = NLMISC::CLine(NLMISC::CVector(0, -3, -3), NLMISC::CVector(0, -3, 3)); // YNeg + m_Driver->drawLine(line, mat); + + mat.setColor(NLMISC::CRGBA::Cyan); + line = NLMISC::CLine(NLMISC::CVector(-3, 0, -3), NLMISC::CVector(-3, 0, 3)); // XNeg + m_Driver->drawLine(line, mat); + + mat.setColor(NLMISC::CRGBA::Blue); + line = NLMISC::CLine(NLMISC::CVector(0, -3, 3), NLMISC::CVector(0, 3, 3)); // ZPos + m_Driver->drawLine(line, mat); + + mat.setColor(NLMISC::CRGBA::Blue); + line = NLMISC::CLine(NLMISC::CVector(0, -3, -3), NLMISC::CVector(0, 3, -3)); // ZNeg + m_Driver->drawLine(line, mat); + + m_Driver->deleteMaterial(mat); + } + */ + { + nlassert(m_GUITexture); + + NLMISC::CQuadUV quad; + + NL3D::UMaterial umat = m_Driver->createMaterial(); + umat.initUnlit(); + umat.setColor(NLMISC::CRGBA::White); + umat.setDoubleSided(true); + umat.setBlend(true); + umat.setAlphaTest(false); + NL3D::CMaterial *mat = umat.getObjectPtr(); + mat->setShader(NL3D::CMaterial::Normal); + mat->setBlendFunc(CMaterial::one, CMaterial::invsrcalpha); + mat->setZWrite(false); + // mat->setZFunc(CMaterial::always); // Not nice + mat->setDoubleSided(true); + mat->setTexture(0, m_GUITexture->getITexture()); + + // user options + float scale = 1.0f; + float distance = 1.5f; + float offcenter = 0.75f; + + float height = scale * distance * 2.0f; + + uint32 winw, winh; + m_Driver->getWindowSize(winw, winh); + float width = height * (float)winw / (float)winh; + + float bottom = -(height * 0.5f); + float top = (height * 0.5f); + + NLMISC::CQuadUV quadUV; + quadUV.V0 = CVector(-(width * 0.5f), distance, -(height * 0.5f)); + quadUV.V1 = CVector((width * 0.5f), distance, -(height * 0.5f)); + quadUV.V2 = CVector((width * 0.5f), distance, (height * 0.5f)); + quadUV.V3 = CVector(-(width * 0.5f), distance, (height * 0.5f)); + quadUV.Uv0 = CUV(0.f, 0.f); + quadUV.Uv1 = CUV(1.f, 0.f); + quadUV.Uv2 = CUV(1.f, 1.f); + quadUV.Uv3 = CUV(0.f, 1.f); + + const uint nbQuads = 128; + static CVertexBuffer vb; + static CIndexBuffer ib; + + vb.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag); + vb.setPreferredMemory(CVertexBuffer::RAMVolatile, false); + vb.setNumVertices((nbQuads + 1) * 2); + + { + CVertexBufferReadWrite vba; + vb.lock(vba); + float radius = distance + offcenter; + float relWidth = width / radius; + float quadWidth = relWidth / (float)nbQuads; + for (uint i = 0; i < nbQuads + 1; ++i) + { + uint vi0 = i * 2; + uint vi1 = vi0 + 1; + float lineH = -(relWidth * 0.5f) + quadWidth * (float)i; + float lineUV = (float)i / (float)(nbQuads); + float left = sin(lineH) * radius; + float forward = cos(lineH) * radius; + vba.setVertexCoord(vi0, left, forward - offcenter, bottom); + vba.setTexCoord(vi0, 0, lineUV, 0.0f); + vba.setVertexCoord(vi1, left, forward - offcenter, top); + vba.setTexCoord(vi1, 0, lineUV, 1.0f); + } + } + + ib.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT); + ib.setPreferredMemory(CIndexBuffer::RAMVolatile, false); + ib.setNumIndexes(nbQuads * 6); + + { + CIndexBufferReadWrite iba; + ib.lock(iba); + for (uint i = 0; i < nbQuads; ++i) + { + uint ti0 = i * 2; + uint ti1 = ti0 + 1; + uint bl = ti0; + uint tl = ti0 + 1; + uint br = ti0 + 2; + uint tr = ti0 + 3; + iba.setTri(ti0 * 3, bl, tl, br); + iba.setTri(ti1 * 3, br, tl, tr); + } + } + + IDriver *driver = static_cast(m_Driver)->getDriver(); + // m_Driver->setPolygonMode(UDriver::Line); + driver->activeVertexBuffer(vb); + driver->activeIndexBuffer(ib); + driver->renderTriangles(*umat.getObjectPtr(), 0, nbQuads * 2); //renderRawQuads(umat, 0, 128); + // m_Driver->setPolygonMode(UDriver::Filled); + + // m_Driver->drawQuad(quadUV, umat); + + m_Driver->deleteMaterial(umat); + + /*{ + // nldebug("Render GUI lines"); + NL3D::UMaterial rmat = m_Driver->createMaterial(); + rmat.setZWrite(false); + rmat.setZFunc(UMaterial::always); // Not nice! + rmat.setDoubleSided(true); + rmat.setColor(NLMISC::CRGBA::Red); + rmat.setBlend(false); + + m_Driver->setPolygonMode(UDriver::Line); + driver->activeVertexBuffer(vb); + driver->activeIndexBuffer(ib); + driver->renderTriangles(*rmat.getObjectPtr(), 0, nbQuads * 2); + m_Driver->setPolygonMode(UDriver::Filled); + + m_Driver->deleteMaterial(rmat); + }*/ + } +} + +/// Returns true if a render target was fully drawn +bool CStereoOVR::endRenderTarget() +{ + // after rendering of course + // nlassert(m_SubStage > 1); + + // End GUI render target + if (m_Driver && m_Stage == 2 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // End GUI render target + nlassert(m_GUITexture); + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); + } + + // End of 3D Interface pass left + if (m_Driver && m_Stage == 5 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // Render 2D GUI in 3D space, assume existing camera is OK + renderGUI(); + } + + // End of 3D Interface pass right + if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + // Render 2D GUI in 3D space, assume existing camera is OK + renderGUI(); + + // Recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_GUITexture); + m_GUITexture = NULL; + } + + // End 3D scene render target + if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + nlassert(m_SceneTexture); + + //nldebug("OVR: End render target"); + // m_Driver->endDefaultRenderTarget(NULL); // DEBUG + + // end render target + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); + + // backup + bool fogEnabled = m_Driver->fogEnabled(); + m_Driver->enableFog(false); + + // must clear everything to black (can we get a mesh to only handle the parts outside of the distortion mesh?) + m_Driver->clearRGBABuffer(CRGBA(0, 0, 0, 255)); + + CDriverUser *dru = static_cast(m_Driver); + IDriver *drv = dru->getDriver(); + + // set matrix mode + CViewport vp; + m_Driver->setViewport(vp); + m_Driver->setMatrixMode2D11(); + + for (uint eye = 0; eye < ovrEye_Count; ++eye) + { + CMaterial *mat = m_UnlitMat.getObjectPtr(); + mat->setTexture(0, m_SceneTexture->getITexture()); + mat->setTexture(1, m_SceneTexture->getITexture()); + mat->setTexture(2, m_SceneTexture->getITexture()); + mat->setTexture(3, m_SceneTexture->getITexture()); + + //m_Driver->setPolygonMode(UDriver::Line); + drv->activeVertexBuffer(m_VB[eye]); + drv->activeIndexBuffer(m_IB[eye]); + drv->renderTriangles(*mat, 0, m_NbTris[eye]); + //m_Driver->setPolygonMode(UDriver::Filled); + + mat->setTexture(0, NULL); + mat->setTexture(1, NULL); + mat->setTexture(2, NULL); + mat->setTexture(3, NULL); + } + + // restore + m_Driver->enableFog(fogEnabled); + + // recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_SceneTexture); + m_SceneTexture = NULL; + + return true; + } + + /*if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) // set to 4 to turn off distortion of 2d gui + { + nlassert(m_SceneTexture); + + CTextureUser texNull; + (static_cast(m_Driver))->setRenderTarget(texNull); + bool fogEnabled = m_Driver->fogEnabled(); + m_Driver->enableFog(false); + + m_Driver->setMatrixMode2D11(); + CViewport vp = CViewport(); + m_Driver->setViewport(vp); + uint32 width, height; + m_Driver->getWindowSize(width, height); + NL3D::IDriver *drvInternal = (static_cast(m_Driver))->getDriver(); + NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr(); + barrelMat->setTexture(0, m_SceneTexture->getITexture()); + + drvInternal->activePixelProgram(m_PixelProgram); + + float w = float(m_BarrelQuadLeft.V1.x),// / float(width), + h = float(m_BarrelQuadLeft.V2.y),// / float(height), + x = float(m_BarrelQuadLeft.V0.x),/// / float(width), + y = float(m_BarrelQuadLeft.V0.y);// / float(height); + + float lensOffset = m_DevicePtr->HMDInfo.LensSeparationDistance * 0.5f; + float lensShift = m_DevicePtr->HMDInfo.HScreenSize * 0.25f - lensOffset; + float lensViewportShift = 4.0f * lensShift / m_DevicePtr->HMDInfo.HScreenSize; + + float lensCenterX = x + (w + lensViewportShift * 0.5f) * 0.5f; + float lensCenterY = y + h * 0.5f; + float screenCenterX = x + w * 0.5f; + float screenCenterY = y + h * 0.5f; + float scaleX = (w / 2); + float scaleY = (h / 2); + float scaleInX = (2 / w); + float scaleInY = (2 / h); + + + drvInternal->setUniform2f(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().LensCenter, + lensCenterX, lensCenterY); + + drvInternal->setUniform2f(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().ScreenCenter, + screenCenterX, screenCenterY); + + drvInternal->setUniform2f(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().Scale, + scaleX, scaleY); + + drvInternal->setUniform2f(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().ScaleIn, + scaleInX, scaleInY); + + + drvInternal->setUniform4fv(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().HmdWarpParam, + 1, m_DevicePtr->HMDInfo.DistortionK); + + m_Driver->drawQuad(m_BarrelQuadLeft, m_BarrelMat); + + x = w; + lensCenterX = x + (w - lensViewportShift * 0.5f) * 0.5f; + screenCenterX = x + w * 0.5f; + + + drvInternal->setUniform2f(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().LensCenter, + lensCenterX, lensCenterY); + + drvInternal->setUniform2f(IDriver::PixelProgram, + m_PixelProgram->ovrIndices().ScreenCenter, + screenCenterX, screenCenterY); + + + m_Driver->drawQuad(m_BarrelQuadRight, m_BarrelMat); + + drvInternal->activePixelProgram(NULL); + m_Driver->enableFog(fogEnabled); + + // Recycle render target + m_Driver->getRenderTargetManager().recycleRenderTarget(m_SceneTexture); + m_SceneTexture = NULL; + + return true; + }*/ + + return false; +} + +NLMISC::CQuat CStereoOVR::getOrientation() const +{ + // broken + + /*NLMISC::CQuat quat; + quat.identity(); + return quat;*/ + + if (m_OrientationCached) + return m_OrientationCache; + + ovrTrackingState ts = ovrHmd_GetTrackingState(m_DevicePtr, ovr_GetTimeInSeconds()); // TODO: Predict forward + if (ts.StatusFlags & ovrStatus_OrientationTracked) + { + // get just the orientation + ovrQuatf quatovr = ts.HeadPose.ThePose.Orientation; + NLMISC::CMatrix coordsys; + float csys[] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + coordsys.set(csys); + NLMISC::CMatrix matovr; + matovr.setRot(NLMISC::CQuat(quatovr.x, quatovr.y, quatovr.z, quatovr.w)); + NLMISC::CMatrix matr; + // matr.rotateZ(NLMISC::Pi); // uncomment when backwards ... + matr.rotateX(NLMISC::Pi * 0.5f); // fix this properly... :) (note: removing this allows you to use rift while lying down) + NLMISC::CMatrix matnel = matr * matovr * coordsys; + NLMISC::CQuat finalquat = matnel.getRot(); + m_OrientationCache = finalquat; + m_OrientationCached = true; + return finalquat; + } + else + { + if (!m_DebugDevice) + nlwarning("OVR: No orientation returned"); + // return old orientation + m_OrientationCached = true; + return m_OrientationCache; + } +} + +/// Get GUI shift +void CStereoOVR::getInterface2DShift(uint cid, float &x, float &y, float distance) const +{ + +} + +void CStereoOVR::setEyePosition(const NLMISC::CVector &v) +{ + m_EyePosition = v; +} + +const NLMISC::CVector &CStereoOVR::getEyePosition() const +{ + return m_EyePosition; +} + +void CStereoOVR::setScale(float s) +{ + m_EyePosition = m_EyePosition * (s / m_Scale); + m_Scale = s; +} + + + +void CStereoOVR::listDevices(std::vector &devicesOut) +{ + if (!s_StereoOVRSystem.Init()) + return; + + ++s_DetectId; + uint hmdDetect = ovrHmd_Detect(); + nldebug("OVR: Detected %u HMDs", hmdDetect); + + for (uint i = 0; i < hmdDetect; ++i) + { + devicesOut.resize(devicesOut.size() + 1); + CStereoDeviceInfo &deviceInfoOut = devicesOut[devicesOut.size() - 1]; + ovrHmd hmd = ovrHmd_Create(i); + CStereoOVRDeviceFactory *factory = new CStereoOVRDeviceFactory(); + factory->DetectId = s_DetectId; + factory->DeviceIndex = i; + factory->DebugDevice = false; + deviceInfoOut.Factory = factory; + deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD; + deviceInfoOut.Library = CStereoDeviceInfo::OVR; + deviceInfoOut.Manufacturer = hmd->Manufacturer; + deviceInfoOut.ProductName = hmd->ProductName; + deviceInfoOut.AllowAuto = true; + deviceInfoOut.Serial = hmd->SerialNumber; + ovrHmd_Destroy(hmd); + } + +#if !FINAL_VERSION + // Debug DK1 + { + devicesOut.resize(devicesOut.size() + 1); + CStereoDeviceInfo &deviceInfoOut = devicesOut[devicesOut.size() - 1]; + ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK1); + CStereoOVRDeviceFactory *factory = new CStereoOVRDeviceFactory(); + factory->DetectId = s_DetectId; + factory->DebugDevice = true; + factory->DebugDeviceType = ovrHmd_DK1; + deviceInfoOut.Factory = factory; + deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD; + deviceInfoOut.Library = CStereoDeviceInfo::OVR; + deviceInfoOut.Manufacturer = hmd->Manufacturer; + deviceInfoOut.ProductName = hmd->ProductName; + deviceInfoOut.AllowAuto = false; + deviceInfoOut.Serial = "OVR-DK1-DEBUG"; + ovrHmd_Destroy(hmd); + } + // Debug DK2 + { + devicesOut.resize(devicesOut.size() + 1); + CStereoDeviceInfo &deviceInfoOut = devicesOut[devicesOut.size() - 1]; + ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2); + CStereoOVRDeviceFactory *factory = new CStereoOVRDeviceFactory(); + factory->DetectId = s_DetectId; + factory->DebugDevice = true; + factory->DebugDeviceType = ovrHmd_DK2; + deviceInfoOut.Factory = factory; + deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD; + deviceInfoOut.Library = CStereoDeviceInfo::OVR; + deviceInfoOut.Manufacturer = hmd->Manufacturer; + deviceInfoOut.ProductName = hmd->ProductName; + deviceInfoOut.AllowAuto = false; + deviceInfoOut.Serial = "OVR-DK2-DEBUG"; + ovrHmd_Destroy(hmd); + } +#endif +} + +bool CStereoOVR::isLibraryInUse() +{ + nlassert(s_DeviceCounter >= 0); + return s_DeviceCounter > 0; +} + +void CStereoOVR::releaseLibrary() +{ + nlassert(s_DeviceCounter == 0); + s_StereoOVRSystem.Release(); +} + +bool CStereoOVR::isDeviceCreated() +{ + return m_DevicePtr != NULL; +} + +} /* namespace NL3D */ + +#endif /* HAVE_LIBOVR */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_ovr_04_program.h b/code/nel/src/3d/stereo_ovr_04_program.h new file mode 100644 index 000000000..f8c253aeb --- /dev/null +++ b/code/nel/src/3d/stereo_ovr_04_program.h @@ -0,0 +1,4 @@ + +// TODO + +/* end of file */ diff --git a/code/nel/src/3d/stereo_ovr_fp.cpp b/code/nel/src/3d/stereo_ovr_fp.cpp index 940be0bfe..84a74598e 100644 --- a/code/nel/src/3d/stereo_ovr_fp.cpp +++ b/code/nel/src/3d/stereo_ovr_fp.cpp @@ -21,6 +21,8 @@ limitations under the License. ************************************************************************************/ +#include "std3d.h" + namespace NL3D { const char *g_StereoOVR_fp40 = "!!ARBfp1.0\n" diff --git a/code/nel/src/3d/text_context.cpp b/code/nel/src/3d/text_context.cpp index 4b6e46c85..456ab77a6 100644 --- a/code/nel/src/3d/text_context.cpp +++ b/code/nel/src/3d/text_context.cpp @@ -40,6 +40,7 @@ CTextContext::CTextContext() _ScaleZ = 1.0f; _Shaded = false; + _ShadeOutline = false; _ShadeExtent = 0.001f; _ShadeColor = NLMISC::CRGBA(0,0,0); diff --git a/code/nel/src/3d/text_context_user.cpp b/code/nel/src/3d/text_context_user.cpp index 570c879f9..6ee880d91 100644 --- a/code/nel/src/3d/text_context_user.cpp +++ b/code/nel/src/3d/text_context_user.cpp @@ -148,6 +148,18 @@ bool CTextContextUser::getShaded() const return _TextContext.getShaded(); } +void CTextContextUser::setShadeOutline(bool b) +{ + H_AUTO2; + + _TextContext.setShadeOutline(b); +} +bool CTextContextUser::getShadeOutline() const +{ + H_AUTO2; + + return _TextContext.getShadeOutline(); +} void CTextContextUser::setShadeExtent(float shext) { H_AUTO2; diff --git a/code/nel/src/gui/ctrl_text_button.cpp b/code/nel/src/gui/ctrl_text_button.cpp index d3a0f6765..cdf9ea0d2 100644 --- a/code/nel/src/gui/ctrl_text_button.cpp +++ b/code/nel/src/gui/ctrl_text_button.cpp @@ -23,6 +23,7 @@ #include "nel/gui/group_container_base.h" #include "nel/gui/lua_ihm.h" #include "nel/gui/widget_manager.h" +#include "nel/gui/interface_factory.h" #include "nel/misc/i18n.h" using namespace std; @@ -66,8 +67,6 @@ namespace NLGUI { if( _ViewText != NULL ) { - if( _Parent != NULL ) - _Parent->delView( _ViewText, true ); delete _ViewText; _ViewText = NULL; } @@ -569,6 +568,7 @@ namespace NLGUI ((CViewTextID*)_ViewText)->parseTextIdOptions(cur); // Same RenderLayer as us. _ViewText->setRenderLayer(getRenderLayer()); + _ViewText->setParentElm(this); // Parse the hardText (if not text id) if(!_IsViewTextId) { @@ -863,6 +863,8 @@ namespace NLGUI } if(getFrozen() && getFrozenHalfTone()) _ViewText->setAlpha(_ViewText->getAlpha()>>2); + + _ViewText->draw(); } } @@ -873,6 +875,9 @@ namespace NLGUI // Should have been setuped with addCtrl nlassert(_Setuped); + if( _Name == "==MARKED==" ) + bool marked = true; + // Compute Size according to bitmap and Text. if (!(_SizeRef & 1)) { @@ -886,6 +891,8 @@ namespace NLGUI } CViewBase::updateCoords(); + + _ViewText->updateCoords(); } // *************************************************************************** @@ -901,7 +908,7 @@ namespace NLGUI if( _ViewText == NULL ) { - CViewBase *v = CWidgetManager::getInstance()->getParser()->createClass( "text" ); + CViewBase *v = CInterfaceFactory::createClass( "text" ); nlassert( v != NULL ); _ViewText = dynamic_cast< CViewText* >( v ); _ViewText->setId( _Id + "_text" ); @@ -910,15 +917,13 @@ namespace NLGUI } // setup the viewText and add to parent - _ViewText->setParent (getParent()); + _ViewText->setParentElm (this); _ViewText->setParentPos (this); _ViewText->setParentPosRef (_TextParentPosRef); _ViewText->setPosRef (_TextPosRef); _ViewText->setActive(_Active); _ViewText->setX(_TextX); _ViewText->setY(_TextY); - - getParent()->addView(_ViewText); } // *************************************************************************** @@ -1007,17 +1012,18 @@ namespace NLGUI // *************************************************************************** void CCtrlTextButton::onRemoved() { - if( _ViewText != NULL ) - { - if( _Parent != NULL ) - _Parent->delView( _ViewText, true ); - } } void CCtrlTextButton::onWidgetDeleted( CInterfaceElement *e ) { - if( e == _ViewText ) - _ViewText = NULL; + } + + void CCtrlTextButton::moveBy( sint32 x, sint32 y ) + { + CInterfaceElement::moveBy( x, y ); + + if( _ViewText != NULL ) + _ViewText->updateCoords(); } } diff --git a/code/nel/src/gui/group_container.cpp b/code/nel/src/gui/group_container.cpp index c3a7834c5..18a65bc5f 100644 --- a/code/nel/src/gui/group_container.cpp +++ b/code/nel/src/gui/group_container.cpp @@ -2373,7 +2373,7 @@ namespace NLGUI { setMaxH(_PopupMaxH); // _W is given by scripter-man - newH = pLayer->H_T; + newH = (pLayer->H_T - pLayer->InsetT); } else { @@ -2382,7 +2382,7 @@ namespace NLGUI _W = _Parent->getW(); } setMaxH (16384); // No scrollbar for container of layer > 0 - newH = pLayer->H_T; + newH = (pLayer->H_T - pLayer->InsetT); } if (_Opened) @@ -2396,11 +2396,11 @@ namespace NLGUI _HeaderOpened->setY (- newH); _HeaderOpened->setW (_W-(pLayer->W_L+pLayer->W_R)); _HeaderOpened->updateCoords(); - newH += max (_HeaderOpened->getHReal(), pLayer->getValSInt32 ("header_h")); + newH += max (_HeaderOpened->getHReal(), pLayer->HeaderH); } else { - newH += pLayer->getValSInt32 ("header_h"); + newH += pLayer->HeaderH; } newH -= (sint32) _ContentYOffset; @@ -2448,12 +2448,12 @@ namespace NLGUI if (_LayerSetup == 0) { // zeH is the height to substract to total height of the container to obtain height of the list - sint32 zeH = pLayer->H_T + pLayer->H_B_Open + pLayer->H_EM_Open; + sint32 zeH = (pLayer->H_T - pLayer->InsetT) + pLayer->H_B_Open + pLayer->H_EM_Open; if (_HeaderOpened != NULL) - zeH += max (_HeaderOpened->getHReal(), pLayer->getValSInt32 ("header_h")); + zeH += max (_HeaderOpened->getHReal(), pLayer->HeaderH); else - zeH += pLayer->getValSInt32 ("header_h"); + zeH += pLayer->HeaderH; if (_Content != NULL) zeH += _Content->getHReal(); @@ -2513,11 +2513,11 @@ namespace NLGUI _HeaderClosed->setY (-newH); _HeaderClosed->setW (_W-(pLayer->W_L+pLayer->W_R)); _HeaderClosed->updateCoords(); - newH += max (_HeaderClosed->getHReal(), pLayer->getValSInt32 ("header_h")); + newH += max (_HeaderClosed->getHReal(), pLayer->HeaderH); } else { - newH += pLayer->getValSInt32 ("header_h"); + newH += pLayer->HeaderH; } newH += pLayer->H_B; @@ -2731,7 +2731,8 @@ namespace NLGUI // h is the size of what is on top of the child list sint32 x, y, w, h; - h = pLayer->H_T + pLayer->H_B_Open; + bool bHasChild = (_List->getNbElement() > 0); + h = (pLayer->H_T - pLayer->InsetT) + (((!_Opened) || (!bHasChild)) ? pLayer->H_B : pLayer->H_B_Open); if (_Opened) { @@ -2749,7 +2750,6 @@ namespace NLGUI { h = _HReal; } - bool bHasChild = (_List->getNbElement() > 0); x = _XReal; y = _YReal+_HReal-h; @@ -2767,7 +2767,7 @@ namespace NLGUI // Top Right rVR.drawRotFlipBitmap (rl, x+w-pLayer->W_TR, y+h-pLayer->H_TR, pLayer->W_TR, pLayer->H_TR, 0, false, pLayer->TxId_TR, col); - if ((!_Opened) || (_Opened && !bHasChild)) + if ((!_Opened) || (!bHasChild)) { // Not opened // Left if (pLayer->Tile_L == 0) // Tiling ? @@ -2817,9 +2817,9 @@ namespace NLGUI rVR.drawRotFlipBitmap (rl, x+w-pLayer->W_BR_Open, y, pLayer->W_BR_Open, pLayer->H_BR_Open, 0, false, pLayer->TxId_BR_Open, col); // Content if (pLayer->Tile_Blank == 0) // Tiling ? - rVR.drawRotFlipBitmap (rl, x+pLayer->W_L, y+pLayer->H_B, w-(pLayer->W_R+pLayer->W_L), h-(pLayer->H_B_Open+pLayer->H_T), 0, false, pLayer->TxId_Blank, col); + rVR.drawRotFlipBitmap (rl, x+pLayer->W_L, y+pLayer->H_B_Open, w-(pLayer->W_R+pLayer->W_L), h-(pLayer->H_B_Open+pLayer->H_T), 0, false, pLayer->TxId_Blank, col); else - rVR.drawRotFlipBitmapTiled (rl, x+pLayer->W_L, y+pLayer->H_B, w-(pLayer->W_R+pLayer->W_L), h-(pLayer->H_B_Open+pLayer->H_T), 0, false, pLayer->TxId_Blank, pLayer->Tile_Blank-1, col); + rVR.drawRotFlipBitmapTiled (rl, x+pLayer->W_L, y+pLayer->H_B_Open, w-(pLayer->W_R+pLayer->W_L), h-(pLayer->H_B_Open+pLayer->H_T), 0, false, pLayer->TxId_Blank, pLayer->Tile_Blank-1, col); // ScrollBar Placement if (pLayer->Tile_M_Open == 0) // Tiling ? rVR.drawRotFlipBitmap (rl, x, _YReal+pLayer->H_EL_Open, pLayer->W_M_Open, _HReal-h-pLayer->H_EL_Open, 0, false, pLayer->TxId_M_Open, col); @@ -2848,7 +2848,7 @@ namespace NLGUI // Top Right rVR.drawRotFlipBitmap (rl, x+w-pLayer->W_TR, y+h-pLayer->H_TR, pLayer->W_TR, pLayer->H_TR, 0, false, pLayer->TxId_TR, col); - if ((!_Opened) || (_Opened && !bHasChild)) + if ((!_Opened) || (!bHasChild)) { // Left if (pLayer->Tile_L == 0) // Tiling ? @@ -2856,7 +2856,7 @@ namespace NLGUI else rVR.drawRotFlipBitmapTiled (rl, x, y+pLayer->H_BL, pLayer->W_L, h-(pLayer->H_BL+pLayer->H_TL), 0, false, pLayer->TxId_L, pLayer->Tile_L-1, col); // Right - if (pLayer->Tile_T == 0) // Tiling ? + if (pLayer->Tile_R == 0) // Tiling ? rVR.drawRotFlipBitmap (rl, x+w-pLayer->W_R, y+pLayer->H_BR, pLayer->W_R, h-(pLayer->H_BL+pLayer->H_TL), 0, false, pLayer->TxId_R, col); else rVR.drawRotFlipBitmapTiled (rl, x+w-pLayer->W_R, y+pLayer->H_BR, pLayer->W_R, h-(pLayer->H_BL+pLayer->H_TL), 0, false, pLayer->TxId_R, pLayer->Tile_R-1, col); @@ -3003,18 +3003,16 @@ namespace NLGUI col.A = nInverted; else col.A = max(_HighLightedAlpha, nInverted); - sint32 hw, hh; // size of highlight texture - rVR.getTextureSizeFromId(pLayer->TxId_TL_HighLight, hw, hh); // corners - rVR.drawRotFlipBitmap (_RenderLayer, x, y + h - hh, hw, hh, 0, false, pLayer->TxId_TL_HighLight, col); - rVR.drawRotFlipBitmap (_RenderLayer, x + _WReal - hw, y + h - hh, hw, hh, 0, false, pLayer->TxId_TR_HighLight, col); - rVR.drawRotFlipBitmap (_RenderLayer, x, _YReal, hw, hh, 0, false, pLayer->TxId_BL_HighLight, col); - rVR.drawRotFlipBitmap (_RenderLayer, x + _WReal - hw, _YReal, hw, hh, 0, false, pLayer->TxId_BR_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x, y + h - pLayer->H_T_HighLight, pLayer->W_TL_HighLight, pLayer->H_TL_HighLight, 0, false, pLayer->TxId_TL_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x + _WReal - pLayer->W_TR_HighLight, y + h - pLayer->H_T_HighLight, pLayer->W_TR_HighLight, pLayer->H_TR_HighLight, 0, false, pLayer->TxId_TR_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x, _YReal, pLayer->W_BL_HighLight, pLayer->H_BL_HighLight, 0, false, pLayer->TxId_BL_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x + _WReal - pLayer->W_BR_HighLight, _YReal, pLayer->W_BR_HighLight, pLayer->H_BR_HighLight, 0, false, pLayer->TxId_BR_HighLight, col); // border - rVR.drawRotFlipBitmap (_RenderLayer, x + hw, y + h - hh, _WReal - 2 * hw, hh, 0, false, pLayer->TxId_T_HighLight, col); - rVR.drawRotFlipBitmap (_RenderLayer, x + hw, _YReal, _WReal - 2 * hw, hh, 0, false, pLayer->TxId_B_HighLight, col); - rVR.drawRotFlipBitmap (_RenderLayer, x, _YReal + hh, hw, _HReal - 2 * hh, 0, false, pLayer->TxId_L_HighLight, col); - rVR.drawRotFlipBitmap (_RenderLayer, x + _WReal - hw, _YReal + hh, hw, _HReal - 2 * hh, 0, false, pLayer->TxId_R_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x + pLayer->W_TL_HighLight, y + h - pLayer->H_T_HighLight, _WReal - pLayer->W_TL_HighLight - pLayer->W_TR_HighLight, pLayer->H_T_HighLight, 0, false, pLayer->TxId_T_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x + pLayer->W_BL_HighLight, _YReal, _WReal - pLayer->W_BL_HighLight - pLayer->W_BR_HighLight, pLayer->H_B_HighLight, 0, false, pLayer->TxId_B_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x, _YReal + pLayer->H_B_HighLight, pLayer->W_L_HighLight, _HReal - pLayer->H_T_HighLight - pLayer->H_B_HighLight, 0, false, pLayer->TxId_L_HighLight, col); + rVR.drawRotFlipBitmap (_RenderLayer, x + _WReal - pLayer->W_R_HighLight, _YReal + pLayer->H_B_HighLight, pLayer->W_R_HighLight, _HReal - pLayer->H_T_HighLight - pLayer->H_B_HighLight, 0, false, pLayer->TxId_R_HighLight, col); } @@ -3715,6 +3713,7 @@ namespace NLGUI _TitleOpened->setParentPosRef (Hotspot_TL); _TitleOpened->setPosRef (Hotspot_TL); _TitleOpened->setShadow (true); + _TitleOpened->setShadowOutline (false); _TitleOpened->setColor (CRGBA(255,255,255,255)); _TitleOpened->setModulateGlobalColor(getModulateGlobalColor()); _TitleOpened->setOverExtendViewText(_TitleOverExtendViewText); @@ -3766,6 +3765,7 @@ namespace NLGUI _TitleClosed->setParentPosRef (Hotspot_TL); _TitleClosed->setPosRef (Hotspot_TL); _TitleClosed->setShadow (true); + _TitleClosed->setShadowOutline (false); _TitleClosed->setColor (CRGBA(255,255,255,255)); _TitleClosed->setModulateGlobalColor(getModulateGlobalColor()); _TitleClosed->setOverExtendViewText(_TitleOverExtendViewText); diff --git a/code/nel/src/gui/group_editbox.cpp b/code/nel/src/gui/group_editbox.cpp index 751d9241b..92ae46703 100644 --- a/code/nel/src/gui/group_editbox.cpp +++ b/code/nel/src/gui/group_editbox.cpp @@ -27,7 +27,7 @@ #include "nel/gui/widget_manager.h" #include "nel/gui/view_renderer.h" #include "nel/gui/db_manager.h" -#include +#include "nel/gui/interface_factory.h" using namespace std; using namespace NLMISC; @@ -1320,6 +1320,16 @@ namespace NLGUI } } + // if click, and not frozen, then get the focus + if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup && !_Frozen) + { + _SelectingText = false; + if (_SelectCursorPos == _CursorPos) + _CurrSelection = NULL; + + return true; + } + if (!isIn(eventDesc.getX(), eventDesc.getY())) return false; @@ -1329,6 +1339,7 @@ namespace NLGUI _SelectingText = true; stopParentBlink(); CWidgetManager::getInstance()->setCaptureKeyboard (this); + CWidgetManager::getInstance()->setCapturePointerLeft (this); // set the right cursor position uint newCurPos; bool cursorAtPreviousLineEnd; @@ -1356,16 +1367,6 @@ namespace NLGUI return true; } - // if click, and not frozen, then get the focus - if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup && !_Frozen) - { - _SelectingText = false; - if (_SelectCursorPos == _CursorPos) - _CurrSelection = NULL; - - return true; - } - if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown) { CWidgetManager::getInstance()->setCapturePointerRight(this); @@ -1542,7 +1543,7 @@ namespace NLGUI if( editorMode ) { nlwarning( "Trying to create a new 'edit_text' for %s", getId().c_str() ); - _ViewText = dynamic_cast< CViewText* >( CWidgetManager::getInstance()->getParser()->createClass( "text" ) ); + _ViewText = dynamic_cast< CViewText* >( CInterfaceFactory::createClass( "text" ) ); if( _ViewText != NULL ) { _ViewText->setParent( this ); diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 9f19f383a..dd7eebdef 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -1289,16 +1289,19 @@ namespace NLGUI string name; ucstring ucValue; uint size = 120; + uint maxlength = 1024; if (present[MY_HTML_INPUT_NAME] && value[MY_HTML_INPUT_NAME]) name = value[MY_HTML_INPUT_NAME]; if (present[MY_HTML_INPUT_SIZE] && value[MY_HTML_INPUT_SIZE]) fromString(value[MY_HTML_INPUT_SIZE], size); if (present[MY_HTML_INPUT_VALUE] && value[MY_HTML_INPUT_VALUE]) ucValue.fromUtf8(value[MY_HTML_INPUT_VALUE]); + if (present[MY_HTML_INPUT_MAXLENGTH] && value[MY_HTML_INPUT_MAXLENGTH]) + fromString(value[MY_HTML_INPUT_MAXLENGTH], maxlength); string textTemplate(!templateName.empty() ? templateName : DefaultFormTextGroup); // Add the editbox - CInterfaceGroup *textArea = addTextArea (textTemplate, name.c_str (), 1, size/12, false, ucValue); + CInterfaceGroup *textArea = addTextArea (textTemplate, name.c_str (), 1, size/12, false, ucValue, maxlength); if (textArea) { // Add the text area to the form @@ -1450,6 +1453,8 @@ namespace NLGUI getPercentage (table->ForceWidthMin, table->TableRatio, value[MY_HTML_TABLE_WIDTH]); if (present[MY_HTML_TABLE_BORDER] && value[MY_HTML_TABLE_BORDER]) fromString(value[MY_HTML_TABLE_BORDER], table->Border); + if (present[MY_HTML_TABLE_BORDERCOLOR] && value[MY_HTML_TABLE_BORDERCOLOR]) + table->BorderColor = getColor (value[MY_HTML_TABLE_BORDERCOLOR]); if (present[MY_HTML_TABLE_CELLSPACING] && value[MY_HTML_TABLE_CELLSPACING]) fromString(value[MY_HTML_TABLE_CELLSPACING], table->CellSpacing); if (present[MY_HTML_TABLE_CELLPADDING] && value[MY_HTML_TABLE_CELLPADDING]) @@ -1514,11 +1519,19 @@ namespace NLGUI } } } + + if (present[MY_HTML_TD_COLSPAN] && value[MY_HTML_TD_COLSPAN]) + fromString(value[MY_HTML_TD_COLSPAN], _Cells.back()->ColSpan); + if (present[MY_HTML_TD_ROWSPAN] && value[MY_HTML_TD_ROWSPAN]) + fromString(value[MY_HTML_TD_ROWSPAN], _Cells.back()->RowSpan); + _Cells.back()->BgColor = _CellParams.back().BgColor; _Cells.back()->Align = _CellParams.back().Align; _Cells.back()->VAlign = _CellParams.back().VAlign; _Cells.back()->LeftMargin = _CellParams.back().LeftMargin; _Cells.back()->NoWrap = _CellParams.back().NoWrap; + _Cells.back()->ColSpan = std::max(1, _Cells.back()->ColSpan); + _Cells.back()->RowSpan = std::max(1, _Cells.back()->RowSpan); float temp; if (present[MY_HTML_TD_WIDTH] && value[MY_HTML_TD_WIDTH]) @@ -1553,12 +1566,15 @@ namespace NLGUI _TextAreaRow = 1; _TextAreaCols = 10; _TextAreaContent = ""; - if (present[HTML_TEXTAREA_NAME] && value[HTML_TEXTAREA_NAME]) - _TextAreaName = value[HTML_TEXTAREA_NAME]; - if (present[HTML_TEXTAREA_ROWS] && value[HTML_TEXTAREA_ROWS]) - fromString(value[HTML_TEXTAREA_ROWS], _TextAreaRow); - if (present[HTML_TEXTAREA_COLS] && value[HTML_TEXTAREA_COLS]) - fromString(value[HTML_TEXTAREA_COLS], _TextAreaCols); + _TextAreaMaxLength = 1024; + if (present[MY_HTML_TEXTAREA_NAME] && value[MY_HTML_TEXTAREA_NAME]) + _TextAreaName = value[MY_HTML_TEXTAREA_NAME]; + if (present[MY_HTML_TEXTAREA_ROWS] && value[MY_HTML_TEXTAREA_ROWS]) + fromString(value[MY_HTML_TEXTAREA_ROWS], _TextAreaRow); + if (present[MY_HTML_TEXTAREA_COLS] && value[MY_HTML_TEXTAREA_COLS]) + fromString(value[MY_HTML_TEXTAREA_COLS], _TextAreaCols); + if (present[MY_HTML_TEXTAREA_MAXLENGTH] && value[MY_HTML_TEXTAREA_MAXLENGTH]) + fromString(value[MY_HTML_TEXTAREA_MAXLENGTH], _TextAreaMaxLength); _TextAreaTemplate = !templateName.empty() ? templateName : DefaultFormTextAreaGroup; _TextArea = true; @@ -1675,21 +1691,19 @@ namespace NLGUI break; case HTML_TEXTAREA: { - // Add the editbox - // nlinfo("textarea temp '%s'", _TextAreaTemplate.c_str()); - // nlinfo("textarea name '%s'", _TextAreaName.c_str()); - // nlinfo("textarea %d %d", _TextAreaRow, _TextAreaCols); - // nlinfo("textarea content '%s'", _TextAreaContent.toUtf8().c_str()); - CInterfaceGroup *textArea = addTextArea (_TextAreaTemplate, _TextAreaName.c_str (), _TextAreaRow, _TextAreaCols, true, _TextAreaContent); - if (textArea) - { - // Add the text area to the form - CGroupHTML::CForm::CEntry entry; - entry.Name = _TextAreaName; - entry.TextArea = textArea; - _Forms.back().Entries.push_back (entry); - } _TextArea = false; + if (!(_Forms.empty())) + { + CInterfaceGroup *textArea = addTextArea (_TextAreaTemplate, _TextAreaName.c_str (), _TextAreaRow, _TextAreaCols, true, _TextAreaContent, _TextAreaMaxLength); + if (textArea) + { + // Add the text area to the form + CGroupHTML::CForm::CEntry entry; + entry.Name = _TextAreaName; + entry.TextArea = textArea; + _Forms.back().Entries.push_back (entry); + } + } } break; case HTML_TITLE: @@ -3149,116 +3163,62 @@ namespace NLGUI void CGroupHTML::addImage(const char *img, bool globalColor, bool reloadImg) { // In a paragraph ? - if (_Paragraph) + if (!_Paragraph) { - string finalUrl; + newParagraph (0); + paragraphChange (); + } + string finalUrl; + + // No more text in this text view + _CurrentViewLink = NULL; + + // Not added ? + CViewBitmap *newImage = new CViewBitmap (TCtorParam()); + + // + // 1/ try to load the image with the old system (local files in bnp) + // + string image = CFile::getPath(img) + CFile::getFilenameWithoutExtension(img) + ".tga"; + if (lookupLocalFile (finalUrl, image.c_str(), false)) + { + newImage->setRenderLayer(getRenderLayer()+1); + image = finalUrl; + } + else + { // - // 1/ try to load the image with the old system (local files in bnp) + // 2/ if it doesn't work, try to load the image in cache // - string image = CFile::getPath(img) + CFile::getFilenameWithoutExtension(img) + ".tga"; - if (lookupLocalFile (finalUrl, image.c_str(), false)) + image = localImageName(img); + if (!reloadImg && lookupLocalFile (finalUrl, image.c_str(), false)) { - // No more text in this text view - _CurrentViewLink = NULL; - - // Not added ? - CViewBitmap *newImage = new CViewBitmap (TCtorParam()); - /* todo link in image - if (getA()) - { - newImage->Link = getLink(); - newImage->setHTMLView (this); - }*/ - newImage->setRenderLayer(getRenderLayer()+1); - newImage->setTexture (finalUrl); - newImage->setModulateGlobalColor(globalColor); - - /* todo link in image - if (getA()) - getParagraph()->addChildLink(newImage); - else*/ - getParagraph()->addChild(newImage); - paragraphChange (); + // don't display image that are not power of 2 + uint32 w, h; + CBitmap::loadSize (image, w, h); + if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures())) + image.clear(); } else { // - // 2/ if it doesn't work, try to load the image in cache + // 3/ if it doesn't work, display a placeholder and ask to dl the image into the cache // - image = localImageName(img); - if (!reloadImg && lookupLocalFile (finalUrl, image.c_str(), false)) - { - // No more text in this text view - _CurrentViewLink = NULL; - - // Not added ? - CViewBitmap *newImage = new CViewBitmap (TCtorParam()); - /* todo link in image - if (getA()) - { - newImage->Link = getLink(); - newImage->setHTMLView (this); - }*/ - - // don't display image that are not power of 2 - uint32 w, h; - CBitmap::loadSize (image, w, h); - if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures())) - image.clear(); - - newImage->setTexture (image); - // newImage->setTexture (finalUrl); - newImage->setModulateGlobalColor(globalColor); - - /* todo link in image - if (getA()) - getParagraph()->addChildLink(newImage); - else*/ - getParagraph()->addChild(newImage); - paragraphChange (); - } - else - { - - // - // 3/ if it doesn't work, display a placeholder and ask to dl the image into the cache - // - image = "web_del.tga"; - if (lookupLocalFile (finalUrl, image.c_str(), false)) - { - // No more text in this text view - _CurrentViewLink = NULL; - - // Not added ? - CViewBitmap *newImage = new CViewBitmap (TCtorParam()); - /* todo link in image - if (getA()) - { - newImage->Link = getLink(); - newImage->setHTMLView (this); - }*/ - newImage->setTexture (image); - // newImage->setTexture (finalUrl); - newImage->setModulateGlobalColor(globalColor); - - addImageDownload(img, newImage); - - /* todo link in image - if (getA()) - getParagraph()->addChildLink(newImage); - else*/ - getParagraph()->addChild(newImage); - paragraphChange (); - } - } + image = "web_del.tga"; + addImageDownload(img, newImage); } } + newImage->setTexture (image); + newImage->setModulateGlobalColor(globalColor); + + getParagraph()->addChild(newImage); + paragraphChange (); } // *************************************************************************** - CInterfaceGroup *CGroupHTML::addTextArea(const std::string &templateName, const char *name, uint /* rows */, uint cols, bool multiLine, const ucstring &content) + CInterfaceGroup *CGroupHTML::addTextArea(const std::string &templateName, const char *name, uint /* rows */, uint cols, bool multiLine, const ucstring &content, uint maxlength) { // In a paragraph ? if (!_Paragraph) @@ -3280,7 +3240,8 @@ namespace NLGUI templateParams.push_back (std::pair ("multiline", multiLine?"true":"false")); templateParams.push_back (std::pair ("want_return", multiLine?"true":"false")); templateParams.push_back (std::pair ("enter_recover_focus", "false")); - templateParams.push_back (std::pair ("max_num_chars", "1024")); + if (maxlength > 0) + templateParams.push_back (std::pair ("max_num_chars", toString(maxlength))); CInterfaceGroup *textArea = CWidgetManager::getInstance()->getParser()->createGroupInstance (templateName.c_str(), getParagraph()->getId(), templateParams.empty()?NULL:&(templateParams[0]), (uint)templateParams.size()); diff --git a/code/nel/src/gui/group_menu.cpp b/code/nel/src/gui/group_menu.cpp index 85ed1959e..08f887e9e 100644 --- a/code/nel/src/gui/group_menu.cpp +++ b/code/nel/src/gui/group_menu.cpp @@ -1203,6 +1203,7 @@ namespace NLGUI pV->setColor (_GroupMenu->_Color); pV->setFontSize (_GroupMenu->_FontSize); pV->setShadow (_GroupMenu->_Shadow); + pV->setShadowOutline (_GroupMenu->_ShadowOutline); pV->setCheckable(checkable); pV->setChecked(checked); pV->setModulateGlobalColor(_GroupMenu->_ModulateGlobalColor); @@ -1282,6 +1283,7 @@ namespace NLGUI pV->setColor (_GroupMenu->_Color); pV->setFontSize (_GroupMenu->_FontSize); pV->setShadow (_GroupMenu->_Shadow); + pV->setShadowOutline (_GroupMenu->_ShadowOutline); pV->setCheckable(checkable); pV->setChecked(checked); pV->setModulateGlobalColor(_GroupMenu->_ModulateGlobalColor); @@ -1922,6 +1924,7 @@ namespace NLGUI _HighLightOver.set(128, 0, 0, 255); _FontSize = 12; _Shadow = false; + _ShadowOutline = false; _ResizeFromChildH = _ResizeFromChildW = true; _DisplayFrame = false; _RootMenu = NULL; @@ -1998,6 +2001,11 @@ namespace NLGUI return toString( _Shadow ); } else + if( name == "shadow_outline" ) + { + return toString( _ShadowOutline ); + } + else if( name == "formatted" ) { return toString( _Formatted ); @@ -2110,6 +2118,14 @@ namespace NLGUI return; } else + if( name == "shadow_outline" ) + { + bool b; + if( fromString( value, b ) ) + _ShadowOutline = b; + return; + } + else if( name == "formatted" ) { bool b; @@ -2152,6 +2168,7 @@ namespace NLGUI xmlSetProp( node, BAD_CAST "space", BAD_CAST toString( _Space ).c_str() ); xmlSetProp( node, BAD_CAST "fontsize", BAD_CAST toString( _FontSize ).c_str() ); xmlSetProp( node, BAD_CAST "shadow", BAD_CAST toString( _Shadow ).c_str() ); + xmlSetProp( node, BAD_CAST "shadow_outline", BAD_CAST toString( _ShadowOutline ).c_str() ); xmlSetProp( node, BAD_CAST "formatted", BAD_CAST toString( _Formatted ).c_str() ); if( _RootMenu == NULL ) @@ -2197,6 +2214,7 @@ namespace NLGUI _Color = gm->_Color; _ShadowColor = gm->_ShadowColor; _Shadow = gm->_Shadow; + _ShadowOutline = gm->_ShadowOutline; _FontSize = gm->_FontSize; _ColorOver = gm->_ColorOver; _ShadowColorOver = gm->_ShadowColorOver; @@ -2266,6 +2284,10 @@ namespace NLGUI if (prop) _Shadow = convertBool(prop); + prop = (char*) xmlGetProp( in, (xmlChar*)"shadow_outline" ); + if (prop) + _ShadowOutline = convertBool(prop); + prop = (char*) xmlGetProp( in, (xmlChar*)"formatted" ); if (prop) _Formatted = convertBool(prop); diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index 2fdd7e364..65ed2d93d 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -44,9 +44,12 @@ namespace NLGUI TableRatio = 0.f; WidthWanted = 0; Height = 0; + ColSpan = 1; + RowSpan = 1; + TableColumnIndex = 0; Group = new CInterfaceGroup(CViewBase::TCtorParam()); Align = Left; - VAlign = Top; + VAlign = Middle; LeftMargin = 0; NoWrap = false; IgnoreMaxWidth = false; @@ -249,6 +252,22 @@ namespace NLGUI AddChildW = b; return; } + else + if (name == "colspan" ) + { + sint32 i; + if (fromString( value, i ) ) + ColSpan = std::max(1, i); + return; + } + else + if (name == "rowspan" ) + { + sint32 i; + if (fromString( value, i ) ) + RowSpan = std::max(1, i); + return; + } else CInterfaceGroup::setProperty( name, value ); } @@ -310,6 +329,8 @@ namespace NLGUI xmlSetProp( node, BAD_CAST "ignore_max_width", BAD_CAST toString( IgnoreMaxWidth ).c_str() ); xmlSetProp( node, BAD_CAST "ignore_min_width", BAD_CAST toString( IgnoreMinWidth ).c_str() ); xmlSetProp( node, BAD_CAST "add_child_w", BAD_CAST toString( AddChildW ).c_str() ); + xmlSetProp( node, BAD_CAST "colspan", BAD_CAST toString( ColSpan ).c_str() ); + xmlSetProp( node, BAD_CAST "rowspan", BAD_CAST toString( RowSpan ).c_str() ); return node; } @@ -422,6 +443,22 @@ namespace NLGUI { AddChildW = convertBool(ptr); } + // + ptr = (char*) xmlGetProp( cur, (xmlChar*)"colspan" ); + if (ptr) + { + sint32 i; + if (fromString((const char*)ptr, i)) + ColSpan = std::max(1, i); + } + // + ptr = (char*) xmlGetProp( cur, (xmlChar*)"rowspan" ); + if (ptr) + { + sint32 i; + if (fromString((const char*)ptr, i)) + RowSpan = std::max(1, i); + } return true; } @@ -499,6 +536,29 @@ namespace NLGUI } } + // Get the parent table + if (getParent ()) + { + CGroupTable *table = static_cast (getParent ()); + if (table->Border) { + CRGBA lighter = blend(table->BorderColor, CRGBA::White, 0.5f); + + CRGBA borderColorTL; + borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); + borderColorTL.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorTL.A) >> 8); + + CRGBA borderColorBR; + borderColorBR.modulateFromColor (table->BorderColor, CWidgetManager::getInstance()->getGlobalColor()); + borderColorBR.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorBR.A) >> 8); + + CViewRenderer &rVR = *CViewRenderer::getInstance(); + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorTL ); + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorBR ); + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_HReal-1, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorBR ); + rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorTL ); + } + } + CInterfaceGroup::draw (); } @@ -559,8 +619,9 @@ namespace NLGUI TableRatio = 0.f; ForceWidthMin = 0; Border=0; - CellPadding=0; - CellSpacing=0; + BorderColor = CRGBA(32, 32, 32, 255); + CellPadding=1; + CellSpacing=2; ContinuousUpdate = false; } @@ -692,35 +753,75 @@ namespace NLGUI // New cell ? if (cell->NewLine) + { + while (column < _Columns.size()) + { + if (_Columns[column].RowSpan > 1) + _Columns[column].RowSpan--; + column++; + } column = 0; + } // Resize the array if (column>=_Columns.size()) _Columns.resize(column+1); + // Handle rowspan from previous row + while (_Columns[column].RowSpan > 1) + { + _Columns[column].RowSpan--; + column++; + // if previous row had less elements, then we missing columns + if (column>=_Columns.size()) + _Columns.resize(column+1); + } + + // remember column index for later use + cell->TableColumnIndex = column; + + // new column, set rowspan from current + _Columns[column].RowSpan = cell->RowSpan; + float colspan = 1.f / cell->ColSpan; + float rowspan = 1.f / cell->RowSpan; + // Update sizes - if (cellWidth > _Columns[column].Width) - _Columns[column].Width = cellWidth; - if (cell->WidthMax > _Columns[column].WidthMax) - _Columns[column].WidthMax = cell->WidthMax; - if (cell->TableRatio > _Columns[column].TableRatio) - _Columns[column].TableRatio = cell->TableRatio; - if (cell->WidthWanted + additionnalWidth > _Columns[column].WidthWanted) - _Columns[column].WidthWanted = cell->WidthWanted + additionnalWidth; - if (cell->Height > _Columns[column].Height) - _Columns[column].Height = cell->Height; + if (cellWidth*colspan > _Columns[column].Width) + _Columns[column].Width = cellWidth*colspan; + if (cell->WidthMax*colspan > _Columns[column].WidthMax) + _Columns[column].WidthMax = cell->WidthMax*colspan; + if (cell->TableRatio*colspan > _Columns[column].TableRatio) + _Columns[column].TableRatio = cell->TableRatio*colspan; + if (cell->WidthWanted*colspan + additionnalWidth > _Columns[column].WidthWanted) + _Columns[column].WidthWanted = (sint32)(cell->WidthWanted*colspan) + additionnalWidth; if (_Columns[column].WidthWanted + additionnalWidth) _Columns[column].WidthMax = _Columns[column].WidthWanted + additionnalWidth; if (_Columns[column].WidthWanted > _Columns[column].Width) _Columns[column].Width = _Columns[column].WidthWanted; + if (cell->ColSpan > 1) { + // copy this info to all spanned columns, create new columns as needed + uint newsize = column + cell->ColSpan - 1; + if (newsize >= _Columns.size()) + _Columns.resize(newsize+1); + for(uint span = 0; span < cell->ColSpan -1; span++){ + column++; + _Columns[column].Width = _Columns[column-1].Width; + _Columns[column].WidthMax = _Columns[column-1].WidthMax; + _Columns[column].TableRatio = _Columns[column-1].TableRatio; + _Columns[column].WidthWanted = _Columns[column-1].WidthWanted; + _Columns[column].RowSpan = _Columns[column-1].RowSpan; + } + } + // Next column column++; } // Width of cells and table borders - sint32 borderWidth = 2*Border + ((sint32)_Columns.size()+1) * CellSpacing + ((sint32)_Columns.size()*2) * CellPadding; + sint32 padding = CellPadding + (Border ? 1 : 0); + sint32 borderWidth = 2*Border + ((sint32)_Columns.size()+1) * CellSpacing + ((sint32)_Columns.size()*2) * padding; // Get the width sint32 tableWidthMax = ForceWidthMin?ForceWidthMin:_LastParentW; // getWReal(); @@ -802,7 +903,6 @@ namespace NLGUI // Some space ? space = finalWidth - tableWidth; - if (space > 0) { // Then add in wanted Width cells @@ -892,6 +992,18 @@ namespace NLGUI } } } + + // If there is still space left, then sum up column widths + // and add all the remaining space to final column. + if (space > 0) + { + sint32 innerWidth = 0; + for(i=0;i<_Columns.size();i++) + innerWidth += _Columns[i].Width; + + if (innerWidth > 0 && finalWidth > innerWidth) + _Columns[_Columns.size()-1].Width += finalWidth - innerWidth; + } } } } @@ -902,7 +1014,8 @@ namespace NLGUI column = 0; sint32 row = 0; - sint32 currentX = Border + CellSpacing + CellPadding; + sint32 currentX = Border + CellSpacing + padding; + _Rows.clear (); for (i=0; i<_Cells.size(); i++) { @@ -911,25 +1024,41 @@ namespace NLGUI if (cell->NewLine) { column = 0; - currentX = Border + CellSpacing + CellPadding; + currentX = Border + CellSpacing + padding; + _Rows.push_back(CRow()); } + if (cell->TableColumnIndex > 0) + { + // we have active rowspan, must add up 'skipped' columns + for( ; columnTableColumnIndex; column++) + currentX += _Columns[column].Width + padding*2 + CellSpacing; + } + // Set the x and width // Check align sint32 alignmentX = 0; sint32 widthReduceX = 0; - if (cell->WidthMax < _Columns[column].Width) + sint32 columnWidth = _Columns[column].Width; + if (cell->ColSpan > 1) + { + // scan ahead and add up column widths as they might be different + for(int j = 1; jColSpan; j++) + columnWidth += CellSpacing + padding*2 + _Columns[column+j].Width; + } + + if (cell->WidthMax < columnWidth) { switch (cell->Align) { case CGroupCell::Center: - alignmentX = (_Columns[column].Width - cell->WidthMax) / 2; + alignmentX = (columnWidth - cell->WidthMax) / 2; widthReduceX = alignmentX * 2; break; case CGroupCell::Right: - alignmentX = _Columns[column].Width - cell->WidthMax; + alignmentX = columnWidth - cell->WidthMax; widthReduceX = alignmentX; break; default: @@ -937,11 +1066,11 @@ namespace NLGUI } } - cell->setX(currentX); - cell->setW(_Columns[column].Width); + cell->setX(currentX - padding); + cell->setW(columnWidth + padding*2); - cell->Group->setX(alignmentX+cell->LeftMargin); - cell->Group->setW(_Columns[column].Width - widthReduceX); + cell->Group->setX(alignmentX + cell->LeftMargin + padding); + cell->Group->setW(columnWidth - widthReduceX); cell->Group->CInterfaceElement::updateCoords(); // Update coords to get H @@ -949,16 +1078,17 @@ namespace NLGUI cell->Group->updateCoords(); // Resize the row array - _Rows.back().Height = std::max(cell->Height, std::max(_Rows.back().Height, (sint32)cell->Group->getH())); + float rowspan = 1 / cell->RowSpan; + _Rows.back().Height = std::max((sint32)(cell->Height*rowspan), std::max(_Rows.back().Height, (sint32)(cell->Group->getH()*rowspan))); // Next column - currentX += _Columns[column].Width + 2*CellPadding + CellSpacing; - column ++; + currentX += columnWidth + 2*padding + CellSpacing; + column += cell->ColSpan; } // Set cell Y row = 0; - sint32 currentY = -(Border + CellSpacing + CellPadding); + sint32 currentY = -(Border + CellSpacing + padding); for (i=0; i<_Cells.size(); i++) { // New cell ? @@ -967,37 +1097,45 @@ namespace NLGUI { if (_Rows[row].Height != 0) { - currentY -= _Rows[row].Height + 2*CellPadding + CellSpacing; + currentY -= _Rows[row].Height + 2*padding + CellSpacing; } row++; } // Check align sint32 alignmentY = 0; - if ((sint32)cell->Group->getH() < _Rows[row].Height) + sint32 rowHeight = _Rows[row].Height; + if (cell->RowSpan > 1) + { + // we need to scan down and add up row heights + int k = std::min((sint32)_Rows.size(), row + cell->RowSpan); + for(int j=row+1; jGroup->getH() < rowHeight) { switch (cell->VAlign) { case CGroupCell::Middle: - alignmentY = (_Rows[row].Height - (sint32)cell->Group->getH()) / 2; + alignmentY = (rowHeight - (sint32)cell->Group->getH()) / 2; break; case CGroupCell::Bottom: - alignmentY = _Rows[row].Height - (sint32)cell->Group->getH(); + alignmentY = rowHeight - (sint32)cell->Group->getH(); break; default: break; } } - cell->setY(currentY); - cell->setH (_Rows[row].Height); - cell->Group->setY(-alignmentY); + cell->setY(currentY + padding); + cell->setH (rowHeight + 2*padding); + cell->Group->setY(-(alignmentY + padding)); } // Resize the table setW(finalWidth+borderWidth-_LastParentW); if (!_Rows.empty()) - currentY -= _Rows[row].Height + CellPadding + CellSpacing + Border; + currentY -= _Rows[row].Height + padding + CellSpacing + Border; setH(-currentY); // All done @@ -1177,60 +1315,66 @@ namespace NLGUI if (gr == NULL) CurrentAlpha = 255; - if (!_Columns.empty() && !_Rows.empty() && BgColor.A) + if (!_Columns.empty() && !_Rows.empty()) { - sint32 border = Border + CellSpacing + CellPadding; - if (border) + sint32 border = Border + CellSpacing; + if (border && BgColor.A) { CRGBA finalColor; finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor()); finalColor.A = CurrentAlpha; - // Draw the top and bottom lines + // Draw the top line CViewRenderer &rVR = *CViewRenderer::getInstance(); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, border, 0, false, rVR.getBlankTextureId(), finalColor); rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal-border+_HReal, _WReal, border, 0, false, rVR.getBlankTextureId(), finalColor); - // Draw the left and right lines - sint32 insideHeight = std::max((sint32)0, (sint32)_HReal - (sint32)2*border); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+border, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-border, _YReal+border, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor); + // Draw the left line + sint32 insideHeight = std::max((sint32)0, (sint32)_HReal - (sint32)border); + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor); // Draw the inside borders - sint32 insideWidth = 2*CellPadding + CellSpacing; - if (insideWidth) + if (CellSpacing) { - // Draw the inside verticals uint i; - sint32 x = _XReal + _Columns[0].Width + border; - for (i=1; i<_Columns.size(); i++) + sint32 x, y; + for (i=0; i<_Cells.size(); i++) { - rVR.drawRotFlipBitmap (_RenderLayer, x, _YReal+border, insideWidth, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor); - x += _Columns[i].Width + insideWidth; - } + CGroupCell *cell = _Cells[i]; - // Draw the inside horizontals - sint32 y = _YReal + _HReal - border - _Rows[0].Height; - if (_Rows[0].Height != 0) - { - y -= insideWidth; - } - for (i=1; i<_Rows.size(); i++) - { - uint j; - x = _XReal + border; - if (_Rows[i].Height != 0) - { - for (j=0; j<_Columns.size(); j++) - { - rVR.drawRotFlipBitmap (_RenderLayer, x, y, _Columns[j].Width, insideWidth, 0, false, rVR.getBlankTextureId(), finalColor); - x += _Columns[j].Width + insideWidth; - } - y -= _Rows[i].Height+ insideWidth; - } + x = cell->getXReal(); + y = cell->getYReal() - CellSpacing; + // right + rVR.drawRotFlipBitmap (_RenderLayer, x + cell->getW(), y, CellSpacing, cell->getH() + CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor); + // bottom + rVR.drawRotFlipBitmap (_RenderLayer, x, y, cell->getW(), CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor); } } + } + if (Border) + { + CViewRenderer &rVR = *CViewRenderer::getInstance(); + + CRGBA borderColorTL; + CRGBA lighter = blend(BorderColor, CRGBA::White, 0.5f); + borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); + borderColorTL.A = CurrentAlpha; + + CRGBA borderColorBR; + borderColorBR.modulateFromColor (BorderColor, CWidgetManager::getInstance()->getGlobalColor()); + borderColorBR.A = CurrentAlpha; + + // beveled table border + for (sint32 i=0; igetParser()->getParentPosAssociation( (CInterfaceElement*)this ); + std::string pp; + getPosParent( pp ); + return pp; } else if( name == "sizeparent" ) { - return CWidgetManager::getInstance()->getParser()->getParentSizeAssociation( (CInterfaceElement*)this ); + std::string sp; + getSizeParent( sp ); + return sp; } else if( name == "global_color" ) @@ -226,13 +230,13 @@ namespace NLGUI else if( name == "posref" ) { - convertHotSpot( value.c_str() ); + _PosRef = convertHotSpot( value.c_str() ); return; } else if( name == "parentposref" ) { - convertHotSpot( value.c_str() ); + _ParentPosRef = convertHotSpot( value.c_str() ); } else if( name == "sizeref" ) @@ -294,11 +298,13 @@ namespace NLGUI xmlNewProp( node, BAD_CAST "w", BAD_CAST toString( _W ).c_str() ); xmlNewProp( node, BAD_CAST "h", BAD_CAST toString( _H ).c_str() ); xmlNewProp( node, BAD_CAST "posref", BAD_CAST HotSpotCoupleToString( _ParentPosRef, _PosRef ).c_str() ); - xmlNewProp( node, BAD_CAST "posparent", - BAD_CAST CWidgetManager::getInstance()->getParser()->getParentPosAssociation( (CInterfaceElement*)this ).c_str() ); + + std::string pp; + getPosParent( pp ); + xmlNewProp( node, BAD_CAST "posparent", BAD_CAST pp.c_str() ); xmlNewProp( node, BAD_CAST "sizeref", BAD_CAST getSizeRefAsString().c_str() ); - xmlNewProp( node, BAD_CAST "sizeparent", - BAD_CAST CWidgetManager::getInstance()->getParser()->getParentSizeAssociation( (CInterfaceElement*)this ).c_str() ); + getSizeParent( pp ); + xmlNewProp( node, BAD_CAST "sizeparent", BAD_CAST pp.c_str() ); xmlNewProp( node, BAD_CAST "global_color", BAD_CAST toString( _ModulateGlobalColor ).c_str() ); xmlNewProp( node, BAD_CAST "render_layer", BAD_CAST toString( _RenderLayer ).c_str() ); @@ -382,13 +388,13 @@ namespace NLGUI ptr = (char*) xmlGetProp( cur, (xmlChar*)"posparent" ); if (ptr) { - setPosParent( std::string( (const char*)ptr ) ); + parsePosParent( (const char*)ptr ); } ptr = (char*) xmlGetProp( cur, (xmlChar*)"sizeparent" ); if (ptr) { - setSizeParent( std::string( (const char*)ptr ) ); + parseSizeParent( (const char*)ptr ); } ptr = (char*) xmlGetProp (cur, (xmlChar*)"sizeref"); @@ -1526,42 +1532,170 @@ namespace NLGUI return false; } + void CInterfaceElement::parsePosParent( const std::string &id ) + { + CInterfaceElement *p = getParent(); + + if( ( id == "parent" ) || ( id.empty() ) ) + { + setParentPos( p ); + return; + } + + std::string ppId; + + if( p != NULL ) + ppId = p->getId() + ":" + id; + else + ppId = std::string( "ui:" ) + id; + + CWidgetManager::getInstance()->getParser()->addParentPositionAssociation( this, ppId ); + } + void CInterfaceElement::setPosParent( const std::string &id ) { - std::string Id = stripId( id ); - - if( Id != "parent" ) + // Parent or empty id simply means the group parent + if( ( id == "parent" ) || ( id.empty() ) ) { - std::string idParent; - if( _Parent != NULL ) - idParent = _Parent->getId() + ":"; - else - idParent = "ui:"; - CWidgetManager::getInstance()->getParser()->addParentPositionAssociation( this, idParent + Id ); + setParentPos( getParent() ); + return; } + + CInterfaceElement *pp = NULL; + + // Check if it's a short Id + std::string::size_type idx = id.find( "ui:" ); + if( idx == std::string::npos ) + { + // If it is, find the widget in the parent group and set as posparent + CInterfaceGroup *p = getParent(); + if( p != NULL ) + { + pp = p->findFromShortId( id ); + } + } + else + { + // If it is not, find using the widgetmanager + // TODO: refactor, shouldn't use a singleton + pp = CWidgetManager::getInstance()->getElementFromId( id ); + } + + if( pp != NULL ) + setParentPos( pp ); + + } + + void CInterfaceElement::getPosParent( std::string &id ) const + { + + // If there's no pos parent set, then the parent group is the pos parent + if( getParentPos() == NULL ) + { + id = "parent"; + return; + } + + // If pos parent and parent are the same then ofc the parent group is the pos parent... + CInterfaceElement *p = getParent(); + if( getParentPos() == p ) + { + id = "parent"; + return; + } + + // If parent is in the same group, use the short id + p = getParentPos(); + if( p->isInGroup( getParent() ) ) + { + id = p->getShortId(); + return; + } + + // Otherwise use the full id + id = p->getId(); + } + + void CInterfaceElement::parseSizeParent( const std::string &id ) + { + CInterfaceElement *p = getParent(); + + if( ( id == "parent" ) || ( id.empty() ) ) + { + setParentSize( p ); + return; + } + + std::string spId; + + if( p != NULL ) + spId = p->getId() + ":" + id; + else + spId = std::string( "ui:" ) + id; + + CWidgetManager::getInstance()->getParser()->addParentSizeAssociation( this, spId ); } void CInterfaceElement::setSizeParent( const std::string &id ) { - std::string Id = stripId( id ); - std::string idParent; - - if( Id != "parent" ) + // Parent or empty id simply means the group parent + if( ( id == "parent" ) || ( id.empty() ) ) { - if( _Parent != NULL ) - idParent = _Parent->getId() + ":"; - else - idParent = "ui:"; - CWidgetManager::getInstance()->getParser()->addParentSizeAssociation( this, idParent + Id ); + setParentSize( getParent() ); + return; + } + + CInterfaceElement *pp = NULL; + + // Check if it's a short Id + std::string::size_type idx = id.find( "ui:" ); + if( idx == std::string::npos ) + { + // If it is, find the widget in the parent group and set as posparent + CInterfaceGroup *p = getParent(); + if( p != NULL ) + { + pp = p->findFromShortId( id ); + } } else { - if( _Parent != NULL ) - { - idParent = _Parent->getId(); - CWidgetManager::getInstance()->getParser()->addParentSizeAssociation( this, idParent ); - } + // If it is not, find using the widgetmanager + // TODO: refactor, shouldn't use a singleton + pp = CWidgetManager::getInstance()->getElementFromId( id ); } + + if( pp != NULL ) + setParentSize( pp ); + } + + void CInterfaceElement::getSizeParent( std::string &id ) const + { + CInterfaceElement *p = getParentSize(); + + // If there's no parent set then the size parent is the parent + if( p == NULL ) + { + id = "parent"; + return; + } + + // If the size parent is the same as the group parent, then the size parent is the parent ofc + if( p == getParent() ) + { + id = "parent"; + return; + } + + // If the size parent is in the parent group, use the short Id + if( p->isInGroup( getParent() ) ) + { + id = p->getShortId(); + return; + } + + // Otherwise use the full Id + id = p->getId(); } void CInterfaceElement::registerDeletionWatcher( IDeletionWatcher *watcher ) @@ -1594,6 +1728,105 @@ namespace NLGUI } } + void CInterfaceElement::getHSCoords( const THotSpot &hs, sint32 &x, sint32 &y ) const + { + x = _XReal; + y = _YReal; + + if( ( hs & Hotspot_Mx ) != 0 ) + y += _HReal / 2; + else + if( ( hs & Hotspot_Tx ) != 0 ) + y += _HReal; + + + if( ( hs & Hotspot_xM ) != 0 ) + x += _WReal / 2; + else + if( ( hs & Hotspot_xR ) != 0 ) + x += _WReal; + } + + void CInterfaceElement::getClosestHotSpot( const CInterfaceElement *other, THotSpot &hs ) + { + /// Iterate over the following hotspots, calculate the distance and store the closest + + + static THotSpot hslist[] = + { + Hotspot_BL, + Hotspot_BR, + Hotspot_MM, + Hotspot_TL, + Hotspot_TR + }; + + int c = sizeof( hslist ) / sizeof( THotSpot ); + + int x,y,ox,oy,vx,vy; + float d; + float closestd = 9999999.0f; + THotSpot closestHS = Hotspot_TR; + + for( int i = 0; i < c; i++ ) + { + other->getHSCoords( hslist[ i ], ox, oy ); + getHSCoords( hslist[ i ], x, y ); + + // Make a vector between the two hotspots + vx = x - ox; + vy = y - oy; + + // Calculate length + d = sqrt( pow( vx, 2.0f ) + pow( vy, 2.0f ) ); + + // If these hotspots are the closest, store the hotspot + if( d < closestd ) + { + closestd = d; + closestHS = hslist[ i ]; + } + } + + hs = closestHS; + } + + void CInterfaceElement::alignTo( CInterfaceElement *other ) + { + if( other == this ) + return; + + // Check which hotspot is the closest + THotSpot hs; + other->getClosestHotSpot( this, hs ); + + // Get the hotspot coordinates + sint32 x, y, ox, oy; + getHSCoords( hs, x, y ); + other->getHSCoords( hs, ox, oy ); + + // Calculate the difference between the hotspot we found and our current position, + sint32 dx = ox - x; + sint32 dy = oy - y; + + // This difference is our offset, so we remain in the same position + setX( -1 * dx ); + setY( -1 * dy ); + + setPosRef( hs ); + setParentPosRef( hs ); + + invalidateCoords(); + } + + void CInterfaceElement::onWidgetDeleted( CInterfaceElement *e ) + { + if( e == getParentPos() ) + setParentPos( NULL ); + if( e == getParentSize() ) + setParentSize( NULL ); + } + CStringMapper* CStringShared::_UIStringMapper = NULL; diff --git a/code/nel/src/misc/input_device.cpp b/code/nel/src/gui/interface_factory.cpp similarity index 65% rename from code/nel/src/misc/input_device.cpp rename to code/nel/src/gui/interface_factory.cpp index 3825935a6..ec914baa6 100644 --- a/code/nel/src/misc/input_device.cpp +++ b/code/nel/src/gui/interface_factory.cpp @@ -1,4 +1,4 @@ -// NeL - MMORPG Framework +// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify @@ -14,18 +14,16 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -#include "stdmisc.h" -#include "nel/misc/input_device.h" +#include "nel/gui/interface_factory.h" +#include "nel/gui/view_base.h" +#include "nel/misc/factory.h" -// remove stupid VC6 warnings -void foo_input_device_cpp() {} - -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NLMISC +namespace NLGUI { + CViewBase* CInterfaceFactory::createClass( const std::string &name ) + { + return NLMISC_GET_FACTORY( CViewBase, std::string ).createObject( std::string( name ) , CViewBase::TCtorParam() ); + } +} -} // NLMISC diff --git a/code/nel/src/gui/interface_group.cpp b/code/nel/src/gui/interface_group.cpp index 5fa83e1c5..29ad75f8c 100644 --- a/code/nel/src/gui/interface_group.cpp +++ b/code/nel/src/gui/interface_group.cpp @@ -911,6 +911,31 @@ namespace NLGUI } } + // ------------------------------------------------------------------------------------------------ + void CInterfaceGroup::addElement (CInterfaceElement *child, sint eltOrder /*= -1*/) + { + if (!child) + { + nlwarning(" : tried to add a NULL view"); + return; + } + + if( child->isGroup() ) + { + addGroup( static_cast< CInterfaceGroup* >( child ), eltOrder ); + } + else + if( child->isCtrl() ) + { + addCtrl( static_cast< CCtrlBase* >( child ), eltOrder ); + } + else + if( child->isView() ) + { + addView( static_cast< CViewBase* >( child ), eltOrder ); + } + } + // ------------------------------------------------------------------------------------------------ void CInterfaceGroup::addView (CViewBase *child, sint eltOrder /*= -1*/) { @@ -1312,6 +1337,11 @@ namespace NLGUI for (ite = _EltOrder.begin() ; ite != _EltOrder.end(); ite++) { CViewBase *pVB = *ite; + if( pVB->getName() == "=MARKED=" ) + { + nlinfo( "=MARKED=" ); + } + if (pVB->getActive()) pVB->draw(); } @@ -1638,6 +1668,32 @@ namespace NLGUI return delView(static_cast(pIE)); } + // ------------------------------------------------------------------------------------------------ + CInterfaceElement* CInterfaceGroup::takeElement( CInterfaceElement *e ) + { + bool ok = false; + + if( e->isGroup() ) + { + ok = delGroup( static_cast< CInterfaceGroup* >( e ), true ); + } + else + if( e->isCtrl() ) + { + ok = delCtrl( static_cast< CCtrlBase* >( e ), true ); + } + else + if( e->isView() ) + { + ok = delView( static_cast< CViewBase* >( e ), true ); + } + + if( ok ) + return e; + else + return NULL; + } + // ------------------------------------------------------------------------------------------------ bool CInterfaceGroup::isWindowUnder (sint32 x, sint32 y) { @@ -2488,5 +2544,101 @@ namespace NLGUI for( std::vector< CInterfaceGroup* >::iterator itr = _ChildrenGroups.begin(); itr != _ChildrenGroups.end(); ++itr ) (*itr)->onWidgetDeleted( e ); } + + void CInterfaceGroup::moveBy( sint32 x, sint32 y ) + { + CInterfaceElement::moveBy( x, y ); + + for( int i = 0; i < _EltOrder.size(); i++ ) + { + CViewBase *v = _EltOrder[ i ]; + v->updateCoords(); + } + } + + bool CInterfaceGroup::explode() + { + CInterfaceGroup *p = getParent(); + if( p == NULL ) + return false; + + std::string oldId; + + // Reparent children + for( sint32 i = 0; i < _EltOrder.size(); i++ ) + { + CInterfaceElement *e = _EltOrder[ i ]; + + oldId = e->getId(); + + e->setW( e->getWReal() ); + e->setH( e->getHReal() ); + e->setSizeRef( "" ); + + e->setParent( p ); + + e->setParentPos( p ); + e->setParentSize( p ); + e->alignTo( p ); + + p->addElement( e ); + e->setIdRecurse( e->getShortId() ); + + CWidgetManager::getInstance()->onWidgetMoved( oldId, e->getId() ); + } + + _EltOrder.clear(); + _Views.clear(); + _Controls.clear(); + _ChildrenGroups.clear(); + + return true; + } + + void CInterfaceGroup::spanElements() + { + sint32 minx = std::numeric_limits< sint32 >::max(); + sint32 miny = std::numeric_limits< sint32 >::max(); + sint32 maxx = std::numeric_limits< sint32 >::min(); + sint32 maxy = std::numeric_limits< sint32 >::min(); + + sint32 tlx,tly,brx,bry; + + // Find the min and max coordinates of the elements + for( int i = 0; i < _EltOrder.size(); i++ ) + { + CViewBase *v = _EltOrder[ i ]; + + v->getHSCoords( Hotspot_TL, tlx, tly ); + v->getHSCoords( Hotspot_BR, brx, bry ); + + if( tlx < minx ) + minx = tlx; + if( brx > maxx ) + maxx = brx; + if( bry < miny ) + miny = bry; + if( tly > maxy ) + maxy = tly; + } + + // Set the position and the width and height based on these coords + setW( maxx - minx ); + setH( maxy - miny ); + _WReal = getW(); + _HReal = getH(); + _XReal = minx; + _YReal = miny; + } + + void CInterfaceGroup::alignElements() + { + for( int i = 0; i < _EltOrder.size(); i++ ) + { + CViewBase *v = _EltOrder[ i ]; + v->alignTo( this ); + } + } + } diff --git a/code/nel/src/gui/interface_options.cpp b/code/nel/src/gui/interface_options.cpp index 9f70ceeff..3de015d65 100644 --- a/code/nel/src/gui/interface_options.cpp +++ b/code/nel/src/gui/interface_options.cpp @@ -271,16 +271,25 @@ namespace NLGUI // TxId_TL_HighLight = rVR.getTextureIdFromName (getValStr("tx_tl_highlight")); + rVR.getTextureSizeFromId(TxId_TL_HighLight, W_TL_HighLight, H_TL_HighLight); TxId_T_HighLight = rVR.getTextureIdFromName (getValStr("tx_t_highlight")); + rVR.getTextureSizeFromId(TxId_T_HighLight, W_T_HighLight, H_T_HighLight); TxId_TR_HighLight = rVR.getTextureIdFromName (getValStr("tx_tr_highlight")); + rVR.getTextureSizeFromId(TxId_TR_HighLight, W_TR_HighLight, H_TR_HighLight); TxId_L_HighLight = rVR.getTextureIdFromName (getValStr("tx_l_highlight")); + rVR.getTextureSizeFromId(TxId_L_HighLight, W_L_HighLight, H_L_HighLight); TxId_R_HighLight = rVR.getTextureIdFromName (getValStr("tx_r_highlight")); + rVR.getTextureSizeFromId(TxId_R_HighLight, W_R_HighLight, H_R_HighLight); TxId_BL_HighLight = rVR.getTextureIdFromName (getValStr("tx_bl_highlight")); + rVR.getTextureSizeFromId(TxId_BL_HighLight, W_BL_HighLight, H_BL_HighLight); TxId_B_HighLight = rVR.getTextureIdFromName (getValStr("tx_b_highlight")); + rVR.getTextureSizeFromId(TxId_B_HighLight, W_B_HighLight, H_B_HighLight); TxId_BR_HighLight = rVR.getTextureIdFromName (getValStr("tx_br_highlight")); + rVR.getTextureSizeFromId(TxId_BR_HighLight, W_BR_HighLight, H_BR_HighLight); // HeaderH = getValSInt32("header_h"); + InsetT = getValSInt32("inset_t"); return true; } diff --git a/code/nel/src/gui/interface_parser.cpp b/code/nel/src/gui/interface_parser.cpp index b26a403c4..096c001ae 100644 --- a/code/nel/src/gui/interface_parser.cpp +++ b/code/nel/src/gui/interface_parser.cpp @@ -37,6 +37,7 @@ #include "nel/gui/lua_helper.h" #include "nel/gui/lua_ihm.h" #include "nel/gui/lua_manager.h" +#include "nel/gui/root_group.h" #ifdef LUA_NEVRAX_VERSION #include "lua_ide_dll_nevrax/include/lua_ide_dll/ide_interface.h" // external debugger @@ -113,86 +114,6 @@ namespace NLGUI return node; } - - - // ---------------------------------------------------------------------------- - // CRootGroup - // ---------------------------------------------------------------------------- - - class CRootGroup : public CInterfaceGroup - { - public: - CRootGroup(const TCtorParam ¶m) - : CInterfaceGroup(param) - { } - - /// Destructor - virtual ~CRootGroup() { } - - virtual CInterfaceElement* getElement (const std::string &id) - { - if (_Id == id) - return this; - - if (id.substr(0, _Id.size()) != _Id) - return NULL; - - vector::const_iterator itv; - for (itv = _Views.begin(); itv != _Views.end(); itv++) - { - CViewBase *pVB = *itv; - if (pVB->getId() == id) - return pVB; - } - - vector::const_iterator itc; - for (itc = _Controls.begin(); itc != _Controls.end(); itc++) - { - CCtrlBase* ctrl = *itc; - if (ctrl->getId() == id) - return ctrl; - } - - // Accelerate - string sTmp = id; - sTmp = sTmp.substr(_Id.size()+1,sTmp.size()); - string::size_type pos = sTmp.find(':'); - if (pos != string::npos) - sTmp = sTmp.substr(0,pos); - - map::iterator it = _Accel.find(sTmp); - if (it != _Accel.end()) - { - CInterfaceGroup *pIG = it->second; - return pIG->getElement(id); - } - return NULL; - } - - virtual void addGroup (CInterfaceGroup *child, sint eltOrder = -1) - { - string sTmp = child->getId(); - sTmp = sTmp.substr(_Id.size()+1,sTmp.size()); - _Accel.insert(pair(sTmp, child)); - CInterfaceGroup::addGroup(child,eltOrder); - } - - virtual bool delGroup (CInterfaceGroup *child, bool dontDelete = false) - { - string sTmp = child->getId(); - sTmp = sTmp.substr(_Id.size()+1,sTmp.size()); - map::iterator it = _Accel.find(sTmp); - if (it != _Accel.end()) - { - _Accel.erase(it); - } - return CInterfaceGroup::delGroup(child,dontDelete); - } - - private: - map _Accel; - }; - // ---------------------------------------------------------------------------- // CInterfaceParser // ---------------------------------------------------------------------------- @@ -233,6 +154,22 @@ namespace NLGUI destStream.seek(0, NLMISC::IStream::begin); } + std::string CInterfaceParser::lookup( const std::string &file ) + { + std::string filename; + + if( editorMode && !_WorkDir.empty() ) + { + std::string wdpath = CPath::standardizePath( _WorkDir ) + file; + if( CFile::fileExists( wdpath ) ) + filename = wdpath; + } + if( filename.empty() ) + filename = CPath::lookup( file ); + + return filename; + } + // ---------------------------------------------------------------------------- bool CInterfaceParser::parseInterface (const std::vector & strings, bool reload, bool isFilename, bool checkInData) { @@ -270,7 +207,7 @@ namespace NLGUI { //get the first file document pointer firstFileName = *it; - string filename = CPath::lookup(firstFileName); + string filename = lookup( firstFileName ); bool isInData = false; string::size_type pos = filename.find ("@"); if (pos != string::npos) @@ -283,7 +220,7 @@ namespace NLGUI isInData = true; } - if ((needCheck && !isInData) || !file.open (CPath::lookup(firstFileName))) + if ((needCheck && !isInData) || !file.open (lookup(firstFileName))) { // todo hulud interface syntax error nlwarning ("could not open file %s, skipping xml parsing",firstFileName.c_str()); @@ -331,7 +268,7 @@ namespace NLGUI { saveParseResult = true; std::string archive = CPath::lookup(nextFileName + "_compressed", false, false); - std::string current = CPath::lookup(nextFileName, false, false); + std::string current = lookup(nextFileName); if (!archive.empty() && !current.empty()) { if (CFile::getFileModificationDate(current) <= CFile::getFileModificationDate(archive)) @@ -351,7 +288,7 @@ namespace NLGUI { if (isFilename) { - if (!file.open(CPath::lookup(nextFileName, false, false))) + if (!file.open(lookup(nextFileName))) { // todo hulud interface syntax error nlwarning ("could not open file %s, skipping xml parsing",nextFileName.c_str()); @@ -3014,6 +2951,34 @@ namespace NLGUI itr->second = linkData; } + void CInterfaceParser::setVariable( const VariableData &v ) + { + CInterfaceProperty prop; + const std::string &type = v.type; + const std::string &value = v.value; + const std::string &entry = v.entry; + + if( type == "sint64" ) + prop.readSInt64( value.c_str(), entry ); + else + if( type == "sint32" ) + prop.readSInt32( value.c_str(), entry ); + else + if( type == "float" || type == "double" ) + prop.readDouble( value.c_str(), entry ); + else + if( type == "bool" ) + prop.readBool( value.c_str(), entry ); + else + if( type == "rgba" ) + prop.readRGBA( value.c_str(), entry ); + else + if( type == "hotspot" ) + prop.readHotSpot( value.c_str(), entry ); + + variableCache[ entry ] = v; + } + bool CInterfaceParser::serializeVariables( xmlNodePtr parentNode ) const { diff --git a/code/nel/src/gui/libwww.cpp b/code/nel/src/gui/libwww.cpp index 1e5f7a226..b17d1cccb 100644 --- a/code/nel/src/gui/libwww.cpp +++ b/code/nel/src/gui/libwww.cpp @@ -86,6 +86,7 @@ namespace NLGUI HTML_ATTR(TABLE,ALIGN), HTML_ATTR(TABLE,BGCOLOR), HTML_ATTR(TABLE,BORDER), + HTML_ATTR(TABLE,BORDERCOLOR), HTML_ATTR(TABLE,CELLPADDING), HTML_ATTR(TABLE,CELLSPACING), HTML_ATTR(TABLE,CLASS), @@ -201,6 +202,7 @@ namespace NLGUI HTML_ATTR(TEXTAREA,DISABLED), HTML_ATTR(TEXTAREA,ID), HTML_ATTR(TEXTAREA,LANG), + HTML_ATTR(TEXTAREA,MAXLENGTH), HTML_ATTR(TEXTAREA,NAME), HTML_ATTR(TEXTAREA,READONLY), HTML_ATTR(TEXTAREA,ROWS), diff --git a/code/nel/src/gui/root_group.cpp b/code/nel/src/gui/root_group.cpp new file mode 100644 index 000000000..bffdd5579 --- /dev/null +++ b/code/nel/src/gui/root_group.cpp @@ -0,0 +1,94 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#include "nel/gui/root_group.h" +#include + +namespace NLGUI +{ + + CRootGroup::CRootGroup(const TCtorParam ¶m) : + CInterfaceGroup(param) + { + } + + CRootGroup::~CRootGroup() + { + } + + CInterfaceElement* CRootGroup::getElement (const std::string &id) + { + if (_Id == id) + return this; + + if (id.substr(0, _Id.size()) != _Id) + return NULL; + + std::vector::const_iterator itv; + for (itv = _Views.begin(); itv != _Views.end(); itv++) + { + CViewBase *pVB = *itv; + if (pVB->getId() == id) + return pVB; + } + + std::vector::const_iterator itc; + for (itc = _Controls.begin(); itc != _Controls.end(); itc++) + { + CCtrlBase* ctrl = *itc; + if (ctrl->getId() == id) + return ctrl; + } + + // Accelerate + std::string sTmp = id; + sTmp = sTmp.substr(_Id.size()+1,sTmp.size()); + std::string::size_type pos = sTmp.find(':'); + if (pos != std::string::npos) + sTmp = sTmp.substr(0,pos); + + std::map::iterator it = _Accel.find(sTmp); + if (it != _Accel.end()) + { + CInterfaceGroup *pIG = it->second; + return pIG->getElement(id); + } + return NULL; + } + + void CRootGroup::addGroup (CInterfaceGroup *child, sint eltOrder) + { + std::string sTmp = child->getId(); + sTmp = sTmp.substr(_Id.size()+1,sTmp.size()); + _Accel.insert(std::pair(sTmp, child)); + CInterfaceGroup::addGroup(child,eltOrder); + } + + bool CRootGroup::delGroup (CInterfaceGroup *child, bool dontDelete) + { + std::string sTmp = child->getId(); + sTmp = sTmp.substr(_Id.size()+1,sTmp.size()); + std::map::iterator it = _Accel.find(sTmp); + if (it != _Accel.end()) + { + _Accel.erase(it); + } + return CInterfaceGroup::delGroup(child,dontDelete); + } + +} + diff --git a/code/nel/src/gui/stdpch.h b/code/nel/src/gui/stdpch.h index bb983f77c..3270e6482 100644 --- a/code/nel/src/gui/stdpch.h +++ b/code/nel/src/gui/stdpch.h @@ -18,6 +18,7 @@ #define NELGUI_H #include +#include #include "nel/misc/types_nl.h" #include "nel/misc/algo.h" diff --git a/code/nel/src/gui/view_base.cpp b/code/nel/src/gui/view_base.cpp index 05d958d3e..2b09061a9 100644 --- a/code/nel/src/gui/view_base.cpp +++ b/code/nel/src/gui/view_base.cpp @@ -57,7 +57,7 @@ namespace NLGUI { if( editorMode ) { - CWidgetManager::getInstance()->setCurrentEditorSelection( getId() ); + CWidgetManager::getInstance()->selectWidget( getId() ); return true; } } diff --git a/code/nel/src/gui/view_text.cpp b/code/nel/src/gui/view_text.cpp index 6ff1930af..db069a29d 100644 --- a/code/nel/src/gui/view_text.cpp +++ b/code/nel/src/gui/view_text.cpp @@ -28,8 +28,6 @@ #include "nel/gui/lua_ihm.h" #include "nel/gui/view_pointer_base.h" -#include - using namespace std; using namespace NLMISC; using namespace NL3D; @@ -62,6 +60,7 @@ namespace NLGUI CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont ).getValSInt32(); _Color = CRGBA(255,255,255,255); _Shadow = false; + _ShadowOutline = false; _ShadowColor = CRGBA(0,0,0,255); _MultiLine = false; @@ -111,7 +110,7 @@ namespace NLGUI ///constructor // *************************************************************************** CViewText:: CViewText (const std::string& id, const std::string Text, sint FontSize, - NLMISC::CRGBA Color, bool Shadow) + NLMISC::CRGBA Color, bool Shadow, bool ShadowOutline) :CViewBase(TCtorParam()) { _Id = id; @@ -120,6 +119,7 @@ namespace NLGUI _FontSize = FontSize + CWidgetManager::getInstance()->getSystemOption( CWidgetManager::OptionAddCoefFont).getValSInt32(); _Color = Color; _Shadow = Shadow; + _ShadowOutline = ShadowOutline; setText(Text); computeFontSize (); } @@ -159,6 +159,7 @@ namespace NLGUI _FontSize = vt._FontSize; _Color = vt._Color; _Shadow = vt._Shadow; + _ShadowOutline = vt._ShadowOutline; _ShadowColor = vt._ShadowColor; _MultiLine = false; @@ -225,6 +226,11 @@ namespace NLGUI return toString( _Shadow ); } else + if( name == "shadow_outline" ) + { + return toString( _ShadowOutline ); + } + else if( name == "shadow_color" ) { return toString( _ShadowColor ); @@ -360,6 +366,14 @@ namespace NLGUI return true; } else + if( name == "shadow_outline" ) + { + bool b; + if( fromString( value, b ) ) + _ShadowOutline = b; + return true; + } + else if( name == "shadow_color" ) { CRGBA c; @@ -520,6 +534,7 @@ namespace NLGUI ).c_str() ); xmlSetProp( node, BAD_CAST "shadow", BAD_CAST toString( _Shadow ).c_str() ); + xmlSetProp( node, BAD_CAST "shadow_outline", BAD_CAST toString( _ShadowOutline ).c_str() ); xmlSetProp( node, BAD_CAST "shadow_color", BAD_CAST toString( _ShadowColor ).c_str() ); xmlSetProp( node, BAD_CAST "multi_line", BAD_CAST toString( _MultiLine ).c_str() ); @@ -604,6 +619,11 @@ namespace NLGUI if (prop) _Shadow = convertBool(prop); + prop = (char*) xmlGetProp( cur, (xmlChar*)"shadow_outline" ); + _ShadowOutline = false; + if (prop) + _ShadowOutline = convertBool(prop); + prop= (char*) xmlGetProp( cur, (xmlChar*)"shadow_color" ); _ShadowColor = CRGBA(0,0,0,255); if (prop) @@ -864,6 +884,7 @@ namespace NLGUI TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setShadeColor (shcol); TextContext->setFontSize (_FontSize); @@ -978,6 +999,7 @@ namespace NLGUI TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setShadeColor (shcol); TextContext->setFontSize (_FontSize); @@ -1146,6 +1168,14 @@ namespace NLGUI invalidateContent(); } + // *************************************************************************** + void CViewText::setShadowOutline (bool bShadowOutline) + { + _ShadowOutline = bShadowOutline; + computeFontSize (); + invalidateContent(); + } + // *************************************************************************** void CViewText::setShadowColor(const NLMISC::CRGBA & color) { @@ -1647,6 +1677,7 @@ namespace NLGUI TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setFontSize (_FontSize); // default state @@ -1814,9 +1845,18 @@ namespace NLGUI if (_AutoClamp) { CViewBase::updateCoords (); - if (_Parent) + + // If there's no parent, try the parent of the parent element. + // Since we will be under the same group + CInterfaceGroup *parent = _Parent; + if( parent == NULL ) + { + if( _ParentElm != NULL ) + parent = _ParentElm->getParent(); + } + + if (parent) { - CInterfaceGroup *parent = _Parent; // avoid resizing parents to compute the limiter while (parent && (parent->getResizeFromChildW() || parent->isGroupList() )) { @@ -1958,6 +1998,7 @@ namespace NLGUI NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(); TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setFontSize (_FontSize); // CViewRenderer &rVR = *CViewRenderer::getInstance(); height = getFontHeight(); @@ -2089,6 +2130,7 @@ namespace NLGUI // setup the text context TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setFontSize (_FontSize); // find the line where the character is // CViewRenderer &rVR = *CViewRenderer::getInstance(); @@ -2363,6 +2405,7 @@ namespace NLGUI NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(); TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setFontSize (_FontSize); TCharPos linePos = 0; @@ -2447,6 +2490,7 @@ namespace NLGUI NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(); TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setFontSize (_FontSize); // Current position in text @@ -2498,12 +2542,13 @@ namespace NLGUI NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(); TextContext->setHotSpot (UTextContext::BottomLeft); TextContext->setShaded (_Shadow); + TextContext->setShadeOutline (_ShadowOutline); TextContext->setFontSize (_FontSize); // Letter size UTextContext::CStringInfo si = TextContext->getStringInfo(ucstring("|")); // for now we can't now that directly from UTextContext - _FontHeight = (uint) si.StringHeight + (_Shadow?1:0); - _FontLegHeight = (uint) si.StringLine + (_Shadow?1:0); + _FontHeight = (uint) si.StringHeight; // + (_Shadow?(_ShadowOutline?2:1):0); + _FontLegHeight = (uint) si.StringLine; // + (_Shadow?(_ShadowOutline?2:1):0); // Space width si = TextContext->getStringInfo(ucstring(" ")); @@ -2789,7 +2834,8 @@ namespace NLGUI pTooltip->setId(_Id+"_tt"+toString(i)); pTooltip->setAvoidResizeParent(avoidResizeParent()); pTooltip->setRenderLayer(getRenderLayer()); - pTooltip->setDefaultContextHelp(CI18N::get(tempTooltips[i].toString())); + bool isI18N = tempTooltips[i].size() >= 2 && tempTooltips[i][0] == 'u' && tempTooltips[i][1] == 'i'; + pTooltip->setDefaultContextHelp(isI18N ? CI18N::get(tempTooltips[i].toString()) : tempTooltips[i]); pTooltip->setParentPos(this); pTooltip->setParentPosRef(Hotspot_BR); pTooltip->setPosRef(Hotspot_BR); @@ -2960,6 +3006,7 @@ namespace NLGUI f.serial(_SpaceWidth); f.serial(_Color); f.serial(_Shadow); + f.serial(_ShadowOutline); f.serialEnum(_CaseMode); f.serial(_ShadowColor); f.serial(_LineMaxW); diff --git a/code/nel/src/gui/widget_manager.cpp b/code/nel/src/gui/widget_manager.cpp index 16357d373..81fbaf28b 100644 --- a/code/nel/src/gui/widget_manager.cpp +++ b/code/nel/src/gui/widget_manager.cpp @@ -34,8 +34,8 @@ #include "nel/gui/interface_expr.h" #include "nel/gui/reflect_register.h" #include "nel/gui/editor_selection_watcher.h" -#include "nel/gui/widget_addition_watcher.h" #include "nel/misc/events.h" +#include "nel/gui/root_group.h" namespace NLGUI { @@ -1036,12 +1036,14 @@ namespace NLGUI setCapturePointerLeft(NULL); setCapturePointerRight(NULL); _CapturedView = NULL; - + resetColorProps(); resetAlphaRolloverSpeedProps(); resetGlobalAlphasProps(); activeAnims.clear(); + + editorSelection.clear(); } @@ -1186,6 +1188,7 @@ namespace NLGUI vtDst->setColor (vtSrc->getColor()); vtDst->setModulateGlobalColor(vtSrc->getModulateGlobalColor()); vtDst->setShadow(vtSrc->getShadow()); + vtDst->setShadowOutline(vtSrc->getShadowOutline()); vtDst->setShadowColor(vtSrc->getShadowColor()); vtDst->setCaseMode(vtSrc->getCaseMode()); vtDst->setUnderlined(vtSrc->getUnderlined()); @@ -2039,6 +2042,12 @@ namespace NLGUI } } + if( draggedElement != NULL ) + { + CInterfaceElement *e = draggedElement; + static_cast< CViewBase* >( e )->draw(); + } + if ( (nPriority == WIN_PRIORITY_WORLD_SPACE) && !camera.empty()) { driver->setMatrixMode2D11(); @@ -2072,9 +2081,9 @@ namespace NLGUI if( CInterfaceElement::getEditorMode() ) { - if( !currentEditorSelection.empty() ) + for( int i = 0; i < editorSelection.size(); i++ ) { - CInterfaceElement *e = getElementFromId( currentEditorSelection ); + CInterfaceElement *e = getElementFromId( editorSelection[ i ] ); if( e != NULL ) e->drawHighlight(); } @@ -2096,276 +2105,328 @@ namespace NLGUI if( activeAnims[i]->isDisableButtons() ) return false; - if( evnt.getType() == CEventDescriptor::system ) - { - const CEventDescriptorSystem &systemEvent = reinterpret_cast< const CEventDescriptorSystem& >( evnt ); - if( systemEvent.getEventTypeExtended() == CEventDescriptorSystem::setfocus ) - { - if( getCapturePointerLeft() != NULL ) - { - getCapturePointerLeft()->handleEvent( evnt ); - setCapturePointerLeft( NULL ); - } - - if( getCapturePointerRight() != NULL ) - { - getCapturePointerRight()->handleEvent( evnt ); - setCapturePointerRight( NULL ); - } - - if( _CapturedView != NULL ) - { - _CapturedView->handleEvent( evnt ); - _CapturedView = NULL; - } - } - } - bool handled = false; CViewPointer *_Pointer = static_cast< CViewPointer* >( getPointer() ); + if( evnt.getType() == CEventDescriptor::system ) + { + handleSystemEvent( evnt ); + } + else if (evnt.getType() == CEventDescriptor::key) { - CEventDescriptorKey &eventDesc = (CEventDescriptorKey&)evnt; - //_LastEventKeyDesc = eventDesc; + handled = handleKeyboardEvent( evnt ); + } + else if (evnt.getType() == CEventDescriptor::mouse ) + { + handled = handleMouseEvent( evnt ); + } - // Any Key event disable the ContextHelp - disableContextHelp(); + CDBManager::getInstance()->flushObserverCalls(); - // Hide menu if the key is pushed - // if ((eventDesc.getKeyEventType() == CEventDescriptorKey::keydown) && !_ModalStack.empty() && !eventDesc.getKeyAlt() && !eventDesc.getKeyCtrl() && !eventDesc.getKeyShift()) - // Hide menu (or popup menu) is ESCAPE pressed - if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyESCAPE ) + return handled; + } + + bool CWidgetManager::handleSystemEvent( const CEventDescriptor &evnt ) + { + const CEventDescriptorSystem &systemEvent = reinterpret_cast< const CEventDescriptorSystem& >( evnt ); + if( systemEvent.getEventTypeExtended() == CEventDescriptorSystem::setfocus ) + { + if( getCapturePointerLeft() != NULL ) { - if( hasModal() ) + getCapturePointerLeft()->handleEvent( evnt ); + setCapturePointerLeft( NULL ); + } + + if( getCapturePointerRight() != NULL ) + { + getCapturePointerRight()->handleEvent( evnt ); + setCapturePointerRight( NULL ); + } + + if( _CapturedView != NULL ) + { + _CapturedView->handleEvent( evnt ); + _CapturedView = NULL; + } + } + + return true; + } + + bool CWidgetManager::handleKeyboardEvent( const CEventDescriptor &evnt ) + { + bool handled = false; + + CEventDescriptorKey &eventDesc = (CEventDescriptorKey&)evnt; + + //_LastEventKeyDesc = eventDesc; + + // Any Key event disable the ContextHelp + disableContextHelp(); + + // Hide menu if the key is pushed +// if ((eventDesc.getKeyEventType() == CEventDescriptorKey::keydown) && !_ModalStack.empty() && !eventDesc.getKeyAlt() && !eventDesc.getKeyCtrl() && !eventDesc.getKeyShift()) + // Hide menu (or popup menu) is ESCAPE pressed + if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyESCAPE ) + { + if( hasModal() ) + { + SModalWndInfo mwi = getModal(); + if (mwi.ModalExitKeyPushed) + disableModalWindow(); + } + } + + // Manage "quit window" If the Key is ESCAPE, no captureKeyboard + if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyESCAPE ) + { + // Get the last escapable active top window. NB: this is ergonomically better. + CInterfaceGroup *win= getLastEscapableTopWindow(); + if( win ) + { + // If the window is a modal, must pop it. + if( dynamic_cast(win) ) { - SModalWndInfo mwi = getModal(); - if (mwi.ModalExitKeyPushed) - disableModalWindow(); + if(!win->getAHOnEscape().empty()) + CAHManager::getInstance()->runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams()); + popModalWindow(); + handled= true; + } + // else just disable it. + // Special case: leave the escape Key to the CaptureKeyboard . + else if( !getCaptureKeyboard() ) + { + if(!win->getAHOnEscape().empty()) + CAHManager::getInstance()->runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams()); + win->setActive(false); + handled= true; + } + } + } + + // Manage complex "Enter" + if (eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyRETURN) + { + // If the top window has Enter AH + CInterfaceGroup *tw= getTopWindow(); + if(tw && !tw->getAHOnEnter().empty()) + { + // if the captured keyboard is in this Modal window, then must handle him in priority + if( getCaptureKeyboard() && getCaptureKeyboard()->getRootWindow()==tw) + { + bool result = getCaptureKeyboard()->handleEvent(evnt); + CDBManager::getInstance()->flushObserverCalls(); + return result; + } + else + { + // The window or modal control the OnEnter. Execute, and don't go to the chat. + CAHManager::getInstance()->runActionHandler(tw->getAHOnEnter(), tw, tw->getAHOnEnterParams()); + handled= true; } } - // Manage "quit window" If the Key is ESCAPE, no captureKeyboard - if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyESCAPE ) + // else the 'return' key bring back to the last edit box (if possible) + CCtrlBase *oldCapture = getOldCaptureKeyboard() ? getOldCaptureKeyboard() : getDefaultCaptureKeyboard(); + if ( getCaptureKeyboard() == NULL && oldCapture && !handled) { - // Get the last escapable active top window. NB: this is ergonomically better. - CInterfaceGroup *win= getLastEscapableTopWindow(); - if( win ) + /* If the editbox does not want to recover focus, then abort. This possibility is normaly avoided + through setCaptureKeyboard() which already test getRecoverFocusOnEnter(), but it is still possible + for the default capture (main chat) or the old captured window to not want to recover + (temporary Read Only chat for instance) + */ + if(!dynamic_cast(oldCapture) || + dynamic_cast(oldCapture)->getRecoverFocusOnEnter()) { - // If the window is a modal, must pop it. - if( dynamic_cast(win) ) + setCaptureKeyboard( oldCapture ); + notifyElementCaptured(getCaptureKeyboard() ); + // make sure all parent windows are active + CCtrlBase *cb = getCaptureKeyboard(); + CGroupContainer *lastContainer = NULL; + for(;;) { - if(!win->getAHOnEscape().empty()) - CAHManager::getInstance()->runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams()); - popModalWindow(); - handled= true; + CGroupContainer *gc = dynamic_cast(cb); + if (gc) lastContainer = gc; + cb->forceOpen(); + if (cb->getParent()) + { + cb = cb->getParent(); + } + else + { + cb->invalidateCoords(); + break; + } } - // else just disable it. - // Special case: leave the escape Key to the CaptureKeyboard . - else if( !getCaptureKeyboard() ) + if (lastContainer) { - if(!win->getAHOnEscape().empty()) - CAHManager::getInstance()->runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams()); - win->setActive(false); - handled= true; + setTopWindow(lastContainer); + lastContainer->enableBlink(1); } + handled= true; } } + } - // Manage complex "Enter" - if (eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyRETURN) + // General case: handle it in the Captured keyboard + if ( getCaptureKeyboard() != NULL && !handled) + { + bool result = getCaptureKeyboard()->handleEvent(evnt); + CDBManager::getInstance()->flushObserverCalls(); + return result; + } + + lastKeyEvent = eventDesc; + + return handled; + } + + bool CWidgetManager::handleMouseEvent( const CEventDescriptor &evnt ) + { + bool handled = false; + + CEventDescriptorMouse &eventDesc = (CEventDescriptorMouse&)evnt; + + if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown ) + _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() | NLMISC::leftButton ) ); + else + if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown ) + _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() | NLMISC::rightButton ) ); + else + if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup ) + _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() & ~NLMISC::leftButton ) ); + if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup ) + _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() & ~NLMISC::rightButton ) ); + + if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mousemove ) + handleMouseMoveEvent( eventDesc ); + + eventDesc.setX( _Pointer->getX() ); + eventDesc.setY( _Pointer->getY() ); + + if( CInterfaceElement::getEditorMode() ) + { + // Let's pretend we've handled the event... or actually we have! + if( ( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown ) || + ( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup ) ) + return true; + } + + if( isMouseHandlingEnabled() ) + { + // First thing to do : Capture handling + if ( getCapturePointerLeft() != NULL) + handled|= getCapturePointerLeft()->handleEvent(evnt); + + if ( getCapturePointerRight() != NULL && + getCapturePointerLeft() != getCapturePointerRight() ) + handled|= getCapturePointerRight()->handleEvent(evnt); + + if( _CapturedView != NULL && + _CapturedView != getCapturePointerLeft() && + _CapturedView != getCapturePointerRight() ) + _CapturedView->handleEvent( evnt ); + + CInterfaceGroup *ptr = getWindowUnder (eventDesc.getX(), eventDesc.getY()); + setCurrentWindowUnder( ptr ); + + // Any Mouse event but move disable the ContextHelp + if(eventDesc.getEventTypeExtended() != CEventDescriptorMouse::mousemove) { - // If the top window has Enter AH - CInterfaceGroup *tw= getTopWindow(); - if(tw && !tw->getAHOnEnter().empty()) + disableContextHelp(); + } + + // get the group under the mouse + CInterfaceGroup *pNewCurrentWnd = getCurrentWindowUnder(); + setMouseOverWindow( pNewCurrentWnd != NULL ); + + + NLMISC::CRefPtr clickedOutModalWindow; + + // modal special features + if ( hasModal() ) + { + CWidgetManager::SModalWndInfo mwi = getModal(); + if(mwi.ModalWindow) { - // if the captured keyboard is in this Modal window, then must handle him in priority - if( getCaptureKeyboard() && getCaptureKeyboard()->getRootWindow()==tw) + // If we are not in "click out" mode so we dont handle controls other than those of the modal + if (pNewCurrentWnd != mwi.ModalWindow && !mwi.ModalExitClickOut) { - bool result = getCaptureKeyboard()->handleEvent(evnt); - CDBManager::getInstance()->flushObserverCalls(); - return result; + pNewCurrentWnd = NULL; } else { - // The window or modal control the OnEnter. Execute, and don't go to the chat. - CAHManager::getInstance()->runActionHandler(tw->getAHOnEnter(), tw, tw->getAHOnEnterParams()); - handled= true; + // If there is a handler on click out launch it + if (pNewCurrentWnd != mwi.ModalWindow) + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown || + (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown)) + if (!mwi.ModalHandlerClickOut.empty()) + CAHManager::getInstance()->runActionHandler(mwi.ModalHandlerClickOut,NULL,mwi.ModalClickOutParams); + + // If the current window is not the modal and if must quit on click out + if(pNewCurrentWnd != mwi.ModalWindow && mwi.ModalExitClickOut) + { + // NB: don't force handle==true because to quit a modal does not avoid other actions + + // quit if click outside + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown || + (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown)) + { + clickedOutModalWindow = dynamic_cast((CInterfaceGroup*)mwi.ModalWindow); + // disable the modal + popModalWindow(); + if ( hasModal() ) + { + // don't handle event unless it is a previous modal window + if( !isPreviousModal( pNewCurrentWnd ) ) + pNewCurrentWnd = NULL; // can't handle event before we have left all modal windows + } + movePointer (0,0); // Reget controls under pointer + } + } + } + } + } + + // Manage LeftClick. + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) + { + if ((pNewCurrentWnd != NULL) && (!hasModal()) && (pNewCurrentWnd->getOverlappable())) + { + CGroupContainer *pGC = dynamic_cast(pNewCurrentWnd); + if (pGC != NULL) + { + if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd); + } + else + { + setTopWindow(pNewCurrentWnd); } } - // else the 'return' key bring back to the last edit box (if possible) - CCtrlBase *oldCapture = getOldCaptureKeyboard() ? getOldCaptureKeyboard() : getDefaultCaptureKeyboard(); - if ( getCaptureKeyboard() == NULL && oldCapture && !handled) + bool captured = false; + + // must not capture a new element if a sheet is currentlty being dragged. + // This may happen when alt-tab has been used => the sheet is dragged but the left button is up + if (!CCtrlDraggable::getDraggedSheet()) { - /* If the editbox does not want to recover focus, then abort. This possibility is normaly avoided - through setCaptureKeyboard() which already test getRecoverFocusOnEnter(), but it is still possible - for the default capture (main chat) or the old captured window to not want to recover - (temporary Read Only chat for instance) - */ - if(!dynamic_cast(oldCapture) || - dynamic_cast(oldCapture)->getRecoverFocusOnEnter()) + if( CInterfaceElement::getEditorMode() && _GroupSelection ) { - setCaptureKeyboard( oldCapture ); - notifyElementCaptured(getCaptureKeyboard() ); - // make sure all parent windows are active - CCtrlBase *cb = getCaptureKeyboard(); - CGroupContainer *lastContainer = NULL; - for(;;) + for( sint32 i = _GroupsUnderPointer.size() - 1; i >= 0; i-- ) { - CGroupContainer *gc = dynamic_cast(cb); - if (gc) lastContainer = gc; - cb->forceOpen(); - if (cb->getParent()) + CInterfaceGroup *g = _GroupsUnderPointer[ i ]; + if( ( g != NULL ) && ( g->isInGroup( pNewCurrentWnd ) ) ) { - cb = cb->getParent(); - } - else - { - cb->invalidateCoords(); + _CapturedView = g; + captured = true; break; } } - if (lastContainer) - { - setTopWindow(lastContainer); - lastContainer->enableBlink(1); - } - handled= true; - } - } - } - - // General case: handle it in the Captured keyboard - if ( getCaptureKeyboard() != NULL && !handled) - { - bool result = getCaptureKeyboard()->handleEvent(evnt); - CDBManager::getInstance()->flushObserverCalls(); - return result; - } - - lastKeyEvent = eventDesc; - } - - //////////////////////////////////////////////// Keyboard handling ends here //////////////////////////////////// - - else if (evnt.getType() == CEventDescriptor::mouse ) - { - CEventDescriptorMouse &eventDesc = (CEventDescriptorMouse&)evnt; - - if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown ) - _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() | NLMISC::leftButton ) ); - else - if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown ) - _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() | NLMISC::rightButton ) ); - else - if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup ) - _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() & ~NLMISC::leftButton ) ); - if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup ) - _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() & ~NLMISC::rightButton ) ); - - if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mousemove ) - handleMouseMoveEvent( eventDesc ); - - eventDesc.setX( _Pointer->getX() ); - eventDesc.setY( _Pointer->getY() ); - - if( isMouseHandlingEnabled() ) - { - // First thing to do : Capture handling - if ( getCapturePointerLeft() != NULL) - handled|= getCapturePointerLeft()->handleEvent(evnt); - - if ( getCapturePointerRight() != NULL && - getCapturePointerLeft() != getCapturePointerRight() ) - handled|= getCapturePointerRight()->handleEvent(evnt); - - if( _CapturedView != NULL ) - _CapturedView->handleEvent( evnt ); - - CInterfaceGroup *ptr = getWindowUnder (eventDesc.getX(), eventDesc.getY()); - setCurrentWindowUnder( ptr ); - - // Any Mouse event but move disable the ContextHelp - if(eventDesc.getEventTypeExtended() != CEventDescriptorMouse::mousemove) - { - disableContextHelp(); - } - - // get the group under the mouse - CInterfaceGroup *pNewCurrentWnd = getCurrentWindowUnder(); - setMouseOverWindow( pNewCurrentWnd != NULL ); - - - NLMISC::CRefPtr clickedOutModalWindow; - - // modal special features - if ( hasModal() ) - { - CWidgetManager::SModalWndInfo mwi = getModal(); - if(mwi.ModalWindow) - { - // If we are not in "click out" mode so we dont handle controls other than those of the modal - if (pNewCurrentWnd != mwi.ModalWindow && !mwi.ModalExitClickOut) - { - pNewCurrentWnd = NULL; - } - else - { - // If there is a handler on click out launch it - if (pNewCurrentWnd != mwi.ModalWindow) - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown || - (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown)) - if (!mwi.ModalHandlerClickOut.empty()) - CAHManager::getInstance()->runActionHandler(mwi.ModalHandlerClickOut,NULL,mwi.ModalClickOutParams); - - // If the current window is not the modal and if must quit on click out - if(pNewCurrentWnd != mwi.ModalWindow && mwi.ModalExitClickOut) - { - // NB: don't force handle==true because to quit a modal does not avoid other actions - - // quit if click outside - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown || - (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown)) - { - clickedOutModalWindow = dynamic_cast((CInterfaceGroup*)mwi.ModalWindow); - // disable the modal - popModalWindow(); - if ( hasModal() ) - { - // don't handle event unless it is a previous modal window - if( !isPreviousModal( pNewCurrentWnd ) ) - pNewCurrentWnd = NULL; // can't handle event before we have left all modal windows - } - movePointer (0,0); // Reget controls under pointer - } - } - } - } - } - - // Manage LeftClick. - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) - { - if ((pNewCurrentWnd != NULL) && (!hasModal()) && (pNewCurrentWnd->getOverlappable())) - { - CGroupContainer *pGC = dynamic_cast(pNewCurrentWnd); - if (pGC != NULL) - { - if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd); - } - else - { - setTopWindow(pNewCurrentWnd); - } } - bool captured = false; - - // must not capture a new element if a sheet is currentlty being dragged. - // This may happen when alt-tab has been used => the sheet is dragged but the left button is up - if (!CCtrlDraggable::getDraggedSheet()) + if( !captured ) { // Take the top most control. uint nMaxDepth = 0; @@ -2384,168 +2445,181 @@ namespace NLGUI } } } + } - if( CInterfaceElement::getEditorMode() && !captured ) + if( CInterfaceElement::getEditorMode() && !captured ) + { + for( sint32 i = _ViewsUnderPointer.size()-1; i >= 0; i-- ) { - for( sint32 i = _ViewsUnderPointer.size()-1; i >= 0; i-- ) + CViewBase *v = _ViewsUnderPointer[i]; + if( ( v != NULL ) && v->isInGroup( pNewCurrentWnd ) ) { - CViewBase *v = _ViewsUnderPointer[i]; - if( ( v != NULL ) && v->isInGroup( pNewCurrentWnd ) ) - { - _CapturedView = v; - captured = true; - break; - } + _CapturedView = v; + captured = true; + break; } } - - notifyElementCaptured( getCapturePointerLeft() ); - if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty()) - { - CAHManager::getInstance()->runActionHandler(clickedOutModalWindow->OnPostClickOut, getCapturePointerLeft(), clickedOutModalWindow->OnPostClickOutParams); - } } - //if found - if ( captured ) - { - // consider clicking on a control implies handling of the event. - handled= true; - // handle the capture - if( getCapturePointerLeft() != NULL ) - getCapturePointerLeft()->handleEvent(evnt); - else - _CapturedView->handleEvent( evnt ); + notifyElementCaptured( getCapturePointerLeft() ); + if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty()) + { + CAHManager::getInstance()->runActionHandler(clickedOutModalWindow->OnPostClickOut, getCapturePointerLeft(), clickedOutModalWindow->OnPostClickOutParams); } } - - // Manage RightClick - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown) + //if found + if ( captured ) { - if ((pNewCurrentWnd != NULL) && (!hasModal()) && (pNewCurrentWnd->getOverlappable())) - { - CGroupContainer *pGC = dynamic_cast(pNewCurrentWnd); - if (pGC != NULL) - { - if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd); - } - else - { - setTopWindow(pNewCurrentWnd); - } - } + // consider clicking on a control implies handling of the event. + handled= true; - // Take the top most control. - { - uint nMaxDepth = 0; - const std::vector< CCtrlBase* >& _CtrlsUnderPointer = getCtrlsUnderPointer(); - for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--) - { - CCtrlBase *ctrl= _CtrlsUnderPointer[i]; - if (ctrl && ctrl->isCapturable() && ctrl->isInGroup( pNewCurrentWnd ) ) - { - uint d = ctrl->getDepth( pNewCurrentWnd ); - if (d > nMaxDepth) - { - nMaxDepth = d; - setCapturePointerRight( ctrl ); - } - } - } - notifyElementCaptured( getCapturePointerRight() ); - if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty()) - { - CAHManager::getInstance()->runActionHandler(clickedOutModalWindow->OnPostClickOut, getCapturePointerRight(), clickedOutModalWindow->OnPostClickOutParams); - } - } - //if found - if ( getCapturePointerRight() != NULL) - { - // handle the capture - handled |= getCapturePointerRight()->handleEvent(evnt); - } + if( getCapturePointerLeft() != NULL ) + _CapturedView = getCapturePointerLeft(); + + // handle the capture + _CapturedView->handleEvent( evnt ); } - - - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup) - { - if (!handled) - if (pNewCurrentWnd != NULL) - pNewCurrentWnd->handleEvent(evnt); - if ( getCapturePointerRight() != NULL) - { - setCapturePointerRight(NULL); - handled= true; - } - } - - // window handling. if not handled by a control - if (!handled) + else { - if (((pNewCurrentWnd != NULL) && !hasModal()) || - ((hasModal() && getModal().ModalWindow == pNewCurrentWnd))) - { - CEventDescriptorMouse ev2 = eventDesc; - sint32 x= eventDesc.getX(), y = eventDesc.getY(); - if (pNewCurrentWnd) - { - pNewCurrentWnd->absoluteToRelative (x, y); - ev2.setX (x); ev2.setY (y); - handled|= pNewCurrentWnd->handleEvent (ev2); - } - - // After handle event of a left click, may set window Top if movable (infos etc...) - //if( (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) && pNewCurrentWnd->isMovable() ) - // setTopWindow(pNewCurrentWnd); - } + if( CInterfaceElement::getEditorMode() ) + clearEditorSelection(); } - - // Put here to let a chance to the window to handle if the capture dont - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) - { - if ( getCapturePointerLeft() != NULL) - { - setCapturePointerLeft(NULL); - handled = true; - } - } - - - // If the current window is the modal, may Modal quit. Do it after standard event handle - if(hasModal() && pNewCurrentWnd == getModal().ModalWindow) - { - // NB: don't force handle==true because to quit a modal does not avoid other actions - CWidgetManager::SModalWndInfo mwi = getModal(); - // and if must quit on click right - if(mwi.ModalExitClickR) - { - // quit if click right - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup) - // disable the modal - disableModalWindow(); - } - - // and if must quit on click left - if(mwi.ModalExitClickL) - { - // quit if click right - if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) - // disable the modal - disableModalWindow(); - } - } - - // If the mouse is over a window, always consider the event is taken (avoid click behind) - handled|= isMouseOverWindow(); } - } - CDBManager::getInstance()->flushObserverCalls(); + // Manage RightClick + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown) + { + if ((pNewCurrentWnd != NULL) && (!hasModal()) && (pNewCurrentWnd->getOverlappable())) + { + CGroupContainer *pGC = dynamic_cast(pNewCurrentWnd); + if (pGC != NULL) + { + if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd); + } + else + { + setTopWindow(pNewCurrentWnd); + } + } + + // Take the top most control. + { + uint nMaxDepth = 0; + const std::vector< CCtrlBase* >& _CtrlsUnderPointer = getCtrlsUnderPointer(); + for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--) + { + CCtrlBase *ctrl= _CtrlsUnderPointer[i]; + if (ctrl && ctrl->isCapturable() && ctrl->isInGroup( pNewCurrentWnd ) ) + { + uint d = ctrl->getDepth( pNewCurrentWnd ); + if (d > nMaxDepth) + { + nMaxDepth = d; + setCapturePointerRight( ctrl ); + } + } + } + notifyElementCaptured( getCapturePointerRight() ); + if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty()) + { + CAHManager::getInstance()->runActionHandler(clickedOutModalWindow->OnPostClickOut, getCapturePointerRight(), clickedOutModalWindow->OnPostClickOutParams); + } + } + //if found + if ( getCapturePointerRight() != NULL) + { + // handle the capture + handled |= getCapturePointerRight()->handleEvent(evnt); + } + } + + + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup) + { + if (!handled) + if (pNewCurrentWnd != NULL) + pNewCurrentWnd->handleEvent(evnt); + if ( getCapturePointerRight() != NULL) + { + setCapturePointerRight(NULL); + handled= true; + } + } + + // window handling. if not handled by a control + if (!handled) + { + if (((pNewCurrentWnd != NULL) && !hasModal()) || + ((hasModal() && getModal().ModalWindow == pNewCurrentWnd))) + { + CEventDescriptorMouse ev2 = eventDesc; + sint32 x= eventDesc.getX(), y = eventDesc.getY(); + if (pNewCurrentWnd) + { + pNewCurrentWnd->absoluteToRelative (x, y); + ev2.setX (x); ev2.setY (y); + handled|= pNewCurrentWnd->handleEvent (ev2); + } + + // After handle event of a left click, may set window Top if movable (infos etc...) + //if( (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) && pNewCurrentWnd->isMovable() ) + // setTopWindow(pNewCurrentWnd); + } + } + + // Put here to let a chance to the window to handle if the capture dont + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) + { + if ( getCapturePointerLeft() != NULL) + { + if( !handled ) + { + CCtrlBase *c = getCapturePointerLeft(); + c->handleEvent( evnt ); + } + + setCapturePointerLeft(NULL); + handled = true; + } + + _CapturedView = NULL; + + if( CInterfaceElement::getEditorMode() ) + stopDragging(); + } + + + // If the current window is the modal, may Modal quit. Do it after standard event handle + if(hasModal() && pNewCurrentWnd == getModal().ModalWindow) + { + // NB: don't force handle==true because to quit a modal does not avoid other actions + CWidgetManager::SModalWndInfo mwi = getModal(); + // and if must quit on click right + if(mwi.ModalExitClickR) + { + // quit if click right + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup) + // disable the modal + disableModalWindow(); + } + + // and if must quit on click left + if(mwi.ModalExitClickL) + { + // quit if click right + if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) + // disable the modal + disableModalWindow(); + } + } + + // If the mouse is over a window, always consider the event is taken (avoid click behind) + handled|= isMouseOverWindow(); + } return handled; } - bool CWidgetManager::handleMouseMoveEvent( const CEventDescriptor &eventDesc ) { if( getPointer() == NULL ) @@ -2580,8 +2654,76 @@ namespace NLGUI ve.setY( getPointer()->getY() ); } + if( CInterfaceElement::getEditorMode() ) + { + if( ( _CapturedView != NULL ) && ( draggedElement == NULL ) ) + { + startDragging(); + } + else + if( draggedElement != NULL ) + { + sint32 dx = newX - oldX; + sint32 dy = newY - oldY; + + draggedElement->moveBy( dx, dy ); + } + } + return true; } + + // ------------------------------------------------------------------------------------------------ + bool CWidgetManager::startDragging() + { + CInterfaceElement *e = NULL; + + CInterfaceGroup *g = _CapturedView->getParent(); + if( g != NULL ) + { + e = g->takeElement( _CapturedView ); + if( e == NULL ) + { + nlinfo( "Something went horribly wrong :(" ); + return false; + } + } + else + e = _CapturedView; + + e->setParent( NULL ); + draggedElement = e; + + return true; + } + + void CWidgetManager::stopDragging() + { + if( draggedElement != NULL ) + { + CInterfaceGroup *g = getGroupUnder( draggedElement->getXReal(), draggedElement->getYReal() ); + CInterfaceElement *e = draggedElement; + CInterfaceGroup *tw = getTopWindow(); + + if( g == NULL ) + g = tw; + + std::string oldid = e->getId(); + + e->setParent( g ); + e->setIdRecurse( e->getShortId() ); + e->setParentPos( g ); + e->setParentSize( g ); + g->addElement( e ); + + e->alignTo( g ); + //e->setName( "==MARKED==" ); + + draggedElement = NULL; + + onWidgetMoved( oldid, e->getId() ); + } + } // ------------------------------------------------------------------------------------------------ void CWidgetManager::movePointer (sint32 dx, sint32 dy) @@ -3211,25 +3353,53 @@ namespace NLGUI } } - - void CWidgetManager::setCurrentEditorSelection( const std::string &name ) + void CWidgetManager::getEditorSelection( std::vector< std::string > &selection ) { + selection.clear(); + for( int i = 0; i < editorSelection.size(); i++ ) + selection.push_back( editorSelection[ i ] ); + } + + void CWidgetManager::selectWidget( const std::string &name ) + { + std::vector< std::string >::iterator itr + = std::find( editorSelection.begin(), editorSelection.end(), name ); + CInterfaceElement *e = getElementFromId( name ); - if( e != NULL ) + + if( itr != editorSelection.end() ) { - if( !currentEditorSelection.empty() ) + // If multiselection is on unselect if already selected + if( multiSelection ) { - CInterfaceElement *prev = getElementFromId( currentEditorSelection ); - if( prev != NULL ) - prev->setEditorSelected( false ); + editorSelection.erase( itr ); + if( e != NULL ) + e->setEditorSelected( false ); } - e->setEditorSelected( true ); } else - if( !name.empty() ) - return; - - currentEditorSelection = name; + { + // Select if not yet selected + if( e != NULL ) + { + // If multiselection is off, we can only have 1 widget selected + if( !multiSelection ) + { + editorSelection.clear(); + } + + e->setEditorSelected( true ); + editorSelection.push_back( name ); + } + + } + + notifySelectionWatchers(); + } + + void CWidgetManager::clearEditorSelection() + { + editorSelection.clear(); notifySelectionWatchers(); } @@ -3238,7 +3408,7 @@ namespace NLGUI std::vector< IEditorSelectionWatcher* >::iterator itr = selectionWatchers.begin(); while( itr != selectionWatchers.end() ) { - (*itr)->selectionChanged( currentEditorSelection ); + (*itr)->selectionChanged(); ++itr; } } @@ -3267,36 +3437,46 @@ namespace NLGUI selectionWatchers.erase( itr ); } - void CWidgetManager::notifyAdditionWatchers( const std::string &widgetName ) + void CWidgetManager::onWidgetAdded( const std::string &id ) { - std::vector< IWidgetAdditionWatcher* >::const_iterator itr = additionWatchers.begin(); - while( itr != additionWatchers.end() ) + std::vector< IWidgetWatcher* >::const_iterator itr = widgetWatchers.begin(); + while( itr != widgetWatchers.end() ) { - (*itr)->widgetAdded( widgetName ); + (*itr)->onWidgetAdded( id ); ++itr; } } - void CWidgetManager::registerAdditionWatcher( IWidgetAdditionWatcher *watcher ) + void CWidgetManager::onWidgetMoved( const std::string &oldid, const std::string &newid ) { - std::vector< IWidgetAdditionWatcher* >::const_iterator itr - = std::find( additionWatchers.begin(), additionWatchers.end(), watcher ); - // already exists - if( itr != additionWatchers.end() ) - return; - - additionWatchers.push_back( watcher ); + std::vector< IWidgetWatcher* >::const_iterator itr = widgetWatchers.begin(); + while( itr != widgetWatchers.end() ) + { + (*itr)->onWidgetMoved( oldid, newid ); + ++itr; + } } - void CWidgetManager::unregisterAdditionWatcher( IWidgetAdditionWatcher *watcher ) + void CWidgetManager::registerWidgetWatcher( IWidgetWatcher *watcher ) { - std::vector< IWidgetAdditionWatcher* >::iterator itr - = std::find( additionWatchers.begin(), additionWatchers.end(), watcher ); - // doesn't exist - if( itr == additionWatchers.end() ) + std::vector< IWidgetWatcher* >::const_iterator itr + = std::find( widgetWatchers.begin(), widgetWatchers.end(), watcher ); + // already exists + if( itr != widgetWatchers.end() ) return; - additionWatchers.erase( itr ); + widgetWatchers.push_back( watcher ); + } + + void CWidgetManager::unregisterWidgetWatcher( IWidgetWatcher *watcher ) + { + std::vector< IWidgetWatcher* >::iterator itr + = std::find( widgetWatchers.begin(), widgetWatchers.end(), watcher ); + // doesn't exist + if( itr == widgetWatchers.end() ) + return; + + widgetWatchers.erase( itr ); } CInterfaceElement* CWidgetManager::addWidgetToGroup( std::string &group, std::string &widgetClass, std::string &widgetName ) @@ -3329,11 +3509,165 @@ namespace NLGUI else g->addView( v ); - notifyAdditionWatchers( v->getId() ); + onWidgetAdded( v->getId() ); return v; } + bool CWidgetManager::groupSelection() + { + std::vector< CInterfaceElement* > elms; + + // Resolve the widget names + for( int i = 0; i < editorSelection.size(); i++ ) + { + CInterfaceElement *e = getElementFromId( editorSelection[ i ] ); + if( e != NULL ) + elms.push_back( e ); + } + + editorSelection.clear(); + + if( elms.empty() ) + return false; + + // Create the group as the subgroup of the top window + CInterfaceGroup *g = static_cast< CInterfaceGroup* >( getParser()->createClass( "interface_group" ) ); + getTopWindow()->addGroup( g ); + g->setParent( getTopWindow() ); + g->setIdRecurse( std::string( "group" ) + NLMISC::toString( _WidgetCount ) ); + _WidgetCount++; + onWidgetAdded( g->getId() ); + + std::string oldId; + + // Reparent the widgets to the new group + for( int i = 0; i < elms.size(); i++ ) + { + CInterfaceElement *e = elms[ i ]; + oldId = e->getId(); + CInterfaceGroup *p = e->getParent(); + if( p != NULL ) + p->takeElement( e ); + + g->addElement( e ); + e->setParent( g ); + e->setParentPos( g ); + e->setParentSize( g ); + e->setIdRecurse( e->getShortId() ); + + onWidgetMoved( oldId, e->getId() ); + } + elms.clear(); + + // Make sure widgets aren't clipped because the group isn't big enough + g->spanElements(); + // Make sure widgets are aligned + g->alignElements(); + // Align the new group to the top window + g->alignTo( getTopWindow() ); + + g->setActive( true ); + + return true; + } + + bool CWidgetManager::unGroupSelection() + { + if( editorSelection.size() != 1 ) + return false; + + // Does the element exist? + CInterfaceElement *e = getElementFromId( editorSelection[ 0 ] ); + if( e == NULL ) + return false; + + // Is the element a group? + CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( e ); + if( g == NULL ) + return false; + + // Can't blow up a root group :( + CInterfaceGroup *p = g->getParent(); + if( p == NULL ) + return false; + + // KABOOM! + bool ok = g->explode(); + if( !ok ) + return false; + + p->delElement( g ); + + clearEditorSelection(); + + p->updateCoords(); + + return true; + } + + + bool CWidgetManager::createNewGUI( const std::string &project, const std::string &window ) + { + reset(); + + for( int i = 0; i < _MasterGroups.size(); i++ ) + delete _MasterGroups[i].Group; + _MasterGroups.clear(); + + // First create the master group + CRootGroup *root = new CRootGroup( CViewBase::TCtorParam() ); + + SMasterGroup mg; + mg.Group = root; + + root->setIdRecurse( project ); + root->setW( 1024 ); + root->setH( 768 ); + root->setActive( true ); + + // Create the first / main window + CInterfaceGroup *wnd = new CInterfaceGroup( CViewBase::TCtorParam() ); + wnd->setW( 1024 ); + wnd->setH( 768 ); + wnd->setParent( root ); + wnd->setParentPos( root ); + wnd->setParentSize( root ); + wnd->setPosRef( Hotspot_MM ); + wnd->setParentPosRef( Hotspot_MM ); + wnd->setIdRecurse( window ); + wnd->setActive( true ); + + // Add the window + root->addElement( wnd ); + mg.addWindow( wnd, wnd->getPriority() ); + _MasterGroups.push_back( mg ); + + _Pointer = new CViewPointer( CViewBase::TCtorParam() ); + + IParser *parser = getParser(); + + + // Set base color to white + VariableData v; + v.type = "sint32"; + v.value = "255"; + + v.entry = "UI:SAVE:COLOR:R"; + parser->setVariable( v ); + + v.entry = "UI:SAVE:COLOR:G"; + parser->setVariable( v ); + + v.entry = "UI:SAVE:COLOR:B"; + parser->setVariable( v ); + + v.entry = "UI:SAVE:COLOR:A"; + parser->setVariable( v ); + + return true; + } + CWidgetManager::CWidgetManager() { @@ -3372,7 +3706,9 @@ namespace NLGUI setScreenWH( 0, 0 ); - currentEditorSelection = ""; + _GroupSelection = false; + multiSelection = false; + _WidgetCount = 0; } CWidgetManager::~CWidgetManager() @@ -3386,6 +3722,8 @@ namespace NLGUI curContextHelp = NULL; CStringShared::deleteStringMapper(); + + editorSelection.clear(); } } diff --git a/code/nel/src/ligo/primitive.cpp b/code/nel/src/ligo/primitive.cpp index 9cf7df13f..ba9b69435 100644 --- a/code/nel/src/ligo/primitive.cpp +++ b/code/nel/src/ligo/primitive.cpp @@ -2738,8 +2738,17 @@ CPrimitiveContext::CPrimitiveContext(): } +static bool LIGORegistered = false; + + void Register () { + if( LIGORegistered ) + { + nlinfo( "LIGO classes have already been registered." ); + return; + } + NLMISC_REGISTER_CLASS(CPropertyString); NLMISC_REGISTER_CLASS(CPropertyStringArray); NLMISC_REGISTER_CLASS(CPropertyColor); @@ -2748,6 +2757,8 @@ void Register () NLMISC_REGISTER_CLASS(CPrimPath); NLMISC_REGISTER_CLASS(CPrimZone); NLMISC_REGISTER_CLASS(CPrimAlias); + + LIGORegistered = true; } // *************************************************************************** diff --git a/code/nel/src/misc/config_file/cf_bison.simple b/code/nel/src/misc/config_file/cf_bison.simple index 3ab0e5b1a..64e930f27 100644 --- a/code/nel/src/misc/config_file/cf_bison.simple +++ b/code/nel/src/misc/config_file/cf_bison.simple @@ -328,7 +328,7 @@ yynewstate: #endif /* Get the current used size of the three stacks, in elements. */ - int size = yyssp - yyss + 1; + int size = (int)(yyssp - yyss + 1); #ifdef yyoverflow /* Each stack pointer address is followed by the size of diff --git a/code/nel/src/misc/config_file/cf_flex.skl b/code/nel/src/misc/config_file/cf_flex.skl index 5da2aa3f6..b69bed057 100644 --- a/code/nel/src/misc/config_file/cf_flex.skl +++ b/code/nel/src/misc/config_file/cf_flex.skl @@ -1000,7 +1000,7 @@ int yyFlexLexer::yyinput() else { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; + int offset = (int)(yy_c_buf_p - yytext_ptr); ++yy_c_buf_p; switch ( yy_get_next_buffer() ) diff --git a/code/nel/src/misc/config_file/cf_lexical.cpp b/code/nel/src/misc/config_file/cf_lexical.cpp index f47696ff9..80fd4fd36 100644 --- a/code/nel/src/misc/config_file/cf_lexical.cpp +++ b/code/nel/src/misc/config_file/cf_lexical.cpp @@ -2773,7 +2773,7 @@ static int input() else { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; + int offset = (int)(yy_c_buf_p - yytext_ptr); ++yy_c_buf_p; switch ( yy_get_next_buffer() ) diff --git a/code/nel/src/misc/di_event_emitter.cpp b/code/nel/src/misc/di_event_emitter.cpp deleted file mode 100644 index 8f41f6453..000000000 --- a/code/nel/src/misc/di_event_emitter.cpp +++ /dev/null @@ -1,354 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - - -#include "stdmisc.h" - -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/events.h" -#include "nel/misc/win_event_emitter.h" -// -#include "di_mouse_device.h" -#include "di_keyboard_device.h" -#include "di_game_device.h" - - -#ifdef NL_OS_WINDOWS - -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NLMISC -{ - -static const char DirectInputLibName[] = "dinput8.dll"; - -///////////////////////////////// -// CDIEventEmitter statics // -///////////////////////////////// - -HMODULE CDIEventEmitter::_DirectInputLibHandle = 0; -CDIEventEmitter::TPDirectInput8Create CDIEventEmitter::_PDirectInput8Create = NULL; -uint CDIEventEmitter::_NumCreatedInterfaces = 0; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////// -// CDIEventEmitter implementation // -//////////////////////////////////// - - -//====================================================== -CDIEventEmitter::CDIEventEmitter(HWND hwnd, CWinEventEmitter *we) -: - _hWnd(hwnd), - _WE(we), - _DInput8(NULL), - _Keyboard(NULL), - _Mouse(NULL), - _ButtonsFlags(noButton) -{ -} -//====================================================== -CDIEventEmitter::~CDIEventEmitter() -{ - releaseMouse(); - releaseKeyboard(); - // release all devices - while (_DeviceServer.getNumDevices() != 0) - { - IInputDevice *dev = _DeviceServer.getDevice(0); - _DeviceServer.removeDevice(dev); - delete dev; - } - if (_DInput8) _DInput8->Release(); - -- _NumCreatedInterfaces; - if (_NumCreatedInterfaces == 0) unloadLib(); -} - -//====================================================== -CDIEventEmitter *CDIEventEmitter::create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we) throw(EDirectInput) -{ - if (!loadLib()) throw EDirectInputLibNotFound(); - std::auto_ptr dxee(new CDIEventEmitter(hwnd, we)); - HRESULT result = _PDirectInput8Create(hinst, - DIRECTINPUT_VERSION, - IID_IDirectInput8A, - (void **) &dxee->_DInput8, - NULL); - if (result != DI_OK) throw EDirectInputInitFailed(); - - // ok, everything's fine, commit changes - ++_NumCreatedInterfaces; - return dxee.release(); -} - - -//====================================================== -bool CDIEventEmitter::loadLib() -{ - if (_DirectInputLibHandle != 0) return true; // library already loaded ? - HMODULE handle = ::LoadLibrary(DirectInputLibName); - if (handle == 0) return false; - // try to get the creation function - TPDirectInput8Create cf = (TPDirectInput8Create) ::GetProcAddress(handle, "DirectInput8Create"); - if (!cf) - { - ::FreeLibrary(handle); - return false; - } - // commit changes - _DirectInputLibHandle = handle; - _PDirectInput8Create = cf; - return true; -} - - -//====================================================== -void CDIEventEmitter::unloadLib() -{ - nlassert(_DirectInputLibHandle != 0); - ::FreeLibrary(_DirectInputLibHandle); - _DirectInputLibHandle = 0; - _PDirectInput8Create = NULL; -} - -//====================================================== -void CDIEventEmitter::poll(CEventServer *server) -{ - if (_WE) _ButtonsFlags = _WE->buildFlags(); - if (!server) - server=&_InternalServer; - _DeviceServer.poll(server); -} - - -//====================================================== -TMouseButton CDIEventEmitter::buildButtonsFlags() const -{ - uint mouseFlags; - uint keybFlags; - // - if (_Mouse) // takes the flags from the direct input mouse - { - mouseFlags = (_Mouse->getButton(0) ? leftButton : 0) - | (_Mouse->getButton(1) ? rightButton : 0) - | (_Mouse->getButton(2) ? middleButton : 0); - } - else // takes the flags from the system mouse - { - mouseFlags = _ButtonsFlags & (leftButton | rightButton | middleButton); - } - // - if (_Keyboard) // takes the flags from the direct input keyboard - { - keybFlags = (_Keyboard->ShiftPressed ? shiftButton : 0) - | (_Keyboard->AltPressed ? altButton : 0) - | (_Keyboard->CtrlPressed ? ctrlButton : 0); - } - else // takes the flags from the system keyboard - { - keybFlags = _ButtonsFlags & (shiftButton | altButton | ctrlButton); - } - return (TMouseButton) (keybFlags | mouseFlags); -} - -//====================================================== -IMouseDevice *CDIEventEmitter::getMouseDevice(bool hardware) throw(EInputDevice) -{ - if (_Mouse) return _Mouse; // already created ? - try - { - // Create a mouse - std::auto_ptr mouse(CDIMouse::createMouseDevice(_DInput8, _hWnd, this, hardware, _WE)); - // register to the device server - _DeviceServer.registerDevice(mouse.get()); - _Mouse = mouse.get(); - return mouse.release(); - } - catch (...) - { - if (_WE) _WE->enableMouseEvents(true); - throw; - } -} - -//====================================================== -void CDIEventEmitter::releaseMouse() -{ - if (!_Mouse) return; - // reupdate the system keyboard flags - if (_WE) - { - _WE->resetButtonFlagState(); - _WE->enableMouseEvents(true); - } - // remove the device - _DeviceServer.removeDevice(_Mouse); - delete _Mouse; - _Mouse = NULL; -} - -//=========================================================================== -IKeyboardDevice *CDIEventEmitter::getKeyboardDevice() throw(EInputDevice) -{ - if (_Keyboard) return _Keyboard; - try - { - // create a keyboard - std::auto_ptr keyboard(CDIKeyboard::createKeyboardDevice(_DInput8, _hWnd, this, _WE)); - // register to the device server - _DeviceServer.registerDevice(keyboard.get()); - _Keyboard = keyboard.get(); - return keyboard.release(); - } - catch (...) - { - if (_WE) _WE->enableKeyboardEvents(true); - throw; - } -} - -//========================================================================== -void CDIEventEmitter::releaseKeyboard() -{ - if (!_Keyboard) return; - // reupdate the system keyboard flags - if (_WE) - { - _WE->resetButtonFlagState(); - _WE->enableKeyboardEvents(true); - } - // - _DeviceServer.removeDevice(_Keyboard); - delete _Keyboard; - _Keyboard = NULL; -} - - -//========================================================================== -void CDIEventEmitter::submitEvents(CEventServer &server, bool allWindows) -{ - _InternalServer.setServer(&server); - _InternalServer.pump(allWindows); -} - -//========================================================================== -void CDIEventEmitter::emulateMouseRawMode(bool enable) -{ - nlerror("no raw mode emulation on windows, the CDIMouse has a real raw mode"); -} - -//========================================================================== -/// Tool fct to retrieve the game devices. -static BOOL CALLBACK DIEnumDevicesDescCallback -( - LPCDIDEVICEINSTANCE lpddi, - LPVOID pvRef -) -{ - CGameDeviceDesc desc; - desc.InstanceName = lpddi->tszInstanceName; - desc.ProductName = lpddi->tszProductName; - switch (lpddi->wUsage & 0xff) - { - case DI8DEVTYPE_JOYSTICK: desc.DevType = CGameDeviceDesc::Joystick; break; - case DI8DEVTYPE_GAMEPAD: desc.DevType = CGameDeviceDesc::GamePad; break; - default: desc.DevType = CGameDeviceDesc::DontKnow; break; - } - TDeviceDescVect *dv = (TDeviceDescVect *) pvRef; - dv->push_back(desc); - return DIENUM_CONTINUE; -} - - -//========================================================================== -/// Tool fct to retrieve the game devices GUID -static BOOL CALLBACK DIEnumDevicesGUIDCallback -( - LPCDIDEVICEINSTANCE lpddi, - LPVOID pvRef -) -{ - std::vector *gv = (std::vector *) pvRef; - gv->push_back(lpddi->guidInstance); - return DIENUM_CONTINUE; -} - - -//========================================================================== -void CDIEventEmitter::enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice) -{ - uint k; - nlassert(_DInput8); - descs.clear(); - // enum all devices of interest - _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesDescCallback, (LPVOID) &descs, DIEDFL_ALLDEVICES); - for (k = 0; k < descs.size(); ++k) descs[k].Connected = false; - // enum all connected devices - static TDeviceDescVect connecteds; - _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesDescCallback, (LPVOID) &connecteds, DIEDFL_ATTACHEDONLY); - // see which devices are connected - for (k = 0; k < connecteds.size(); ++k) - { - TDeviceDescVect::iterator it = std::find(descs.begin(), descs.end(), connecteds[k]); - it->Connected = true; - } -} - -//========================================================================== -IGameDevice *CDIEventEmitter::createGameDevice(const std::string &instanceName) throw(EInputDevice) -{ - static TDeviceDescVect deviceDescs; - static std::vector deviceGUID; - - nlassert(_DInput8); - enumerateGameDevice(deviceDescs); - // get the ID for each device - deviceGUID.clear(); - HRESULT r = _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesGUIDCallback, (LPVOID) &deviceGUID, DIEDFL_ALLDEVICES); - nlassert(r == DI_OK); - nlassert(deviceDescs.size() == deviceGUID.size()); - - // search the device that match the instance name - for (uint k = 0; k < deviceDescs.size(); ++k) - { - if (deviceDescs[k].InstanceName == instanceName) - { - std::auto_ptr gd(CDIGameDevice::createGameDevice(_DInput8, _hWnd, this, deviceDescs[k], deviceGUID[k])); - // insert in the device server - _DeviceServer.registerDevice(gd.get()); - return gd.release(); - } - } - return NULL; -} - -//========================================================================== -void CDIEventEmitter::releaseGameDevice(IGameDevice *gd) -{ - nlassert(gd); - CDIGameDevice *digd = safe_cast(gd); - _DeviceServer.removeDevice(digd); - delete gd; -} - - -} // NLMISC - -#endif // NL_OS_WINDOWS diff --git a/code/nel/src/misc/di_game_device.cpp b/code/nel/src/misc/di_game_device.cpp deleted file mode 100644 index 5adfb4b9b..000000000 --- a/code/nel/src/misc/di_game_device.cpp +++ /dev/null @@ -1,523 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - - -#include "stdmisc.h" -#include "di_game_device.h" -#include "nel/misc/game_device_events.h" - -#ifdef NL_OS_WINDOWS - -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NLMISC -{ - -//============================================================================ -CDIGameDevice::CDIGameDevice() : _Device(NULL) -{ - ::memset(&_CurrentState, 0, sizeof(_CurrentState)); -} - -//============================================================================ -CDIGameDevice::~CDIGameDevice() -{ - if (_Device) - { - _Device->Unacquire(); - _Device->Release(); - } -} - -//============================================================================ -CDIGameDevice *CDIGameDevice::createGameDevice(IDirectInput8 *di8, - HWND hwnd, - CDIEventEmitter *diEventEmitter, - const CGameDeviceDesc &desc, - REFGUID rguid) throw(EDirectInput) -{ - nlassert(diEventEmitter); - nlassert(di8); - std::auto_ptr dev(new CDIGameDevice); - // - - HRESULT r = di8->CreateDevice(rguid, &dev->_Device, NULL); - if (r != DI_OK) throw EDirectInputGameDeviceNotCreated(); - - r = dev->_Device->SetDataFormat(pJoyDataFormat); - nlassert(r == DI_OK); - // - r = dev->_Device->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); - if (r != DI_OK) throw EDirectInputCooperativeLevelFailed(); - // - // - dev->_Desc = desc; - dev->_EventEmitter = diEventEmitter; - dev->querryControls(); - return dev.release(); -} - -//============================================================================ -void CDIGameDevice::begin(CEventServer *server) -{ - nlassert(_Device); - HRESULT r; - r = _Device->Poll(); - if (r == DIERR_INPUTLOST || r == DIERR_NOTACQUIRED) - { - r = _Device->Acquire(); - if (r != DI_OK) return; - r = _Device->Poll(); - if (r != DI_OK) return; - } - - CDIJoyState newState; - r = _Device->GetDeviceState(sizeof(CDIJoyState), &newState); - if (r != DI_OK) return; - - uint k; - ////////// - // Axis // - ////////// - for (k = 0; k < MaxNumAxis; ++k) - { - CAxis &axis = _Axis[k]; - if (axis.Present) - { - - if (((LONG *) &newState)[k] != ((LONG *) &_CurrentState)[k]) // state changed ? - { - // update position - axis.Value = 2.f * (((LONG *) &newState)[k] - axis.Min) / (float) (axis.Max - axis.Min) - 1.f; - // create event - CGDAxisMoved *event = new CGDAxisMoved((IGameDevice::TAxis) k, axis.Value, this, _EventEmitter); - // update state - ((LONG *) &_CurrentState)[k] = ((LONG *) &newState)[k]; - // - server->postEvent(event); - // - } - } - } - - - ///////////// - // Buttons // - ///////////// - for (k = 0; k < _Buttons.size(); ++k) - { - CButton &bt = _Buttons[k]; - if ((newState.rgbButtons[k] & 0x80) != (_CurrentState.rgbButtons[k] & 0x80)) - { - bool pushed = (newState.rgbButtons[k] & 0x80) != 0; - // update the state of the button - bt.Pushed = pushed; - CGDButton *event; - if (pushed) event = new CGDButtonDown(k, this, _EventEmitter); - else event = new CGDButtonUp(k, this, _EventEmitter); - // update state - _CurrentState.rgbButtons[k] = newState.rgbButtons[k]; - server->postEvent(event); - } - } - - ///////////// - // Sliders // - ///////////// - for (k = 0; k < _Sliders.size(); ++k) - { - CSlider &sl = _Sliders[k]; - if (newState.rglSlider[k] != _CurrentState.rglSlider[k]) // state changed ? - { - // update position - sl.Pos = ( newState.rglSlider[k] - sl.Min) / (float) (sl.Max - sl.Min); - // create event - CGDSliderMoved *event = new CGDSliderMoved(sl.Pos, k, this, _EventEmitter); - // update state - _CurrentState.rglSlider[k] = newState.rglSlider[k]; - // - server->postEvent(event); - } - } - - ////////// - // POVs // - ////////// - for (k = 0; k < _POVs.size(); ++k) - { - CPOV &pov = _POVs[k]; - if (newState.rgdwPOV[k] != _CurrentState.rgdwPOV[k]) // state changed ? - { - DWORD value = newState.rgdwPOV[k]; - - pov.Centered = (LOWORD(value) == 0xFFFF); - if (!pov.Centered) - { - // update position - pov.Angle = value / 100.f; - } - // create event - CGDPOVChanged *event = new CGDPOVChanged(pov.Centered, pov.Angle, k, this, _EventEmitter); - // update state - _CurrentState.rgdwPOV[k] = newState.rgdwPOV[k]; - // - server->postEvent(event); - } - } - -} - -//============================================================================ -void CDIGameDevice::poll(CInputDeviceServer *dev) -{ - // buffered datas not supported -} - -//============================================================================ -void CDIGameDevice::submit(IInputDeviceEvent *deviceEvent, CEventServer *server) -{ - // should never be called, buffered datas not supported - nlassert(0); -} - - -//============================================================================ -/** Tool fct : tests whether a DIDEVICEOBJECTINSTANCE contains a controls name and return it, - * or build a default one - */ -static void BuildCtrlName(LPCDIDEVICEOBJECTINSTANCE lpddoi, - std::string &destName, - const char *defaultName) -{ - if (lpddoi->dwSize >= offsetof(DIDEVICEOBJECTINSTANCE, tszName) + sizeof(TCHAR[MAX_PATH])) - { - destName = (::strcmp("N/A", lpddoi->tszName) == 0) ? defaultName - : lpddoi->tszName; - } - else - { - destName = defaultName; - } -} - -//============================================================================ -// A callback to enumerate the controls of a device -BOOL CALLBACK DIEnumDeviceObjectsCallback -( - LPCDIDEVICEOBJECTINSTANCE lpddoi, - LPVOID pvRef -) -{ - - CDIGameDevice *gd = (CDIGameDevice *) pvRef; - return gd->processEnumObject(lpddoi); -} - - - -//======================================================================= -// get range for an axis -static HRESULT GetDIAxisRange(LPDIRECTINPUTDEVICE8 device, uint offset, DWORD type, sint &min, sint &max) -{ - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.diph.dwObj = offset; - - // Set the range for the axis - HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph); - - if (r == DIERR_OBJECTNOTFOUND) - { - // try from its ID - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = type; - - // Set the range for the axis - HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph); - if (r != DI_OK) - { - // setup default values ... - min = 0; - max = 65535; - return r; - } - } - else if (r != DI_OK) - { - min = 0; - max = 65535; - return r; - } - - -/* switch (r) - { - default: - nlinfo("ok"); - break; - case DIERR_INVALIDPARAM: - nlinfo("invalid param"); - break; - case DIERR_NOTEXCLUSIVEACQUIRED: - nlinfo("DIERR_NOTEXCLUSIVEACQUIRED"); - break; - case DIERR_NOTINITIALIZED: - nlinfo("DIERR_NOTINITIALIZED"); - break; - case DIERR_OBJECTNOTFOUND: - nlinfo("DIERR_OBJECTNOTFOUND"); - break; - case DIERR_UNSUPPORTED: - nlinfo("DIERR_UNSUPPORTED"); - break; - }*/ - - - min = (sint) diprg.lMin; - max = (sint) diprg.lMax; - - return r; -} - -//============================================================================ -BOOL CDIGameDevice::processEnumObject(LPCDIDEVICEOBJECTINSTANCE lpddoi) -{ - // the dwSize field gives us the size of the objects, and the available fields - // has this object the field guidType and dwOfs ? - if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwOfs) + sizeof(DWORD)) return DIENUM_CONTINUE; - - uint ctrlType = (uint) lpddoi->dwType; - - /////////////////////////////////////////// - // axis, we only support absolute ones // - /////////////////////////////////////////// - - if (lpddoi->guidType == GUID_XAxis && (ctrlType & DIDFT_ABSAXIS) ) - { - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[XAxis].Min, _Axis[XAxis].Max); - BuildCtrlName(lpddoi, _Axis[XAxis].Name, "X Axis"); - _Axis[XAxis].Present = true; - return DIENUM_CONTINUE; - } - if (lpddoi->guidType == GUID_YAxis && (ctrlType & DIDFT_ABSAXIS)) - { - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[YAxis].Min, _Axis[YAxis].Max); - BuildCtrlName(lpddoi, _Axis[YAxis].Name, "Y Axis"); - _Axis[YAxis].Present = true; - return DIENUM_CONTINUE; - } - - if (lpddoi->guidType == GUID_ZAxis && (ctrlType & DIDFT_ABSAXIS)) - { - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[ZAxis].Min, _Axis[ZAxis].Max); - BuildCtrlName(lpddoi, _Axis[ZAxis].Name, "Z Axis"); - _Axis[ZAxis].Present = true; - return DIENUM_CONTINUE; - } - if (lpddoi->guidType == GUID_RxAxis && (ctrlType & DIDFT_ABSAXIS)) - { - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RXAxis].Min, _Axis[RXAxis].Max); - BuildCtrlName(lpddoi, _Axis[RXAxis].Name, "RX Axis"); - _Axis[RXAxis].Present = true; - return DIENUM_CONTINUE; - } - if (lpddoi->guidType == GUID_RyAxis && (ctrlType & DIDFT_ABSAXIS)) - { - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RYAxis].Min, _Axis[RYAxis].Max); - BuildCtrlName(lpddoi, _Axis[RYAxis].Name, "RY Axis"); - _Axis[RYAxis].Present = true; - return DIENUM_CONTINUE; - } - if (lpddoi->guidType == GUID_RzAxis && (ctrlType & DIDFT_ABSAXIS)) - { - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RZAxis].Min, _Axis[RZAxis].Max); - BuildCtrlName(lpddoi, _Axis[RZAxis].Name, "RZ Axis"); - _Axis[RZAxis].Present = true; - return DIENUM_CONTINUE; - } - - - // has this object the field dwType ? - if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwType) + sizeof(DWORD)) return DIENUM_CONTINUE; - - - uint type = lpddoi->dwType; - ///////////// - // Buttons // - ///////////// - if (type & DIDFT_BUTTON) - { - if (_Buttons.size() < MaxNumButtons) - { - _Buttons.push_back(CButton()); - uint buttonIndex = (uint)_Buttons.size() - 1; - char defaultButtonName[32]; - smprintf(defaultButtonName, 32, "BUTTON %d", buttonIndex + 1); - BuildCtrlName(lpddoi, _Buttons[buttonIndex].Name, defaultButtonName); - return DIENUM_CONTINUE; - } - } - - ///////////// - // Sliders // - ///////////// - if (type & DIDFT_ABSAXIS) - { - if (_Sliders.size() < MaxNumSliders) - { - _Sliders.push_back(CSlider()); - uint sliderIndex = (uint)_Sliders.size() - 1; - GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Sliders[sliderIndex].Min, _Sliders[sliderIndex].Max); - char defaultSliderName[32]; - smprintf(defaultSliderName, 32, "SLIDER %d", sliderIndex + 1); - BuildCtrlName(lpddoi, _Sliders[sliderIndex].Name, defaultSliderName); - } - return DIENUM_CONTINUE; - } - - - ////////// - // POVs // - ////////// - if (type & DIDFT_POV) - { - if (_POVs.size() < MaxNumPOVs) - { - _POVs.push_back(CPOV()); - uint povIndex = (uint)_POVs.size() - 1; - char defaultPOVName[16]; - smprintf(defaultPOVName, 16, "POV %d", povIndex + 1); - BuildCtrlName(lpddoi, _POVs[povIndex].Name, defaultPOVName); - } - return DIENUM_CONTINUE; - } - - return DIENUM_CONTINUE; -} - -//============================================================================ -void CDIGameDevice::querryControls() -{ - HRESULT r = _Device->EnumObjects(&DIEnumDeviceObjectsCallback, (LPVOID) this, DIDFT_ALL); - nlassert(r == DI_OK); -} - -//============================================================================ -bool CDIGameDevice::setBufferSize(uint size) -{ - // uisually not supported by this kind of devices - return false; -} - -//============================================================================ -uint CDIGameDevice::getBufferSize() const -{ - // uisually not supported by this kind of devices - return 0; -} - -//============================================================================ -uint CDIGameDevice::getNumButtons() const -{ - return (uint)_Buttons.size(); -} - -//============================================================================ -bool CDIGameDevice::hasAxis(TAxis axis) const -{ - nlassert(axis < MaxNumAxis); - return _Axis[axis].Present; -} - -//============================================================================ -uint CDIGameDevice::getNumSliders() const -{ - return (uint)_Sliders.size(); -} - -//============================================================================ -uint CDIGameDevice::getNumPOV() const -{ - return (uint)_POVs.size(); -} -//============================================================================ -const char *CDIGameDevice::getButtonName(uint index) const -{ - nlassert(index < _Buttons.size()); - return _Buttons[index].Name.c_str(); -} - -//============================================================================ -const char *CDIGameDevice::getAxisName(TAxis axis) const -{ - nlassert(axis < MaxNumAxis); - nlassert(hasAxis(axis)); // ! Not an axis of this device - return _Axis[axis].Name.c_str(); -} - -//============================================================================ -const char *CDIGameDevice::getSliderName(uint index) const -{ - nlassert(index < _Sliders.size()); - return _Sliders[index].Name.c_str(); -} - -//============================================================================ -const char *CDIGameDevice::getPOVName(uint index) const -{ - nlassert(index < _POVs.size()); - return _POVs[index].Name.c_str(); -} - -//============================================================================ -bool CDIGameDevice::getButtonState(uint index) const -{ - nlassert(index < _Buttons.size()); - return _Buttons[index].Pushed; -} - -//============================================================================ -float CDIGameDevice::getAxisValue(TAxis axis) const -{ - nlassert(axis < MaxNumAxis); - nlassert(hasAxis(axis)); // ! Not an axis of this device - return _Axis[axis].Value; -} - -//============================================================================ -float CDIGameDevice::getSliderPos(uint index) const -{ - nlassert(index < _Sliders.size()); - return _Sliders[index].Pos; -} - -//============================================================================ -float CDIGameDevice::getPOVAngle(uint index) const -{ - nlassert(index < _POVs.size()); - return _POVs[index].Angle; -} - - - -} // NLMISC - - -#endif // NL_OS_WINDOWS diff --git a/code/nel/src/misc/di_game_device.h b/code/nel/src/misc/di_game_device.h deleted file mode 100644 index cc44aaf4c..000000000 --- a/code/nel/src/misc/di_game_device.h +++ /dev/null @@ -1,170 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_DI_GAME_DEVICE_H -#define NL_DI_GAME_DEVICE_H - -#include "nel/misc/types_nl.h" - -#ifdef NL_OS_WINDOWS - -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/game_device.h" - -namespace NLMISC -{ - -// -typedef DIJOYSTATE2 CDIJoyState; -const DIDATAFORMAT * const pJoyDataFormat = &c_dfDIJoystick2; -const uint MaxNumSliders = 2; -const uint MaxNumPOVs = 4; -const uint MaxNumButtons = 128; -// - -struct EDirectInputGameDeviceNotCreated : EDirectInput -{ - EDirectInputGameDeviceNotCreated() : EDirectInput("Unable to create a game device") {} -}; - - -/** - * Direct input implementation of a game device. - */ - -class CDIGameDevice : public IGameDevice -{ -public: - /// Create a direct input game device from the given RGUID. Destroy it with delete - static CDIGameDevice *createGameDevice(IDirectInput8 *di8, - HWND hwnd, - CDIEventEmitter *diEventEmitter, - const CGameDeviceDesc &desc, - REFGUID rguid) throw(EDirectInput); - ~CDIGameDevice(); - - ///\name From IInputDevice - //@{ - virtual bool setBufferSize(uint size); - virtual uint getBufferSize() const; - //@} - - ///\name From IGameDevice - //@{ - virtual const CGameDeviceDesc &getDescription() const { return _Desc; } - // - virtual uint getNumButtons() const; - virtual bool hasAxis(TAxis axis) const; - virtual uint getNumSliders() const; - virtual uint getNumPOV() const; - // - virtual const char *getButtonName(uint index) const; - virtual const char *getAxisName(TAxis axis) const; - virtual const char *getSliderName(uint index) const; - virtual const char *getPOVName(uint index) const; - // - virtual bool getButtonState(uint index) const; - virtual float getAxisValue(TAxis axis) const; - virtual float getSliderPos(uint index) const; - virtual float getPOVAngle(uint index) const; - //@} - - -/////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////// -private: - - // base class for controls - struct CCtrl - { - std::string Name; - }; - - // a button - struct CButton : public CCtrl - { - bool Pushed; - CButton() : Pushed(false) {} - }; - - // an axis. Its value either gives its position (-1 .. 1) or its angle (CCW in radians) - struct CAxis : public CCtrl - { - bool Present; // is this axis used ? - // min and max values from Direct Input - sint Min, Max; - float Value; - CAxis() : Value(0.f), Present(false) {} - }; - - // a slider - struct CSlider : public CCtrl - { - sint Min, Max; - float Pos; - CSlider() : Pos(0.f) {} - }; - - // a POV - struct CPOV : public CCtrl - { - bool Centered; - float Angle; - CPOV() : Angle(0.f), Centered(true) {} - }; - - -private: - // ctor - CDIGameDevice(); - ///\name From IInputDevice - //@{ - virtual void begin(CEventServer *server); - virtual void poll(CInputDeviceServer *dev); - virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server); - //@} - /** Get the controls (buttons, slider..) of this device from the Direct Input interface to build this object infos. - */ - void querryControls(); - - /// Called during EnumObject - BOOL processEnumObject(LPCDIDEVICEOBJECTINSTANCE lpddoi); - friend BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); -private: - LPDIRECTINPUTDEVICE8 _Device; - CGameDeviceDesc _Desc; - CDIEventEmitter *_EventEmitter; - - ///\name Device infos - //@{ - CAxis _Axis[MaxNumAxis]; - std::vector _Buttons; - std::vector _Sliders; - std::vector _POVs; - //@} - CDIJoyState _CurrentState; - -}; - - -} // NLMISC - -#endif // NL_OS_WINDOWS - - -#endif // NL_DI_GAME_DEVICE_H - -/* End of di_play_device.h */ diff --git a/code/nel/src/misc/di_keyboard_device.cpp b/code/nel/src/misc/di_keyboard_device.cpp deleted file mode 100644 index 8b5d9c6e1..000000000 --- a/code/nel/src/misc/di_keyboard_device.cpp +++ /dev/null @@ -1,686 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - - - -#include "stdmisc.h" -#include "di_keyboard_device.h" - -#ifdef NL_OS_WINDOWS - -#include "nel/misc/win_event_emitter.h" -#include -#include - -#include "Mmsystem.h" - -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NLMISC -{ - -// used to do a conversion from DX key code to Nel keys enums -struct CKeyConv -{ - uint DIKey; - TKey NelKey; - const char *KeyName; - bool Repeatable; -}; - -// this is used to build a conversion table -static const CKeyConv DIToNel[] = -{ - // - {DIK_F1, KeyF1, "F1", true}, - {DIK_F2, KeyF2, "F2", true}, - {DIK_F3, KeyF3, "F3", true}, - {DIK_F4, KeyF4, "F4", true}, - {DIK_F5, KeyF5, "F5", true}, - {DIK_F6, KeyF6, "F6", true}, - {DIK_F7, KeyF7, "F7", true}, - {DIK_F8, KeyF8, "F8", true}, - {DIK_F9, KeyF9, "F9", true}, - {DIK_F10, KeyF10, "F10", true}, - {DIK_F11, KeyF11, "F11", true}, - {DIK_F12, KeyF12, "F12", true}, - {DIK_F13, KeyF13, "F13", true}, - {DIK_F14, KeyF14, "F14", true}, - {DIK_F15, KeyF15, "F15", true}, - // - {DIK_NUMPAD0, KeyNUMPAD0, "NUMPAD0", true}, - {DIK_NUMPAD1, KeyNUMPAD1, "NUMPAD1", true}, - {DIK_NUMPAD2, KeyNUMPAD2, "NUMPAD2", true}, - {DIK_NUMPAD3, KeyNUMPAD3, "NUMPAD3", true}, - {DIK_NUMPAD4, KeyNUMPAD4, "NUMPAD4", true}, - {DIK_NUMPAD5, KeyNUMPAD5, "NUMPAD5", true}, - {DIK_NUMPAD6, KeyNUMPAD6, "NUMPAD6", true}, - {DIK_NUMPAD7, KeyNUMPAD7, "NUMPAD7", true}, - {DIK_NUMPAD8, KeyNUMPAD8, "NUMPAD8", true}, - {DIK_NUMPAD9, KeyNUMPAD9, "NUMPAD9", true}, - // - {DIK_DIVIDE, KeyDIVIDE, "/", true}, - {DIK_DECIMAL, KeyDECIMAL, "NUMPAD .", true}, - // - {DIK_LSHIFT, KeyLSHIFT, "LEFT SHIFT", false}, - {DIK_RSHIFT, KeyRSHIFT, "RIGHT SHIFT", false}, - // - {DIK_LCONTROL, KeyLCONTROL, "LEFT CONTROL", false}, - {DIK_RCONTROL, KeyRCONTROL, "RIGHT CONTROL", false}, - // - {DIK_LMENU, KeyLMENU, "ALT", false}, - {DIK_RMENU, KeyRMENU, "ALT GR", false}, - // - {DIK_UP, KeyUP, "UP", true}, - {DIK_PRIOR, KeyPRIOR, "PRIOR", true}, - {DIK_LEFT, KeyLEFT, "LEFT", true}, - {DIK_RIGHT, KeyRIGHT, "RIGHT", true}, - {DIK_END, KeyEND, "END", true}, - {DIK_DOWN, KeyDOWN, "DOWN", true}, - {DIK_NEXT, KeyNEXT, "NEXT", true}, - {DIK_INSERT, KeyINSERT, "INSERT", true}, - {DIK_DELETE, KeyDELETE, "DELETE", true}, - {DIK_HOME, KeyHOME, "HOME", true}, - {DIK_LWIN, KeyLWIN, "LEFT WIN", false}, - {DIK_RWIN, KeyRWIN, "RIGHT WIN", false}, - {DIK_APPS, KeyAPPS, "APPS", false}, - {DIK_BACK, KeyBACK, "BACK", true}, - // - {DIK_SYSRQ, KeySNAPSHOT, "SNAPSHOT", false}, - {DIK_SCROLL, KeySCROLL, "SCROLL", false}, - {DIK_PAUSE, KeyPAUSE, "PAUSE", false}, - // - {DIK_NUMLOCK, KeyNUMLOCK, "NUMLOCK", false}, - // - {DIK_NUMPADENTER, KeyRETURN, "RETURN", true}, - //{DIK_NUMPADENTER, KeyRETURN, "ENTER", true}, - // - {DIK_CONVERT, KeyCONVERT, "CONVERT", false}, - {DIK_NOCONVERT, KeyNONCONVERT, "NOCONVERT", true}, - // - {DIK_KANA, KeyKANA, "KANA", false}, - {DIK_KANJI, KeyKANJI, "KANJI", false}, -}; - - -///======================================================================== -const CKeyConv *CDIKeyboard::DIKeyToNelKeyTab[CDIKeyboard::NumKeys]; - -///======================================================================== -CDIKeyboard::CDIKeyboard(CWinEventEmitter *we, HWND hwnd) -: _Keyboard(NULL), - _WE(we), - ShiftPressed(false), - CtrlPressed(false), - AltPressed(false), - _CapsLockToggle(true), - _hWnd(hwnd), - _RepeatDelay(250), - _RepeatPeriod(200), - _FirstPressDate(-1), - _LastDIKeyPressed(0) -{ - if (::GetKeyboardState((PBYTE) _VKKeyState) == FALSE) - { - std::fill(_VKKeyState, _VKKeyState + NumKeys, 0); - } - // test whether the user toggle its keyboard with shift or not.. - HKEY hKey; - if (::RegOpenKeyEx(HKEY_CURRENT_USER, "Keyboard Layout", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - DWORD type = REG_DWORD; - DWORD value; - DWORD size = sizeof(DWORD); - if (::RegQueryValueEx(hKey, "Attributes", NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS) - { - _CapsLockToggle = (value & (1 << 16)) == 0; - } - ::RegCloseKey(hKey); - } - // get repeat delay and period - int keybDelay; - if (::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &keybDelay, 0) != 0) - { - _RepeatDelay = 250 + 250 * keybDelay; - } - DWORD keybSpeed; - if (::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &keybSpeed, 0) != 0) - { - _RepeatPeriod = (uint) (1000.f / (keybSpeed * (27.5f / 31.f) + 2.5f)); - } - // get keyboard layout - _KBLayout = ::GetKeyboardLayout(0); - - _RepetitionDisabled.resize(NumKeys); - _RepetitionDisabled.clearAll(); -} - -///======================================================================== -void CDIKeyboard::updateVKKeyState(uint diKey, bool pressed, TKey &keyValue, TKey &charValue) -{ - bool extKey; - bool repeatable; - keyValue = DIKeyToNelKey(diKey, extKey, repeatable); - // - if (keyValue == 0) - { - charValue = keyValue; - return; - } - // - if (pressed) - { - // check for toggle key - switch (keyValue) - { - case KeyPAUSE: - case KeyKANA: - case KeyKANJI: - _VKKeyState[keyValue] ^= 0x01; // toggle first bit - break; - case KeyCAPITAL: - if (_CapsLockToggle) - { - _VKKeyState[keyValue] ^= 0x01; - //toggleCapsLock(false); - } - else - { - if ((_VKKeyState[keyValue] & 0x01) == 0) - { - _VKKeyState[keyValue] |= 0x01; - //toggleCapsLock(false); - } - } - break; - case KeyNUMLOCK: - _VKKeyState[keyValue] ^= 0x01; - //setNumLock((_VKKeyState[keyValue] & 0x01) != 0); - break; - case KeySCROLL: - _VKKeyState[keyValue] ^= 0x01; - //toggleScrollLock(); - break; - - } - - _VKKeyState[keyValue] |= 0x80; - } - else - { - _VKKeyState[keyValue] &= ~0x80; - } - // - switch (keyValue) - { - case KeyLSHIFT: charValue = KeySHIFT; break; - case KeyRSHIFT: charValue = KeySHIFT; break; - case KeyLCONTROL: charValue = KeyCONTROL; break; - case KeyRCONTROL: charValue = KeyCONTROL; break; - case KeyLMENU: charValue = KeyMENU; break; - case KeyRMENU: charValue = KeyMENU; break; - default: charValue = keyValue; break; - } - // - if (charValue == KeySHIFT && !_CapsLockToggle) - { - if (_VKKeyState[KeyCAPITAL] & 0x01) - { - _VKKeyState[KeyCAPITAL] &= ~0x01; - //toggleCapsLock(true); - } - } - // - if (charValue != keyValue) - { - _VKKeyState[charValue] = _VKKeyState[keyValue]; - } - // - updateCtrlAltShiftValues(); -} - -///======================================================================== -void CDIKeyboard::updateCtrlAltShiftValues() -{ - ShiftPressed = (_VKKeyState[KeySHIFT] & 0x80) != 0; - CtrlPressed = (_VKKeyState[KeyCONTROL] & 0x80) != 0; - AltPressed = (_VKKeyState[KeyMENU] & 0x80) != 0; -} - -///======================================================================== -CDIKeyboard::~CDIKeyboard() -{ - if (_Keyboard) - { - _Keyboard->Unacquire(); - _Keyboard->Release(); - } -} - -///======================================================================== -CDIKeyboard *CDIKeyboard::createKeyboardDevice(IDirectInput8 *di8, - HWND hwnd, - CDIEventEmitter *diEventEmitter, - CWinEventEmitter *we - ) throw(EDirectInput) -{ - std::auto_ptr kb(new CDIKeyboard(we, hwnd)); - kb->_DIEventEmitter = diEventEmitter; - HRESULT result = di8->CreateDevice(GUID_SysKeyboard, &kb->_Keyboard, NULL); - if (result != DI_OK) throw EDirectInputNoKeyboard(); - result = kb->_Keyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); - if (result != DI_OK) throw EDirectInputCooperativeLevelFailed(); - result = kb->_Keyboard->SetDataFormat(&c_dfDIKeyboard); - kb->setBufferSize(16); - kb->_Keyboard->Acquire(); - - // Enable win32 keyboard messages only if hardware mouse in normal mode - if (kb->_WE) - kb->_WE->enableKeyboardEvents(false); - - return kb.release(); -} - -///======================================================================== -void CDIKeyboard::poll(CInputDeviceServer *dev) -{ - nlassert(_Keyboard); - nlassert(_KeyboardBufferSize > 0); - static std::vector datas; - datas.resize(_KeyboardBufferSize); - DWORD numElements = _KeyboardBufferSize; - HRESULT result = _Keyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0); - if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) - { - result = _Keyboard->Acquire(); - if (result != DI_OK) return; - // get device state - ::GetKeyboardState((unsigned char *) _VKKeyState); - _LastDIKeyPressed = 0; - updateCtrlAltShiftValues(); - result = _Keyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0); - if (result != DI_OK) return; - } - else if (result != DI_OK) - { - return; - } - - _PollTime = (uint32) CTime::getLocalTime(); - - - // process each message in the list - for (uint k = 0; k < numElements; ++k) - { - CDIEvent *die = new CDIEvent; - die->Emitter = this; - die->Datas = datas[k]; - dev->submitEvent(die); - } -} - -///======================================================================== -void CDIKeyboard::transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage) -{ - repeatKey(buildDateFromEvent(nextMessage), server); -} - -///======================================================================== -TKeyButton CDIKeyboard::buildKeyButtonsFlags() const -{ - return (TKeyButton) ( (ShiftPressed ? shiftKeyButton : 0) - | (CtrlPressed ? ctrlKeyButton : 0) - | (AltPressed ? altKeyButton : 0) - ); -} - -///======================================================================== -void CDIKeyboard::keyTriggered(bool pressed, uint dikey, CEventServer *server, uint32 date) -{ - #if 0 - const uint numPairs = sizeof(DIToNel) / sizeof(CKeyConv); - for (uint k = 0; k < numPairs; ++k) - { - if (DIToNel[k].DIKey == key) - { - nlinfo(DIToNel[k].KeyName); - } - } - #endif - - - TKey keyValue, charValue; - updateVKKeyState(dikey, pressed, keyValue, charValue); - if (keyValue == 0) return; - - CEventKey *ek; - if (pressed ) - { - ek = new CEventKeyDown(keyValue, buildKeyButtonsFlags(), true, _DIEventEmitter); - } - else - { - ek = new CEventKeyUp(keyValue, buildKeyButtonsFlags(), _DIEventEmitter); - } - server->postEvent(ek); - - if (pressed) - { - if (_RepetitionDisabled[(uint) keyValue] == false) - { - _LastEmitDate = _FirstPressDate = date; - _LastDIKeyPressed = dikey; - } - else // not a repeatable key - { - _LastDIKeyPressed = 0; - return; - } - } - else - { - // key released ? - if (dikey == _LastDIKeyPressed) - { - _LastDIKeyPressed = 0; - } - - if (_RepetitionDisabled[(uint) keyValue] == true) - { - return; - } - } - - // first char event (if repetition not disabled) - if (keyValue >= KeyNUMPAD0 && keyValue <= KeyNUMPAD9 || keyValue == KeyDECIMAL) - { - if ((_VKKeyState[KeyNUMLOCK] & 0x01) != 0) - { - sendUnicode(charValue, dikey, server, pressed); - } - } - else - { - sendUnicode(charValue, dikey, server, pressed); - } - - _FirstPressDate = (uint32) NLMISC::CTime::getLocalTime(); // can't use the time stamp, because we can't not sure it matches the local time. - // time stamp is used for evenrts sorting only -} - -///======================================================================== -void CDIKeyboard::submit(IInputDeviceEvent *deviceEvent, CEventServer *server) -{ - CDIEvent *die = safe_cast(deviceEvent); - bool pressed = (die->Datas.dwData & 0x80) != 0; - keyTriggered(pressed, (uint) die->Datas.dwOfs, server, die->Datas.dwTimeStamp); -} - -///======================================================================== -TMouseButton CDIKeyboard::buildKeyboardButtonFlags() const -{ - nlassert(_Keyboard); - return _DIEventEmitter->buildKeyboardButtonFlags(); -} - -///======================================================================== -bool CDIKeyboard::setBufferSize(uint size) -{ - nlassert(size > 0); - nlassert(_Keyboard); - _Keyboard->Unacquire(); - DIPROPDWORD dipdw; - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = size; - HRESULT r = _Keyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ); - if (r != DI_OK) return false; - _KeyboardBufferSize = size; - return true; -} - -///======================================================================== -uint CDIKeyboard::getBufferSize() const -{ - return _KeyboardBufferSize; -} - -///======================================================================== -TKey CDIKeyboard::DIKeyToNelKey(uint diKey, bool &extKey, bool &repeatable) -{ - // some key are not handled by MapVirtualKeyEx so we need to convert them ourselves - static bool tableBuilt = false; - - if (!tableBuilt) - { - uint k; - for (k = 0; k < NumKeys; ++k) - { - DIKeyToNelKeyTab[k] = NULL; // set as not a valid key by default - } - const uint numPairs = sizeof(DIToNel) / sizeof(CKeyConv); - for (k = 0; k < numPairs; ++k) - { - DIKeyToNelKeyTab[DIToNel[k].DIKey] = &DIToNel[k]; - } - tableBuilt = true; - } - - - // - if (DIKeyToNelKeyTab[diKey] != NULL) - { - const CKeyConv &keyConv = *DIKeyToNelKeyTab[diKey]; - extKey = true; - repeatable = keyConv.Repeatable; - return keyConv.NelKey; - } - - - - // try doing the conversion using MapVirtualKey - TKey key = (TKey) ::MapVirtualKeyEx(diKey, 1, _KBLayout); - extKey = false; - return key; -} - -///======================================================================== -void CDIKeyboard::sendUnicode(TKey vkey, uint dikey, CEventServer *server, bool pressed) -{ - uint8 oldShift = _VKKeyState[KeySHIFT]; - /// If caps lock is off when pressing shift, we must disable shift, to get no minuscule letters when it is pressed and capslocks is on. - if (!_CapsLockToggle && _VKKeyState[KeyCAPITAL] & 0x01) - { - _VKKeyState[KeySHIFT] = 0; - } - // 'ToUnicode??' is supported since NT4.0 only - // Check if there's support - - - static bool init = false; - static bool toUnicodeSupported = false; - if (!init) - { - init = true; - OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (::GetVersionEx (&osvi)) - { - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - if (osvi.dwMajorVersion >= 4) - { - toUnicodeSupported = true; - } - } - } - } - - - if (toUnicodeSupported) - { - const uint maxNumKeys = 8; - WCHAR keyUnicodes[maxNumKeys]; - int res = ::ToUnicodeEx(vkey, dikey | (pressed ? 0 : (1 << 15)), (unsigned char *) _VKKeyState, keyUnicodes, maxNumKeys, 0, _KBLayout); - // - _VKKeyState[KeySHIFT] = oldShift; - // - for (sint k = 0; k < res; ++k) - { - CEventChar *evc = new CEventChar((ucchar) keyUnicodes[k], buildKeyButtonsFlags(), _DIEventEmitter); - server->postEvent(evc); - } - } - else - { - unsigned char buf[2]; - int res = ::ToAsciiEx(vkey, dikey | (pressed ? 0 : (1 << 15)), (unsigned char *) _VKKeyState, (LPWORD) buf, 0, _KBLayout); - for (sint k = 0; k < res; ++k) - { - CEventChar *evc = new CEventChar((ucchar) buf[k], buildKeyButtonsFlags(), _DIEventEmitter); - server->postEvent(evc); - } - } -} - -///======================================================================== -void CDIKeyboard::repeatKey(uint32 currentDate, CEventServer *server) -{ - if (_LastDIKeyPressed == 0 || _LastDIKeyPressed == DIK_INSERT) return; - bool extKey; - bool repeatable; - TKey vkey = DIKeyToNelKey(_LastDIKeyPressed, extKey, repeatable); - if (vkey == 0) return; - if (currentDate - _FirstPressDate < _RepeatDelay) return; - - sint32 firstDate = _LastEmitDate - (_FirstPressDate + _RepeatDelay); - sint32 lastDate = currentDate - (_FirstPressDate + _RepeatDelay); - if (firstDate < 0) firstDate = 0; - - if (lastDate < firstDate) return; - - uint numRep = (uint) ((lastDate + _RepeatPeriod - 1) / _RepeatPeriod - (firstDate + _RepeatPeriod - 1) / _RepeatPeriod); - //numRep = std::min(16u, numRep); // too much repetitions don't make sense... - if ((sint) numRep < 0) return; // 50 days loop.. - numRep = 1; // fix : for now it seems better to limit the number of repetition to 1 per frame (it can be greater than 1 only if framerate is slow, but its not very useable) - - - // numpad case - if (vkey >= KeyNUMPAD0 && vkey <= KeyNUMPAD9 || vkey == KeyDECIMAL) - { - // check whether numlock is activated - if ((_VKKeyState[KeyNUMLOCK] & 0x01) != 0) - { - for (uint k = 0; k < numRep; ++k) - { - sendUnicode(vkey, _LastDIKeyPressed, server, true); - } - } - else - { - // arrow, home, end.. events - for (uint k = 0; k < numRep; ++k) - { - CEventKey *ek = new CEventKeyDown(vkey, buildKeyButtonsFlags(), false, _DIEventEmitter); - server->postEvent(ek); - } - } - } - else - { - for (uint k = 0; k < numRep; ++k) - { - // if it is an extended key, repetition won't be managed by sendUnicode - if (extKey && repeatable) - { - CEventKey *ek = new CEventKeyDown(vkey, buildKeyButtonsFlags(), false, _DIEventEmitter); - server->postEvent(ek); - } - else - { - sendUnicode(vkey, _LastDIKeyPressed, server, true); - } - } - } - - _LastEmitDate = currentDate; -} - -///======================================================================== -uint32 CDIKeyboard::buildDateFromEvent(const IInputDeviceEvent *deviceEvent) -{ - if (deviceEvent) - { - const CDIEvent *die = safe_cast(deviceEvent); - return (uint32) die->Datas.dwData; - } - else - { - return _PollTime; - } -} - -///======================================================================== -void CDIKeyboard::disableRepetition(const TKey *keyTab, uint numKey) -{ - _RepetitionDisabled.clearAll(); - for (uint k = 0; k < numKey; ++k) - { - _RepetitionDisabled.set((sint) keyTab[k]); - } - - if (_LastDIKeyPressed != 0) - { - bool extKey; - bool repeatable; - TKey key = DIKeyToNelKey(_LastDIKeyPressed, extKey, repeatable); - if (_RepetitionDisabled[(uint) key]) - { - // disable this key repetition - _LastDIKeyPressed = 0; - } - } -} - -///======================================================================== -uint CDIKeyboard::getNumDisabledRepetition() const -{ - uint numKey = 0; - for (uint k = 0; k < NumKeys; ++k) - { - if (_RepetitionDisabled[k]) ++numKey; - } - return numKey; -} - -///======================================================================== -void CDIKeyboard::getDisabledRepetitions(TKey *destTab) const -{ - for (uint k = 0; k < NumKeys; ++k) - { - if (_RepetitionDisabled[k]) *destTab++ = (TKey) k; - } -} - - - -} // NLMISC - -#endif // NL_OS_WINDOWS diff --git a/code/nel/src/misc/di_keyboard_device.h b/code/nel/src/misc/di_keyboard_device.h deleted file mode 100644 index d28285894..000000000 --- a/code/nel/src/misc/di_keyboard_device.h +++ /dev/null @@ -1,163 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_DI_KEYBOARD_H -#define NL_DI_KEYBOARD_H - -#include "nel/misc/types_nl.h" - -#ifdef NL_OS_WINDOWS - -#include "nel/misc/input_device_server.h" -#include "nel/misc/keyboard_device.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/bit_set.h" - - - - - -namespace NLMISC -{ - -class CWinEventEmitter; - -// -struct EDirectInputNoKeyboard : public EDirectInput -{ - EDirectInputNoKeyboard() : EDirectInput("No keyboard found") {} -}; - - -struct CKeyConv; - -/** - * Direct Input implementation of a keyboard. - * \see CDIEventEmitter - * \author Nicolas Vizerie - * \author Nevrax France - * \date 2002 - */ -class CDIKeyboard : public IKeyboardDevice -{ -public: - bool ShiftPressed, CtrlPressed, AltPressed; -public: - ///\name Object - //@{ - /** Create a keyboard device, that must then be deleted by the caller - * An optional WinEventEmiter can be provided, so that its flags can be in sync - * with a win32 keyboard flags (shift, ctrl, and alt) - */ - static CDIKeyboard *createKeyboardDevice(IDirectInput8 *di8, - HWND hwnd, - CDIEventEmitter *diEventEmitter, - CWinEventEmitter *we = NULL - ) throw(EDirectInput); - // dtor - virtual ~CDIKeyboard(); - //@} - - ///\name From IInputDevice - //@{ - virtual bool setBufferSize(uint size); - virtual uint getBufferSize() const; - //@} - - ///\name From IInputDevice - //@{ - uint getKeyRepeatDelay() const { return _RepeatDelay; } - void setKeyRepeatDelay(uint delay) { nlassert(delay > 0); _RepeatDelay = delay; } - uint getKeyRepeatPeriod() const { return _RepeatPeriod; } - void setKeyRepeatPeriod(uint period) { nlassert(period > 0); _RepeatPeriod = period; } - void disableRepetition(const TKey *keyTab, uint numKey); - uint getNumDisabledRepetition() const; - void getDisabledRepetitions(TKey *destTab) const; - //@} - - TMouseButton buildKeyboardFlags() const; -/////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////// -private: - // - bool _CapsLockToggle; // true if caps lock off is triggered by caps lock, false if it toggled by shift - uint _RepeatDelay; // the delay before a key is repeated (in ms) - uint _RepeatPeriod; // The period for key repetitions (in ms) - // - LPDIRECTINPUTDEVICE8 _Keyboard; - uint _KeyboardBufferSize; - // virtual code state - uint8 _VKKeyState[NumKeys]; - // tells for which keys repetition is disabled - CBitSet _RepetitionDisabled; - // The date at which the last key pressed has been pressed (not using 64 bits since note handled by Direct Input) - uint32 _FirstPressDate; - // The last date at which key repetition occured (not using 64 bits since note handled by Direct Input) - uint32 _LastEmitDate; - // The system date at which the last polling occured (not using 64 bits since note handled by Direct Input) - uint32 _PollTime; - uint _LastDIKeyPressed; - CWinEventEmitter *_WE; - HWND _hWnd; - HKL _KBLayout; - // - CDIEventEmitter *_DIEventEmitter; - // - static const CKeyConv *DIKeyToNelKeyTab[NumKeys]; -private: - /// ctor - CDIKeyboard(CWinEventEmitter *we, HWND hwnd); - /** Convert a direct input scancode to a virtual key. Note that DirectInput scancodes do not always match system scan codes. - * Repeatable has a meaning only for extended keys - */ - TKey DIKeyToNelKey(uint diKey, bool &extKey, bool &repeatable); - /** This update virtual key state table. - * \param keyValue contains the value to send to a EventKeyDown or EventKeyUp message. - * \param charValue contains the value that must be used for Unicode conversion (which generate EventChar messages) - */ - void updateVKKeyState(uint diKey, bool pressed, TKey &keyValue, TKey &charValue); - // Use the given virtual key code and the current keyb state to produce Unicode - void sendUnicode(TKey vkey, uint dikey, CEventServer *server, bool pressed); - // Build a TKeyButton value from the state of shift, ctrl and alt - TKeyButton buildKeyButtonsFlags() const; - // Update the state of this object and send the appropriate message when a direct / input key has been pressed / released - void keyTriggered(bool pressed, uint key, CEventServer *server, uint32 date); - // The same as buildKeyButtonsFlags(), but the return is a TMouseButtonValue (with no mouse value setupped) - TMouseButton buildKeyboardButtonFlags() const; - // setup the state of the Ctrl, Alt and Shift key from the state in the _VKKeyState buffer - void updateCtrlAltShiftValues(); - /// Repeat the current key, and create events - void repeatKey(uint32 currentDate, CEventServer *server); - /// Build a date by using an event time stamp, or generate one if NULL - uint32 buildDateFromEvent(const IInputDeviceEvent *deviceEvent); - - ///\name From IInputDevice - //@{ - virtual void poll(CInputDeviceServer *dev); - virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server); - virtual void transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage); - //@} -}; - - -} // NLMISC - - -#endif // NL_OS_WINDOWS - -#endif // NL_DI_KEYBOARD_H - -/* End of di_keyboard.h */ diff --git a/code/nel/src/misc/di_mouse_device.cpp b/code/nel/src/misc/di_mouse_device.cpp deleted file mode 100644 index 273725c5c..000000000 --- a/code/nel/src/misc/di_mouse_device.cpp +++ /dev/null @@ -1,507 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#include "stdmisc.h" - -#include "di_mouse_device.h" -#include "nel/misc/game_device_events.h" -#include "nel/misc/win_event_emitter.h" - - -#ifdef NL_OS_WINDOWS - -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -#ifdef NL_COMP_MINGW -# undef FIELD_OFFSET -# define FIELD_OFFSET(t,f) offsetof(t,f) -#endif - - -namespace NLMISC -{ - -//====================================================== -CDIMouse::CDIMouse() : _MessageMode(RawMode), - _MouseSpeed(1.0f), - _MouseAccel(10000), - _Mouse(NULL), - _XAcc(0), - _YAcc(0), - _XMousePos(0), - _YMousePos(0), - _LastMouseButtonClicked(-1), - _DoubleClickDelay(300), - _XFactor(1.f), - _YFactor(1.f), - OldDIXPos(0), - OldDIYPos(0), - OldDIZPos(0), - _FirstX(true), - _FirstY(true), - _SwapButton(false) - -{ - std::fill(_MouseButtons, _MouseButtons + MaxNumMouseButtons, false); - std::fill(_MouseAxisMode, _MouseAxisMode + NumMouseAxis, Raw); - _MouseFrame.setWH(0, 0, 640, 480); -} - -//====================================================== -CDIMouse::~CDIMouse() -{ - if (_Mouse) - { - _Mouse->Unacquire(); - _Mouse->Release(); - } -} - -//====================================================== -void CDIMouse::setMouseMode(TAxis axis, TAxisMode axisMode) -{ - nlassert(axisMode < AxisModeLast); - nlassert(axis < AxisLast); - _MouseAxisMode[axis] = axisMode; - clampMouseAxis(); -} - -//====================================================== -CDIMouse::TAxisMode CDIMouse::getMouseMode(TAxis axis) const -{ - nlassert((int)axis < (int)NumMouseAxis); - return _MouseAxisMode[axis]; -} - -//====================================================== -void CDIMouse::setMouseSpeed(float speed) -{ - nlassert(_MessageMode == NormalMode); - nlassert(speed > 0); - _MouseSpeed = speed; -} - -//====================================================== -void CDIMouse::setMouseAcceleration(uint accel) -{ - _MouseAccel = accel; -} - -//====================================================== -uint CDIMouse::getMouseAcceleration() const -{ - return _MouseAccel; -} - -//====================================================== -bool CDIMouse::setBufferSize(uint size) -{ - nlassert(size > 0); - nlassert(_Mouse); - _Mouse->Unacquire(); - DIPROPDWORD dipdw; - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = size; - HRESULT r = _Mouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ); - if (r != DI_OK) return false; - _MouseBufferSize = size; - return true; -} - -//====================================================== -uint CDIMouse::getBufferSize() const { return _MouseBufferSize; } - -//====================================================== -void CDIMouse::setMousePos(float x, float y) -{ - nlassert(_MessageMode == NormalMode); - _XMousePos = (sint64) ((double) x * ((sint64) 1 << 32)); - _YMousePos = (sint64) ((double) y * ((sint64) 1 << 32)); -} - -//====================================================== -CDIMouse *CDIMouse::createMouseDevice(IDirectInput8 *di8, HWND hwnd, CDIEventEmitter *diEventEmitter, bool hardware, CWinEventEmitter *we) throw(EDirectInput) -{ - std::auto_ptr mouse(new CDIMouse); - mouse->_DIEventEmitter = diEventEmitter; - mouse->_Hardware = hardware; - HRESULT result = di8->CreateDevice(GUID_SysMouse, &(mouse->_Mouse), NULL); - if (result != DI_OK) throw EDirectInputNoMouse(); - result = mouse->_Mouse->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | (!hardware ? DISCL_EXCLUSIVE:DISCL_NONEXCLUSIVE)); - if (result != DI_OK) throw EDirectInputCooperativeLevelFailed(); - mouse->_Mouse->SetDataFormat(&c_dfDIMouse2); - mouse->setBufferSize(64); - mouse->_WE = we; - mouse->setDoubleClickDelay(::GetDoubleClickTime()); - - /** we want an absolute mouse mode, so that, if the event buffer get full, we can retrieve the right position - */ - DIPROPDWORD prop; - prop.diph.dwSize = sizeof(DIPROPDWORD); - prop.diph.dwHeaderSize = sizeof(DIPROPHEADER); - prop.diph.dwHow = DIPH_DEVICE; - prop.diph.dwObj = 0; - prop.dwData = DIPROPAXISMODE_ABS; - HRESULT r = mouse->_Mouse->SetProperty(DIPROP_AXISMODE, &prop.diph); - nlassert(r == DI_OK); // should always succeed... - // - mouse->_Mouse->Acquire(); - mouse->_hWnd = hwnd; - - // Enable win32 mouse message only if hardware mouse in normal mode - if (mouse->_WE) - mouse->_WE->enableMouseEvents(mouse->_Hardware && (mouse->_MessageMode == IMouseDevice::NormalMode)); - - mouse->_SwapButton = GetSystemMetrics(SM_SWAPBUTTON) != 0; - - return mouse.release(); -} - -//====================================================== -float CDIMouse::getMouseSpeed() const -{ - nlassert(_MessageMode == NormalMode); - return _MouseSpeed; -} - -//====================================================== -const CRect &CDIMouse::getMouseFrame() const -{ - nlassert(_MessageMode == NormalMode); - return _MouseFrame; -} - -//====================================================== -uint CDIMouse::getDoubleClickDelay() const { return _DoubleClickDelay; } - -//====================================================== -inline void CDIMouse::clampMouseAxis() -{ - if (_MouseAxisMode[XAxis] == Clamped) clamp(_XMousePos, (sint64) _MouseFrame.X << 32, (sint64) (_MouseFrame.X + _MouseFrame.Width - 1) << 32); - if (_MouseAxisMode[YAxis] == Clamped) clamp(_YMousePos, (sint64) _MouseFrame.Y << 32, (sint64) (_MouseFrame.X + _MouseFrame.Height - 1) << 32); -} - -//====================================================== -void CDIMouse::poll(CInputDeviceServer *dev) -{ - nlassert(_Mouse); - nlassert(_MouseBufferSize > 0); - static std::vector datas; - datas.resize(_MouseBufferSize); - DWORD numElements = _MouseBufferSize; - HRESULT result = _Mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0); - if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) - { - result = _Mouse->Acquire(); - HRESULT result = _Mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0); - if (result != DI_OK) return; - } - else if (result != DI_OK) return; - - if (::IsWindowEnabled(_hWnd) && ::IsWindowVisible(_hWnd)) - { - for(uint k = 0; k < numElements; ++k) - { - CDIEvent *die = new CDIEvent; - die->Emitter = this; - die->Datas = datas[k]; - dev->submitEvent(die); - } - } -} - - -//====================================================================== -TMouseButton CDIMouse::buildMouseButtonFlags() const -{ - if (_SwapButton) - return (TMouseButton) ( - _DIEventEmitter->buildKeyboardButtonFlags() - | (_MouseButtons[0] ? rightButton : 0) - | (_MouseButtons[1] ? leftButton : 0) - | (_MouseButtons[2] ? middleButton : 0) - ); - else - return (TMouseButton) ( - _DIEventEmitter->buildKeyboardButtonFlags() - | (_MouseButtons[0] ? leftButton : 0) - | (_MouseButtons[1] ? rightButton : 0) - | (_MouseButtons[2] ? middleButton : 0) - ); -} - -//====================================================== -TMouseButton CDIMouse::buildMouseSingleButtonFlags(uint button) -{ - static const TMouseButton mb[] = { leftButton, rightButton, middleButton }; - static const TMouseButton mbswap[] = { rightButton, leftButton, middleButton }; - nlassert(button < MaxNumMouseButtons); - if (_SwapButton) - return (TMouseButton) (_DIEventEmitter->buildKeyboardButtonFlags() | mbswap[button]); - else - return (TMouseButton) (_DIEventEmitter->buildKeyboardButtonFlags() | mb[button]); -} - -//====================================================== -void CDIMouse::onButtonClicked(uint button, CEventServer *server, uint32 date) -{ - // check for double click - if (_LastMouseButtonClicked == (sint) button) - { - if (date - _MouseButtonsLastClickDate < _DoubleClickDelay) - { - CEventMouseDblClk *emdc - = new CEventMouseDblClk((float) (_XMousePos >> 32), - (float) (_YMousePos >> 32), - buildMouseSingleButtonFlags(button), - _DIEventEmitter); - server->postEvent(emdc); - _LastMouseButtonClicked = -1; - } - else - { - _MouseButtonsLastClickDate = date; - } - } - else - { - _LastMouseButtonClicked = button; - _MouseButtonsLastClickDate = date; - } -} - -//====================================================== -void CDIMouse::processButton(uint button, bool pressed, CEventServer *server, uint32 date) -{ - updateMove(server); - float mx = (float) (_XFactor * (double) _XMousePos / ((double) 65536 * (double) 65536)); - float my = (float) (_YFactor * (double) _YMousePos / ((double) 65536 * (double) 65536)); - if (pressed) - { - CEventMouseDown *emd = - new CEventMouseDown(mx, my, buildMouseSingleButtonFlags(button), - _DIEventEmitter); - server->postEvent(emd); - } - else - { - CEventMouseUp *emu = - new CEventMouseUp(mx, my, buildMouseSingleButtonFlags(button), _DIEventEmitter); - server->postEvent(emu); - onButtonClicked(button, server, date); - } - _MouseButtons[button] = pressed; -} - -//====================================================== -void CDIMouse::submit(IInputDeviceEvent *deviceEvent, CEventServer *server) -{ - if (!_Hardware || (_MessageMode == RawMode)) - { - CDIEvent *die = safe_cast(deviceEvent); - bool pressed; - switch(die->Datas.dwOfs) - { - case DIMOFS_X: - { - if (!_FirstX) - { - sint dep = (sint32) die->Datas.dwData - OldDIXPos; - - // Acceleration - if (_MouseAccel) - { - sint accelFactor = abs (dep) / (sint)_MouseAccel; - dep <<= accelFactor; - } - - _XAcc += dep; - } - else - { - _FirstX = false; - } - OldDIXPos = (sint32) die->Datas.dwData; - } - break; - case DIMOFS_Y: - { - if (!_FirstY) - { - sint dep = (sint32) die->Datas.dwData - OldDIYPos; - - // Acceleration - if (_MouseAccel) - { - sint accelFactor = abs (dep) / (sint)_MouseAccel; - dep <<= accelFactor; - } - - _YAcc -= dep; - } - else - { - _FirstY = false; - } - OldDIYPos = (sint32) die->Datas.dwData; - } - break; - case DIMOFS_Z: - { - updateMove(server); - sint dep = die->Datas.dwData - OldDIZPos; - OldDIZPos = (sint32) die->Datas.dwData; - CEventMouseWheel *emw = - new CEventMouseWheel((float) (_XMousePos >> 32), - (float) (_XMousePos >> 32), - buildMouseButtonFlags(), - dep > 0, - _DIEventEmitter); - server->postEvent(emw); - } - break; - case DIMOFS_BUTTON0: /* left button */ - pressed = (die->Datas.dwData & 0x80) != 0; - processButton(0, pressed, server, die->Datas.dwTimeStamp); - break; - case DIMOFS_BUTTON1: /* right button */ - pressed = (die->Datas.dwData & 0x80) != 0; - processButton(1, pressed, server, die->Datas.dwTimeStamp); - break; - case DIMOFS_BUTTON2: /* middle button */ - pressed = (die->Datas.dwData & 0x80) != 0; - processButton(2, pressed, server, die->Datas.dwTimeStamp); - break; - default: - return; - break; - } - } -} - -//====================================================== -void CDIMouse::updateMove(CEventServer *server) -{ - if (_XAcc != 0 || _YAcc != 0) - { - if (_MessageMode == NormalMode) - { - _XMousePos += (sint64) ((double) _MouseSpeed * (sint64) _XAcc * ((sint64) 1 << 32)); - _YMousePos += (sint64) ((double) _MouseSpeed * (sint64) _YAcc * ((sint64) 1 << 32)); - clampMouseAxis(); - CEventMouseMove *emm = new CEventMouseMove((float) (_XFactor * (double) _XMousePos / ((double) 65536 * (double) 65536)), (float) (_YFactor * (double) _YMousePos / ((double) 65536 * (double) 65536)), buildMouseButtonFlags(), _DIEventEmitter); - server->postEvent(emm); - } - else - { - CGDMouseMove *emm = new CGDMouseMove(_DIEventEmitter, this, _XAcc, _YAcc); - server->postEvent(emm); - } - _XAcc = _YAcc = 0; - } -} - - -//====================================================== -void CDIMouse::convertStdMouseMoveInMickeys(float &dx, float &dy) const -{ - // get in same scale as _XAcc and _YAcc - double xacc= ((double)dx/_XFactor) / _MouseSpeed; - double yacc= ((double)dy/_YFactor) / _MouseSpeed; - - dx= float(xacc); - dy =float(yacc); -} - - -//====================================================== -void CDIMouse::transitionOccured(CEventServer *server, const IInputDeviceEvent *) -{ - updateMove(server); -} - -//====================================================== -void CDIMouse::setButton(uint button, bool pushed) -{ - nlassert(button < MaxNumMouseButtons); - _MouseButtons[button] = pushed; -} - -//====================================================== -bool CDIMouse::getButton(uint button) const -{ - nlassert(button < MaxNumMouseButtons); - return _MouseButtons[button]; -} - -//====================================================== -void CDIMouse::setDoubleClickDelay(uint ms) -{ - nlassert(ms > 0); - _DoubleClickDelay = ms; -} - -//====================================================== -void CDIMouse::setMouseFrame(const CRect &rect) -{ - nlassert(_MessageMode == NormalMode); - _MouseFrame = rect; -} - -//====================================================== -void CDIMouse::setMessagesMode(TMessageMode mode) -{ - nlassert(mode < MessageModeLast); - _MessageMode = mode; - _FirstX = _FirstY = true; - - // Enable win32 mouse message only if hardware mouse in normal mode - if (_WE) - _WE->enableMouseEvents(_Hardware && (_MessageMode == NormalMode)); -} - - -} // NLMISC - -#endif // NL_OS_WINDOWS - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/nel/src/misc/di_mouse_device.h b/code/nel/src/misc/di_mouse_device.h deleted file mode 100644 index aab678ffc..000000000 --- a/code/nel/src/misc/di_mouse_device.h +++ /dev/null @@ -1,167 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#ifndef NL_DI_MOUSE_DEVICE_H -#define NL_DI_MOUSE_DEVICE_H - -#include "nel/misc/types_nl.h" - -#ifdef NL_OS_WINDOWS - - -#include "nel/misc/rect.h" -#include "nel/misc/di_event_emitter.h" -#include "nel/misc/input_device_server.h" -#include "nel/misc/mouse_device.h" -#include - - -namespace NLMISC -{ - - -// -struct EDirectInputNoMouse : public EDirectInput -{ - EDirectInputNoMouse() : EDirectInput("No mouse found") {} -}; - - -class CDXEventEmitter; - - -/** - * Direct Input implementation of a mouse - * \see CDIEventEmitter - * \author Nicolas Vizerie - * \author Nevrax France - * \date 2002 - */ -class CDIMouse : public IMouseDevice -{ -public: - enum { MaxNumMouseButtons = 3, NumMouseAxis = 3}; -public: - ///\name Object - //@{ - virtual ~CDIMouse(); - /** Create a mouse device from a valid DirectInput8 pointer. This must then be deleted by the caller. - * \return the interface or throw an exception if the creation failed - */ - static CDIMouse *createMouseDevice(IDirectInput8 *di8, HWND hwnd, CDIEventEmitter *diEventEmitter, bool hardware, class CWinEventEmitter *we) throw(EDirectInput); - //@} - - ///\name Mouse params, inherited from IMouseDevice - //@{ - void setMessagesMode(TMessageMode mode); - TMessageMode getMessagesMode() const { return _MessageMode; } - void setMouseMode(TAxis axis, TAxisMode axisMode); - TAxisMode getMouseMode(TAxis axis) const; - void setMouseSpeed(float speed); - float getMouseSpeed() const; - void setMouseAcceleration(uint speed); - uint getMouseAcceleration() const; - void setMouseFrame(const CRect &rect); - const CRect &getMouseFrame() const; - void setDoubleClickDelay(uint ms); - uint getDoubleClickDelay() const; - void setMousePos(float x, float y); - void setFactors(float xFactor, float yFactor) - { - nlassert(_MessageMode == NormalMode); - _XFactor = xFactor; - _YFactor = yFactor; - } - float getXFactor() const { nlassert(_MessageMode == NormalMode); return _XFactor; } - float getYFactor() const { nlassert(_MessageMode == NormalMode); return _YFactor; } - void convertStdMouseMoveInMickeys(float &dx, float &dy) const; - //@} - - ///\name From IInputDevice - //@{ - - virtual bool setBufferSize(uint size); - virtual uint getBufferSize() const; - //@} - - ///\name From IInputDevice - //@{ - void setButton(uint button, bool pushed); - bool getButton(uint button) const; - //@} - -////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////// - -private: - LPDIRECTINPUTDEVICE8 _Mouse; - // - bool _Hardware; - // - TMessageMode _MessageMode; - // - TAxisMode _MouseAxisMode[NumMouseAxis]; - sint64 _XMousePos, _YMousePos; // position encoded in fixed point 32 : 32. This allow wrapping and no loss of precision, when not in clamped mode - // NB: this is sint64 because of max range reached with 16:16 when looping around x with great mouse speed - bool _FirstX, _FirstY; - float _MouseSpeed; - uint _MouseAccel; - CRect _MouseFrame; - // - bool _MouseButtons[MaxNumMouseButtons]; - uint32 _MouseButtonsLastClickDate; - sint _LastMouseButtonClicked; - uint _DoubleClickDelay; - uint _MouseBufferSize; - HWND _hWnd; - // - sint32 OldDIXPos, OldDIYPos, OldDIZPos; // old positions reported by direct input - sint _XAcc, _YAcc; // accumulate move (needed because they are generated on a single axis for each DI event) - float _XFactor, _YFactor; - // - CDIEventEmitter *_DIEventEmitter; - // The windows emitter to enable / disble win32 mouse messages - NLMISC::CRefPtr _WE; - // Does the button left and right are swapped ? - bool _SwapButton; -private: - /// ctor - CDIMouse(); - /// Clamp the mouse axis that need to be. - void clampMouseAxis(); - /// Sum the mouse move and produce an event - void updateMove(CEventServer *server); - void processButton(uint button, bool pressed, CEventServer *server, uint32 date); - TMouseButton buildMouseButtonFlags() const; - TMouseButton buildMouseSingleButtonFlags(uint button); - void onButtonClicked(uint button, CEventServer *server, uint32 date); - ///\name From IInputDevice - //@{ - virtual void poll(CInputDeviceServer *dev); - virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server); - virtual void transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage); - //@} -}; - - -} // NL3D - - -#endif // NL_OS_WINDOWS - -#endif // NL_DI_MOUSE_H - -/* End of di_mouse.h */ diff --git a/code/nel/src/misc/event_emitter_multi.cpp b/code/nel/src/misc/event_emitter_multi.cpp index 52bc235cd..45559ebc4 100644 --- a/code/nel/src/misc/event_emitter_multi.cpp +++ b/code/nel/src/misc/event_emitter_multi.cpp @@ -84,11 +84,6 @@ void CEventEmitterMulti::submitEvents(CEventServer &server, bool allWindows) } } -///============================================================ -void CEventEmitterMulti::emulateMouseRawMode(bool enable) -{ -} - ///============================================================ IEventEmitter *CEventEmitterMulti::getEmitter(uint index) { diff --git a/code/nel/src/misc/input_device_server.cpp b/code/nel/src/misc/input_device_server.cpp deleted file mode 100644 index 253b68e71..000000000 --- a/code/nel/src/misc/input_device_server.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#include "stdmisc.h" - -#include "nel/misc/input_device_server.h" -#include "nel/misc/input_device.h" -#include "nel/misc/debug.h" - -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NLMISC -{ -//======================================================================= -void CInputDeviceServer::registerDevice(IInputDevice *device) -{ - nlassert(!isDevice(device)); - _Devices.push_back(device); -} - -//======================================================================= -void CInputDeviceServer::removeDevice(IInputDevice *device) -{ - TDeviceCont::iterator it = std::find(_Devices.begin(), _Devices.end(), device); - nlassert(it != _Devices.end()); - _Devices.erase(it); -} - -//======================================================================= -bool CInputDeviceServer::isDevice(IInputDevice *device) const -{ - TDeviceCont::const_iterator it = std::find(_Devices.begin(), _Devices.end(), device); - return it != _Devices.end(); -} - -//======================================================================= -// Predicate to compare vents dates -struct CInputDeviceEventLess -{ - bool operator()(const IInputDeviceEvent *lhs, const IInputDeviceEvent *rhs) const - { - return *lhs < *rhs; - } -}; - -//======================================================================= -void CInputDeviceServer::poll(CEventServer *server) -{ - nlassert(_Events.empty()); - TDeviceCont::iterator deviceIt; - for (deviceIt = _Devices.begin(); deviceIt != _Devices.end(); ++deviceIt) - { - (*deviceIt)->begin(server); - (*deviceIt)->poll(this); - } - // Sort the messages to get the right dates. - std::sort(_Events.begin(), _Events.end(), CInputDeviceEventLess()); - // submit the result to the server - IInputDevice *lastVisitedDevice = NULL; - TEventCont::iterator eventIt; - for (eventIt = _Events.begin(); eventIt != _Events.end(); ++eventIt) - { - // see if this message is from a previous device then the last we visited. - if (lastVisitedDevice && (*eventIt)->Emitter != lastVisitedDevice) - { - // yes, tells that a transition occured - lastVisitedDevice->transitionOccured(server, *eventIt); - lastVisitedDevice = (*eventIt)->Emitter; - } - nlassert((*eventIt)->Emitter != NULL); - (*eventIt)->Emitter->submit(*eventIt, server); - } - // - for (deviceIt = _Devices.begin(); deviceIt != _Devices.end(); ++deviceIt) - { - (*deviceIt)->transitionOccured(server, NULL); - } - // delete the messages - for (eventIt = _Events.begin(); eventIt != _Events.end(); ++eventIt) - { - delete *eventIt; - } - // - _Events.clear(); -} - -//======================================================================= -void CInputDeviceServer::submitEvent(IInputDeviceEvent *deviceEvent) -{ - _Events.push_back(deviceEvent); -} - - -} // NLMISC diff --git a/code/nel/src/misc/win_event_emitter.cpp b/code/nel/src/misc/win_event_emitter.cpp index 3c74d9241..01da89564 100644 --- a/code/nel/src/misc/win_event_emitter.cpp +++ b/code/nel/src/misc/win_event_emitter.cpp @@ -57,14 +57,6 @@ void CWinEventEmitter::submitEvents(CEventServer & server, bool allWindows) _InternalServer.pump (allWindows); } -/*------------------------------------------------------------------*\ - emulateMouseRawMode() -\*------------------------------------------------------------------*/ -void CWinEventEmitter::emulateMouseRawMode(bool enable) -{ - nlerror("no raw mode emulation on windows, the CDIMouse has a real raw mode"); -} - /*------------------------------------------------------------------*\ processMessage() \*------------------------------------------------------------------*/ @@ -320,7 +312,7 @@ bool CWinEventEmitter::processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPA case WM_INPUTLANGCHANGE: if ( _IMEEventsEnabled ) { - // wParam = Specifies the character set of the new locale. + // wParam = Specifies the character set of the new locale. // lParam = Input locale identifier. server->postEvent( new CEventIME( msg, (uint32)wParam, (uint32)lParam, this ) ); return true; // trap message diff --git a/code/nel/tools/3d/plugin_max/nel_export/nel_export.rc b/code/nel/tools/3d/plugin_max/nel_export/nel_export.rc index 57edca682..d01762618 100644 --- a/code/nel/tools/3d/plugin_max/nel_export/nel_export.rc +++ b/code/nel/tools/3d/plugin_max/nel_export/nel_export.rc @@ -575,8 +575,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0, 10, 0, 0 - PRODUCTVERSION 0, 10, 0, 0 + FILEVERSION 0, 11, 0, 0 + PRODUCTVERSION 0, 11, 0, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -593,14 +593,14 @@ BEGIN BEGIN VALUE "Comments", "Based on Kinetix 3D Studio Max 3.0 plugin sample\0" VALUE "CompanyName", "Ryzom Core\0" - VALUE "FileVersion", "0.10.0\0" + VALUE "FileVersion", "0.11.0\0" VALUE "InternalName", "CNelExport\0" VALUE "LegalCopyright", "\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "CNelExport.dlu\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "Ryzom Core\0" - VALUE "ProductVersion", "0.10.0\0" + VALUE "ProductVersion", "0.11.0\0" VALUE "SpecialBuild", "\0" END END diff --git a/code/nel/tools/3d/plugin_max/nel_patch_converter/nel_patch_converter.rc b/code/nel/tools/3d/plugin_max/nel_patch_converter/nel_patch_converter.rc index aa8749a3e..b6eea41a6 100644 --- a/code/nel/tools/3d/plugin_max/nel_patch_converter/nel_patch_converter.rc +++ b/code/nel/tools/3d/plugin_max/nel_patch_converter/nel_patch_converter.rc @@ -85,8 +85,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0, 10, 0, 0 - PRODUCTVERSION 0, 10, 0, 0 + FILEVERSION 0, 11, 0, 0 + PRODUCTVERSION 0, 11, 0, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -103,12 +103,12 @@ BEGIN BEGIN VALUE "Comments", "http://www.ryzomcore.org/" VALUE "FileDescription", "PatchMesh to RykolPatchMesh" - VALUE "FileVersion", "0.10.0" + VALUE "FileVersion", "0.11.0" VALUE "InternalName", "PatchMesh to RykolPatchMesh" VALUE "LegalCopyright", "Copyright, 2000 Nevrax Ltd." VALUE "OriginalFilename", "nel_convert_patch.dlm" VALUE "ProductName", "NeL Patch Converter" - VALUE "ProductVersion", "0.10.0" + VALUE "ProductVersion", "0.11.0" END END BLOCK "VarFileInfo" diff --git a/code/nel/tools/3d/plugin_max/nel_patch_edit/mods.rc b/code/nel/tools/3d/plugin_max/nel_patch_edit/mods.rc index adc44260e..243e02da8 100644 --- a/code/nel/tools/3d/plugin_max/nel_patch_edit/mods.rc +++ b/code/nel/tools/3d/plugin_max/nel_patch_edit/mods.rc @@ -514,8 +514,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0, 10, 0, 0 - PRODUCTVERSION 0, 10, 0, 0 + FILEVERSION 0, 11, 0, 0 + PRODUCTVERSION 0, 11, 0, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -533,13 +533,13 @@ BEGIN VALUE "Comments", "Based on Kinetix 3D Studio Max 3.0 plugin sample\0" VALUE "CompanyName", "Ryzom Core" VALUE "FileDescription", "NeL Patch Edit" - VALUE "FileVersion", "0.10.0" + VALUE "FileVersion", "0.11.0" VALUE "InternalName", "neleditpatch" VALUE "LegalCopyright", "Copyright © 2000 Nevrax Ltd. Copyright © 1998 Autodesk Inc." VALUE "LegalTrademarks", "The following are registered trademarks of Autodesk, Inc.: 3D Studio MAX. The following are trademarks of Autodesk, Inc.: Kinetix, Kinetix(logo), BIPED, Physique, Character Studio, MAX DWG, DWG Unplugged, Heidi, FLI, FLC, DXF." VALUE "OriginalFilename", "neleditpatch.dlm" VALUE "ProductName", "Ryzom Core" - VALUE "ProductVersion", "0.10.0" + VALUE "ProductVersion", "0.11.0" END END BLOCK "VarFileInfo" diff --git a/code/nel/tools/3d/plugin_max/nel_patch_paint/nel_patch_paint.rc b/code/nel/tools/3d/plugin_max/nel_patch_paint/nel_patch_paint.rc index fadbde308..534efb2ac 100644 --- a/code/nel/tools/3d/plugin_max/nel_patch_paint/nel_patch_paint.rc +++ b/code/nel/tools/3d/plugin_max/nel_patch_paint/nel_patch_paint.rc @@ -96,8 +96,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0, 10, 0, 0 - PRODUCTVERSION 0, 10, 0, 0 + FILEVERSION 0, 11, 0, 0 + PRODUCTVERSION 0, 11, 0, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -116,14 +116,14 @@ BEGIN VALUE "Comments", "TECH: cyril.corvazier\0" VALUE "CompanyName", "Ryzom Core\0" VALUE "FileDescription", "NeL Patch Paint\0" - VALUE "FileVersion", "0.10.0\0" + VALUE "FileVersion", "0.11.0\0" VALUE "InternalName", "mods\0" VALUE "LegalCopyright", "Copyright © 2000 Nevrax Ltd\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "nelpatchpaint.dlm\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "Ryzom Core\0" - VALUE "ProductVersion", "0.10.0\0" + VALUE "ProductVersion", "0.11.0\0" VALUE "SpecialBuild", "\0" END END diff --git a/code/nel/tools/3d/plugin_max/nel_vertex_tree_paint/vertex_tree_paint.rc b/code/nel/tools/3d/plugin_max/nel_vertex_tree_paint/vertex_tree_paint.rc index bf5fdd549..4e70d1afc 100644 --- a/code/nel/tools/3d/plugin_max/nel_vertex_tree_paint/vertex_tree_paint.rc +++ b/code/nel/tools/3d/plugin_max/nel_vertex_tree_paint/vertex_tree_paint.rc @@ -125,8 +125,8 @@ IDC_DROPPER_CURSOR CURSOR DISCARDABLE "dropcurs.cur" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0, 10, 0, 0 - PRODUCTVERSION 0, 10, 0, 0 + FILEVERSION 0, 11, 0, 0 + PRODUCTVERSION 0, 11, 0, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -145,13 +145,13 @@ BEGIN VALUE "Comments", "TECH: \0" VALUE "CompanyName", "Ryzom Core\0" VALUE "FileDescription", "Vertex Tree Paint\0" - VALUE "FileVersion", "0.10.0\0" + VALUE "FileVersion", "0.11.0\0" VALUE "InternalName", "VertexTreePaint\0" VALUE "LegalCopyright", "Copyright © 2000 Nevrax Ltd. Copyright © 1998 Autodesk Inc.\0" VALUE "LegalTrademarks", "The following are registered trademarks of Autodesk, Inc.: 3D Studio MAX. The following are trademarks of Autodesk, Inc.: Kinetix, Kinetix(logo), BIPED, Physique, Character Studio, MAX DWG, DWG Unplugged, Heidi, FLI, FLC, DXF.\0" VALUE "OriginalFilename", "nel_vertex_tree_paint.dlm\0" VALUE "ProductName", "Ryzom Core\0" - VALUE "ProductVersion", "0.10.0\0" + VALUE "ProductVersion", "0.11.0\0" END END BLOCK "VarFileInfo" diff --git a/code/nel/tools/3d/plugin_max/scripts/nel_assets_ps_batched.ms b/code/nel/tools/3d/plugin_max/scripts/nel_assets_ps_batched.ms new file mode 100644 index 000000000..f8165e25e --- /dev/null +++ b/code/nel/tools/3d/plugin_max/scripts/nel_assets_ps_batched.ms @@ -0,0 +1,378 @@ + +NEL3D_APPDATA_INTERFACE_FILE = 1423062700 + +-- Allocate 20 Me for the script +heapSize += 15000000 + +nlErrorFilename = "W:/database/conversion.log" +nlErrorStream = openFile nlErrorFilename mode:"w" +if nlErrorStream == undefined then + nlErrorStream = createFile nlErrorFilename + +-- Log a message +fn nllog message = +( + if nlErrorStream != undefined then + ( + format "%\n" message to:nlErrorStream + flush nlErrorStream + ) + + -- To the console + print message +) + +include "nel_utility.ms" + +fn findFile dir fileName = +( + if (doesFileExist (dir + "\\" + fileName)) then + ( + return (dir + "\\" + fileName) + ) + + dirArr = GetDirectories (dir + "\\*") + + for d in dirArr do + ( + local fileFound = findFile d fileName + if (fileFound != "") then + return fileFound + ) + + return "" +) + +fn getFixedPath ps = +( + if not (doesFileExist ps) then + ( + local fileName = filenameFromPath ps + local fileFound = findFile "W:\\database\\sfx" fileName + if (fileFound != "") then + return fileFound + else + return fileName + ) + else + ( + return ps + ) +) + +fn renameParticleSystem ps = +( + local newFileName = getFixedPath ps.ps_file_name + if (newFileName != ps.ps_file_name) then + ( + ps.ps_file_name = newFileName + return 1 + ) + else + ( + return 0 + ) +) + + +rollout assets_ps_rollout "Properties" +( + fn do_it = + ( + local result = 0 + + for m in getClassInstances nel_ps do + ( + if (renameParticleSystem m) == 1 then + result = 1 + ) + + max select none + + actionMan.executeAction 0 "40021" -- Selection: Select All + actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected + actionMan.executeAction 0 "40807" -- Views: Activate All Maps + actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps + actionMan.executeAction 0 "40043" -- Selection: Select None + + max views redraw + + return result + ) + + -- This script is a base script to include to add multiple functionality to your script + + -- To use this script + -- Include it in your script into the rollout at the beginning. + -- Implement a do_it function to do the job in your rollout. + -- The function should retun -1 if an arror occured, else the count of modification done + -- It the function returns <1, the project will not be overwritten + + Group "Running properties" + ( + RadioButtons SourceFiles "Source projects" labels:#("Current project", "All Projects in a folder") align:#left + + Label DirectoryLabel "Source directory" align:#left + EditText Directory "" width:500 align:#left enabled:false + Button BrowseDirectory "Browse..." align:#left enabled:false + + CheckBox Recurse "Look in subfolders" checked:true enabled:false + CheckBox Test "Test only, do not save" checked:false enabled:false + CheckBox BackupFiles "Backup files" checked:false enabled:false + CheckBox StopOnError "Stop on error" checked:false enabled:false + CheckBox UseTag "Use tag" checked:false enabled:false + + Label ProgressText width:500 align:#left + ProgressBar Progress width:500 align:#left + + Button GoButton "Go" width:500 align:#left + ) + + local countModifications + local countErrors + local fileModified + local fileParsed + + fn UpdateData = + ( + if SourceFiles.state == 2 then + isSourceDir = true + else + isSourceDir = false + if Test.checked == true then + isTest = true + else + isTest = false + + Directory.enabled = isSourceDir + BrowseDirectory.enabled = isSourceDir + Recurse.enabled = isSourceDir + Test.enabled = isSourceDir + BackupFiles.enabled = isSourceDir and (isTest == false) + StopOnError.enabled = isSourceDir + UseTag.enabled = isSourceDir + ) + + on SourceFiles changed state do + ( + UpdateData () + ) + + on Test changed state do + ( + UpdateData () + ) + + fn call_do_it = + ( + local result + + -- One more project + fileParsed = fileParsed + 1 + + -- Call it + result = do_it () + + -- Error ? + if result < 0 then + countErrors = countErrors + 1 + else + countModifications = countModifications + result + + -- Return result + return result + ) + + fn BackupFile file = + ( + local i + local newFilename + + i = 0 + while true do + ( + -- New file name + newFilename = file + ".backup_" + (i as string) + + -- File exist ? + if (fileExist newFilename) == false then + ( + if (copyFile file newFilename) == false then + return false + else + return true + ) + i = i + 1 + ) + ) + + fn RecurseFolder currentDirectory = + ( + resetMAXFile #noprompt + + local result + local file + local files + local origAnimStart + local origAnimEnd + local origFrameRate + + -- Parse files + files = getFiles (currentDirectory+"/*.max") + + -- For each files + for i = 1 to files.count do + ( + -- File name + file = files[i] + + -- Progress bar + ProgressText.text = "In directory "+currentDirectory+", compute file \"" + (getFilenameFile file) + "\"" + Progress.value = i*100/files.count + + if (UseTag.checked == false) or ((NeLTestFileDate file "W:/database/conversion.tag") == true) then + ( + resetMAXFile #noprompt + + nllog("CONVERT " + file) + + -- Open the max project + if loadMaxFile file quiet:true == true then + ( + objXRefMgr.UpdateAllRecords() + + result = call_do_it () + + -- Error ? + if result < 0 then + ( + if StopOnError.checked == true then + Messagebox ("Error in file " + file) + ) + else + ( + -- Save the max project ? + if (Test.checked == false) and (result != 0) then + ( + -- Backup the max project ? + local ok + ok = true + if BackupFiles.checked == true then + ( + -- Backup the file + if (BackupFile file) == false then + ( + -- Don't save the file because backup has failed + ok = false + + if StopOnError.checked == true then + Messagebox ("Can't backup file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + + -- Save the max project ? + if ok == true then + ( + if (saveMaxFile file) == true then + ( + fileModified = fileModified + 1 + ) + else + ( + if StopOnError.checked == true then + Messagebox ("Can't write file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + ) + ) + ) + else + ( + if StopOnError.checked == true then + Messagebox ("Can't load file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + else + ( + nllog("SKIP " + file + " by tag") + ) + ) + + -- Parse sub directory ? + if (Recurse.checked == true) then + ( + local directories + + -- Get the directories + directories = getDirectories (currentDirectory+"/*") + + -- For each directories + for dir in directories do + ( + RecurseFolder dir + ) + ) + ) + + on BrowseDirectory pressed do + ( + local dir + try + ( + dir = getSavePath () -- caption:"Select the projects directory" + if dir != undefined then + Directory.text = dir + ) + catch + ( + ) + ) + + on GoButton pressed do + ( + -- Reset count + countModifications = 0 + countErrors = 0 + fileModified = 0 + fileParsed = 0 + + -- Get files in the shape_source_directory + if SourceFiles.state == 2 then + ( + -- Should warning user ? + if (SourceFiles.state == 2) and (Test.checked == false) then + ( + -- Warning ! + if ((queryBox "Warning, all the files in the specified folders will be overwrited.\nYou should backup your files before executing this script.\nDo you want to continue executing this script ?" beep:true) == true) then + RecurseFolder (adjustPathStringForScript Directory.text) + ) + else + ( + RecurseFolder (adjustPathStringForScript Directory.text) + ) + ) + else + ( + -- Just compute the current project + call_do_it () + ) + + -- Show errors + ProgressText.text = (fileParsed as string) + " project(s) opened, " + (countModifications as string) + " project modification(s), " + (fileModified as string) + " project(s) saved, " + (countErrors as string) + " error(s)." + Progress.value = 100 + ) +) + +assets_ps_floater = newRolloutFloater "NeL Assets PS Database" 550 400 +addrollout assets_ps_rollout assets_ps_floater rolledUp:false + + diff --git a/code/nel/tools/3d/plugin_max/scripts/nel_assets_resave.ms b/code/nel/tools/3d/plugin_max/scripts/nel_assets_resave.ms new file mode 100644 index 000000000..ab9e45325 --- /dev/null +++ b/code/nel/tools/3d/plugin_max/scripts/nel_assets_resave.ms @@ -0,0 +1,329 @@ + +NEL3D_APPDATA_INTERFACE_FILE = 1423062700 + +-- Allocate 20 Me for the script +heapSize += 15000000 + +nlErrorFilename = "W:/database/conversion.log" +nlErrorStream = openFile nlErrorFilename mode:"w" +if nlErrorStream == undefined then + nlErrorStream = createFile nlErrorFilename + +-- Log a message +fn nllog message = +( + if nlErrorStream != undefined then + ( + format "%\n" message to:nlErrorStream + flush nlErrorStream + ) + + -- To the console + print message +) + +include "nel_utility.ms" + +rollout assets_resave_rollout "Properties" +( + fn do_it = + ( + max select none + + actionMan.executeAction 0 "40021" -- Selection: Select All + actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected + actionMan.executeAction 0 "40807" -- Views: Activate All Maps + actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps + actionMan.executeAction 0 "40043" -- Selection: Select None + + max views redraw + + return 1 + ) + + -- This script is a base script to include to add multiple functionality to your script + + -- To use this script + -- Include it in your script into the rollout at the beginning. + -- Implement a do_it function to do the job in your rollout. + -- The function should retun -1 if an arror occured, else the count of modification done + -- It the function returns <1, the project will not be overwritten + + Group "Running properties" + ( + RadioButtons SourceFiles "Source projects" labels:#("Current project", "All Projects in a folder") align:#left + + Label DirectoryLabel "Source directory" align:#left + EditText Directory "" width:500 align:#left enabled:false + Button BrowseDirectory "Browse..." align:#left enabled:false + + CheckBox Recurse "Look in subfolders" checked:true enabled:false + CheckBox Test "Test only, do not save" checked:false enabled:false + CheckBox BackupFiles "Backup files" checked:false enabled:false + CheckBox StopOnError "Stop on error" checked:false enabled:false + CheckBox UseTag "Use tag" checked:false enabled:false + + Label ProgressText width:500 align:#left + ProgressBar Progress width:500 align:#left + + Button GoButton "Go" width:500 align:#left + ) + + local countModifications + local countErrors + local fileModified + local fileParsed + + fn UpdateData = + ( + if SourceFiles.state == 2 then + isSourceDir = true + else + isSourceDir = false + if Test.checked == true then + isTest = true + else + isTest = false + + Directory.enabled = isSourceDir + BrowseDirectory.enabled = isSourceDir + Recurse.enabled = isSourceDir + Test.enabled = isSourceDir + BackupFiles.enabled = isSourceDir and (isTest == false) + StopOnError.enabled = isSourceDir + UseTag.enabled = isSourceDir + ) + + on SourceFiles changed state do + ( + UpdateData () + ) + + on Test changed state do + ( + UpdateData () + ) + + fn call_do_it = + ( + local result + + -- One more project + fileParsed = fileParsed + 1 + + -- Call it + result = do_it () + + -- Error ? + if result < 0 then + countErrors = countErrors + 1 + else + countModifications = countModifications + result + + -- Return result + return result + ) + + fn BackupFile file = + ( + local i + local newFilename + + i = 0 + while true do + ( + -- New file name + newFilename = file + ".backup_" + (i as string) + + -- File exist ? + if (fileExist newFilename) == false then + ( + if (copyFile file newFilename) == false then + return false + else + return true + ) + i = i + 1 + ) + ) + + fn RecurseFolder currentDirectory = + ( + resetMAXFile #noprompt + + local result + local file + local files + local origAnimStart + local origAnimEnd + local origFrameRate + + -- Parse files + files = getFiles (currentDirectory+"/*.max") + + -- For each files + for i = 1 to files.count do + ( + -- File name + file = files[i] + + -- Progress bar + ProgressText.text = "In directory "+currentDirectory+", compute file \"" + (getFilenameFile file) + "\"" + Progress.value = i*100/files.count + + if (UseTag.checked == false) or ((NeLTestFileDate file "W:/database/conversion.tag") == true) then + ( + resetMAXFile #noprompt + + nllog("CONVERT " + file) + + -- Open the max project + if loadMaxFile file quiet:true == true then + ( + origAnimStart = animationRange.start + origAnimEnd = animationRange.end + origFrameRate = frameRate + + resetMAXFile #noprompt + + animationRange = interval origAnimStart origAnimEnd + frameRate = origFrameRate + + -- Merge the max project + if mergeMaxFile file quiet:true == true then + ( + result = call_do_it () + + -- Error ? + if result < 0 then + ( + if StopOnError.checked == true then + Messagebox ("Error in file " + file) + ) + else + ( + -- Save the max project ? + if (Test.checked == false) and (result != 0) then + ( + -- Backup the max project ? + local ok + ok = true + if BackupFiles.checked == true then + ( + -- Backup the file + if (BackupFile file) == false then + ( + -- Don't save the file because backup has failed + ok = false + + if StopOnError.checked == true then + Messagebox ("Can't backup file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + + -- Save the max project ? + if ok == true then + ( + if (saveMaxFile file) == true then + ( + fileModified = fileModified + 1 + ) + else + ( + if StopOnError.checked == true then + Messagebox ("Can't write file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + ) + ) + ) + else + ( + if StopOnError.checked == true then + Messagebox ("Can't load file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + ) + else + ( + nllog("SKIP " + file + " by tag") + ) + ) + + -- Parse sub directory ? + if (Recurse.checked == true) then + ( + local directories + + -- Get the directories + directories = getDirectories (currentDirectory+"/*") + + -- For each directories + for dir in directories do + ( + RecurseFolder dir + ) + ) + ) + + on BrowseDirectory pressed do + ( + local dir + try + ( + dir = getSavePath () -- caption:"Select the projects directory" + if dir != undefined then + Directory.text = dir + ) + catch + ( + ) + ) + + on GoButton pressed do + ( + -- Reset count + countModifications = 0 + countErrors = 0 + fileModified = 0 + fileParsed = 0 + + -- Get files in the shape_source_directory + if SourceFiles.state == 2 then + ( + -- Should warning user ? + if (SourceFiles.state == 2) and (Test.checked == false) then + ( + -- Warning ! + if ((queryBox "Warning, all the files in the specified folders will be overwrited.\nYou should backup your files before executing this script.\nDo you want to continue executing this script ?" beep:true) == true) then + RecurseFolder (adjustPathStringForScript Directory.text) + ) + else + ( + RecurseFolder (adjustPathStringForScript Directory.text) + ) + ) + else + ( + -- Just compute the current project + call_do_it () + ) + + -- Show errors + ProgressText.text = (fileParsed as string) + " project(s) opened, " + (countModifications as string) + " project modification(s), " + (fileModified as string) + " project(s) saved, " + (countErrors as string) + " error(s)." + Progress.value = 100 + ) +) + +assets_resave_floater = newRolloutFloater "NeL Assets Resave Database" 550 874 +addrollout assets_resave_rollout assets_resave_floater rolledUp:false + diff --git a/code/nel/tools/3d/plugin_max/scripts/nel_assets_resave_hard.ms b/code/nel/tools/3d/plugin_max/scripts/nel_assets_resave_hard.ms new file mode 100644 index 000000000..05220c7a5 --- /dev/null +++ b/code/nel/tools/3d/plugin_max/scripts/nel_assets_resave_hard.ms @@ -0,0 +1,316 @@ + +NEL3D_APPDATA_INTERFACE_FILE = 1423062700 + +-- Allocate 20 Me for the script +heapSize += 15000000 + +nlErrorFilename = "W:/database/conversion.log" +nlErrorStream = openFile nlErrorFilename mode:"w" +if nlErrorStream == undefined then + nlErrorStream = createFile nlErrorFilename + +-- Log a message +fn nllog message = +( + if nlErrorStream != undefined then + ( + format "%\n" message to:nlErrorStream + flush nlErrorStream + ) + + -- To the console + print message +) + +include "nel_utility.ms" + +rollout assets_resave_rollout "Properties" +( + fn do_it = + ( + max select none + + actionMan.executeAction 0 "40021" -- Selection: Select All + actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected + actionMan.executeAction 0 "40807" -- Views: Activate All Maps + actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps + actionMan.executeAction 0 "40043" -- Selection: Select None + + max views redraw + + return 1 + ) + + -- This script is a base script to include to add multiple functionality to your script + + -- To use this script + -- Include it in your script into the rollout at the beginning. + -- Implement a do_it function to do the job in your rollout. + -- The function should retun -1 if an arror occured, else the count of modification done + -- It the function returns <1, the project will not be overwritten + + Group "Running properties" + ( + RadioButtons SourceFiles "Source projects" labels:#("Current project", "All Projects in a folder") align:#left + + Label DirectoryLabel "Source directory" align:#left + EditText Directory "" width:500 align:#left enabled:false + Button BrowseDirectory "Browse..." align:#left enabled:false + + CheckBox Recurse "Look in subfolders" checked:true enabled:false + CheckBox Test "Test only, do not save" checked:false enabled:false + CheckBox BackupFiles "Backup files" checked:false enabled:false + CheckBox StopOnError "Stop on error" checked:false enabled:false + CheckBox UseTag "Use tag" checked:false enabled:false + + Label ProgressText width:500 align:#left + ProgressBar Progress width:500 align:#left + + Button GoButton "Go" width:500 align:#left + ) + + local countModifications + local countErrors + local fileModified + local fileParsed + + fn UpdateData = + ( + if SourceFiles.state == 2 then + isSourceDir = true + else + isSourceDir = false + if Test.checked == true then + isTest = true + else + isTest = false + + Directory.enabled = isSourceDir + BrowseDirectory.enabled = isSourceDir + Recurse.enabled = isSourceDir + Test.enabled = isSourceDir + BackupFiles.enabled = isSourceDir and (isTest == false) + StopOnError.enabled = isSourceDir + UseTag.enabled = isSourceDir + ) + + on SourceFiles changed state do + ( + UpdateData () + ) + + on Test changed state do + ( + UpdateData () + ) + + fn call_do_it = + ( + local result + + -- One more project + fileParsed = fileParsed + 1 + + -- Call it + result = do_it () + + -- Error ? + if result < 0 then + countErrors = countErrors + 1 + else + countModifications = countModifications + result + + -- Return result + return result + ) + + fn BackupFile file = + ( + local i + local newFilename + + i = 0 + while true do + ( + -- New file name + newFilename = file + ".backup_" + (i as string) + + -- File exist ? + if (fileExist newFilename) == false then + ( + if (copyFile file newFilename) == false then + return false + else + return true + ) + i = i + 1 + ) + ) + + fn RecurseFolder currentDirectory = + ( + resetMAXFile #noprompt + + local result + local file + local files + local origAnimStart + local origAnimEnd + local origFrameRate + + -- Parse files + files = getFiles (currentDirectory+"/*.max") + + -- For each files + for i = 1 to files.count do + ( + -- File name + file = files[i] + + -- Progress bar + ProgressText.text = "In directory "+currentDirectory+", compute file \"" + (getFilenameFile file) + "\"" + Progress.value = i*100/files.count + + if (UseTag.checked == false) or ((NeLTestFileDate file "W:/database/conversion.tag") == true) then + ( + resetMAXFile #noprompt + + nllog("CONVERT " + file) + + -- Merge the max project + if mergeMaxFile file quiet:true == true then + ( + result = call_do_it () + + -- Error ? + if result < 0 then + ( + if StopOnError.checked == true then + Messagebox ("Error in file " + file) + ) + else + ( + -- Save the max project ? + if (Test.checked == false) and (result != 0) then + ( + -- Backup the max project ? + local ok + ok = true + if BackupFiles.checked == true then + ( + -- Backup the file + if (BackupFile file) == false then + ( + -- Don't save the file because backup has failed + ok = false + + if StopOnError.checked == true then + Messagebox ("Can't backup file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + + -- Save the max project ? + if ok == true then + ( + if (saveMaxFile file) == true then + ( + fileModified = fileModified + 1 + ) + else + ( + if StopOnError.checked == true then + Messagebox ("Can't write file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + ) + ) + ) + else + ( + if StopOnError.checked == true then + Messagebox ("Can't load file " + file) + + -- One more error + countErrors = countErrors + 1 + ) + ) + else + ( + nllog("SKIP " + file + " by tag") + ) + ) + + -- Parse sub directory ? + if (Recurse.checked == true) then + ( + local directories + + -- Get the directories + directories = getDirectories (currentDirectory+"/*") + + -- For each directories + for dir in directories do + ( + RecurseFolder dir + ) + ) + ) + + on BrowseDirectory pressed do + ( + local dir + try + ( + dir = getSavePath () -- caption:"Select the projects directory" + if dir != undefined then + Directory.text = dir + ) + catch + ( + ) + ) + + on GoButton pressed do + ( + -- Reset count + countModifications = 0 + countErrors = 0 + fileModified = 0 + fileParsed = 0 + + -- Get files in the shape_source_directory + if SourceFiles.state == 2 then + ( + -- Should warning user ? + if (SourceFiles.state == 2) and (Test.checked == false) then + ( + -- Warning ! + if ((queryBox "Warning, all the files in the specified folders will be overwrited.\nYou should backup your files before executing this script.\nDo you want to continue executing this script ?" beep:true) == true) then + RecurseFolder (adjustPathStringForScript Directory.text) + ) + else + ( + RecurseFolder (adjustPathStringForScript Directory.text) + ) + ) + else + ( + -- Just compute the current project + call_do_it () + ) + + -- Show errors + ProgressText.text = (fileParsed as string) + " project(s) opened, " + (countModifications as string) + " project modification(s), " + (fileModified as string) + " project(s) saved, " + (countErrors as string) + " error(s)." + Progress.value = 100 + ) +) + +assets_resave_floater = newRolloutFloater "NeL Assets Resave Database Hard" 550 874 +addrollout assets_resave_rollout assets_resave_floater rolledUp:false + diff --git a/code/nel/tools/3d/plugin_max/tile_utility/tile_utility.rc b/code/nel/tools/3d/plugin_max/tile_utility/tile_utility.rc index c6118c2f8..80d1d390d 100644 --- a/code/nel/tools/3d/plugin_max/tile_utility/tile_utility.rc +++ b/code/nel/tools/3d/plugin_max/tile_utility/tile_utility.rc @@ -124,8 +124,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0, 10, 0, 0 - PRODUCTVERSION 0, 10, 0, 0 + FILEVERSION 0, 11, 0, 0 + PRODUCTVERSION 0, 11, 0, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -142,12 +142,12 @@ BEGIN BEGIN VALUE "Comments", "Based on Kinetix 3D Studio Max 3.0 plugin sample\0" VALUE "CompanyName", "Ryzom Core\0" - VALUE "FileVersion", "0.10.0\0" + VALUE "FileVersion", "0.11.0\0" VALUE "InternalName", "Tile_utility\0" VALUE "LegalCopyright", "\0" VALUE "OriginalFilename", "Tile_utility.dlu\0" VALUE "ProductName", "Ryzom Core\0" - VALUE "ProductVersion", "0.10.0\0" + VALUE "ProductVersion", "0.11.0\0" VALUE "FileDescription", "Create material for tiles\0" VALUE "Comments", "TECH: \0" VALUE "LegalTrademarks", "\0" diff --git a/code/nel/tools/build_gamedata/0_setup.py b/code/nel/tools/build_gamedata/0_setup.py index aeac30eaf..8eff34131 100755 --- a/code/nel/tools/build_gamedata/0_setup.py +++ b/code/nel/tools/build_gamedata/0_setup.py @@ -432,6 +432,8 @@ if not args.noverify: findTool(log, ToolDirectories, TgaCutTool, ToolSuffix) findTool(log, ToolDirectories, PatchGenTool, ToolSuffix) findTool(log, ToolDirectories, TranslationToolsTool, ToolSuffix) + findTool(log, ToolDirectories, BuildWorldPackedColTool, ToolSuffix) + findTool(log, ToolDirectories, R2IslandsTexturesTool, ToolSuffix) log.close() if os.path.isfile("0_setup.log"): diff --git a/code/nel/tools/build_gamedata/b1_client_dev.py b/code/nel/tools/build_gamedata/b1_client_dev.py index d8c77c1fa..a23ee693c 100755 --- a/code/nel/tools/build_gamedata/b1_client_dev.py +++ b/code/nel/tools/build_gamedata/b1_client_dev.py @@ -52,6 +52,10 @@ if not os.path.isfile(ClientDevDirectory + "/client.cfg"): cfg.write("PreDataPath = {\n") cfg.write("\t\"" + InstallDirectory + "\", \"user\", \"patch\", \"data\", \"examples\" \n") cfg.write("};\n") + cfg.write("PatchWanted = 0;\n") + cfg.write("DisplayLuaDebugInfo = 1;\n") + cfg.write("AllowDebugLua = 1;\n") + cfg.write("FullScreen = 0;\n") printLog(log, "") printLog(log, ">>> Install data <<<") diff --git a/code/nel/tools/build_gamedata/characters_dev.bat b/code/nel/tools/build_gamedata/characters_dev.bat new file mode 100644 index 000000000..f2b374c47 --- /dev/null +++ b/code/nel/tools/build_gamedata/characters_dev.bat @@ -0,0 +1,11 @@ +title Ryzom Core: 1_export.py (CHARACTERS) +1_export.py -ipj common/characters common/characters_maps_hr +title Ryzom Core: 2_build.py (CHARACTERS) +2_build.py -ipj common/characters common/characters_maps_hr +title Ryzom Core: 3_install.py (CHARACTERS) +3_install.py -ipj common/characters common/characters_maps_hr +title Ryzom Core: b1_client_dev.py (CHARACTERS) +b1_client_dev.py +title Ryzom Core: b2_shard_data.py (CHARACTERS) +b2_shard_data.py +title Ryzom Core: Ready (CHARACTERS) diff --git a/code/nel/tools/build_gamedata/configuration/tools.py b/code/nel/tools/build_gamedata/configuration/tools.py index 1a31d2986..c0c962360 100755 --- a/code/nel/tools/build_gamedata/configuration/tools.py +++ b/code/nel/tools/build_gamedata/configuration/tools.py @@ -91,3 +91,5 @@ AiBuildWmapTool = "ai_build_wmap" TgaCutTool = "tga_cut" PatchGenTool = "patch_gen" TranslationToolsTool = "translation_tools" +BuildWorldPackedColTool = "build_world_packed_col" +R2IslandsTexturesTool = "r2_islands_textures" diff --git a/code/nel/tools/build_gamedata/panoply_dev.bat b/code/nel/tools/build_gamedata/panoply_dev.bat new file mode 100644 index 000000000..13afac56c --- /dev/null +++ b/code/nel/tools/build_gamedata/panoply_dev.bat @@ -0,0 +1,11 @@ +title Ryzom Core: 1_export.py (PANOPLY) +1_export.py -ipj common/characters_maps_hr +title Ryzom Core: 2_build.py (PANOPLY) +2_build.py -ipj common/characters_maps_hr +title Ryzom Core: 3_install.py (PANOPLY) +3_install.py -ipj common/characters_maps_hr +title Ryzom Core: b1_client_dev.py (PANOPLY) +b1_client_dev.py +title Ryzom Core: b2_shard_data.py (PANOPLY) +b2_shard_data.py +title Ryzom Core: Ready (PANOPLY) diff --git a/code/nel/tools/build_gamedata/processes/cartographer/0_setup.py b/code/nel/tools/build_gamedata/processes/cartographer/0_setup.py new file mode 100644 index 000000000..6f8b9a754 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/cartographer/0_setup.py @@ -0,0 +1,114 @@ +#!/usr/bin/python +# +# \file 0_setup.py +# \brief setup cartographer +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Setup cartographer +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Setup cartographer") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +# Setup build directories +printLog(log, ">>> Setup build directories <<<") +mkPath(log, ExportBuildDirectory + "/" + CartographerBuildDirectory) + +# Setup lookup directories +printLog(log, ">>> Setup lookup directories <<<") +mkPath(log, ExportBuildDirectory + "/" + AiWmapBuildDirectory) # IN +mkPath(log, ExportBuildDirectory + "/" + ZoneLightBuildDirectory) # IN (.zonel) +mkPath(log, ExportBuildDirectory + "/" + ZoneLightIgLandBuildDirectory) # IN (.ig) +mkPath(log, ExportBuildDirectory + "/" + SmallbankExportDirectory) # IN +mkPath(log, ExportBuildDirectory + "/" + FarbankBuildDirectory) # IN +mkPath(log, ExportBuildDirectory + "/" + DisplaceExportDirectory) # IN +mkPath(log, ExportBuildDirectory + "/" + TilesExportDirectory) # IN +mkPath(log, LeveldesignDataCommonDirectory) # IN +mkPath(log, LeveldesignDfnDirectory) # IN +mkPath(log, LeveldesignDirectory) # IN +for dir in PropertiesExportBuildSearchPaths: + mkPath(log, ExportBuildDirectory + "/" + dir) + +# Setup client directories +printLog(log, ">>> Setup install directories <<<") +mkPath(log, InstallDirectory + "/" + CartographerInstallDirectory) + +# Setup client directories +printLog(log, ">>> Setup configuration <<<") +mkPath(log, ActiveProjectDirectory + "/generated") +cfg = open(ActiveProjectDirectory + "/generated/island_screenshots.cfg", "w") +cfg.write("\n") +cfg.write("// BUILD CARTOGRAPHER CONFIGURATION\n") +cfg.write("\n") +cfg.write("SearchPaths = {\n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + AiWmapBuildDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + ZoneLightBuildDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + ZoneLightIgLandBuildDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + SmallbankExportDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + FarbankBuildDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + DisplaceExportDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + TilesExportDirectory + "\", \n") +cfg.write("\t\"" + LeveldesignDataCommonDirectory + "\", \n") +cfg.write("\t\"" + LeveldesignDfnDirectory + "\", \n") +cfg.write("\t\"" + LeveldesignDirectory + "\", \n") +for dir in PropertiesExportBuildSearchPaths: + cfg.write("\t\"" + ExportBuildDirectory + "/" + dir + "\", \n") +cfg.write("};\n") +cfg.write("\n") +cfg.write("OutDir = \"" + ExportBuildDirectory + "/" + CartographerBuildDirectory + "\";\n") +cfg.write("\n") +cfg.write("Continents = {\n") +cfg.write("\t\"" + CartographerContinent + "\", \n") +cfg.write("};\n") +cfg.write("\n") +cfg.write("SeasonSuffixes = {\n") +for suffix in MultipleTilesPostfix: + cfg.write("\t\"" + suffix + "\", \n") +cfg.write("};\n") +cfg.write("\n") +cfg.write("InverseZTest = true;\n") +cfg.write("Vegetation = true;\n") +cfg.write("MeterPixelSize = 2;\n") +cfg.write("\n") +cfg.write("CompleteIslandsFile = \"r2_islands.xml\";\n") +cfg.write("EntryPointsFile = \"r2_entry_points.txt\";\n") +cfg.write("\n") +cfg.close() + +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/cartographer/1_export.py b/code/nel/tools/build_gamedata/processes/cartographer/1_export.py new file mode 100644 index 000000000..319316728 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/cartographer/1_export.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# +# \file 1_export.py +# \brief Export cartographer +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Export cartographer +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Export cartographer") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/cartographer/2_build.py b/code/nel/tools/build_gamedata/processes/cartographer/2_build.py new file mode 100644 index 000000000..c3c14e9aa --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/cartographer/2_build.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +# +# \file 2_build.py +# \brief Build cartographer +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Build cartographer +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Build cartographer") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +# Find tools +R2IslandsTextures = findTool(log, ToolDirectories, R2IslandsTexturesTool, ToolSuffix) + +if R2IslandsTextures == "": + toolLogFail(log, R2IslandsTexturesTool, ToolSuffix) +else: + printLog(log, ">>> Copy island_screenshots.cfg <<<") + cfgPath = ActiveProjectDirectory + "/generated/island_screenshots.cfg" + shutil.copy(cfgPath, "island_screenshots.cfg") + printLog(log, ">>> Build cartographer <<<") + subprocess.call([ R2IslandsTextures ]) +printLog(log, "") + +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/cartographer/3_install.py b/code/nel/tools/build_gamedata/processes/cartographer/3_install.py new file mode 100644 index 000000000..f241318c4 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/cartographer/3_install.py @@ -0,0 +1,57 @@ +#!/usr/bin/python +# +# \file 3_install.py +# \brief Install cartographer +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Install cartographer +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Install cartographer") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +installPath = InstallDirectory + "/" + CartographerInstallDirectory +mkPath(log, installPath) + +printLog(log, ">>> Install cartographer <<<") +mkPath(log, ExportBuildDirectory + "/" + CartographerBuildDirectory) +copyFilesNoTreeIfNeeded(log, ExportBuildDirectory + "/" + CartographerBuildDirectory, installPath) + +printLog(log, "") +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/clodbank/0_setup.py b/code/nel/tools/build_gamedata/processes/clodbank/0_setup.py index 532113523..a4ab0f4df 100755 --- a/code/nel/tools/build_gamedata/processes/clodbank/0_setup.py +++ b/code/nel/tools/build_gamedata/processes/clodbank/0_setup.py @@ -74,6 +74,8 @@ cfgOut.write("{\n") cfgOut.write("\t\"" + ExportBuildDirectory + "/" + ClodExportDirectory + "\", \n") cfgOut.write("\t\"" + ExportBuildDirectory + "/" + SkelExportDirectory + "\", \n") cfgOut.write("\t\"" + ExportBuildDirectory + "/" + AnimBuildDirectory + "\", \n") +cfgOut.write("\t\"" + ExportBuildDirectory + "/" + ShapeOptimizedBuildDirectory + "\", \n") +cfgOut.write("\t\"" + ExportBuildDirectory + "/" + ShapeWithCoarseMeshBuildDirectory + "\", \n") cfgOut.write("};\n") cfgOut.write("\n") cfgOut.close() diff --git a/code/nel/tools/build_gamedata/processes/pz/0_setup.py b/code/nel/tools/build_gamedata/processes/pz/0_setup.py new file mode 100644 index 000000000..e9f22be11 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/pz/0_setup.py @@ -0,0 +1,97 @@ +#!/usr/bin/python +# +# \file 0_setup.py +# \brief setup pz +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Setup pz +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Setup pz") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +# Setup build directories +printLog(log, ">>> Setup build directories <<<") +mkPath(log, ExportBuildDirectory + "/" + PackedZoneCacheBuildDirectory) +mkPath(log, ExportBuildDirectory + "/" + PackedZoneCWMapCacheBuildDirectory) +mkPath(log, ExportBuildDirectory + "/" + PackedZoneBuildDirectory) + +# Setup lookup directories +printLog(log, ">>> Setup lookup directories <<<") +mkPath(log, ExportBuildDirectory + "/" + AiWmapBuildDirectory) +mkPath(log, ExportBuildDirectory + "/" + ZoneLightBuildDirectory) +mkPath(log, LeveldesignDataCommonDirectory) + +# Setup client directories +printLog(log, ">>> Setup install directories <<<") +mkPath(log, InstallDirectory + "/" + PackedZoneInstallDirectory) + +# Setup client directories +printLog(log, ">>> Setup configuration <<<") +mkPath(log, ActiveProjectDirectory + "/generated") +cfg = open(ActiveProjectDirectory + "/generated/build_world_packed_col.cfg", "w") +cfg.write("\n") +cfg.write("// BUILD WORLD PACKED COL CONFIGURATION\n") +cfg.write("\n") +cfg.write("SearchPaths = {\n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + AiWmapBuildDirectory + "\", \n") +cfg.write("\t\"" + ExportBuildDirectory + "/" + ZoneLightBuildDirectory + "\", \n") +cfg.write("\t\"" + LeveldesignDataCommonDirectory + "\", \n") +cfg.write("};\n") +cfg.write("\n") +cfg.write("CachePath = \"" + ExportBuildDirectory + "/" + PackedZoneCacheBuildDirectory + "\";\n") +cfg.write("CWMapCachePath = \"" + ExportBuildDirectory + "/" + PackedZoneCWMapCacheBuildDirectory + "\";\n") +cfg.write("OutputPath = \"" + ExportBuildDirectory + "/" + PackedZoneBuildDirectory + "\";\n") +cfg.write("\n") +cfg.write("EntryPointsFile = \"r2_islands.xml\";\n") +cfg.write("\n") +cfg.write("CWMapList = {\n") +cfg.write("\t\"" + PackedZoneCWMap + "\", \n") +cfg.write("};\n") +cfg.write("\n") +cfg.write("Fly = 0;\n") +cfg.write("\n") +cfg.write("HeightMapsAsTga = 1;\n") +cfg.write("PixelPerMeter = 1;\n") +cfg.write("\n") +cfg.write("RefineThreshold = 32;\n") +cfg.write("\n") +cfg.close() + +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/pz/1_export.py b/code/nel/tools/build_gamedata/processes/pz/1_export.py new file mode 100644 index 000000000..ff8daf747 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/pz/1_export.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# +# \file 1_export.py +# \brief Export pz +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Export pz +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Export pz") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/pz/2_build.py b/code/nel/tools/build_gamedata/processes/pz/2_build.py new file mode 100644 index 000000000..b632412b0 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/pz/2_build.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +# +# \file 2_build.py +# \brief Build pz +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Build pz +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Build pz") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +# Find tools +BuildWorldPackedCol = findTool(log, ToolDirectories, BuildWorldPackedColTool, ToolSuffix) + +if BuildWorldPackedCol == "": + toolLogFail(log, BuildWorldPackedColTool, ToolSuffix) +else: + printLog(log, ">>> Copy ai_build_wmap.cfg <<<") + cfgPath = ActiveProjectDirectory + "/generated/build_world_packed_col.cfg" + shutil.copy(cfgPath, "build_world_packed_col.cfg") + printLog(log, ">>> Build pz <<<") + subprocess.call([ BuildWorldPackedCol, "build_world_packed_col.cfg" ]) +printLog(log, "") + +log.close() + + +# end of file diff --git a/code/nel/tools/build_gamedata/processes/pz/3_install.py b/code/nel/tools/build_gamedata/processes/pz/3_install.py new file mode 100644 index 000000000..c4feedef1 --- /dev/null +++ b/code/nel/tools/build_gamedata/processes/pz/3_install.py @@ -0,0 +1,58 @@ +#!/usr/bin/python +# +# \file 3_install.py +# \brief Install pz +# \date 2014-09-13 13:32GMT +# \author Jan Boon (Kaetemi) +# Python port of game data build pipeline. +# Install pz +# +# NeL - MMORPG Framework +# Copyright (C) 2014 Jan BOON +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +import time, sys, os, shutil, subprocess, distutils.dir_util +sys.path.append("../../configuration") + +if os.path.isfile("log.log"): + os.remove("log.log") +log = open("log.log", "w") +from scripts import * +from buildsite import * +from process import * +from tools import * +from directories import * + +printLog(log, "") +printLog(log, "-------") +printLog(log, "--- Install pz") +printLog(log, "-------") +printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) +printLog(log, "") + +installPath = InstallDirectory + "/" + PackedZoneInstallDirectory +mkPath(log, installPath) + +printLog(log, ">>> Install pz <<<") +mkPath(log, ExportBuildDirectory + "/" + PackedZoneBuildDirectory) +copyFilesExtNoTreeIfNeeded(log, ExportBuildDirectory + "/" + PackedZoneBuildDirectory, installPath, ".island_hm") +copyFilesExtNoTreeIfNeeded(log, ExportBuildDirectory + "/" + PackedZoneBuildDirectory, installPath, ".packed_island") + +printLog(log, "") +log.close() + + +# end of file diff --git a/code/nel/tools/misc/data_mirror/StdAfx.h b/code/nel/tools/misc/data_mirror/StdAfx.h index 90fe14511..a065be4ed 100644 --- a/code/nel/tools/misc/data_mirror/StdAfx.h +++ b/code/nel/tools/misc/data_mirror/StdAfx.h @@ -10,9 +10,6 @@ #pragma once #endif // _MSC_VER > 1000 -#include "nel/misc/types_nl.h" -#include "nel/misc/file.h" - #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers #include // MFC core and standard components diff --git a/code/ryzom/client/client_default.cfg b/code/ryzom/client/client_default.cfg index a27e69ee0..55e56b012 100644 --- a/code/ryzom/client/client_default.cfg +++ b/code/ryzom/client/client_default.cfg @@ -214,6 +214,12 @@ Shadows_ps1 = 1; Shadows_ps2 = 1; Shadows_ps3 = 1; +FXAA = 1; +FXAA_ps0 = 0; +FXAA_ps1 = 1; +FXAA_ps2 = 1; +FXAA_ps3 = 1; + Bloom = 0; Bloom_ps0 = 0; Bloom_ps1 = 1; @@ -413,7 +419,7 @@ PrintfCommandsFreeTrial = { DisplayMissingAnimFile = 0; -LoadingStringCount = 54; +LoadingStringCount = 0; // Some R2 parameters ... diff --git a/code/ryzom/client/client_default.cfg.in b/code/ryzom/client/client_default.cfg.in index 030a4a2b2..ec699fe14 100644 --- a/code/ryzom/client/client_default.cfg.in +++ b/code/ryzom/client/client_default.cfg.in @@ -210,6 +210,12 @@ Shadows_ps1 = 1; Shadows_ps2 = 1; Shadows_ps3 = 1; +FXAA = 1; +FXAA_ps0 = 0; +FXAA_ps1 = 1; +FXAA_ps2 = 1; +FXAA_ps3 = 1; + Bloom = 0; Bloom_ps0 = 0; Bloom_ps1 = 1; diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml b/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml index 5e9072b93..c2b62cebd 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml @@ -1230,8 +1230,15 @@ posref="BL TL" x="-20" y="-12" /> + + TexturesLoginInterface; std::vector TexturesLoginInterfaceDXTC; @@ -190,8 +190,6 @@ struct CClientConfig /// \name Inputs /// Use a hardware cursor - bool DisableDirectInput; - bool DisableDirectInputKeyboard; bool HardwareCursor; float HardwareCursorScale; // scale for hardware cursor bitmap (in ]0, 1]) float CursorSpeed; @@ -265,6 +263,9 @@ struct CClientConfig float GlobalWindPower; CVector GlobalWindDirection; + // FXAA + bool FXAA; + // Is bloom effect activated bool Bloom; bool SquareBloom; diff --git a/code/ryzom/client/src/connection.cpp b/code/ryzom/client/src/connection.cpp index 3a39dec1d..8b07cc7f2 100644 --- a/code/ryzom/client/src/connection.cpp +++ b/code/ryzom/client/src/connection.cpp @@ -31,6 +31,7 @@ // 3D Interface. #include "nel/3d/u_driver.h" #include "nel/3d/u_text_context.h" +#include // Game Share //#include "game_share/gd_time.h" // \todo GUIGUI : TO DELETE/CHANGE #include "game_share/gender.h" @@ -116,6 +117,8 @@ extern void saveMovieShooting(); extern void displaySpecialTextProgress(const char *text); extern bool InitMouseWithCursor(bool hardware); +extern bool SetMousePosFirstTime; + ///////////// // Globals // initialization occurs in the function : connection ///////////// @@ -203,9 +206,13 @@ void connectionRestaureVideoMode () if (ClientCfg.Width < 800) ClientCfg.Width = 800; if (ClientCfg.Height < 600) ClientCfg.Height = 600; - if ((ClientCfg.Windowed != mode.Windowed) || + if (StereoDisplay) + StereoDisplayAttached = StereoDisplay->attachToDisplay(); + + if (!StereoDisplayAttached && ( + (ClientCfg.Windowed != mode.Windowed) || (ClientCfg.Width != mode.Width) || - (ClientCfg.Height != mode.Height)) + (ClientCfg.Height != mode.Height))) { mode.Windowed = ClientCfg.Windowed; mode.Depth = uint8(ClientCfg.Depth); @@ -216,7 +223,7 @@ void connectionRestaureVideoMode () } // And setup hardware mouse if we have to - InitMouseWithCursor (ClientCfg.HardwareCursor); + InitMouseWithCursor (ClientCfg.HardwareCursor && !StereoDisplayAttached); SetMouseFreeLook (); SetMouseCursor (); SetMouseSpeed (ClientCfg.CursorSpeed); @@ -251,6 +258,10 @@ void setOutGameFullScreen() // NB: don't setup fullscreen if player wants to play in window if (!ClientCfg.Local && ClientCfg.SelectCharacter == -1) { + if (StereoDisplayAttached) + StereoDisplay->detachFromDisplay(); + StereoDisplayAttached = false; + UDriver::CMode currMode; Driver->getCurrentScreenMode(currMode); UDriver::CMode wantedMode; @@ -267,6 +278,8 @@ void setOutGameFullScreen() { setVideoMode(wantedMode); } + + InitMouseWithCursor(ClientCfg.HardwareCursor && !StereoDisplayAttached); /* InitMouseWithCursor (true); Driver->showCursor(false); @@ -385,7 +398,7 @@ bool connection (const string &cookie, const string &fsaddr) // not initialized at login and remain hardware until here ... // Re-initialise the mouse (will be now in hardware mode, if required) - //InitMouseWithCursor (ClientCfg.HardwareCursor); // the return value of enableLowLevelMouse() has already been tested at startup + //InitMouseWithCursor (ClientCfg.HardwareCursor && !StereoDisplayAttached); // the return value of enableLowLevelMouse() has already been tested at startup // no ui init if character selection is automatic //SetMouseFreeLook (); @@ -544,7 +557,8 @@ bool reconnection() if (ClientCfg.SelectCharacter == -1) { // Re-initialise the mouse (will be now in hardware mode, if required) - InitMouseWithCursor (ClientCfg.HardwareCursor); // the return value of enableLowLevelMouse() has already been tested at startup + SetMousePosFirstTime = true; + InitMouseWithCursor (ClientCfg.HardwareCursor && !StereoDisplayAttached); // the return value of enableLowLevelMouse() has already been tested at startup // no ui init if character selection is automatic SetMouseFreeLook (); diff --git a/code/ryzom/client/src/debug_client.cpp b/code/ryzom/client/src/debug_client.cpp index 8800384ba..0af4207ae 100644 --- a/code/ryzom/client/src/debug_client.cpp +++ b/code/ryzom/client/src/debug_client.cpp @@ -345,6 +345,7 @@ void displayStreamingDebug () //----------------// // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(ClientCfg.DebugFontSize); // Set the text color @@ -390,6 +391,7 @@ void displayStreamingDebug () // No more shadow when displaying a text. TextContext->setShaded(false); + TextContext->setShadeOutline(false); } } @@ -567,6 +569,7 @@ void displayNetDebug () //----------------// // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(ClientCfg.DebugFontSize); // Set the text color diff --git a/code/ryzom/client/src/events_listener.cpp b/code/ryzom/client/src/events_listener.cpp index 1d05f8a4e..89963a2ab 100644 --- a/code/ryzom/client/src/events_listener.cpp +++ b/code/ryzom/client/src/events_listener.cpp @@ -21,7 +21,6 @@ #include "events_listener.h" #include "nel/misc/events.h" -#include "nel/misc/game_device_events.h" #include "nel/misc/event_server.h" #include "release.h" #include "actions.h" @@ -29,11 +28,13 @@ #include "time_client.h" #include "input.h" #include "interface_v3/interface_manager.h" +#include "global.h" using namespace NLMISC; extern CActionsManager Actions; // Actions Manager. +extern bool MouseFreeLook; //--------------------------------------------------- // CEventsListener : @@ -82,7 +83,6 @@ CEventsListener::~CEventsListener() //--------------------------------------------------- void CEventsListener::addToServer(CEventServer& server) { - server.addListener(EventGDMouseMove, this); server.addListener(EventMouseMoveId, this); server.addListener(EventMouseDownId, this); server.addListener(EventMouseUpId, this); @@ -101,7 +101,6 @@ void CEventsListener::addToServer(CEventServer& server) //--------------------------------------------------- void CEventsListener::removeFromServer (CEventServer& server) { - server.removeListener(EventGDMouseMove, this); server.removeListener(EventMouseMoveId, this); server.removeListener(EventMouseDownId, this); server.removeListener(EventMouseUpId, this); @@ -113,6 +112,12 @@ void CEventsListener::removeFromServer (CEventServer& server) server.removeListener(EventSetFocusId, this); }// removeFromServer // +static bool s_MouseFreeLookReady = false; +static sint s_MouseFreeLookLastX; +static sint s_MouseFreeLookLastY; +static sint s_MouseFreeLookFrameX = 0; +static sint s_MouseFreeLookFrameY = 0; +static bool s_MouseFreeLookWaitCenter; //--------------------------------------------------- // operator() : @@ -148,20 +153,64 @@ void CEventsListener::operator()(const CEvent& event) { CAHManager::getInstance()->runActionHandler("enter_modal", NULL, "group=ui:interface:quit_dialog"); } - // Event from the Mouse (ANGLE) - if(event == EventGDMouseMove) - { - CGDMouseMove* mouseEvent=(CGDMouseMove*)&event; - // Mouse acceleration - sint dX = mouseEvent->X; - sint dY = ClientCfg.FreeLookInverted ? -mouseEvent->Y : mouseEvent->Y; - updateFreeLookPos((float) dX, (float) dY); - } // Event from the Mouse (MOVE) else if(event == EventMouseMoveId) { CEventMouseMove* mouseEvent=(CEventMouseMove*)&event; - updateCursorPos(mouseEvent->X, mouseEvent->Y); + if (!MouseFreeLook) + { + updateCursorPos(mouseEvent->X, mouseEvent->Y); + s_MouseFreeLookReady = false; + } + else + { + // Get in pixel space, centered + uint32 drW, drH; + Driver->getWindowSize(drW, drH); + float fX = mouseEvent->X; // from 0 to 1.0 + float fY = (ClientCfg.FreeLookInverted ? -mouseEvent->Y : mouseEvent->Y); + sint scX = (sint32)(fX * (float)drW) - ((sint32)drW >> 1); // in pixels, centered + sint scY = (sint32)(fY * (float)drH) - ((sint32)drH >> 1); + if (!s_MouseFreeLookReady) + { + float pfX = _MouseX; + float pfY = (ClientCfg.FreeLookInverted ? -_MouseY : _MouseY); + sint pscX = (sint32)(pfX * (float)drW) - ((sint32)drW >> 1); // in pixels, centered + sint pscY = (sint32)(pfY * (float)drH) - ((sint32)drH >> 1); + s_MouseFreeLookReady = true; + s_MouseFreeLookLastX = pscX; + s_MouseFreeLookLastY = pscY; + s_MouseFreeLookWaitCenter = false; + } + + // NOTE: No 0, 0 center mouse message in Windows (lower mouse message rate), but safe to assume any movement messages are requeued relative to our new position + // In case free look bugs on other platform, we may need to push in our own message on setMousePos for Windows + if (s_MouseFreeLookWaitCenter) // scX == 0 && scY == 0) + { + // Centered, set last to 0 + s_MouseFreeLookLastX = 0; + s_MouseFreeLookLastY = 0; + s_MouseFreeLookWaitCenter = false; + } + + // Get delta since last center + sint scXd = scX - s_MouseFreeLookLastX; + sint scYd = scY - s_MouseFreeLookLastY; + s_MouseFreeLookLastX = scX; + s_MouseFreeLookLastY = scY; + + s_MouseFreeLookFrameX += scXd; + s_MouseFreeLookFrameY += scYd; + // updateFreeLookPos is called in updateMouseSmoothing per frame + + // Center cursor + bool outsideBounds = ((abs(scX) > (drW >> 3)) || (abs(scY) > (drH >> 3))); + if (outsideBounds) + { + s_MouseFreeLookWaitCenter = true; + Driver->setMousePos(0.5f, 0.5f); + } + } } // Event from the Mouse (DOWN BUTTONS) else if(event == EventMouseDownId) @@ -233,16 +282,9 @@ void CEventsListener::updateMouseSmoothing() { if (_LastFreeLookUpdateDate != TimeInSec) { - if (ClientCfg.FreeLookSmoothingPeriod != 0.f && _MouseSmoothingOn) - { - // free look hasn't been updated that frame because there was no - // mouse move msg. - // mouse pos must be updated however because of smoothing - updateFreeLookPos(0, 0); - - - - } + updateFreeLookPos((float)s_MouseFreeLookFrameX, (float)s_MouseFreeLookFrameY); + s_MouseFreeLookFrameX = 0; + s_MouseFreeLookFrameY = 0; } } @@ -267,7 +309,6 @@ void CEventsListener::enableMouseSmoothing(bool on) // *************************************************************** void CEventsListener::updateFreeLookPos(float x, float y) { - if (ClientCfg.FreeLookSmoothingPeriod == 0 || !_MouseSmoothingOn) { _MouseDeltaAX = x * ClientCfg.FreeLookSpeed; diff --git a/code/ryzom/client/src/far_tp.cpp b/code/ryzom/client/src/far_tp.cpp index 5ecd90c9c..4f48d2ff5 100644 --- a/code/ryzom/client/src/far_tp.cpp +++ b/code/ryzom/client/src/far_tp.cpp @@ -1132,7 +1132,7 @@ void CFarTP::disconnectFromPreviousShard() */ NetMngr.reinit(); - if( !isReselectingChar() ) + if (isIngame() && !isReselectingChar()) { nlinfo("FarTP: calling EntitiesMngr.reinit()"); EntitiesMngr.reinit(); diff --git a/code/ryzom/client/src/global.cpp b/code/ryzom/client/src/global.cpp index c965db43f..7c298ca58 100644 --- a/code/ryzom/client/src/global.cpp +++ b/code/ryzom/client/src/global.cpp @@ -25,21 +25,25 @@ using namespace NLMISC; // *************************************************************************** // Main System -NL3D::UDriver *Driver = 0; // The main 3D Driver +NL3D::UDriver *Driver = NULL; // The main 3D Driver NL3D::IStereoDisplay *StereoDisplay = NULL; // Stereo display NL3D::IStereoHMD *StereoHMD = NULL; // Head mount display -CSoundManager *SoundMngr = 0; // the sound manager +bool StereoDisplayAttached = false; // Is stereo display handling the display mode +CSoundManager *SoundMngr = NULL; // the sound manager NL3D::UMaterial GenericMat; // Generic Material -NL3D::UTextContext *TextContext = 0; // Context for all the text in the client. +NL3D::UTextContext *TextContext = NULL; // Context for all the text in the client. + +// Effects +NL3D::CFXAA *FXAA = NULL; // Main 3D Objects -NL3D::UScene *Scene = 0; -NL3D::UScene *SceneRoot = 0; -NL3D::UInstanceGroup *BackgroundIG = 0; -NL3D::ULandscape *Landscape = 0; -NL3D::UCloudScape *CloudScape = 0; +NL3D::UScene *Scene = NULL; +NL3D::UScene *SceneRoot = NULL; +NL3D::UInstanceGroup *BackgroundIG = NULL; +NL3D::ULandscape *Landscape = NULL; +NL3D::UCloudScape *CloudScape = NULL; NL3D::UCamera MainCam; -NL3D::UVisualCollisionManager *CollisionManager = 0; +NL3D::UVisualCollisionManager *CollisionManager = NULL; #ifdef USE_WATER_ENV_MAP CWaterEnvMapRdr WaterEnvMapRdr; NL3D::UWaterEnvMap *WaterEnvMap = NULL; @@ -58,7 +62,7 @@ NLMISC::CMatrix InvMainSceneViewMatrix; // Matrix to transform from camera s // Misc bool InitCloudScape = true; // tells that the cloud scape must be reinitialized -CEntityAnimationManager *EAM = 0; +CEntityAnimationManager *EAM = NULL; CProgress ProgressBar; TBackground LoadingBackground = StartBackground; string LoadingMusic; diff --git a/code/ryzom/client/src/global.h b/code/ryzom/client/src/global.h index 5879eeaec..de9aa6a73 100644 --- a/code/ryzom/client/src/global.h +++ b/code/ryzom/client/src/global.h @@ -42,6 +42,7 @@ namespace NL3D class UWaterEnvMap; class IStereoDisplay; class IStereoHMD; + class CFXAA; } class CEntityAnimationManager; @@ -81,10 +82,14 @@ const float ExtraZoneLoadingVision = 100.f; extern NL3D::UDriver *Driver; // The main 3D Driver extern NL3D::IStereoDisplay *StereoDisplay; // Stereo display extern NL3D::IStereoHMD *StereoHMD; // Head mount display +extern bool StereoDisplayAttached; // Is stereo display handling the display mode extern CSoundManager *SoundMngr; // the sound manager extern NL3D::UMaterial GenericMat; // Generic Material extern NL3D::UTextContext *TextContext; // Context for all the text in the client. +// Effects +extern NL3D::CFXAA *FXAA; + // Main 3D Objects extern NL3D::UScene *Scene; extern NL3D::UScene *SceneRoot; diff --git a/code/ryzom/client/src/graph.cpp b/code/ryzom/client/src/graph.cpp index 1bf370db0..8270762fb 100644 --- a/code/ryzom/client/src/graph.cpp +++ b/code/ryzom/client/src/graph.cpp @@ -134,6 +134,7 @@ void CGraph::renderGraph () if (TextContext != NULL) { TextContext->setShaded (false); + TextContext->setShadeOutline(false); TextContext->setHotSpot (UTextContext::MiddleLeft); TextContext->setColor (frontCol); TextContext->setFontSize (10); diff --git a/code/ryzom/client/src/ground_fx_manager.cpp b/code/ryzom/client/src/ground_fx_manager.cpp index dc064415f..f13309183 100644 --- a/code/ryzom/client/src/ground_fx_manager.cpp +++ b/code/ryzom/client/src/ground_fx_manager.cpp @@ -807,6 +807,7 @@ void CTestGroundFX::displayFXBoxes() const Driver->setFrustum(fr); TextContext->setColor(CRGBA::Green); TextContext->setShaded(false); + TextContext->setShadeOutline(false); TextContext->setFontSize(12); // float size = 0.4f; diff --git a/code/ryzom/client/src/init.cpp b/code/ryzom/client/src/init.cpp index 809232983..1644f7e2d 100644 --- a/code/ryzom/client/src/init.cpp +++ b/code/ryzom/client/src/init.cpp @@ -616,10 +616,16 @@ void initStereoDisplayDevice() std::vector devices; listStereoDisplayDevices(devices); CStereoDeviceInfo *deviceInfo = NULL; - if (ClientCfg.VRDisplayDevice == std::string("Auto") - && devices.begin() != devices.end()) + if (ClientCfg.VRDisplayDevice == std::string("Auto")) { - deviceInfo = &devices[0]; + for (std::vector::iterator it(devices.begin()), end(devices.end()); it != end; ++it) + { + if ((*it).AllowAuto) + { + deviceInfo = &(*it); + break; + } + } } else { @@ -1069,34 +1075,6 @@ void prelogInit() FPU_CHECKER_ONCE - // Test mouse & keyboard low-level mode, if DisableDirectInput not set. - // In case of failure, exit the client. - // In case of success, set it back to normal mode, to provide for the user - // the ability to manually set the firewall's permissions when the client connects. - // The low-level mode will actually be set when "launching" (after loading). - if (!ClientCfg.DisableDirectInput) - { - // Test mouse and set back to normal mode - if (!Driver->enableLowLevelMouse (true, ClientCfg.HardwareCursor)) - { - ExitClientError (CI18N::get ("can_t_initialise_the_mouse").toUtf8 ().c_str ()); - // ExitClientError() call exit() so the code after is never called - return; - } - Driver->enableLowLevelMouse (false, ClientCfg.HardwareCursor); - - // Test keyboard and set back to normal mode - // NB : keyboard will be initialized later now - /*if (!Driver->enableLowLevelKeyboard (true)) - { - ExitClientError (CI18N::get ("can_t_initialise_the_keyboard").toUtf8 ().c_str ()); - // ExitClientError() call exit() so the code after is never called - return; - } - Driver->enableLowLevelKeyboard (false); - */ - } - // Set the monitor color properties CMonitorColorProperties monitorColor; for ( uint i=0; i<3; i++) @@ -1189,7 +1167,7 @@ void prelogInit() CBloomEffect::getInstance().setDriver(Driver); // init bloom effect - CBloomEffect::getInstance().init(driver != UDriver::Direct3d); + CBloomEffect::getInstance().init(); if (StereoDisplay) // VR_CONFIG { diff --git a/code/ryzom/client/src/init_main_loop.cpp b/code/ryzom/client/src/init_main_loop.cpp index 60f4fedb9..390b82e15 100644 --- a/code/ryzom/client/src/init_main_loop.cpp +++ b/code/ryzom/client/src/init_main_loop.cpp @@ -40,6 +40,8 @@ #include "nel/3d/u_cloud_scape.h" #include "nel/3d/u_shape_bank.h" #include "nel/3d/u_water_env_map.h" +#include "nel/3d/material.h" +#include "nel/3d/fxaa.h" // Sound #include "nel/sound/u_audio_mixer.h" // Client @@ -125,6 +127,8 @@ namespace R2 extern bool ReloadUIFlag; } +extern bool SetMousePosFirstTime; + extern EGSPD::CSeason::TSeason ManualSeasonValue; UTextureFile *LoadingBitmap = NULL; UTextureFile *LoadingBitmapFull = NULL; @@ -149,8 +153,12 @@ bool UseEscapeDuringLoading = USE_ESCAPE_DURING_LOADING; #define ENTITY_TEXTURE_NORMAL_LEVEL 1 #define ENTITY_TEXTURE_HIGH_LEVEL 0 // Size in MB of the cache for entity texturing. -#define ENTITY_TEXTURE_NORMAL_MEMORY 10 -#define ENTITY_TEXTURE_HIGH_MEMORY 40 +#define ENTITY_TEXTURE_NORMAL_MEMORY 40 +#define ENTITY_TEXTURE_HIGH_MEMORY 160 +// Size in KB of max upload per frame +#define ENTITY_TEXTURE_LOW_MAXUP 64 +#define ENTITY_TEXTURE_NORMAL_MAXUP 128 +#define ENTITY_TEXTURE_HIGH_MAXUP 256 // Don't Modify, set true for debug purpose only const bool DBG_DisablePreloadShape= false; @@ -563,6 +571,9 @@ void initMainLoop() if(Scene == 0) nlerror("initMainLoop : Cannot create a Scene."); + // create effects + if (ClientCfg.FXAA && !FXAA) FXAA = new NL3D::CFXAA(Driver); + // use this scene for bloom effect CBloomEffect::getInstance().setScene(Scene); @@ -878,8 +889,10 @@ void initMainLoop() { // setup "v2 texture" (or 512*512) Driver->setupAsyncTextureLod(ENTITY_TEXTURE_COARSE_LEVEL, ENTITY_TEXTURE_HIGH_LEVEL); - // Allow a big cache for them (should be on 128 Mo card only) + // Allow a big cache for them (should be on 512 Mo card only) Driver->setupMaxTotalAsyncTextureSize(ENTITY_TEXTURE_HIGH_MEMORY*1024*1024); + // Allow high upload + Driver->setupAsyncTextureMaxUploadPerFrame(ENTITY_TEXTURE_HIGH_MAXUP*1024); } else { @@ -887,6 +900,8 @@ void initMainLoop() Driver->setupAsyncTextureLod(ENTITY_TEXTURE_COARSE_LEVEL, ENTITY_TEXTURE_NORMAL_LEVEL); // Allow a big cache for them Driver->setupMaxTotalAsyncTextureSize(ENTITY_TEXTURE_NORMAL_MEMORY*1024*1024); + // Allow normal upload + Driver->setupAsyncTextureMaxUploadPerFrame(ENTITY_TEXTURE_NORMAL_MAXUP*1024); } } else @@ -897,6 +912,8 @@ void initMainLoop() Driver->setupAsyncTextureLod(ENTITY_TEXTURE_COARSE_LEVEL-1, ENTITY_TEXTURE_NORMAL_LEVEL-1); // Allow a big cache for them Driver->setupMaxTotalAsyncTextureSize(ENTITY_TEXTURE_NORMAL_MEMORY*1024*1024); + // Allow low upload + Driver->setupAsyncTextureMaxUploadPerFrame(ENTITY_TEXTURE_LOW_MAXUP*1024); } } @@ -1253,7 +1270,8 @@ void initMainLoop() // NLMEMORY::CheckHeap (true); // Re-initialise the mouse (will be now in hardware mode, if required) - InitMouseWithCursor (ClientCfg.HardwareCursor); // the return value of enableLowLevelMouse() has already been tested at startup + SetMousePosFirstTime = true; + InitMouseWithCursor (ClientCfg.HardwareCursor && !StereoDisplayAttached); // the return value of enableLowLevelMouse() has already been tested at startup // Re-initialise the keyboard, now in low-level mode, if required // NB nico : done at end of loading @@ -1496,6 +1514,7 @@ void initWelcomeWindow() // *************************************************************************** +// NOTE: This feature is not really used anymore, it is a patch transition void initHardwareCursor(bool secondCall) { CInterfaceManager * pIM = CInterfaceManager::getInstance(); @@ -1571,6 +1590,7 @@ void initBloomConfigUI() if(group) group->setDefaultContextHelp(CI18N::get("uiFxTooltipBloom")); + ClientCfg.writeBool("FXAA", false); ClientCfg.writeBool("Bloom", false); ClientCfg.writeBool("SquareBloom", false); ClientCfg.writeInt("DensityBloom", 0); diff --git a/code/ryzom/client/src/input.cpp b/code/ryzom/client/src/input.cpp index eff4e2bc9..6d0834f07 100644 --- a/code/ryzom/client/src/input.cpp +++ b/code/ryzom/client/src/input.cpp @@ -21,6 +21,7 @@ ///////////// #include "stdpch.h" // Client +#include "global.h" #include "actions.h" #include "input.h" #include "interface_v3/interface_manager.h" @@ -30,7 +31,6 @@ // 3D #include "nel/3d/u_driver.h" // Misc -#include "nel/misc/mouse_device.h" #include "nel/misc/mouse_smoother.h" #include "nel/misc/system_utils.h" // Game Share @@ -54,7 +54,6 @@ extern CActionsManager Actions; // Actions Manager. //////////// // GLOBAL // //////////// -IMouseDevice *MouseDevice = NULL; bool MouseHardware = false; bool MouseFreeLook = false; float MouseCursorSpeed = 1.f; @@ -81,93 +80,40 @@ bool InitMouseWithCursor (bool hardware) { Driver->showCursor(false); - // First init ? - if (MouseDevice) - { - // No.. change soft to hard or hard to soft ? - if (hardware ^ MouseHardware) - { - // Ok, reinit the mouse - Driver->enableLowLevelMouse (false, false); - MouseDevice = NULL; - MouseHardware = false; - } - } - // Get the new mouse state MouseHardware = hardware; CViewPointer::setHWMouse( hardware ); - // Reinit ? - if (MouseDevice == NULL) + // Update mouse information + UpdateMouse (); + + if (InitMouseFirstTime) { - if (!ClientCfg.DisableDirectInput) + InitMouseFirstTime = false; + } + else + { + if (!MouseFreeLook) { - // mouse capture not taken in account for hardware mouse - MouseDevice = Driver->enableLowLevelMouse(true, hardware); - if (!MouseDevice) - return false; - } - - // Update mouse information - UpdateMouse (); - - if (InitMouseFirstTime) - { - InitMouseFirstTime = false; - } - else - { - if (!MouseFreeLook) + // Get the current mouse position + CInterfaceManager *pIm = CInterfaceManager::getInstance(); + CViewPointer *vp = static_cast< CViewPointer* >( CWidgetManager::getInstance()->getPointer() ); + Driver->showCursor(hardware); + if (vp) { - // Get the current mouse position - if (hardware) + float x = (float) vp->getX(); + float y = (float) vp->getY(); + // First, hide the hardware mouse + uint width = Driver->getWindowWidth(); + uint height = Driver->getWindowHeight(); + if (SetMousePosFirstTime) { - Driver->showCursor(true); - - CViewPointer *pointer = static_cast< CViewPointer* >( CWidgetManager::getInstance()->getPointer() ); - if (pointer) - { - float x = (float)pointer->getX()/(float)Driver->getWindowWidth(); - float y = (float)pointer->getY()/(float)Driver->getWindowHeight(); - - if (SetMousePosFirstTime) - { - SetMousePosFirstTime = false; - } - else - { - Driver->setMousePos(x, y); - nlwarning("mouse pos %f,%f", x, y); - } - - } - } - else - { - CInterfaceManager *pIm = CInterfaceManager::getInstance(); - CViewPointer *vp = static_cast< CViewPointer* >( CWidgetManager::getInstance()->getPointer() ); - Driver->showCursor(false); SetMousePosFirstTime = false; - if (vp) - { - float x = (float) vp->getX(); - float y = (float) vp->getY(); - // First, hide the hardware mouse - if (MouseDevice) - { - MouseDevice->setMousePos(x, y); - } - else - { - uint width = Driver->getWindowWidth(); - uint height = Driver->getWindowHeight(); - if (width != 0 && height != 0) - { - Driver->setMousePos(x / width, y / height); - } - } - } + } + else if (width != 0 && height != 0) + { + nlwarning("mouse pos %u, %u", x, y); + Driver->setMousePos(x / width, y / height); } } } @@ -187,45 +133,6 @@ bool IsMouseCursorHardware () // Set the mouse mode. Call this method once per frame to update window size void UpdateMouse () { - // Freelook ? - if (MouseFreeLook) - { - // Raw mode - if (MouseDevice) - { - MouseDevice->setMessagesMode(IMouseDevice::RawMode); - MouseDevice->setMouseAcceleration(ClientCfg.FreeLookAcceleration); - } - else - { - // no mouse device implementation on X11 and Cocoa, emulate raw mode - Driver->emulateMouseRawMode(true); - } - } - else - { - // Set the mouse properties - if (MouseDevice) - { - // Get the driver size - uint32 width, height; - Driver->getWindowSize(width, height); - - MouseDevice->setMessagesMode(IMouseDevice::NormalMode); - MouseDevice->setMouseMode(IMouseDevice::XAxis, IMouseDevice::Clamped); - MouseDevice->setMouseMode(IMouseDevice::YAxis, IMouseDevice::Clamped); - CRect window (0, 0, width, height); - MouseDevice->setMouseFrame(window); - MouseDevice->setFactors(1.f/std::max((float)width, 1.0f), 1.f/std::max((float)height, 1.0f)); - MouseDevice->setMouseSpeed(MouseCursorSpeed); - MouseDevice->setMouseAcceleration(MouseCursorAcceleration); - } - else - { - // no mouse device implementation on X11 and Cocoa, emulate raw mode - Driver->emulateMouseRawMode(false); - } - } if (!Driver->isSystemCursorCaptured()) { DownMouseButtons = 0; @@ -303,19 +210,7 @@ void SetMouseCursor (bool updatePos) if (updatePos) { - if (MouseDevice) - { - MouseDevice->setMousePos((float)ix, (float)iy); - } - else - { - Driver->setMousePos(x, y); - } - - if (MouseHardware) - { - Driver->setMousePos(x, y); - } + Driver->setMousePos(x, y); } // Update the interface pointer @@ -404,25 +299,18 @@ CNiceInputAuto::CNiceInputAuto() { if (_Count == 0) { - - Driver->enableLowLevelMouse(false, false); // but ignore direct input (win 32 msg only) - - Driver->setCursor("curs_default.tga", CRGBA::White, 0, 0x15, 0x18); Driver->showCursor(true); // keep cursor visible in windowed mode - MouseDevice = NULL; - Driver->enableLowLevelKeyboard (false); } - ++ _Count; + ++_Count; } CNiceInputAuto::~CNiceInputAuto() { - -- _Count; + --_Count; nlassert(_Count >= 0); if (_Count == 0) { - InitMouseWithCursor (ClientCfg.HardwareCursor); - Driver->enableLowLevelKeyboard (!ClientCfg.DisableDirectInputKeyboard); // the return value has already been tested at startup + InitMouseWithCursor(ClientCfg.HardwareCursor && !StereoDisplayAttached); } } diff --git a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp index 10fd2d29c..faaf86092 100644 --- a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp +++ b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp @@ -157,6 +157,7 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA CViewText *vt = new CViewText(CViewText::TCtorParam()); // get parameters from config.xml vt->setShadow(isTextShadowed()); + vt->setShadowOutline(false); vt->setFontSize(getTextFontSize()); vt->setMultiLine(true); vt->setTextMode(justified ? CViewText::Justified : CViewText::DontClipWord); diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp index a05d1e4aa..772f99418 100644 --- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp +++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text.cpp @@ -880,6 +880,7 @@ void CDBGroupListSheetText::setup() text->setFontSize(_TextTemplate.getFontSize()); text->setColor(_TextTemplate.getColor()); text->setShadow(_TextTemplate.getShadow()); + text->setShadowOutline(_TextTemplate.getShadowOutline()); text->setLineMaxW(_TextTemplate.getLineMaxW()); text->setMultiLine(_TextTemplate.getMultiLine()); if(text->getMultiLine()) diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_brick_composition.cpp b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_brick_composition.cpp index 67079ba55..c67e69660 100644 --- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_brick_composition.cpp +++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_brick_composition.cpp @@ -95,6 +95,7 @@ void CDBGroupListSheetTextBrickComposition::CSheetChildBrick::init(CDBGroupListS text->setFontSize(compoList->getTextTemplate().getFontSize()); text->setColor(compoList->getTextTemplate().getColor()); text->setShadow(compoList->getTextTemplate().getShadow()); + text->setShadowOutline(compoList->getTextTemplate().getShadowOutline()); text->setMultiLine(false); text->setModulateGlobalColor(compoList->getTextTemplate().getModulateGlobalColor()); diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_share.cpp b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_share.cpp index 35cd90a7e..fcef370e0 100644 --- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_share.cpp +++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_text_share.cpp @@ -121,6 +121,7 @@ void CDBGroupListSheetTextShare::CSheetChildShare::init(CDBGroupListSheetText *p text->setFontSize(compoList->getTextTemplate().getFontSize()); text->setColor(compoList->getTextTemplate().getColor()); text->setShadow(compoList->getTextTemplate().getShadow()); + text->setShadowOutline(compoList->getTextTemplate().getShadowOutline()); text->setMultiLine(false); text->setModulateGlobalColor(compoList->getTextTemplate().getModulateGlobalColor()); // Add it to the scrolled list. @@ -139,6 +140,7 @@ void CDBGroupListSheetTextShare::CSheetChildShare::init(CDBGroupListSheetText *p text->setFontSize(compoList->getTextTemplate().getFontSize()); text->setColor(compoList->getTextTemplate().getColor()); text->setShadow(compoList->getTextTemplate().getShadow()); + text->setShadowOutline(compoList->getTextTemplate().getShadowOutline()); text->setMultiLine(false); text->setModulateGlobalColor(compoList->getTextTemplate().getModulateGlobalColor()); // Add it to the scrolled list. diff --git a/code/ryzom/client/src/interface_v3/group_map.cpp b/code/ryzom/client/src/interface_v3/group_map.cpp index 31d70d0d7..558ab960c 100644 --- a/code/ryzom/client/src/interface_v3/group_map.cpp +++ b/code/ryzom/client/src/interface_v3/group_map.cpp @@ -2333,6 +2333,7 @@ void CGroupMap::createLMWidgets(const std::vector &lms) pNewText->setColor(CRGBA(255,255,255,255)); pNewText->setShadow(true); + pNewText->setShadowOutline(false); pNewText->setShadowColor(CRGBA(0,0,0,255)); pNewText->setModulateGlobalColor(false); pNewText->Type = rCLM.Type; diff --git a/code/ryzom/client/src/interface_v3/input_handler_manager.cpp b/code/ryzom/client/src/interface_v3/input_handler_manager.cpp index 62eac876c..48582652a 100644 --- a/code/ryzom/client/src/interface_v3/input_handler_manager.cpp +++ b/code/ryzom/client/src/interface_v3/input_handler_manager.cpp @@ -20,7 +20,6 @@ #include "nel/misc/i_xml.h" #include "nel/misc/file.h" -#include "nel/misc/game_device_events.h" #include "nel/misc/xml_auto_ptr.h" @@ -92,7 +91,6 @@ void CInputHandlerManager::addToServer(NLMISC::CEventServer * server) _EventServer = server; // System - server->addListener(EventGDMouseMove, this); server->addListener(EventDestroyWindowId, this); server->addListener(EventCloseWindowId, this); server->addListener(EventSetFocusId, this); @@ -117,7 +115,6 @@ void CInputHandlerManager::addToServer(NLMISC::CEventServer * server) void CInputHandlerManager::release() { // System - _EventServer->removeListener(EventGDMouseMove, this); _EventServer->removeListener(EventDestroyWindowId, this); _EventServer->removeListener(EventCloseWindowId, this); _EventServer->removeListener(EventSetFocusId, this); @@ -304,7 +301,7 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) handled |= R2::getEditor().handleEvent(eventDesc); } } - handled |= inputHandler.handleMouseButtonDownEvent( event ); + handled |= inputHandler.handleMouseButtonDownEvent( event ); } // button up ? else if (event==EventMouseUpId) diff --git a/code/ryzom/client/src/landscape_poly_drawer.h b/code/ryzom/client/src/landscape_poly_drawer.h index 73d7fcadc..865112223 100644 --- a/code/ryzom/client/src/landscape_poly_drawer.h +++ b/code/ryzom/client/src/landscape_poly_drawer.h @@ -97,7 +97,9 @@ private: // renderScene is called in main loop. It can called beginRenderLandscapePolyPart and renderLandscapePolyPart // methods. - friend void renderScene(); + friend void beginRenderScene(); + friend void drawRenderScene(bool wantTraversals, bool keepTraversals); + friend void endRenderScene(bool keepTraversals); // Enable stencil test and initialize function and operation of stencil at the beginning of renderScene method, // before opaque render of canopy and main scene parts. diff --git a/code/ryzom/client/src/login.cpp b/code/ryzom/client/src/login.cpp index 210afcea9..091e24a80 100644 --- a/code/ryzom/client/src/login.cpp +++ b/code/ryzom/client/src/login.cpp @@ -73,6 +73,8 @@ using namespace std; // *************************************************************************** +extern bool SetMousePosFirstTime; + vector Shards; string LoginLogin, LoginPassword, ClientApp, Salt; @@ -114,7 +116,7 @@ vector R2PatchURLs; #define CTRL_EDITBOX_CREATEACCOUNT_LOGIN "ui:login:create_account:content:submit_gr:eb_login:eb" #define CTRL_EDITBOX_CREATEACCOUNT_PASSWORD "ui:login:create_account:content:submit_gr:eb_password:eb" #define CTRL_EDITBOX_CREATEACCOUNT_CONFIRMPASSWORD "ui:login:create_account:content:submit_gr:eb_confirm_password:eb" -#define CTRL_EDITBOX_CREATEACCOUNT_EMAIL "ui:login:create_account:content:submit_gr:eb_email:eb" +#define CTRL_EDITBOX_CREATEACCOUNT_EMAIL "ui:login:create_account:content:submit_gr:eb_email:eb" #define UI_VARIABLES_SCREEN_CHECKPASS 0 #define UI_VARIABLES_SCREEN_SHARDDISP 1 @@ -857,16 +859,15 @@ bool login() IngameDbMngr.flushObserverCalls(); NLGUI::CDBManager::getInstance()->flushObserverCalls(); - bool tmpDI = ClientCfg.DisableDirectInput; - ClientCfg.DisableDirectInput = true; + SetMousePosFirstTime = true; InitMouseWithCursor(false); Driver->showCursor (false); SetMouseFreeLook (); SetMouseCursor (false); SetMouseSpeed (ClientCfg.CursorSpeed); SetMouseAcceleration (ClientCfg.CursorAcceleration); - InitMouseWithCursor (ClientCfg.HardwareCursor); - ClientCfg.DisableDirectInput = tmpDI; + SetMousePosFirstTime = true; + InitMouseWithCursor (ClientCfg.HardwareCursor && !StereoDisplayAttached); // if (ClientCfg.TestBrowser) // { @@ -1989,6 +1990,7 @@ class CAHInitResLod : public IActionHandler CfgPresetList.push_back(pair("NbMaxSkeletonNotCLod", false)); CfgPresetList.push_back(pair("CharacterFarClip", true)); + CfgPresetList.push_back(pair("FXAA", false)); CfgPresetList.push_back(pair("Bloom", false)); CfgPresetList.push_back(pair("SquareBloom", false)); CfgPresetList.push_back(pair("DensityBloom", true)); @@ -2410,7 +2412,7 @@ bool initCreateAccount() rulesGr->setActive(false); // must be done after hide rules - CAHManager::getInstance()->runActionHandler("set_keyboard_focus", NULL, "target=" CTRL_EDITBOX_CREATEACCOUNT_LOGIN "|select_all=false"); + CAHManager::getInstance()->runActionHandler("set_keyboard_focus", NULL, "target=" CTRL_EDITBOX_CREATEACCOUNT_LOGIN "|select_all=false"); } diff --git a/code/ryzom/client/src/main_loop.cpp b/code/ryzom/client/src/main_loop.cpp index 0d000310d..9b39c53c9 100644 --- a/code/ryzom/client/src/main_loop.cpp +++ b/code/ryzom/client/src/main_loop.cpp @@ -43,6 +43,9 @@ #include "nel/3d/u_instance_material.h" #include "nel/3d/u_cloud_scape.h" #include "nel/3d/stereo_hmd.h" +#include "nel/3d/render_target_manager.h" +#include "nel/3d/driver_user.h" +#include "nel/3d/fxaa.h" // game share #include "game_share/brick_types.h" #include "game_share/light_cycle.h" @@ -165,7 +168,6 @@ using namespace std; // EXTERN // //////////// extern UDriver *Driver; -extern IMouseDevice *MouseDevice; extern UScene *Scene; extern UScene *SceneRoot; extern ULandscape *Landscape; @@ -421,9 +423,9 @@ void beginRenderMainScenePart() { Scene->beginPartRender(); } -void endRenderMainScenePart() +void endRenderMainScenePart(bool keepTraversals) { - Scene->endPartRender(true); + Scene->endPartRender(!keepTraversals, true, keepTraversals); } void beginRenderSkyPart() @@ -460,7 +462,7 @@ static void renderCanopyPart(UScene::TRenderPart renderPart) // *************************************************************************************************************************** // Render a part of the main scene -static void renderMainScenePart(UScene::TRenderPart renderPart) +static void renderMainScenePart(UScene::TRenderPart renderPart, bool wantTraversals, bool keepTraversals) { H_AUTO_USE ( RZ_Client_Main_Loop_Render_Main ) Driver->setDepthRange(0.f, CANOPY_DEPTH_RANGE_START); @@ -472,7 +474,7 @@ static void renderMainScenePart(UScene::TRenderPart renderPart) { MainFogState.setupInDriver (*Driver); } - Scene->renderPart(renderPart); + Scene->renderPart(renderPart, true, wantTraversals, keepTraversals); } @@ -562,13 +564,15 @@ void clearBuffers() void renderScene(bool forceFullDetail, bool bloom) { + CTextureUser *effectRenderTarget = NULL; if (bloom) { // set bloom parameters before applying bloom effect CBloomEffect::getInstance().setSquareBloom(ClientCfg.SquareBloom); CBloomEffect::getInstance().setDensityBloom((uint8)ClientCfg.DensityBloom); - // init bloom - CBloomEffect::getInstance().initBloom(); + + // init effect render target + Driver->beginDefaultRenderTarget(); } if (forceFullDetail) { @@ -576,7 +580,7 @@ void renderScene(bool forceFullDetail, bool bloom) s_ForceFullDetail.set(); } clearBuffers(); - renderScene(); + doRenderScene(true, false); if (forceFullDetail) { s_ForceFullDetail.restore(); @@ -584,8 +588,10 @@ void renderScene(bool forceFullDetail, bool bloom) if (bloom) { // apply bloom effect - CBloomEffect::getInstance().endBloom(); - CBloomEffect::getInstance().endInterfacesDisplayBloom(); + CBloomEffect::getInstance().applyBloom(); + + // draw final result to backbuffer + Driver->endDefaultRenderTarget(Scene); } } @@ -661,7 +667,7 @@ void updateWeather() updateClouds(); } #endif - + ContinentMngr.getFogState(MainFog, LightCycleManager.getLightLevel(), LightCycleManager.getLightDesc().DuskRatio, LightCycleManager.getState(), View.viewPos(), MainFogState); // TODO: ZBuffer clear was originally before this, but should not be necessary normally. @@ -687,7 +693,7 @@ void updateWeather() Driver->setPolygonMode(oldMode); } #endif - + // Update new sky s_SkyMode = NoSky; if (ContinentMngr.cur() && !ContinentMngr.cur()->Indoor) @@ -713,9 +719,7 @@ void updateWeather() } } -// *************************************************************************************************************************** -// Render all scenes -void renderScene() +void beginRenderScene() { // Update Filter Flags Scene->enableElementRender(UScene::FilterAllMeshNoVP, Filter3D[FilterMeshNoVP]); @@ -737,28 +741,45 @@ void renderScene() beginRenderCanopyPart(); beginRenderMainScenePart(); beginRenderSkyPart(); +} + +void drawRenderScene(bool wantTraversals, bool keepTraversals) +{ // Render part // WARNING: always must begin rendering with at least UScene::RenderOpaque, // else dynamic shadows won't work renderCanopyPart(UScene::RenderOpaque); - renderMainScenePart(UScene::RenderOpaque); + renderMainScenePart(UScene::RenderOpaque, wantTraversals, keepTraversals); // render of polygons on landscape CLandscapePolyDrawer::getInstance().renderLandscapePolyPart(); if (s_SkyMode != NoSky) renderSkyPart((UScene::TRenderPart) (UScene::RenderOpaque | UScene::RenderTransparent)); renderCanopyPart((UScene::TRenderPart) (UScene::RenderTransparent | UScene::RenderFlare)); - renderMainScenePart((UScene::TRenderPart) (UScene::RenderTransparent | UScene::RenderFlare)); + renderMainScenePart((UScene::TRenderPart) (UScene::RenderTransparent | UScene::RenderFlare), wantTraversals, keepTraversals); if (s_SkyMode == NewSky) renderSkyPart(UScene::RenderFlare); +} + +void endRenderScene(bool keepTraversals) +{ // End Part Rendering endRenderSkyPart(); - endRenderMainScenePart(); + endRenderMainScenePart(keepTraversals); endRenderCanopyPart(); // reset depth range Driver->setDepthRange(0.f, CANOPY_DEPTH_RANGE_START); } +// *************************************************************************************************************************** +// Render all scenes +void doRenderScene(bool wantTraversals, bool keepTraversals) +{ + beginRenderScene(); + drawRenderScene(wantTraversals, keepTraversals); + endRenderScene(keepTraversals); +} + // *************************************************************************** class CMusicFader @@ -992,6 +1013,7 @@ bool mainLoop() SetMouseCursor (); // Set the cursor. ContextCur.context("STAND BY"); + UserControls.reset(); // set the default box for keyboard setDefaultChatWindow(PeopleInterraction.ChatGroup.Window); @@ -1387,8 +1409,20 @@ bool mainLoop() MainCam.setRotQuat(View.currentViewQuat()); if (StereoHMD) { + CMatrix camMatrix; + camMatrix.translate(MainCam.getMatrix().getPos()); + CVector dir = MainCam.getMatrix().getJ(); + dir.z = 0; + dir.normalize(); + if (dir.y < 0) + camMatrix.rotateZ(float(NLMISC::Pi+asin(dir.x))); + else + camMatrix.rotateZ(float(NLMISC::Pi+NLMISC::Pi-asin(dir.x))); + + StereoHMD->setInterfaceMatrix(camMatrix); + NLMISC::CQuat hmdOrient = StereoHMD->getOrientation(); - NLMISC::CMatrix camMatrix = MainCam.getMatrix(); + // NLMISC::CMatrix camMatrix = MainCam.getMatrix(); NLMISC::CMatrix hmdMatrix; hmdMatrix.setRot(hmdOrient); NLMISC::CMatrix posMatrix; // minimal head modeling, will be changed in the future @@ -1396,8 +1430,15 @@ bool mainLoop() NLMISC::CMatrix mat = ((camMatrix * hmdMatrix) * posMatrix); MainCam.setPos(mat.getPos()); MainCam.setRotQuat(mat.getRot()); + + if (true) // TODO: ClientCfg.Headphone + { + // NOTE: non-(StereoHMD+Headphone) impl in user_entity.cpp + SoundMngr->setListenerPos(mat.getPos()); // TODO: Move ears back ... :) + SoundMngr->setListenerOrientation(mat.getJ(), mat.getK()); + } } - if (StereoDisplay) + if (StereoDisplay) { StereoDisplay->updateCamera(0, &MainCam); if (SceneRoot) @@ -1596,14 +1637,31 @@ bool mainLoop() { // Update water env map (happens when continent changed etc) updateWaterEnvMap(); - + // Update weather updateWeather(); } } - + uint i = 0; - uint bloomStage = 0; + CTextureUser *effectRenderTarget = NULL; + bool haveEffects = Render && Driver->getPolygonMode() == UDriver::Filled + && (ClientCfg.Bloom || FXAA); + bool defaultRenderTarget = false; + if (haveEffects) + { + if (!StereoDisplay) + { + Driver->beginDefaultRenderTarget(); + defaultRenderTarget = true; + } + if (ClientCfg.Bloom) + { + CBloomEffect::getInstance().setSquareBloom(ClientCfg.SquareBloom); + CBloomEffect::getInstance().setDensityBloom((uint8)ClientCfg.DensityBloom); + } + } + bool fullDetail = false; while ((!StereoDisplay && i == 0) || (StereoDisplay && StereoDisplay->nextPass())) { ++i; @@ -1635,60 +1693,68 @@ bool mainLoop() // Commit camera changes commitCamera(); - + ////////////////////////// // RENDER THE FRAME 3D // ////////////////////////// bool stereoRenderTarget = (StereoDisplay != NULL) && StereoDisplay->beginRenderTarget(); - + if (!StereoDisplay || StereoDisplay->wantClear()) { - if (Render) - { - if (ClientCfg.Bloom) - { - nlassert(bloomStage == 0); - // set bloom parameters before applying bloom effect - CBloomEffect::getInstance().setSquareBloom(ClientCfg.SquareBloom); - CBloomEffect::getInstance().setDensityBloom((uint8)ClientCfg.DensityBloom); - // start bloom effect (just before the first scene element render) - CBloomEffect::instance().initBloom(); - bloomStage = 1; - } - } - // Clear buffers clearBuffers(); } if (!StereoDisplay || StereoDisplay->wantScene()) { - if (!ClientCfg.Light) + if (!ClientCfg.Light && Render) { - // Render - if(Render) + if (!StereoDisplay || StereoDisplay->isSceneFirst()) { // nb : force full detail if a screenshot is asked // todo : move outside render code - bool fullDetail = ScreenshotRequest != ScreenshotRequestNone && ClientCfg.ScreenShotFullDetail; - if (fullDetail) + if (!fullDetail) { - s_ForceFullDetail.backup(); - s_ForceFullDetail.set(); + fullDetail = ScreenshotRequest != ScreenshotRequestNone && ClientCfg.ScreenShotFullDetail; + if (fullDetail) + { + s_ForceFullDetail.backup(); + s_ForceFullDetail.set(); + } } - - // Render scene - renderScene(); + } + // Render scene + bool wantTraversals = !StereoDisplay || StereoDisplay->isSceneFirst(); + bool keepTraversals = StereoDisplay && !StereoDisplay->isSceneLast(); + doRenderScene(wantTraversals, keepTraversals); + + if (!StereoDisplay || StereoDisplay->isSceneLast()) + { if (fullDetail) { s_ForceFullDetail.restore(); + fullDetail = false; } } } } + if (!StereoDisplay || StereoDisplay->wantSceneEffects()) + { + if (!ClientCfg.Light && Render && haveEffects) + { + if (StereoDisplay) Driver->setViewport(NL3D::CViewport()); + UCamera pCam = Scene->getCam(); + Driver->setMatrixMode2D11(); + if (FXAA) FXAA->applyEffect(); + if (ClientCfg.Bloom) CBloomEffect::instance().applyBloom(); + Driver->setMatrixMode3D(pCam); + if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport()); + } + } + if (!StereoDisplay || StereoDisplay->wantInterface3D()) { if (!ClientCfg.Light) @@ -1696,15 +1762,6 @@ bool mainLoop() // Render if (Render) { - if (ClientCfg.Bloom && bloomStage == 1) - { - // End the actual bloom effect visible in the scene. - if (StereoDisplay) Driver->setViewport(NL3D::CViewport()); - CBloomEffect::instance().endBloom(); - if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport()); - bloomStage = 2; - } - // for that frame and // tmp : display height grid //static volatile bool displayHeightGrid = true; @@ -1823,14 +1880,14 @@ bool mainLoop() // special case in OpenGL : all scene has been display in render target, // now, final texture is display with a quad - if (!ClientCfg.Light && ClientCfg.Bloom && Render && bloomStage == 2) + /*if (!ClientCfg.Light && ClientCfg.Bloom && Render && bloomStage == 2) // NO VR BLOOMZ { // End bloom effect system after drawing the 3d interface (z buffer related). if (StereoDisplay) Driver->setViewport(NL3D::CViewport()); CBloomEffect::instance().endInterfacesDisplayBloom(); if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport()); bloomStage = 0; - } + }*/ } { @@ -1868,6 +1925,7 @@ bool mainLoop() // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(10); // Set the text color @@ -2144,6 +2202,12 @@ bool mainLoop() } } /* stereo pass */ + if (defaultRenderTarget) + { + // draw final result to backbuffer + Driver->endDefaultRenderTarget(Scene); + } + // Draw to screen. static CQuat MainCamOri; if (FirstFrame) @@ -2400,6 +2464,7 @@ bool mainLoop() SetMouseCursor (); // Set the cursor. ContextCur.context("STAND BY"); + UserControls.reset(); // set the default box for keyboard CChatWindow *defaultChatWindow; @@ -2446,7 +2511,7 @@ bool mainLoop() connectionState = NetMngr.getConnectionState(); CLuaManager::getInstance().executeLuaScript("game:onFarTpEnd()"); - } + } /////////////// // <- FAR_TP // /////////////// @@ -2524,6 +2589,7 @@ void displaySpecialTextProgress(const char *text) { // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(12); // Set the text color @@ -3184,7 +3250,7 @@ NLMISC_COMMAND(debugUI, "Debug the ui : show/hide quads of bboxs and hotspots", else fromString(args[0], on); } - + CGroupCell::setDebugUICell( on ); DebugUIView = on; DebugUICtrl = on; diff --git a/code/ryzom/client/src/main_loop.h b/code/ryzom/client/src/main_loop.h index 21f64d37e..93e4db36d 100644 --- a/code/ryzom/client/src/main_loop.h +++ b/code/ryzom/client/src/main_loop.h @@ -29,7 +29,7 @@ const uint NUM_MISSION_OPTIONS = 8; bool mainLoop(); // render all -void renderScene(); +void doRenderScene(bool wantTraversals, bool keepTraversals); void renderScene(bool forceFullDetail, bool bloom); void setDefaultChatWindow(CChatWindow *defaultChatWindow); diff --git a/code/ryzom/client/src/main_loop_debug.cpp b/code/ryzom/client/src/main_loop_debug.cpp index 8b224f27f..19ea38414 100644 --- a/code/ryzom/client/src/main_loop_debug.cpp +++ b/code/ryzom/client/src/main_loop_debug.cpp @@ -80,6 +80,7 @@ void displayDebug() //----------------// // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(ClientCfg.DebugFontSize); // Set the text color @@ -470,6 +471,7 @@ void displayDebug() // No more shadow when displaying a text. TextContext->setShaded(false); + TextContext->setShadeOutline(false); }// displayDebug // // ******************************************************************** @@ -491,6 +493,7 @@ void displayDebugFps() //----------------// // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(ClientCfg.DebugFontSize); // Set the text color @@ -533,6 +536,7 @@ void displayDebugUIUnderMouse() //----------------// // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(ClientCfg.DebugFontSize); @@ -707,6 +711,7 @@ void displayHelp() // Create a shadow when displaying a text. TextContext->setShaded(true); + TextContext->setShadeOutline(false); // Set the font size. TextContext->setFontSize(ClientCfg.HelpFontSize); // Set the text color @@ -763,6 +768,7 @@ void displayHelp() // No more shadow when displaying a text. TextContext->setShaded(false); + TextContext->setShadeOutline(false); }// displayHelp // // ******************************************************************** diff --git a/code/ryzom/client/src/main_loop_utilities.cpp b/code/ryzom/client/src/main_loop_utilities.cpp index 194810ea9..cdd3f8394 100644 --- a/code/ryzom/client/src/main_loop_utilities.cpp +++ b/code/ryzom/client/src/main_loop_utilities.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include "game_share/scenario_entry_points.h" @@ -57,8 +59,22 @@ void updateFromClientCfg() ))) { nldebug("Apply VR device change"); + // detach display mode + if (StereoDisplay && StereoDisplayAttached) + StereoDisplay->detachFromDisplay(); + StereoDisplayAttached = false; + // re-init releaseStereoDisplayDevice(); initStereoDisplayDevice(); + // try attach display mode + if (StereoDisplay) + StereoDisplayAttached = StereoDisplay->attachToDisplay(); + // set latest config display mode if not attached + if (!StereoDisplayAttached) + setVideoMode(UDriver::CMode(ClientCfg.Width, ClientCfg.Height, (uint8)ClientCfg.Depth, + ClientCfg.Windowed, ClientCfg.Frequency)); + // force software cursor when attached + InitMouseWithCursor(ClientCfg.HardwareCursor && !StereoDisplayAttached); } // GRAPHICS - GENERAL @@ -69,8 +85,11 @@ void updateFromClientCfg() (ClientCfg.Depth != LastClientCfg.Depth) || (ClientCfg.Frequency != LastClientCfg.Frequency)) { - setVideoMode(UDriver::CMode(ClientCfg.Width, ClientCfg.Height, (uint8)ClientCfg.Depth, - ClientCfg.Windowed, ClientCfg.Frequency)); + if (!StereoDisplayAttached) + { + setVideoMode(UDriver::CMode(ClientCfg.Width, ClientCfg.Height, (uint8)ClientCfg.Depth, + ClientCfg.Windowed, ClientCfg.Frequency)); + } } if (ClientCfg.DivideTextureSizeBy2 != LastClientCfg.DivideTextureSizeBy2) @@ -218,6 +237,22 @@ void updateFromClientCfg() } } + //--------------------------------------------------- + if (ClientCfg.FXAA != LastClientCfg.FXAA) + { + if (ClientCfg.FXAA) + { + nlassert(!FXAA); + FXAA = new NL3D::CFXAA(Driver); + } + else + { + nlassert(FXAA); + delete FXAA; + FXAA = NULL; + } + } + // GRAPHICS - CHARACTERS //--------------------------------------------------- if (ClientCfg.SkinNbMaxPoly != LastClientCfg.SkinNbMaxPoly) @@ -259,7 +294,7 @@ void updateFromClientCfg() { if (ClientCfg.HardwareCursor != IsMouseCursorHardware()) { - InitMouseWithCursor (ClientCfg.HardwareCursor); + InitMouseWithCursor (ClientCfg.HardwareCursor && !StereoDisplayAttached); } } diff --git a/code/ryzom/client/src/motion/user_controls.cpp b/code/ryzom/client/src/motion/user_controls.cpp index 527bfb5d4..897cba9c1 100644 --- a/code/ryzom/client/src/motion/user_controls.cpp +++ b/code/ryzom/client/src/motion/user_controls.cpp @@ -174,6 +174,10 @@ void CUserControls::init() }// init // +void CUserControls::reset() +{ + init(); +} //----------------------------------------------- // needReleaseForward : @@ -414,7 +418,6 @@ void CUserControls::keyboardRotationCameraLR (bool left, bool right) _RotateCameraLRVelocity = 0; } - //----------------------------------------------- // getMouseAngleMove //----------------------------------------------- @@ -424,13 +427,9 @@ void CUserControls::getMouseAngleMove(float &dx, float &dy) dy = 0.0f; // The mouse may still "StandardMove" ie through a CEventMouseMove - // This can happens cause DirectInputDisabled, or because of the - // "Rotation Anti-Lag system" which start to rotate before the mouse is hid - // and message mode passed to RawMode - // - // On X11 and Cocoa, there is no MouseDevice, do it without. - - extern IMouseDevice *MouseDevice; + // This can happen because of the "Rotation Anti-Lag system" which + // start to rotate before the mouse is hid and message mode passed + // to updateFreeLookPos // if the mouse position changed if( EventsListener.getMousePosX() != _LastFrameMousePosX || @@ -441,28 +440,23 @@ void CUserControls::getMouseAngleMove(float &dx, float &dy) float dmpy= EventsListener.getMousePosY() - _LastFrameMousePosY; // simulate mickeys mode if there is a mouse device - if (MouseDevice) - MouseDevice->convertStdMouseMoveInMickeys(dmpx, dmpy); - else - { - dmpx *= (float)Driver->getWindowWidth(); - dmpy *= (float)Driver->getWindowHeight(); - } + dmpx *= (float)Driver->getWindowWidth(); + dmpy *= (float)Driver->getWindowHeight(); // handle inverted mouse, if enabled - if(ClientCfg.FreeLookInverted) dmpy = -dmpy; - + if (ClientCfg.FreeLookInverted) dmpy = -dmpy; + // update free look EventsListener.updateFreeLookPos(dmpx, dmpy); } // If the mouse move on the axis X, with a CGDMouseMove - if(EventsListener.isMouseAngleX()) - dx = -EventsListener.getMouseAngleX (); + if (EventsListener.isMouseAngleX()) + dx = -EventsListener.getMouseAngleX(); // If the mouse move on the axis Y, with a CGDMouseMove - if(EventsListener.isMouseAngleY()) - dy = EventsListener.getMouseAngleY (); + if (EventsListener.isMouseAngleY()) + dy = EventsListener.getMouseAngleY(); } @@ -1294,7 +1288,6 @@ void CUserControls::commonSetView() } } - //----------------------------------------------- // startFreeLook() //----------------------------------------------- diff --git a/code/ryzom/client/src/motion/user_controls.h b/code/ryzom/client/src/motion/user_controls.h index eb4de2020..018b2c8e9 100644 --- a/code/ryzom/client/src/motion/user_controls.h +++ b/code/ryzom/client/src/motion/user_controls.h @@ -152,6 +152,8 @@ public: /// Constructor CUserControls(); + void reset(); + /// Return the string associated to the motion Mode. std::string modeStr() const; /// Return the motion Mode. diff --git a/code/ryzom/client/src/progress.cpp b/code/ryzom/client/src/progress.cpp index 0d5d4e4c9..2631984e7 100644 --- a/code/ryzom/client/src/progress.cpp +++ b/code/ryzom/client/src/progress.cpp @@ -33,6 +33,7 @@ #include "client_cfg.h" #include "bg_downloader_access.h" #include "nel/misc/system_utils.h" +#include "nel/3d/stereo_hmd.h" using namespace std; using namespace NLMISC; @@ -173,186 +174,252 @@ void CProgress::internalProgress (float value) if (Driver->AsyncListener.isKeyPushed (KeyUP)) selectTipsOfTheDay (TipsOfTheDayIndex+1); - // Font factor - float fontFactor = 1; - if (Driver->getWindowHeight() > 0) - fontFactor = (float)Driver->getWindowHeight() / 600.f; - fontFactor *= _FontFactor; - // Set 2d view. - Driver->setMatrixMode2D11(); - Driver->clearBuffers (CRGBA(0,0,0,0)); - - // Display the loading background. - drawLoadingBitmap (value); - - // temporary values for conversions - float x, y, width, height; - - for(uint i = 0; i < ClientCfg.Logos.size(); i++) + // Create camera for stereo mode + bool stereoHMD = StereoHMD && !MainCam.empty() && (MainCam.getTransformMode() == UCamera::RotQuat); + CVector oldPos; + CQuat oldQuat; + if (stereoHMD) { - std::vector res; - explode(ClientCfg.Logos[i], std::string(":"), res); - if(res.size()==9 && idrawBitmap(x/(float)ClientCfg.Width, y/(float)ClientCfg.Height, width/(float)ClientCfg.Width, height/(float)ClientCfg.Height, *LogoBitmaps[i]); - } + MainCam.getPos(oldPos); + MainCam.getRotQuat(oldQuat); + StereoHMD->setInterfaceMatrix(CMatrix()); // identity + NLMISC::CQuat hmdOrient = StereoHMD->getOrientation(); + NLMISC::CMatrix camMatrix; + camMatrix.identity(); + NLMISC::CMatrix hmdMatrix; + hmdMatrix.setRot(hmdOrient); + NLMISC::CMatrix posMatrix; // minimal head modeling, will be changed in the future + posMatrix.translate(StereoHMD->getEyePosition()); + NLMISC::CMatrix mat = ((camMatrix * hmdMatrix) * posMatrix); + MainCam.setPos(mat.getPos()); + MainCam.setRotQuat(mat.getRot()); + StereoDisplay->updateCamera(0, &MainCam); } - - if (TextContext != NULL) + uint i = 0; + while ((!stereoHMD && i == 0) || (stereoHMD && StereoDisplay->nextPass())) { - // Init the Pen. - TextContext->setKeep800x600Ratio(false); - TextContext->setColor(CRGBA(255,255,255)); - TextContext->setFontSize((uint)(12.f * fontFactor)); - TextContext->setHotSpot(UTextContext::TopRight); + ++i; + if (stereoHMD) + { + // modify cameras for stereo display + const CViewport &vp = StereoDisplay->getCurrentViewport(); + Driver->setViewport(vp); + StereoDisplay->getCurrentMatrix(0, &MainCam); + StereoDisplay->getCurrentFrustum(0, &MainCam); + + // begin current pass + StereoDisplay->beginRenderTarget(); + + nldebug("Cam pos: %f, %f, %f", MainCam.getPos().x, MainCam.getPos().y, MainCam.getPos().z); + } + + if (!stereoHMD || StereoDisplay->wantClear()) + { + Driver->clearBuffers(CRGBA(0, 0, 0, 0)); + } + + if (stereoHMD && StereoDisplay->wantScene()) + { + Driver->setMatrixMode3D(MainCam); + } + + if (!stereoHMD || StereoDisplay->wantInterface2D()) + { + // nldebug("Draw progress 2D"); + + // Font factor + float fontFactor = 1; + if (Driver->getWindowHeight() > 0) + fontFactor = (float)Driver->getWindowHeight() / 600.f; + fontFactor *= _FontFactor; + + // Set 2d view. + Driver->setMatrixMode2D11(); + + // Display the loading background. + drawLoadingBitmap(value); + + // temporary values for conversions + float x, y, width, height; + + for(uint i = 0; i < ClientCfg.Logos.size(); i++) + { + std::vector res; + explode(ClientCfg.Logos[i], std::string(":"), res); + if(res.size()==9 && idrawBitmap(x/(float)ClientCfg.Width, y/(float)ClientCfg.Height, width/(float)ClientCfg.Width, height/(float)ClientCfg.Height, *LogoBitmaps[i]); + } + } + + if (TextContext != NULL) + { + // Init the Pen. + TextContext->setKeep800x600Ratio(false); + TextContext->setColor(CRGBA(255,255,255)); + TextContext->setFontSize((uint)(12.f * fontFactor)); + TextContext->setHotSpot(UTextContext::TopRight); #if !FINAL_VERSION - // Display the Text. - TextContext->printAt(1, 0.98f, _ProgressMessage); + // Display the Text. + TextContext->printAt(1, 0.98f, _ProgressMessage); #else - if( ClientCfg.LoadingStringCount > 0 ) - { - TextContext->printAt(1, 0.98f, _ProgressMessage); - } + if( ClientCfg.LoadingStringCount > 0 ) + { + TextContext->printAt(1, 0.98f, _ProgressMessage); + } #endif // FINAL_VERSION - // Display the build version. - TextContext->setFontSize((uint)(12.f * fontFactor)); - TextContext->setHotSpot(UTextContext::TopRight); - string str; + // Display the build version. + TextContext->setFontSize((uint)(12.f * fontFactor)); + TextContext->setHotSpot(UTextContext::TopRight); + string str; #if FINAL_VERSION - str = "FV "; + str = "FV "; #else - str = "DEV "; + str = "DEV "; #endif - str += RYZOM_VERSION; - TextContext->printfAt(1.0f,1.0f, str.c_str()); + str += RYZOM_VERSION; + TextContext->printfAt(1.0f,1.0f, str.c_str()); - // Display the tips of the day. - TextContext->setFontSize((uint)(16.f * fontFactor)); - TextContext->setHotSpot(UTextContext::MiddleTop); - ucstring::size_type index = 0; - ucstring::size_type end = TipsOfTheDay.find((ucchar)'\n'); - if (end == string::npos) - end = TipsOfTheDay.size(); - float fY = ClientCfg.TipsY; - if (!TipsOfTheDay.empty()) - { - while (index < end) - { - // Get the line - ucstring line = TipsOfTheDay.substr (index, end-index); - - // Draw the line - TextContext->printAt(0.5f, fY, line); - fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); - - index=end+1; - end = TipsOfTheDay.find((ucchar)'\n', index); - if (end == ucstring::npos) + // Display the tips of the day. + TextContext->setFontSize((uint)(16.f * fontFactor)); + TextContext->setHotSpot(UTextContext::MiddleTop); + ucstring::size_type index = 0; + ucstring::size_type end = TipsOfTheDay.find((ucchar)'\n'); + if (end == string::npos) end = TipsOfTheDay.size(); - } - - // More help - TextContext->setFontSize((uint)(12.f * fontFactor)); - /* todo tips of the day uncomment - ucstring ucstr = CI18N::get ("uiTipsEnd"); - TextContext->printAt(0.5f, fY, ucstr); */ - fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); - fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); - } - - - - if (!_TPReason.empty()) - { - TextContext->setHotSpot(UTextContext::MiddleMiddle); - TextContext->setFontSize((uint)(14.f * fontFactor)); - TextContext->printAt(0.5f, 0.5f, _TPReason); - TextContext->setHotSpot(UTextContext::BottomLeft); - TextContext->setColor(NLMISC::CRGBA::White); - } - - - - if (!_TPCancelText.empty()) - { - if (ClientCfg.Width != 0 && ClientCfg.Height != 0) - { - TextContext->setFontSize((uint)(15.f * fontFactor)); - TextContext->setHotSpot(UTextContext::BottomLeft); - - ucstring uc = CI18N::get("uiR2EDTPEscapeToInteruptLoading") + " (" + _TPCancelText + ") - " + CI18N::get("uiDelayedTPCancel"); - UTextContext::CStringInfo info = TextContext->getStringInfo(uc); - float stringX = 0.5f - info.StringWidth/(ClientCfg.Width*2); - TextContext->printAt(stringX, 7.f / ClientCfg.Height, uc); - } - } - - - // Teleport help - //fY = ClientCfg.TeleportInfoY; - if (!ApplyTextCommands && LoadingContinent && !LoadingContinent->Indoor) - { - TextContext->setFontSize((uint)(13.f * fontFactor)); - - // Print some more info - uint32 day = RT.getRyzomDay(); - str = toString (CI18N::get ("uiTipsTeleport").toUtf8().c_str(), - CI18N::get (LoadingContinent->LocalizedName).toUtf8().c_str(), - day, - (uint)RT.getRyzomTime(), - CI18N::get ("uiSeason"+toStringEnum(CRyzomTime::getSeasonByDay(day))).toUtf8().c_str(), - CI18N::get (WeatherManager.getCurrWeatherState().LocalizedName).toUtf8().c_str()); - ucstring ucstr; - ucstr.fromUtf8 (str); - TextContext->setHotSpot(UTextContext::MiddleBottom); - TextContext->setColor(CRGBA(186, 179, 163, 255)); - TextContext->printAt(0.5f, 25/768.f, ucstr); - } - - // apply text commands - if( ApplyTextCommands ) - { - std::vector printfCommands = ClientCfg.PrintfCommands; - if(FreeTrial) printfCommands = ClientCfg.PrintfCommandsFreeTrial; - - if( !printfCommands.empty() ) - { - TextContext->setHotSpot(UTextContext::MiddleBottom); - - vector::iterator itpc; - for( itpc = printfCommands.begin(); itpc != printfCommands.end(); ++itpc ) + float fY = ClientCfg.TipsY; + if (!TipsOfTheDay.empty()) { - float x = 0.5f;//((*itpc).X / 1024.f); - float y = ((*itpc).Y / 768.f); - TextContext->setColor( (*itpc).Color ); - TextContext->setFontSize( (uint)(16.f * fontFactor)); - - // build the ucstr(s) - ucstring ucstr = CI18N::get((*itpc).Text); - vector vucstr; - ucstring sep("\n"); - splitUCString(ucstr,sep,vucstr); - - // Letter size - UTextContext::CStringInfo si = TextContext->getStringInfo(ucstring("|")); - uint fontHeight = (uint) si.StringHeight + 2; // we add 2 pixels for the gap - - uint i; - float newy = y; - for( i=0; iprintAt(x,newy, vucstr[i]); - newy = nextLine(fontHeight, Driver->getWindowHeight(), newy); + // Get the line + ucstring line = TipsOfTheDay.substr (index, end-index); + + // Draw the line + TextContext->printAt(0.5f, fY, line); + fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); + + index=end+1; + end = TipsOfTheDay.find((ucchar)'\n', index); + if (end == ucstring::npos) + end = TipsOfTheDay.size(); + } + + // More help + TextContext->setFontSize((uint)(12.f * fontFactor)); + /* todo tips of the day uncomment + ucstring ucstr = CI18N::get ("uiTipsEnd"); + TextContext->printAt(0.5f, fY, ucstr); */ + fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); + fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); + } + + + + if (!_TPReason.empty()) + { + TextContext->setHotSpot(UTextContext::MiddleMiddle); + TextContext->setFontSize((uint)(14.f * fontFactor)); + TextContext->printAt(0.5f, 0.5f, _TPReason); + TextContext->setHotSpot(UTextContext::BottomLeft); + TextContext->setColor(NLMISC::CRGBA::White); + } + + + + if (!_TPCancelText.empty()) + { + if (ClientCfg.Width != 0 && ClientCfg.Height != 0) + { + TextContext->setFontSize((uint)(15.f * fontFactor)); + TextContext->setHotSpot(UTextContext::BottomLeft); + + ucstring uc = CI18N::get("uiR2EDTPEscapeToInteruptLoading") + " (" + _TPCancelText + ") - " + CI18N::get("uiDelayedTPCancel"); + UTextContext::CStringInfo info = TextContext->getStringInfo(uc); + float stringX = 0.5f - info.StringWidth/(ClientCfg.Width*2); + TextContext->printAt(stringX, 7.f / ClientCfg.Height, uc); + } + } + + + // Teleport help + //fY = ClientCfg.TeleportInfoY; + if (!ApplyTextCommands && LoadingContinent && !LoadingContinent->Indoor) + { + TextContext->setFontSize((uint)(13.f * fontFactor)); + + // Print some more info + uint32 day = RT.getRyzomDay(); + str = toString (CI18N::get ("uiTipsTeleport").toUtf8().c_str(), + CI18N::get (LoadingContinent->LocalizedName).toUtf8().c_str(), + day, + (uint)RT.getRyzomTime(), + CI18N::get ("uiSeason"+toStringEnum(CRyzomTime::getSeasonByDay(day))).toUtf8().c_str(), + CI18N::get (WeatherManager.getCurrWeatherState().LocalizedName).toUtf8().c_str()); + ucstring ucstr; + ucstr.fromUtf8 (str); + TextContext->setHotSpot(UTextContext::MiddleBottom); + TextContext->setColor(CRGBA(186, 179, 163, 255)); + TextContext->printAt(0.5f, 25/768.f, ucstr); + } + + // apply text commands + if( ApplyTextCommands ) + { + std::vector printfCommands = ClientCfg.PrintfCommands; + if(FreeTrial) printfCommands = ClientCfg.PrintfCommandsFreeTrial; + + if( !printfCommands.empty() ) + { + TextContext->setHotSpot(UTextContext::MiddleBottom); + + vector::iterator itpc; + for( itpc = printfCommands.begin(); itpc != printfCommands.end(); ++itpc ) + { + float x = 0.5f;//((*itpc).X / 1024.f); + float y = ((*itpc).Y / 768.f); + TextContext->setColor( (*itpc).Color ); + TextContext->setFontSize( (uint)(16.f * fontFactor)); + + // build the ucstr(s) + ucstring ucstr = CI18N::get((*itpc).Text); + vector vucstr; + ucstring sep("\n"); + splitUCString(ucstr,sep,vucstr); + + // Letter size + UTextContext::CStringInfo si = TextContext->getStringInfo(ucstring("|")); + uint fontHeight = (uint) si.StringHeight + 2; // we add 2 pixels for the gap + + uint i; + float newy = y; + for( i=0; iprintAt(x,newy, vucstr[i]); + newy = nextLine(fontHeight, Driver->getWindowHeight(), newy); + } + } } } } } + + if (stereoHMD) + { + StereoDisplay->endRenderTarget(); + } + } /* stereo loop */ + + if (stereoHMD) + { + MainCam.setPos(oldPos); + MainCam.setRotQuat(oldQuat); } // Clamp diff --git a/code/ryzom/client/src/r2/dmc/com_lua_module.cpp b/code/ryzom/client/src/r2/dmc/com_lua_module.cpp index b91aca95c..c9b6a6df2 100644 --- a/code/ryzom/client/src/r2/dmc/com_lua_module.cpp +++ b/code/ryzom/client/src/r2/dmc/com_lua_module.cpp @@ -238,7 +238,15 @@ void CComLuaModule::initLuaLib() }; int initialStackSize = lua_gettop(_LuaState); #if LUA_VERSION_NUM >= 502 - luaL_newlib(_LuaState, methods); + // luaL_newlib(_LuaState, methods); + // lua_setglobal(_LuaState, R2_LUA_PATH); + lua_getglobal(_LuaState, R2_LUA_PATH); + if (lua_isnil(_LuaState, -1)) + { + lua_pop(_LuaState, 1); + lua_newtable(_LuaState); + } + luaL_setfuncs(_LuaState, methods, 0); lua_setglobal(_LuaState, R2_LUA_PATH); #else luaL_openlib(_LuaState, R2_LUA_PATH, methods, 0); diff --git a/code/ryzom/client/src/r2/editor.cpp b/code/ryzom/client/src/r2/editor.cpp index bb09bec52..2bceb4200 100644 --- a/code/ryzom/client/src/r2/editor.cpp +++ b/code/ryzom/client/src/r2/editor.cpp @@ -1789,6 +1789,7 @@ void CEditor::waitScenarioScreen() if (!waitScreen) { TextContext->setShaded(true); + TextContext->setShadeOutline(false); TextContext->setFontSize(40); TextContext->setColor(CRGBA::White); diff --git a/code/ryzom/client/src/release.cpp b/code/ryzom/client/src/release.cpp index 722cbfe57..f88849197 100644 --- a/code/ryzom/client/src/release.cpp +++ b/code/ryzom/client/src/release.cpp @@ -27,6 +27,7 @@ #include "nel/misc/system_utils.h" // 3D Interface. #include "nel/3d/bloom_effect.h" +#include "nel/3d/fxaa.h" #include "nel/3d/fasthls_modifier.h" #include "nel/3d/particle_system_manager.h" #include "nel/3d/particle_system.h" @@ -120,7 +121,6 @@ extern bool userChar; extern bool serverReceivedReady; extern bool CharNameValidArrived; - extern void releaseContextualCursor(); extern void selectTipsOfTheDay (uint tips); @@ -498,7 +498,8 @@ void releaseOutGame() // Remove the Actions listener from the Events Server. EventsListener.removeFromServer(CInputHandlerManager::getInstance()->FilteredEventServer); - // Release Bloom + // Release effects + delete FXAA; FXAA = NULL; CBloomEffect::releaseInstance(); // Release Scene, textcontexts, materials, ... @@ -516,6 +517,16 @@ void releaseStereoDisplayDevice() { if (StereoDisplay) { + StereoDisplay->getOriginalFrustum(0, &MainCam); + if (SceneRoot) + { + UCamera cam = SceneRoot->getCam(); + StereoDisplay->getOriginalFrustum(1, &cam); + } + nlassert(Driver); + Driver->setViewport(NL3D::CViewport()); + nlassert(Scene); + Scene->setViewport(NL3D::CViewport()); delete StereoDisplay; StereoDisplay = NULL; StereoHMD = NULL; @@ -582,7 +593,8 @@ void release() Driver->deleteTextContext(TextContext); TextContext = NULL; - // Release Bloom + // Release effects + delete FXAA; FXAA = NULL; CBloomEffect::releaseInstance(); // Release Scene, textcontexts, materials, ... @@ -650,7 +662,7 @@ void release() delete &CLuaManager::getInstance(); NLGUI::CDBManager::release(); CWidgetManager::release(); - + diff --git a/code/ryzom/client/src/stdpch.h b/code/ryzom/client/src/stdpch.h index 5f046fcfe..96a509e0f 100644 --- a/code/ryzom/client/src/stdpch.h +++ b/code/ryzom/client/src/stdpch.h @@ -55,7 +55,6 @@ #include #include #include -#include #include #include #include diff --git a/code/ryzom/client/src/timed_fx_manager.cpp b/code/ryzom/client/src/timed_fx_manager.cpp index 9f7f40caf..d37ab782f 100644 --- a/code/ryzom/client/src/timed_fx_manager.cpp +++ b/code/ryzom/client/src/timed_fx_manager.cpp @@ -829,6 +829,7 @@ void CTimedFXManager::displayFXBoxes(TDebugDisplayMode displayMode) const Driver->setFrustum(fr); TextContext->setColor(CRGBA::Blue); TextContext->setShaded(false); + TextContext->setShadeOutline(false); TextContext->setFontSize(10); // float size = 0.4f; diff --git a/code/ryzom/client/src/user_entity.cpp b/code/ryzom/client/src/user_entity.cpp index c8652fd43..bb632cf4e 100644 --- a/code/ryzom/client/src/user_entity.cpp +++ b/code/ryzom/client/src/user_entity.cpp @@ -2384,10 +2384,13 @@ void CUserEntity::updateSound(const TTime &time) if (SoundMngr == 0) return; - SoundMngr->setListenerPos(pos()); - const CMatrix &camMat = MainCam.getMatrix(); - SoundMngr->setListenerOrientation(camMat.getJ(), camMat.getK()); - + if (!(StereoHMD && true)) // TODO: ClientCfg.Headphone + { + // NOTE: StereoHMD+Headphone impl in main_loop.cpp + SoundMngr->setListenerPos(pos()); + const CMatrix &camMat = MainCam.getMatrix(); + SoundMngr->setListenerOrientation(camMat.getJ(), camMat.getK()); + } if (ClientCfg.Light) return; diff --git a/code/ryzom/common/data_common/r2/r2_core_user_component_manager.lua b/code/ryzom/common/data_common/r2/r2_core_user_component_manager.lua index 6769d503b..4aa445484 100644 --- a/code/ryzom/common/data_common/r2/r2_core_user_component_manager.lua +++ b/code/ryzom/common/data_common/r2/r2_core_user_component_manager.lua @@ -1116,7 +1116,7 @@ function userComponentManager:export(list, refX, refY, refZ) messageBox(i18n.get("uiR2EDInvalidName")) return end - if string.find(form.ComponentFileName, '\.lua', -4) == nil then + if string.find(form.ComponentFileName, '.lua', -4) == nil then form.ComponentFileName = form.ComponentFileName .. ".lua" end local refPosition = form.RefPosition diff --git a/code/ryzom/common/data_common/r2/r2_debug.lua b/code/ryzom/common/data_common/r2/r2_debug.lua index 6a63b5472..78501dcab 100644 --- a/code/ryzom/common/data_common/r2/r2_debug.lua +++ b/code/ryzom/common/data_common/r2/r2_debug.lua @@ -140,7 +140,8 @@ end function assert(cond) if not cond then - rawDebugInfo(colorTag(255, 0, 255) .. "ASSERTION FAILED !! ") + -- rawDebugInfo(colorTag(255, 0, 255) .. "ASSERTION FAILED !! ") + rawDebugInfo("@{FOFF}ASSERTION FAILED !! ") dumpCallStack(2); error("") end diff --git a/code/ryzom/common/data_common/r2/r2_logic.lua b/code/ryzom/common/data_common/r2/r2_logic.lua index 1ee35d562..d50a15faf 100644 --- a/code/ryzom/common/data_common/r2/r2_logic.lua +++ b/code/ryzom/common/data_common/r2/r2_logic.lua @@ -1679,7 +1679,7 @@ Logic.translateChatSequences = function (context, hlComponent, behavior, rtNpcGr event.Name = "activity_sequence_changed" table.insert(context.RtAct.Events, event) - local rtInitChatStep = r2.Translator.createAction("code", "oldChatStepVar = -1;\n" .. Logic.chatStepVar .." = 0;\n()setTimer(1, " ..Logic.chatTimerId .. ")\;\n") + local rtInitChatStep = r2.Translator.createAction("code", "oldChatStepVar = -1;\n" .. Logic.chatStepVar .." = 0;\n()setTimer(1, " ..Logic.chatTimerId .. ");\n") rtInitChatStep.Name = "init_chat_step" table.insert(context.RtAct.Actions, rtInitChatStep) table.insert(event.ActionsId, rtInitChatStep.Id) diff --git a/code/ryzom/common/data_common/r2/r2_misc.lua b/code/ryzom/common/data_common/r2/r2_misc.lua index ee9e2885e..827e91579 100644 --- a/code/ryzom/common/data_common/r2/r2_misc.lua +++ b/code/ryzom/common/data_common/r2/r2_misc.lua @@ -28,6 +28,19 @@ function forEach(table, fn) end end + +------------------------------------------------------------------------------------------------------------ +-- whatever +table.setn = function(table, n) + assert(table) + local mt = getmetatable(table) + if mt ~= nil then + if mt.__next ~= nil then + table.Size = n + end + end +end + ------------------------------------------------------------------------------------------------------------ -- extension to table library : remove all content of a table without deleting the table object function table.clear(tbl) @@ -174,6 +187,17 @@ end function strify(str) return [["]] .. tostring(str) .. [["]] end + +------------------------------------------------------------------------------------------------- +-- enclose a string by double quotes +function strifyXml(str) + local strxml = string.gsub(tostring(str), ">", ">") + strxml = string.gsub(strxml, "<", "<") + strxml = string.gsub(strxml, "&", "&") + strxml = string.gsub(strxml, "'", "'") + strxml = string.gsub(strxml, '"', """) + return [["]] .. strxml .. [["]] +end ------------------------------------------------------------------------------------------------------------ -- snap a position to ground, returning the z snapped coordinate @@ -251,26 +275,37 @@ end -assert(table.getn ~= nil) -- default lib should have been opened +-- assert(table.getn ~= nil) -- default lib should have been opened + +--if oldTableGetnFunction == nil then +-- oldTableGetnFunction = table.getn +--end +-- +--table.getn = function(table) +-- assert(table) +-- local mt = getmetatable(table) +-- if mt ~= nil then +-- if mt.__next ~= nil then +-- return table.Size +-- end +-- end +-- return oldTableGetnFunction(table) +--end -if oldTableGetnFunction == nil then - oldTableGetnFunction = table.getn -end table.getn = function(table) assert(table) local mt = getmetatable(table) if mt ~= nil then if mt.__next ~= nil then - return table.Size + return table.Size end end - return oldTableGetnFunction(table) + return #table end - -- redefine the hardcoded 'pairs' function to use the redefined 'next' -- hardcoded version uses the C version of next, not the lua one if it has been redefined diff --git a/code/ryzom/common/data_common/r2/r2_translator.lua b/code/ryzom/common/data_common/r2/r2_translator.lua index 600928d98..e1c4701ba 100644 --- a/code/ryzom/common/data_common/r2/r2_translator.lua +++ b/code/ryzom/common/data_common/r2/r2_translator.lua @@ -541,7 +541,7 @@ Translator.translateEventHandlers = function(context, hlNpc, eventHandlers, rtNp while k do local caller = nil if devMode then - caller = function (...) arg[1](arg[2], arg[3], arg[4], arg[5]) return true end + caller = function (...) local arg = {...} arg[1](arg[2], arg[3], arg[4], arg[5]) return true end else caller = pcall @@ -898,6 +898,7 @@ end -- Returns a RtNpcEventHandlerAction if the action is allowed --first parameter: action type Translator.createAction = function(...) + local arg = {...} local debug=config.R2EDExtendedDebug local function header(toto) @@ -2774,6 +2775,7 @@ end --third param : GroupsByName --then, parameters Translator.createEvent = function(...) + local arg = {...} local event = r2.newComponent("RtNpcEventHandler") local eventType = arg[1] event.Event = eventType diff --git a/code/ryzom/common/data_common/r2/r2_ui_event_handlers.lua b/code/ryzom/common/data_common/r2/r2_ui_event_handlers.lua index 0cd5c8638..431d89eae 100644 --- a/code/ryzom/common/data_common/r2/r2_ui_event_handlers.lua +++ b/code/ryzom/common/data_common/r2/r2_ui_event_handlers.lua @@ -1030,6 +1030,7 @@ end -------------------- -------------------- function r2:updateAnimBarActions(...) + local arg = {...} -- forward to the real anim bar r2.ui.AnimBar:updateActions(arg) end diff --git a/code/ryzom/common/data_common/r2/r2_ui_forms.lua b/code/ryzom/common/data_common/r2/r2_ui_forms.lua index ae1b4d656..587581f26 100644 --- a/code/ryzom/common/data_common/r2/r2_ui_forms.lua +++ b/code/ryzom/common/data_common/r2/r2_ui_forms.lua @@ -328,7 +328,7 @@ end local function saveScenarioOnChange(formInstance) r2.print(formInstance.Name) - local name = string.gsub(formInstance.Name, "[\\\/\:\*\?\"\<\>\|]", "_") + local name = string.gsub(formInstance.Name, "[\\/:*?\"<>|]", "_") if name ~= formInstance.Name then fromInstance.Name = name formInstance.Modified = true diff --git a/code/ryzom/common/data_common/r2/r2_ui_property_sheet.lua b/code/ryzom/common/data_common/r2/r2_ui_property_sheet.lua index 962eaf315..e4fbd4632 100644 --- a/code/ryzom/common/data_common/r2/r2_ui_property_sheet.lua +++ b/code/ryzom/common/data_common/r2/r2_ui_property_sheet.lua @@ -47,13 +47,13 @@ function r2:buildEditBox(prop, textRef, entryType, multiLine, maxNumChars, onCha bg_texture="grey_40.tga" onchange="lua" onchange_params="getUICaller():setupDisplayText(); getUICaller():find('edit_text'):updateCoords(); getUICaller():getEnclosingContainer().Env.updateSize()" onenter="lua" on_focus_lost="lua"]] .. - [[ id= ]] .. strify(prop.Name) .. - [[ text_ref = ]] .. strify(textRef) .. - [[ entry_type = ]] .. strify(entryType) .. - [[ multi_line = ]] .. strify(multiLine) .. - [[ max_num_chars = ]] .. strify(maxNumChars) .. - [[ params = ]] .. strify(onChangeAction) .. - [[ on_focus_lost_params = ]] .. strify(onFocusLostAction) .. + [[ id= ]] .. strifyXml(prop.Name) .. + [[ text_ref = ]] .. strifyXml(textRef) .. + [[ entry_type = ]] .. strifyXml(entryType) .. + [[ multi_line = ]] .. strifyXml(multiLine) .. + [[ max_num_chars = ]] .. strifyXml(maxNumChars) .. + [[ params = ]] .. strifyXml(onChangeAction) .. + [[ on_focus_lost_params = ]] .. strifyXml(onFocusLostAction) .. "/>" return result end @@ -73,13 +73,13 @@ end -- bg_texture="grey_40.tga" -- onchange="lua" onchange_params="getUICaller():setupDisplayText(); getUICaller():find('edit_text'):updateCoords(); getUICaller():getEnclosingContainer().Env.updateSize()" -- onenter="lua" on_focus_lost="lua"]] .. --- [[ id= ]] .. strify(prop.Name) .. --- [[ text_ref = ]] .. strify(textRef) .. --- [[ entry_type = ]] .. strify(entryType) .. --- [[ multi_line = ]] .. strify(multiLine) .. --- [[ max_num_chars = ]] .. strify(maxNumChars) .. --- [[ params = ]] .. strify(onChangeAction) .. --- [[ on_focus_lost_params = ]] .. strify(onChangeAction) .. +-- [[ id= ]] .. strifyXml(prop.Name) .. +-- [[ text_ref = ]] .. strifyXml(textRef) .. +-- [[ entry_type = ]] .. strifyXml(entryType) .. +-- [[ multi_line = ]] .. strifyXml(multiLine) .. +-- [[ max_num_chars = ]] .. strifyXml(maxNumChars) .. +-- [[ params = ]] .. strifyXml(onChangeAction) .. +-- [[ on_focus_lost_params = ]] .. strifyXml(onChangeAction) .. -- [[ /> -- -- @@ -1043,7 +1043,7 @@ r2.WidgetStyles.Number = width1 = tmp end - local part0 = [[ ]] + local part0 = [[ ]] local tooltipTextId, tooltipTextIdFound = buildPropTooltipName(className, prop.Name) @@ -1051,7 +1051,7 @@ r2.WidgetStyles.Number = tooltip_parent="win" tooltip_posref="auto" instant_help="true" - tooltip=]] .. strify(tooltipTextId) .. ">" + tooltip=]] .. strifyXml(tooltipTextId) .. ">" part0 = part0 .. buildCoverAllButton(prop) local color = "255 255 255 255" @@ -1066,10 +1066,10 @@ r2.WidgetStyles.Number = end part0 = part0 .. [[ ]] + [[ id = ]] .. strifyXml(prop.Name .. "_Caption") .. + [[ hardtext = ]] .. strifyXml(hardText) .. + [[ color = ]] .. strifyXml(color) .. + [[ global_color=]] .. strifyXml(globalColor) .. [[ fontsize="12" shadow="true" auto_clamp="true"/> ]] part0 = part0 .. "" part0 = part0 .. "" @@ -1086,7 +1086,7 @@ r2.WidgetStyles.Number = -- local widgetXml = string.format([[ - " .. [[ + " .. [[ " result = result .. [[]] -- append enumerated values for k, v in pairs(prop.Enum) do - result = result .. [[]] + result = result .. [[]] end result = result .. "" return result, setter @@ -1201,10 +1201,10 @@ function r2:createPropertyXmlTable(props, className, posparent, posref, x, y, wi result = result .. value end add([[ ]] + part0 = [[ ]] part0 = part0 .. [[" + tooltip=]] .. strifyXml(tooltipTextId) .. ">" part0 = part0 .. [[ ]] + [[ id = ]] .. strifyXml(prop.Name .. "_Caption") .. + [[ hardtext = ]] .. strifyXml(hardText) .. + [[ color = ]] .. strifyXml(color) .. + [[ global_color=]] .. strifyXml(globalColor) .. [[ fontsize="12" shadow="true" auto_clamp="true"/> ]] part0 = part0 .. "" part0 = part0 .. "" else @@ -1268,13 +1268,13 @@ function r2:createPropertyXmlTable(props, className, posparent, posref, x, y, wi end -- build the widget - local part1 = [[ ]] + local part1 = [[ ]] part1 = part1 .. [[" + tooltip=]] .. strifyXml(tooltipTextId) .. ">" part1 = part1 .. widgetXmlDesc .. [[]] if invertWidget then @@ -1397,15 +1397,15 @@ function r2:buildPropRolloutXml(caption, id, posparent, posref, props, className -- add the rollout bar if not isForm then result = result .. - [[ ]] else result = result .. - [[ ]] end @@ -1475,9 +1475,9 @@ function r2:buildPropertySheetXml(class, className, id, title, isForm) if isForm then -- for forms, closing the form is equivalent to clicking on 'cancel' add(' resizer="true" ') local w = defaulting(class.Width, 500) - add(' pop_min_w=' .. strify(w)) - add(' pop_max_w=' .. strify(w)) - add(' w=' .. strify(w)) + add(' pop_min_w=' .. strifyXml(w)) + add(' pop_max_w=' .. strifyXml(w)) + add(' w=' .. strifyXml(w)) local cancelCode = [[ local form = getUICaller() if form.Env.Choice == nil then @@ -1518,7 +1518,7 @@ function r2:buildPropertySheetXml(class, className, id, title, isForm) - add([[id=]] .. strify(id) .. [[ + add([[id=]] .. strifyXml(id) .. [[ >]]) @@ -1647,7 +1647,7 @@ function r2:buildPropertySheetXml(class, className, id, title, isForm) - + ]]) diff --git a/code/ryzom/common/data_common/r2/unit_test/r2_unit_test.lua b/code/ryzom/common/data_common/r2/unit_test/r2_unit_test.lua index 572f2080a..b48e3da5a 100644 --- a/code/ryzom/common/data_common/r2/unit_test/r2_unit_test.lua +++ b/code/ryzom/common/data_common/r2/unit_test/r2_unit_test.lua @@ -36,7 +36,7 @@ UnitTest.testLoadAnimationScenarioUi = function() end local filename = form.LoadScenario_Name - if string.find(filename, '\.r2', -3) == nil then + if string.find(filename, '.r2', -3) == nil then local ui = r2:getForm("LoadScenario") ui.active = true @@ -134,12 +134,12 @@ UnitTest.testLoadScenarioUi = function() local ucName = ucstring() ucName:fromUtf8(form.LoadScenario_Name) local filename = tostring(ucName) - if string.find(filename, '\.r2', -3) == nil then + if string.find(filename, '.r2', -3) == nil then messageBox(i18n.get("uiR2EDLoadScenario_InvalidFileName")) return end --- if string.find(filename, '\.r2', -3) == nil then +-- if string.find(filename, '.r2', -3) == nil then -- filename = form.Name .. ".r2" -- end @@ -206,7 +206,7 @@ function UnitTest.saveScenario(name, overwrite) messageBox(i18n.get("uiR2EDInvalidName")) return end - if string.find(name, '\.r2', -3) == nil then + if string.find(name, '.r2', -3) == nil then name = name .. ".r2" end -- update scenario name with the new name @@ -1103,8 +1103,8 @@ end function t5() - local toto = "&ezr_çà'_\\)d //:1' 2 éééà'..)à\/:*?\"<>|à)@4 58ftgsfdg\"\/:*?\"<>|" - toto = string.gsub(toto, "[\\\/\:\*\?\"\<\>\|]", "_") + local toto = "&ezr_çà'_\\)d //:1' 2 éééà'..)à/:*?\"<>|à)@4 58ftgsfdg\"/:*?\"<>|" + toto = string.gsub(toto, "[\\/:*?\"<>|]", "_") end diff --git a/code/ryzom/server/src/server_share/bmp4image.h b/code/ryzom/common/src/game_share/bmp4image.h similarity index 100% rename from code/ryzom/server/src/server_share/bmp4image.h rename to code/ryzom/common/src/game_share/bmp4image.h diff --git a/code/ryzom/common/src/game_share/crypt.cpp b/code/ryzom/common/src/game_share/crypt.cpp index 0da908817..9a46281f7 100644 --- a/code/ryzom/common/src/game_share/crypt.cpp +++ b/code/ryzom/common/src/game_share/crypt.cpp @@ -18,16 +18,15 @@ #include "crypt.h" -char * rz_crypt(register const char *key, register const char *setting); - +char * rz_crypt(register const char *key, register const char *setting, char *buf); +char *__crypt_sha512(const char *key, const char *setting, char *output); // Crypts password using salt std::string CCrypt::crypt(const std::string& password, const std::string& salt) { - std::string result = ::rz_crypt(password.c_str(), salt.c_str()); - - return result; + char buf[128]; + return ::rz_crypt(password.c_str(), salt.c_str(), buf); } @@ -506,7 +505,7 @@ static char cryptresult[1+4+4+11+1]; /* encrypted result */ * Return a pointer to static data consisting of the "setting" * followed by an encryption produced by the "key" and "setting". */ -char * rz_crypt(register const char *key, register const char *setting) { +char * rz_crypt(register const char *key, register const char *setting, char *buf) { register char *encp; register long i; register int t; @@ -521,6 +520,10 @@ char * rz_crypt(register const char *key, register const char *setting) { return buff; #endif + if (setting[0] == '$' && setting[1] == '6') { + return __crypt_sha512(key, setting, buf); + } + for (i = 0; i < 8; i++) { if ((t = 2*(unsigned char)(*key)) != 0) key++; diff --git a/code/ryzom/common/src/game_share/crypt.h b/code/ryzom/common/src/game_share/crypt.h index ea479d74f..b9fa8556b 100644 --- a/code/ryzom/common/src/game_share/crypt.h +++ b/code/ryzom/common/src/game_share/crypt.h @@ -32,7 +32,7 @@ class CCrypt public: /// Crypts password using salt - static std::string crypt(const std::string& password, const std::string& salt); + static std::string crypt(const std::string& password, const std::string& salt); }; diff --git a/code/ryzom/common/src/game_share/crypt_sha512.cpp b/code/ryzom/common/src/game_share/crypt_sha512.cpp new file mode 100644 index 000000000..4d151880d --- /dev/null +++ b/code/ryzom/common/src/game_share/crypt_sha512.cpp @@ -0,0 +1,375 @@ +/* + * public domain sha512 crypt implementation + * + * original sha crypt design: http://people.redhat.com/drepper/SHA-crypt.txt + * in this implementation at least 32bit int is assumed, + * key length is limited, the $6$ prefix is mandatory, '\n' and ':' is rejected + * in the salt and rounds= setting must contain a valid iteration count, + * on error "*" is returned. + */ + +#include + +#include +#include +#include +#include + +/* public domain sha512 implementation based on fips180-3 */ +/* >=2^64 bits messages are not supported (about 2000 peta bytes) */ + +struct sha512 { + uint64 len; /* processed message length */ + uint64 h[8]; /* hash state */ + uint8 buf[128]; /* message block buffer */ +}; + +static uint64 ror(uint64 n, int k) { return (n >> k) | (n << (64-k)); } +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) ((x & y) | (z & (x | y))) +#define S0(x) (ror(x,28) ^ ror(x,34) ^ ror(x,39)) +#define S1(x) (ror(x,14) ^ ror(x,18) ^ ror(x,41)) +#define R0(x) (ror(x,1) ^ ror(x,8) ^ (x>>7)) +#define R1(x) (ror(x,19) ^ ror(x,61) ^ (x>>6)) + +static const uint64 K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +static void processblock(struct sha512 *s, const uint8 *buf) +{ + uint64 W[80], t1, t2, a, b, c, d, e, f, g, h; + int i; + + for (i = 0; i < 16; i++) { + W[i] = (uint64)buf[8*i]<<56; + W[i] |= (uint64)buf[8*i+1]<<48; + W[i] |= (uint64)buf[8*i+2]<<40; + W[i] |= (uint64)buf[8*i+3]<<32; + W[i] |= (uint64)buf[8*i+4]<<24; + W[i] |= (uint64)buf[8*i+5]<<16; + W[i] |= (uint64)buf[8*i+6]<<8; + W[i] |= buf[8*i+7]; + } + for (; i < 80; i++) + W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16]; + a = s->h[0]; + b = s->h[1]; + c = s->h[2]; + d = s->h[3]; + e = s->h[4]; + f = s->h[5]; + g = s->h[6]; + h = s->h[7]; + for (i = 0; i < 80; i++) { + t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i]; + t2 = S0(a) + Maj(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + s->h[0] += a; + s->h[1] += b; + s->h[2] += c; + s->h[3] += d; + s->h[4] += e; + s->h[5] += f; + s->h[6] += g; + s->h[7] += h; +} + +static void pad(struct sha512 *s) +{ + unsigned r = s->len % 128; + + s->buf[r++] = 0x80; + if (r > 112) { + memset(s->buf + r, 0, 128 - r); + r = 0; + processblock(s, s->buf); + } + memset(s->buf + r, 0, 120 - r); + s->len *= 8; + s->buf[120] = s->len >> 56; + s->buf[121] = s->len >> 48; + s->buf[122] = s->len >> 40; + s->buf[123] = s->len >> 32; + s->buf[124] = s->len >> 24; + s->buf[125] = s->len >> 16; + s->buf[126] = s->len >> 8; + s->buf[127] = s->len; + processblock(s, s->buf); +} + +static void sha512_init(struct sha512 *s) +{ + s->len = 0; + s->h[0] = 0x6a09e667f3bcc908ULL; + s->h[1] = 0xbb67ae8584caa73bULL; + s->h[2] = 0x3c6ef372fe94f82bULL; + s->h[3] = 0xa54ff53a5f1d36f1ULL; + s->h[4] = 0x510e527fade682d1ULL; + s->h[5] = 0x9b05688c2b3e6c1fULL; + s->h[6] = 0x1f83d9abfb41bd6bULL; + s->h[7] = 0x5be0cd19137e2179ULL; +} + +static void sha512_sum(struct sha512 *s, uint8 *md) +{ + int i; + + pad(s); + for (i = 0; i < 8; i++) { + md[8*i] = s->h[i] >> 56; + md[8*i+1] = s->h[i] >> 48; + md[8*i+2] = s->h[i] >> 40; + md[8*i+3] = s->h[i] >> 32; + md[8*i+4] = s->h[i] >> 24; + md[8*i+5] = s->h[i] >> 16; + md[8*i+6] = s->h[i] >> 8; + md[8*i+7] = s->h[i]; + } +} + +static void sha512_update(struct sha512 *s, const void *m, unsigned long len) +{ + const uint8 *p = (uint8 *)m; + unsigned r = s->len % 128; + + s->len += len; + if (r) { + if (len < 128 - r) { + memcpy(s->buf + r, p, len); + return; + } + memcpy(s->buf + r, p, 128 - r); + len -= 128 - r; + p += 128 - r; + processblock(s, s->buf); + } + for (; len >= 128; len -= 128, p += 128) + processblock(s, p); + memcpy(s->buf, p, len); +} + +static const unsigned char b64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static char *to64(char *s, unsigned int u, int n) +{ + while (--n >= 0) { + *s++ = b64[u % 64]; + u /= 64; + } + return s; +} + +/* key limit is not part of the original design, added for DoS protection. + * rounds limit has been lowered (versus the reference/spec), also for DoS + * protection. runtime is O(klen^2 + klen*rounds) */ +#define KEY_MAX 256 +#define SALT_MAX 16 +#define ROUNDS_DEFAULT 5000 +#define ROUNDS_MIN 1000 +#define ROUNDS_MAX 9999999 + +/* hash n bytes of the repeated md message digest */ +static void hashmd(struct sha512 *s, unsigned int n, const void *md) +{ + unsigned int i; + + for (i = n; i > 64; i -= 64) + sha512_update(s, md, 64); + sha512_update(s, md, i); +} + +static char *sha512crypt(const char *key, const char *setting, char *output) +{ + struct sha512 ctx; + unsigned char md[64], kmd[64], smd[64]; + unsigned int i, r, klen, slen; + char rounds[20] = ""; + const char *salt; + char *p; + + /* reject large keys */ + for (i = 0; i <= KEY_MAX && key[i]; i++); + if (i > KEY_MAX) + return 0; + klen = i; + + /* setting: $6$rounds=n$salt$ (rounds=n$ and closing $ are optional) */ + if (strncmp(setting, "$6$", 3) != 0) + return 0; + salt = setting + 3; + + r = ROUNDS_DEFAULT; + if (strncmp(salt, "rounds=", sizeof "rounds=" - 1) == 0) { + unsigned long u; + char *end; + + /* + * this is a deviation from the reference: + * bad rounds setting is rejected if it is + * - empty + * - unterminated (missing '$') + * - begins with anything but a decimal digit + * the reference implementation treats these bad + * rounds as part of the salt or parse them with + * strtoul semantics which may cause problems + * including non-portable hashes that depend on + * the host's value of ULONG_MAX. + */ + salt += sizeof "rounds=" - 1; + if (!isdigit(*salt)) + return 0; + u = strtoul(salt, &end, 10); + if (*end != '$') + return 0; + salt = end+1; + if (u < ROUNDS_MIN) + r = ROUNDS_MIN; + else if (u > ROUNDS_MAX) + r = ROUNDS_MAX; + else + r = u; + /* needed when rounds is zero prefixed or out of bounds */ + sprintf(rounds, "rounds=%u$", r); + } + + for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++) + /* reject characters that interfere with /etc/shadow parsing */ + if (salt[i] == '\n' || salt[i] == ':') + return 0; + slen = i; + + /* B = sha(key salt key) */ + sha512_init(&ctx); + sha512_update(&ctx, key, klen); + sha512_update(&ctx, salt, slen); + sha512_update(&ctx, key, klen); + sha512_sum(&ctx, md); + + /* A = sha(key salt repeat-B alternate-B-key) */ + sha512_init(&ctx); + sha512_update(&ctx, key, klen); + sha512_update(&ctx, salt, slen); + hashmd(&ctx, klen, md); + for (i = klen; i > 0; i >>= 1) + if (i & 1) + sha512_update(&ctx, md, sizeof md); + else + sha512_update(&ctx, key, klen); + sha512_sum(&ctx, md); + + /* DP = sha(repeat-key), this step takes O(klen^2) time */ + sha512_init(&ctx); + for (i = 0; i < klen; i++) + sha512_update(&ctx, key, klen); + sha512_sum(&ctx, kmd); + + /* DS = sha(repeat-salt) */ + sha512_init(&ctx); + for (i = 0; i < 16 + md[0]; i++) + sha512_update(&ctx, salt, slen); + sha512_sum(&ctx, smd); + + /* iterate A = f(A,DP,DS), this step takes O(rounds*klen) time */ + for (i = 0; i < r; i++) { + sha512_init(&ctx); + if (i % 2) + hashmd(&ctx, klen, kmd); + else + sha512_update(&ctx, md, sizeof md); + if (i % 3) + sha512_update(&ctx, smd, slen); + if (i % 7) + hashmd(&ctx, klen, kmd); + if (i % 2) + sha512_update(&ctx, md, sizeof md); + else + hashmd(&ctx, klen, kmd); + sha512_sum(&ctx, md); + } + + /* output is $6$rounds=n$salt$hash */ + p = output; + p += sprintf(p, "$6$%s%.*s$", rounds, slen, salt); +#if 1 + static const unsigned char perm[][3] = { + 0,21,42,22,43,1,44,2,23,3,24,45,25,46,4, + 47,5,26,6,27,48,28,49,7,50,8,29,9,30,51, + 31,52,10,53,11,32,12,33,54,34,55,13,56,14,35, + 15,36,57,37,58,16,59,17,38,18,39,60,40,61,19, + 62,20,41 }; + for (i=0; i<21; i++) p = to64(p, + (md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4); +#else + p = to64(p, (md[0]<<16)|(md[21]<<8)|md[42], 4); + p = to64(p, (md[22]<<16)|(md[43]<<8)|md[1], 4); + p = to64(p, (md[44]<<16)|(md[2]<<8)|md[23], 4); + p = to64(p, (md[3]<<16)|(md[24]<<8)|md[45], 4); + p = to64(p, (md[25]<<16)|(md[46]<<8)|md[4], 4); + p = to64(p, (md[47]<<16)|(md[5]<<8)|md[26], 4); + p = to64(p, (md[6]<<16)|(md[27]<<8)|md[48], 4); + p = to64(p, (md[28]<<16)|(md[49]<<8)|md[7], 4); + p = to64(p, (md[50]<<16)|(md[8]<<8)|md[29], 4); + p = to64(p, (md[9]<<16)|(md[30]<<8)|md[51], 4); + p = to64(p, (md[31]<<16)|(md[52]<<8)|md[10], 4); + p = to64(p, (md[53]<<16)|(md[11]<<8)|md[32], 4); + p = to64(p, (md[12]<<16)|(md[33]<<8)|md[54], 4); + p = to64(p, (md[34]<<16)|(md[55]<<8)|md[13], 4); + p = to64(p, (md[56]<<16)|(md[14]<<8)|md[35], 4); + p = to64(p, (md[15]<<16)|(md[36]<<8)|md[57], 4); + p = to64(p, (md[37]<<16)|(md[58]<<8)|md[16], 4); + p = to64(p, (md[59]<<16)|(md[17]<<8)|md[38], 4); + p = to64(p, (md[18]<<16)|(md[39]<<8)|md[60], 4); + p = to64(p, (md[40]<<16)|(md[61]<<8)|md[19], 4); + p = to64(p, (md[62]<<16)|(md[20]<<8)|md[41], 4); +#endif + p = to64(p, md[63], 2); + *p = 0; + return output; +} + +char *__crypt_sha512(const char *key, const char *setting, char *output) +{ + static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !"; + static const char testsetting[] = "$6$rounds=1234$abc0123456789$"; + static const char testhash[] = "$6$rounds=1234$abc0123456789$BCpt8zLrc/RcyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1"; + char testbuf[128]; + char *p, *q; + + p = sha512crypt(key, setting, output); + + /* self test and stack cleanup */ + q = sha512crypt(testkey, testsetting, testbuf); + if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof(testhash))) + return "*"; + + return p; +} diff --git a/code/ryzom/common/src/game_share/ryzom_version.h b/code/ryzom/common/src/game_share/ryzom_version.h index 2dfdca48e..af714db4d 100644 --- a/code/ryzom/common/src/game_share/ryzom_version.h +++ b/code/ryzom/common/src/game_share/ryzom_version.h @@ -17,7 +17,7 @@ #ifndef RYZOM_VERSION_H #define RYZOM_VERSION_H -#define RYZOM_VERSION "RYZOM CORE" +#define RYZOM_VERSION "ryzomcore/v0.11.0-dev" #endif // RYZOM_VERSION_H diff --git a/code/ryzom/server/patchman_cfg/admin_install/bin/admin b/code/ryzom/server/patchman_cfg/admin_install/bin/admin index c7cfa2fb6..f48de0d15 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/bin/admin +++ b/code/ryzom/server/patchman_cfg/admin_install/bin/admin @@ -99,14 +99,14 @@ then for f in $DOMAIN_LIST do # see if we're setup to run this domain - if [ -e /srv/core/${f}.screen.rc ] && [ -e /srv/core/bin/${f} ] + if [ -e /srv/core/${f}.screen.rc ] && [ -e /srv/core/bin/domain_${f} ] then # see whether the domain is alredy running - if [ $( screen -list | grep \( | cut -f2 | cut -d. -f2| grep \^$f\$ | wc -l) == 0 ] + if [ $( screen -list | grep \\\.${f} | wc -w ) = 0 ] then # the domain isn't running yet so start it echo '****' starting domain: $f '****' - /srv/core/bin/$f batchstart + /srv/core/bin/domain_$f batchstart else echo '****' Domain is already running: $f '****' fi diff --git a/code/ryzom/server/patchman_cfg/admin_install/bin/run_forever b/code/ryzom/server/patchman_cfg/admin_install/bin/run_forever index c6f14b074..91a838a02 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/bin/run_forever +++ b/code/ryzom/server/patchman_cfg/admin_install/bin/run_forever @@ -3,7 +3,7 @@ while true do -if [ "$2" == "" ] +if [ "$2" = "" ] then echo echo USAGE: $0 sleep_time command_line diff --git a/code/ryzom/server/patchman_cfg/admin_install/bin/startup b/code/ryzom/server/patchman_cfg/admin_install/bin/startup index 16bf59fd3..a63c6a3f7 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/bin/startup +++ b/code/ryzom/server/patchman_cfg/admin_install/bin/startup @@ -4,8 +4,8 @@ cd /srv/core rm */*.state */*/*.launch_ctrl */*/*.state /bin/bash /srv/core/bin/admin start -# special case for the "ep1.std01.ryzomcore.org" machine - start the admin tool graph sync script -if [ $(hostname) = "ep1.std01.ryzomcore.org" ] +# special case for the "ep1.std01.ryzomcore.local" machine - start the admin tool graph sync script +if [ $(hostname) = "ep1.std01.ryzomcore.local" ] then nohup /bin/sh /srv/core/bin/sync_rrd_graphs.sh & fi diff --git a/code/ryzom/server/patchman_cfg/admin_install/bin/sync_rrd_graphs.sh b/code/ryzom/server/patchman_cfg/admin_install/bin/sync_rrd_graphs.sh index b23fc285b..cc78fbaf1 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/bin/sync_rrd_graphs.sh +++ b/code/ryzom/server/patchman_cfg/admin_install/bin/sync_rrd_graphs.sh @@ -4,7 +4,7 @@ echo Launched: $(date) while true do # retrieve ATS files from ATS admin tool machine - rsync -t ep1.std01.ryzomcore.org:ats/graph_datas/* /srv/core/mini01/rrd_graphs/ + rsync -t ep1.std01.ryzomcore.local:ats/graph_datas/* /srv/core/mini01/rrd_graphs/ # deal with live files - duplicate files that correspond to unique services to aid with graphing of su & co cd /srv/core/std01/rrd_graphs/ diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.mini01.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.mini01.cfg index bc7be84e9..0e8af6ed9 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.mini01.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.mini01.cfg @@ -10,7 +10,7 @@ AESAliasName= "aes"; DontUseStdIn = 0; // Adress ofthe admin service (default port is 49996) -ASHost = "ep1.mini01.ryzomcore.org"; +ASHost = "ep1.mini01.ryzomcore.local"; // Config for AES AESPort = "46712"; diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.std01.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.std01.cfg index 7bfb80b27..7a4176b93 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.std01.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/admin_executor_service_default.std01.cfg @@ -10,7 +10,7 @@ AESAliasName= "aes"; DontUseStdIn = 0; // Adress ofthe admin service (default port is 49996) -ASHost = "ep1.std01.ryzomcore.org"; +ASHost = "ep1.std01.ryzomcore.local"; // Config for AES AESPort = "46702"; diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman.sh b/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman.sh index 73b151c43..af057f2ae 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman.sh +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman.sh @@ -10,6 +10,7 @@ do chmod 775 bin/ps_services 2> /dev/null chmod 775 bin/run_forever 2> /dev/null chmod 775 bin/shard 2> /dev/null + chmod 775 bin/domain_* 2> /dev/null chmod 775 bin/startup 2> /dev/null chmod 775 bin/*.sh 2> /dev/null chmod 775 patchman/*_service 2> /dev/null diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman_once.sh b/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman_once.sh index 0dd697aa4..f7152cada 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman_once.sh +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_patchman_once.sh @@ -3,8 +3,8 @@ CFGFILENAME=patchman_service.${SERVER_TYPE}.cfg echo cfg file: $CFGFILENAME -AESCFGFILENAME=admin_executor_service_default.${SERVER_TYPE}.cfg -echo aes cfg file: $AESCFGFILENAME +#AESCFGFILENAME=admin_executor_service_default.${SERVER_TYPE}.cfg +#echo aes cfg file: $AESCFGFILENAME cd /srv/core/patchman if [ -e $CFGFILENAME ] @@ -15,8 +15,8 @@ if [ -e $CFGFILENAME ] cp $CFGFILENAME patchman_service.cfg # setup the config file for the admin executor service - echo Using aes configuration file: $AESCFGFILENAME - if [ -e $AESCFGFILENAME ] ; then cp $AESCFGFILENAME admin_executor_service_default.cfg ; fi + #echo Using aes configuration file: $AESCFGFILENAME + #if [ -e $AESCFGFILENAME ] ; then cp $AESCFGFILENAME admin_executor_service_default.cfg ; fi # start the patchman service echo Launching patchman... diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_special_patchman.sh b/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_special_patchman.sh index af1f5b599..6aa9f2ddf 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_special_patchman.sh +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/loop_special_patchman.sh @@ -1,6 +1,6 @@ #!/bin/sh -if [ "$1" == "" ] +if [ "$1" = "" ] then echo echo USAGE: $0 command_line diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/make_next_live.sh b/code/ryzom/server/patchman_cfg/admin_install/patchman/make_next_live.sh index fbaca4ac4..394fc971d 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/make_next_live.sh +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/make_next_live.sh @@ -84,7 +84,7 @@ rm -v */*.*launch_ctrl *.*launch_ctrl 2> /dev/null # initialise the state files for the new services to "xxxxx" and remove directories that are no longer of interest for D in $(ls */log.log | sed "s%/.*%%" | sort -u) do - if [ $(grep \"$D\" admin_executor_service.cfg | wc -l) == 1 ] + if [ $(grep \"$D\" admin_executor_service.cfg | wc -l) = 1 ] then printf "xxxxx" > $D/$D.state else @@ -97,7 +97,7 @@ done printf "1" > ./global.launch_ctrl # create a script for accessing the screen for this shard -SCRIPT_FILE=/srv/core/bin/${DOMAIN} +SCRIPT_FILE=/srv/core/bin/domain_${DOMAIN} echo "#!/bin/sh" > $SCRIPT_FILE echo "cd "$(pwd) >> $SCRIPT_FILE echo '/bin/sh /srv/core/bin/ryzom_domain_screen_wrapper.sh $*' >> $SCRIPT_FILE diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_list b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_list index e90230704..9a9341e9a 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_list +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_list @@ -1,23 +1,23 @@ // default values for different sites -mini01 ep1.mini01.ryzomcore.org -std01 ep1.std01.ryzomcore.org -std01 su1.std01.ryzomcore.org -std01 pd1.std01.ryzomcore.org -std01 pd2.std01.ryzomcore.org -std01 pd3.std01.ryzomcore.org -std01 pd4.std01.ryzomcore.org -std01 mla1.std01.ryzomcore.org -std01 mla2.std01.ryzomcore.org -std01 mla3.std01.ryzomcore.org -std01 mla4.std01.ryzomcore.org -std01 mla5.std01.ryzomcore.org -std01 mlb1.std01.ryzomcore.org -std01 mlb2.std01.ryzomcore.org -std01 mlb3.std01.ryzomcore.org -std01 mlb4.std01.ryzomcore.org -std01 mlb5.std01.ryzomcore.org -std01 rra1.std01.ryzomcore.org -std01 rra2.std01.ryzomcore.org -std01 rrb1.std01.ryzomcore.org -std01 rrb2.std01.ryzomcore.org +mini01 ep1.mini01.ryzomcore.local +std01 ep1.std01.ryzomcore.local +std01 su1.std01.ryzomcore.local +std01 pd1.std01.ryzomcore.local +std01 pd2.std01.ryzomcore.local +std01 pd3.std01.ryzomcore.local +std01 pd4.std01.ryzomcore.local +std01 mla1.std01.ryzomcore.local +std01 mla2.std01.ryzomcore.local +std01 mla3.std01.ryzomcore.local +std01 mla4.std01.ryzomcore.local +std01 mla5.std01.ryzomcore.local +std01 mlb1.std01.ryzomcore.local +std01 mlb2.std01.ryzomcore.local +std01 mlb3.std01.ryzomcore.local +std01 mlb4.std01.ryzomcore.local +std01 mlb5.std01.ryzomcore.local +std01 rra1.std01.ryzomcore.local +std01 rra2.std01.ryzomcore.local +std01 rrb1.std01.ryzomcore.local +std01 rrb2.std01.ryzomcore.local diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.default.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.default.cfg index 981654046..7473aa9a0 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.default.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.default.cfg @@ -10,7 +10,7 @@ StartCommands = // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway bridge_gw", "bridge_gw.transportAdd L3Client l3client", - "bridge_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44749)", + "bridge_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44749)", //------------------------------------------------------------------------------ @@ -19,7 +19,7 @@ StartCommands = // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway spm_gw", "spm_gw.transportAdd L3Client l3client", - "spm_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44752)", + "spm_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44752)", //------------------------------------------------------------------------------ @@ -28,10 +28,3 @@ StartCommands = "pam.plug spm_gw", "pam.plug bridge_gw", }; - -SpaPreCmdLineText="/bin/sh /srv/core/patchman/service_launcher.sh"; -DeploymentRootDirectory="/srv/core/patchman/"; -MakeInstalledVersionLiveCmdLine="/bin/sh /srv/core/patchman/make_next_live.sh"; -SpaLaunchAESCmdLine="/bin/sh /srv/core/patchman/loop_aes.sh"; -InstallArchiveDirectory="/srv/core/"; -InstallArchiveFileName="admin_install.tgz"; diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01.cfg index 41c283b63..f046815ce 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01.cfg @@ -10,7 +10,7 @@ StartCommands = // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway bridge_gw", "bridge_gw.transportAdd L3Client l3client", - "bridge_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44749)", + "bridge_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44749)", //------------------------------------------------------------------------------ @@ -19,7 +19,7 @@ StartCommands = // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway spm_gw", "spm_gw.transportAdd L3Client l3client", - "spm_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44751)", + "spm_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44751)", //------------------------------------------------------------------------------ @@ -36,10 +36,3 @@ StartCommands = "pam.plug spm_gw", "pam.plug bridge_gw", }; - -SpaPreCmdLineText="/bin/sh /srv/core/patchman/service_launcher.sh"; -DeploymentRootDirectory="/srv/core/patchman/"; -MakeInstalledVersionLiveCmdLine="/bin/sh /srv/core/patchman/make_next_live.sh"; -SpaLaunchAESCmdLine="/bin/sh /srv/core/patchman/loop_aes.sh"; -InstallArchiveDirectory="/srv/core/"; -InstallArchiveFileName="admin_install.tgz"; diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01_bridge.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01_bridge.cfg index 32166d6bf..737177202 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01_bridge.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.mini01_bridge.cfg @@ -43,7 +43,7 @@ StartCommands += // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway spm_gw", "spm_gw.transportAdd L3Client l3client", - "spm_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44751)", + "spm_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44751)", //------------------------------------------------------------------------------ diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.std01.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.std01.cfg index e8c2d5787..23175c08b 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.std01.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service.std01.cfg @@ -10,7 +10,7 @@ StartCommands = // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway bridge_gw", "bridge_gw.transportAdd L3Client l3client", - "bridge_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44749)", + "bridge_gw.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44749)", //------------------------------------------------------------------------------ @@ -19,7 +19,7 @@ StartCommands = // Create a gateway module on layer 3 transport and open it "moduleManager.createModule StandardGateway spm_gw", "spm_gw.transportAdd L3Client l3client", - "spm_gw.transportCmd l3client(connect addr=ep1.std01.ryzomcore.org:44752)", + "spm_gw.transportCmd l3client(connect addr=ep1.std01.ryzomcore.local:44752)", //------------------------------------------------------------------------------ @@ -36,10 +36,3 @@ StartCommands = "pam.plug spm_gw", "pam.plug bridge_gw", }; - -SpaPreCmdLineText="/bin/sh /srv/core/patchman/service_launcher.sh"; -DeploymentRootDirectory="/srv/core/patchman/"; -MakeInstalledVersionLiveCmdLine="/bin/sh /srv/core/patchman/make_next_live.sh"; -SpaLaunchAESCmdLine="/bin/sh /srv/core/patchman/loop_aes.sh"; -InstallArchiveDirectory="/srv/core/"; -InstallArchiveFileName="admin_install.tgz"; diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service_base_linux.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service_base_linux.cfg index 8aea88a5f..74290a228 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service_base_linux.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/patchman_service_base_linux.cfg @@ -14,4 +14,9 @@ DontUseStdIn = 0; // 4 = nothing UseYieldMethod = 0; - +SpaPreCmdLineText="/bin/sh /srv/core/patchman/service_launcher.sh"; +DeploymentRootDirectory="/srv/core/patchman/"; +MakeInstalledVersionLiveCmdLine="/bin/sh /srv/core/patchman/make_next_live.sh"; +SpaLaunchAESCmdLine="/bin/sh /srv/core/patchman/loop_aes.sh"; +InstallArchiveDirectory="/srv/core/"; +InstallArchiveFileName="admin_install.tgz"; diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/service_launcher.sh b/code/ryzom/server/patchman_cfg/admin_install/patchman/service_launcher.sh index 091892af7..435c44bc0 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/service_launcher.sh +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/service_launcher.sh @@ -1,25 +1,26 @@ #!/bin/sh -# the object is to make a launcher script that works with a command file to determine when to launch the application that it is responsible for +# the objective is to make a launcher script that works with a command file to determine when to launch the application that it is responsible for DOMAIN=$(pwd |sed "s%/srv/core/%%" | sed "s%/.*%%") NAME_BASE=$(pwd | sed 's/\/srv\/core\///' | sed 's/^.*\///') #if [ _$DOMAIN == _pre_live ] -# then - CTRL_FILE=${NAME_BASE}.launch_ctrl - NEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl +# then + CTRL_FILE=${NAME_BASE}.launch_ctrl + NEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl #elif [ _$DOMAIN == _pre_pre_live ] -# then -# CTRL_FILE=${NAME_BASE}.launch_ctrl -# NEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl +# then +# CTRL_FILE=${NAME_BASE}.launch_ctrl +# NEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl #else -# CTRL_FILE=${NAME_BASE}_immediate.launch_ctrl -# NEXT_CTRL_FILE=${NAME_BASE}_waiting.launch_ctrl +# CTRL_FILE=${NAME_BASE}_immediate.launch_ctrl +# NEXT_CTRL_FILE=${NAME_BASE}_waiting.launch_ctrl #fi STATE_FILE=${NAME_BASE}.state START_COUNTER_FILE=${NAME_BASE}.start_count CTRL_CMDLINE=$* +CTRL_COMMAND="" echo echo --------------------------------------------------------------------------------- @@ -36,6 +37,13 @@ echo echo 0 > $START_COUNTER_FILE START_COUNTER=0 +# always give ras a first run +if [ "${NAME_BASE}" = "ras" ] +then + echo Force admin service first startup + printf LAUNCH > $CTRL_FILE +fi + echo Press ENTER to launch program while true do @@ -45,37 +53,37 @@ do then # a control file exists so read it's contents - CTRL_COMMAND=_$(cat $CTRL_FILE)_ + CTRL_COMMAND=$(cat $CTRL_FILE) # do we have a 'launch' command? - if [ $CTRL_COMMAND = _LAUNCH_ ] + if [ "$CTRL_COMMAND" = "LAUNCH" ] then - # update the start counter - START_COUNTER=$(( $START_COUNTER + 1 )) - echo $START_COUNTER > $START_COUNTER_FILE + # update the start counter + START_COUNTER=$(( $START_COUNTER + 1 )) + echo $START_COUNTER > $START_COUNTER_FILE - # big nasty hack to deal with the special cases of ryzom_naming_service and ryzom_admin_service who have badly names cfg files - for f in ryzom_*cfg - do - cp $f $(echo $f | sed "s/ryzom_//") - done + # big nasty hack to deal with the special cases of ryzom_naming_service and ryzom_admin_service who have badly names cfg files + for f in ryzom_*cfg + do + cp $f $(echo $f | sed "s/ryzom_//") + done - # we have a launch command so prepare, launch, wait for exit and do the housekeeping - echo ----------------------------------------------------------------------- - echo Launching ... - echo - printf RUNNING > $STATE_FILE + # we have a launch command so prepare, launch, wait for exit and do the housekeeping + echo ----------------------------------------------------------------------- + echo Launching ... + echo + printf RUNNING > $STATE_FILE - $CTRL_CMDLINE + $CTRL_CMDLINE - echo ----------------------------------------------------------------------- - printf STOPPED > $STATE_FILE + echo ----------------------------------------------------------------------- + printf STOPPED > $STATE_FILE - # consume (remove) the control file to allow start once - rm $CTRL_FILE + # consume (remove) the control file to allow start once + rm $CTRL_FILE - echo Press ENTER to relaunch + echo Press ENTER to relaunch fi fi @@ -87,9 +95,9 @@ do else # give the terminal user a chance to press enter to provoke a re-launch HOLD=`sh -ic '{ read a; echo "ENTER" 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null` - if [ _${HOLD}_ != _HOLD_ ] - then - printf LAUNCH > $CTRL_FILE + if [ "${HOLD}" = "ENTER" ] + then + printf LAUNCH > $CTRL_FILE fi fi diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman/special_patchman_list b/code/ryzom/server/patchman_cfg/admin_install/patchman/special_patchman_list index b42636e55..bb1114027 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman/special_patchman_list +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman/special_patchman_list @@ -1,10 +1,10 @@ // mini01 - mini manager -mini01_spm ep1.mini01.ryzomcore.org -mini01_bridge ep1.mini01.ryzomcore.org +mini01_spm ep1.mini01.ryzomcore.local +mini01_bridge ep1.mini01.ryzomcore.local // std01 - std manager -std01_spm ep1.std01.ryzomcore.org +std01_spm ep1.std01.ryzomcore.local diff --git a/code/ryzom/server/patchman_cfg/admin_install/patchman_service_local.cfg b/code/ryzom/server/patchman_cfg/admin_install/patchman_service_local.cfg index 45f2afe3f..5b2f35f5f 100644 --- a/code/ryzom/server/patchman_cfg/admin_install/patchman_service_local.cfg +++ b/code/ryzom/server/patchman_cfg/admin_install/patchman_service_local.cfg @@ -1 +1 @@ -SPAHost = "ep1.mini01.ryzomcore.org"; +SPAHost = "ep1.mini01.ryzomcore.local"; diff --git a/code/ryzom/server/patchman_cfg/default/ai_service.cfg b/code/ryzom/server/patchman_cfg/default/ai_service.cfg index 72b278cc0..fdb381b38 100644 --- a/code/ryzom/server/patchman_cfg/default/ai_service.cfg +++ b/code/ryzom/server/patchman_cfg/default/ai_service.cfg @@ -6,7 +6,7 @@ SystemCmd = {}; //NegFiltersDebug += { "LNET", "HNET", "FEVIS"}; //NegFiltersInfo += { "LNET", "HNET", "VISION_DELTA", "FEIMPE", "FEVIS" }; // NegFiltersWarning += { "LNET", "FEHACK", "FERECV"}; -// NegFiltersWarning += { "positional", "faction", "pet" }; +// NegFiltersWarning += { "positional", "faction", "pet" }; ////////////////////////////////////////////////////////////////////////////// //- Basic (specific) heal profile parameters --------------------------------- @@ -49,7 +49,7 @@ DefaultNpcAggroDist = 15; DefaultEscortRange = 10; ////////////////////////////////////////////////////////////////////////////// -// Aggro // +// Aggro // ////////////////////////////////////////////////////////////////////////////// AggroReturnDistCheck = 15.0; AggroReturnDistCheckFauna = 15.0; @@ -318,25 +318,25 @@ StartCommandsWhenMirrorReadyPost = // commands for Ring continents StartCommandsWhenMirrorReadyRing = { - "loadContinent r2_desert", + "loadContinent r2_desert", "createDynamicAIInstance 10000", "loadPrimitiveFile dummy.primitive", - "loadContinent r2_forest", - "createDynamicAIInstance 10001", - "loadPrimitiveFile dummy.primitive", +// "loadContinent r2_forest", +// "createDynamicAIInstance 10001", +// "loadPrimitiveFile dummy.primitive", - "loadContinent r2_lakes", - "createDynamicAIInstance 10003", - "loadPrimitiveFile dummy.primitive", +// "loadContinent r2_lakes", +// "createDynamicAIInstance 10003", +// "loadPrimitiveFile dummy.primitive", - "loadContinent r2_jungle", - "createDynamicAIInstance 10002", - "loadPrimitiveFile dummy.primitive", +// "loadContinent r2_jungle", +// "createDynamicAIInstance 10002", +// "loadPrimitiveFile dummy.primitive", - "loadContinent r2_roots", - "createDynamicAIInstance 10004", - "loadPrimitiveFile dummy.primitive", +// "loadContinent r2_roots", +// "createDynamicAIInstance 10004", +// "loadPrimitiveFile dummy.primitive", // "spawnInstances", "updateAI", diff --git a/code/ryzom/server/patchman_cfg/default/dynamic_scenario_service.cfg b/code/ryzom/server/patchman_cfg/default/dynamic_scenario_service.cfg new file mode 100644 index 000000000..e6d5942ac --- /dev/null +++ b/code/ryzom/server/patchman_cfg/default/dynamic_scenario_service.cfg @@ -0,0 +1,9 @@ + +DelayBeforeStartAct = 1; +MaxNpcs = 300; +MaxStaticObjects = 200; + +StartCommands += +{ + "unifiedNetwork.addService ShardUnifier ( address="+SUAddress+" sendId external autoRetry )", +}; diff --git a/code/ryzom/server/patchman_cfg/default/log_analyser_service.cfg b/code/ryzom/server/patchman_cfg/default/log_analyser_service.cfg new file mode 100644 index 000000000..355984ff5 --- /dev/null +++ b/code/ryzom/server/patchman_cfg/default/log_analyser_service.cfg @@ -0,0 +1,5 @@ + +DontUseNS = 1; + +QueryTimeout = 300; +LinePerPage = 50; diff --git a/code/ryzom/server/patchman_cfg/default/ryzom_as.cfg b/code/ryzom/server/patchman_cfg/default/ryzom_as.cfg index 2755403b7..4227bac69 100644 --- a/code/ryzom/server/patchman_cfg/default/ryzom_as.cfg +++ b/code/ryzom/server/patchman_cfg/default/ryzom_as.cfg @@ -1,7 +1,7 @@ DontUseNS = 1; RRDToolPath = "rrdtool"; -RRDVarPath = "../graph_datas"; +RRDVarPath = "../rrd_graphs"; // Variables required to be defined by other cfgs //AESHost="localhost"; diff --git a/code/ryzom/server/patchman_cfg/shard_ctrl_definitions.txt b/code/ryzom/server/patchman_cfg/shard_ctrl_definitions.txt index 87bd0ce4d..8deb9f533 100644 --- a/code/ryzom/server/patchman_cfg/shard_ctrl_definitions.txt +++ b/code/ryzom/server/patchman_cfg/shard_ctrl_definitions.txt @@ -26,7 +26,7 @@ define exe_set_mini_ring define exe_set_mini_mainland use raes use ms_mini_mainland - use ais_newbyland + use ais_newbieland use egs_mainland use gpms_mainland use ios_mainland @@ -100,7 +100,7 @@ define exe_set_std_mainland_be03 define exe_set_std_mainland_be03_basics // use ais_matis // use ais_tryker - use ais_newbyland + use ais_newbieland // unifier and co ------------------ @@ -170,12 +170,14 @@ define ais_ring cmdLine ai_service -C. -L. --nobreak --writepid -mCommon:Ring use ais data data_r2_desert - data data_r2_forest - data data_r2_jungle - data data_r2_lakes - data data_r2_roots + // data data_r2_forest + // data data_r2_jungle + // data data_r2_lakes + // data data_r2_roots define ais_mainland + name ais + cmdLine ai_service -C. -L. --nobreak --writepid -mCommon:Indoors:Newbieland:Post use ais data data_mainland_common_primitives data data_newbieland_primitives @@ -188,8 +190,8 @@ define ais_mini_mainland cmdLine ai_service -C. -L. --nobreak --writepid -mCommon:Indoors:Newbieland:Post use ais_mainland -define ais_newbyland - name ais_newbyland +define ais_newbieland + name ais_newbieland cmdLine ai_service -C. -L. --nobreak --writepid -mCommon:Indoors:Newbieland:Post use ais data data_mainland_common_primitives @@ -213,36 +215,40 @@ define bms_master use bms cmdLine backup_service -C. -L. --nobreak --writepid -P49990 //cfg #include "../live/cfg/backup_module_service_master.cfg" + cfg #include "../live/service_backup_service/backup_service.cfg" cfgAfter ListeningPort = 49990; cfgAfter L3ListeningPort = 49950; cfgAfter WebPort = 49970; cfgAfter BSReadState = 1; - cfgAfter SaveShardRoot = "../save_shard/"; + cfgAfter SaveShardRoot = "../save_shard_bs/"; define bms_master2 use bms cmdLine backup_service -C. -L. --nobreak --writepid -P49994 //cfg #include "../live/cfg/backup_module_service_master.cfg" + cfg #include "../live/service_backup_service/backup_service.cfg" cfgAfter ListeningPort = 49994; cfgAfter L3ListeningPort = 49954; cfgAfter WebPort = 49974; cfgAfter BSReadState = 1; - cfgAfter SaveShardRoot = "../save_shard/"; + cfgAfter SaveShardRoot = "../save_shard_bs/"; define bms_slave use bms cmdLine backup_service -C. -L. --nobreak --writepid -P49991 - cfg #include "../live/cfg/backup_module_service_slave.cfg" + //cfg #include "../live/cfg/backup_module_service_slave.cfg" + cfg #include "../live/service_backup_service/backup_service.cfg" cfgAfter ListeningPort = 49991; cfgAfter L3ListeningPort = 49951; cfgAfter WebPort = 49971; cfgAfter BSReadState = 0; - cfgAfter SaveShardRoot = "../save_shard/"; + cfgAfter SaveShardRoot = "../save_shard_bs/"; define bms_pd_master use bms cmdLine backup_service -C. -L. --nobreak --writepid -P49992 //cfg #include "../live/cfg/backup_module_service_master.cfg" + cfg #include "../live/service_backup_service/backup_service.cfg" cfgAfter ListeningPort = 49992; cfgAfter L3ListeningPort = 49952; cfgAfter WebPort = 49972; @@ -252,7 +258,8 @@ define bms_pd_master define bms_pd_slave use bms cmdLine backup_service -C. -L. --nobreak --writepid -P49993 - cfg #include "../live/cfg/backup_module_service_slave.cfg" + //cfg #include "../live/cfg/backup_module_service_slave.cfg" + cfg #include "../live/service_backup_service/backup_service.cfg" cfgAfter ListeningPort = 49993; cfgAfter L3ListeningPort = 49953; cfgAfter WebPort = 49973; @@ -263,6 +270,7 @@ define backup_lgs use bms cmdLine backup_service -C. -L. --nobreak --writepid -P49994 //cfg #include "../live/cfg/backup_module_service_master.cfg" + cfg #include "../live/service_backup_service/backup_service.cfg" cfgAfter ListeningPort = 49994; cfgAfter L3ListeningPort = 49995; cfgAfter WebPort = 49972; @@ -320,7 +328,7 @@ define dss define dss_ring use dss - cfg #include "../live/cfg/dynamic_scenario_service_ring.cfg" + // cfg #include "../live/cfg/dynamic_scenario_service_ring.cfg" // egs ----------------------------- @@ -374,17 +382,17 @@ define egs_mainland define egs_ring use egs data data_mainland_common_primitives - data data_newbieland_primitives - data data_newbieland - data data_indoors - cfg #include "../live/cfg/entities_game_service_ring.cfg" + // data data_newbieland_primitives + // data data_newbieland + // data data_indoors + //cfg #include "../live/cfg/entities_game_service_ring.cfg" // care cfg UsedContinents = cfg { cfg "r2_desert", "10000", - cfg "r2_forest", "10001", - cfg "r2_jungle", "10002", - cfg "r2_lakes", "10003", - cfg "r2_roots", "10004", + // cfg "r2_forest", "10001", + // cfg "r2_jungle", "10002", + // cfg "r2_lakes", "10003", + // cfg "r2_roots", "10004", cfg }; cfgAfter MaxXPGainPerPlayer = 30.0; cfgAfter DeathXPFactor = 0.0; @@ -460,16 +468,16 @@ define gpms_mainland use gpms data data_newbieland data data_indoors - cfg #include "../live/cfg/gpm_service_mainland.cfg" + //cfg #include "../live/cfg/gpm_service_mainland.cfg" define gpms_ring use gpms data data_r2_desert - data data_r2_forest - data data_r2_jungle - data data_r2_lakes - data data_r2_roots - cfg #include "../live/cfg/gpm_service_ring.cfg" + // data data_r2_forest + // data data_r2_jungle + // data data_r2_lakes + // data data_r2_roots + //cfg #include "../live/cfg/gpm_service_ring.cfg" // pdss ---------------------------- @@ -534,7 +542,7 @@ define ios_mainland define ios_ring use ios - cfg #include "../live/cfg/input_output_service_ring.cfg" + //cfg #include "../live/cfg/input_output_service_ring.cfg" // las ----------------------------- diff --git a/code/ryzom/server/patchman_cfg/shard_ctrl_mini01.txt b/code/ryzom/server/patchman_cfg/shard_ctrl_mini01.txt index a17f6f922..e09f106ac 100644 --- a/code/ryzom/server/patchman_cfg/shard_ctrl_mini01.txt +++ b/code/ryzom/server/patchman_cfg/shard_ctrl_mini01.txt @@ -30,15 +30,15 @@ define domain_mini01 // domain hosts cfg AESHost = "localhost"; - cfg SUHost = "ep1.mini01.ryzomcore.org"; - cfg MFSHost = "ep1.mini01.ryzomcore.org"; - cfg BSHost = "ep1.mini01.ryzomcore.org:49990"; - cfg SlaveBSHost= "ep1.mini01.ryzomcore.org:49991"; - cfg MasterLGSHost = "ep1.mini01.ryzomcore.org"; - cfg SlaveLGSHost = "ep1.mini01.ryzomcore.org"; - cfg LGSBSHost = "ep1.mini01.ryzomcore.org"; - cfg DBHost = "localhost"; // FIXME "sql.core.ryzomcore.org"; - cfgAfter WebSrvHost = "http://ep1.mini01.ryzomcore.org:50000/"; + cfg SUHost = "ep1.mini01.ryzomcore.local"; + cfg MFSHost = "ep1.mini01.ryzomcore.local"; + cfg BSHost = "ep1.mini01.ryzomcore.local:49990"; + cfg SlaveBSHost= "ep1.mini01.ryzomcore.local:49991"; + cfg MasterLGSHost = "ep1.mini01.ryzomcore.local"; + cfg SlaveLGSHost = "ep1.mini01.ryzomcore.local"; + cfg LGSBSHost = "ep1.mini01.ryzomcore.local"; + cfg DBHost = "ep1.mini01.ryzomcore.local"; + cfgAfter WebSrvHost = "http://ep1.mini01.ryzomcore.local:50000/"; // initial config files cfgFile ../cfg/00_base.cfg @@ -84,7 +84,7 @@ define shard_mini01_unifier use exe_set_std_lgs_slave use backup_lgs cfg DBPass = DBNelPass; - host ep1.mini01.ryzomcore.org + host ep1.mini01.ryzomcore.local // shard mainland01 ---------------- @@ -95,10 +95,10 @@ define shard_mini01_mainland01 cfg ShardId = 301; cfg BasePort = 52000; cfg SaveFilesDirectory="mini01_mainland01/"; - cfg NSHost = "ep1.mini01.ryzomcore.org"; - cfg FSListenHost = "ep1.mini01.ryzomcore.org"; + cfg NSHost = "ep1.mini01.ryzomcore.local"; + cfg FSListenHost = "ep1.mini01.ryzomcore.local"; cfgFile ../cfg/02_shard_type_mini_mainland.cfg - host ep1.mini01.ryzomcore.org + host ep1.mini01.ryzomcore.local // shard ring01 -------------------- @@ -110,7 +110,7 @@ define shard_mini01_ring01 cfg BasePort = 52400; cfg SaveFilesDirectory="mini01_ring01/"; cfg NSPort = 51100; - cfg NSHost = "ep1.mini01.ryzomcore.org" + 51100; + cfg NSHost = "ep1.mini01.ryzomcore.local" + 51100; cfgFile ../cfg/02_shard_type_std_ring.cfg - host ep1.mini01.ryzomcore.org + host ep1.mini01.ryzomcore.local diff --git a/code/ryzom/server/patchman_cfg/shard_ctrl_std01.txt b/code/ryzom/server/patchman_cfg/shard_ctrl_std01.txt index 311261110..5492d6af3 100644 --- a/code/ryzom/server/patchman_cfg/shard_ctrl_std01.txt +++ b/code/ryzom/server/patchman_cfg/shard_ctrl_std01.txt @@ -32,15 +32,15 @@ define domain_std01 // domain hosts cfg AESHost = "localhost"; - cfg SUHost = "su1.std01.ryzomcore.org"; - cfg MFSHost = "su1.std01.ryzomcore.org"; - cfg BSHost = "pd1.std01.ryzomcore.org:49990"; // Backup service host for domain - cfg SlaveBSHost= "pd2.std01.ryzomcore.org:49991"; - cfg MasterLGSHost = "pd3.std01.ryzomcore.org"; - cfg SlaveLGSHost = "pd4.std01.ryzomcore.org"; - cfg LGSBSHost = "csr.core.ryzomcore.org"; // Backup service host for log service - cfg DBHost = "sql.core.ryzomcore.org"; - cfgAfter WebSrvHost = "http://su1.std01.ryzomcore.org:50000/"; + cfg SUHost = "su1.std01.ryzomcore.local"; + cfg MFSHost = "su1.std01.ryzomcore.local"; + cfg BSHost = "pd1.std01.ryzomcore.local:49990"; // Backup service host for domain + cfg SlaveBSHost= "pd2.std01.ryzomcore.local:49991"; + cfg MasterLGSHost = "pd3.std01.ryzomcore.local"; + cfg SlaveLGSHost = "pd4.std01.ryzomcore.local"; + cfg LGSBSHost = "csr.core.ryzomcore.local"; // Backup service host for log service + cfg DBHost = "sql.core.ryzomcore.local"; + cfgAfter WebSrvHost = "http://su1.std01.ryzomcore.local:50000/"; // initial config files cfgFile ../cfg/00_base.cfg @@ -86,11 +86,11 @@ define shard_std01_unifier define shard_exe_set_std01_ras use ras - host ep1.std01.ryzomcore.org + host ep1.std01.ryzomcore.local define shard_exe_set_std01_unifier use exe_set_std_unifier - host su1.std01.ryzomcore.org + host su1.std01.ryzomcore.local cfg DBPass = DBNelPass; @@ -106,30 +106,30 @@ define shard_std01_mainland01 cfg ShardId = 101; cfg BasePort = 51000; cfg SaveFilesDirectory="std01_mainland01/"; - cfg NSHost = "mla1.std01.ryzomcore.org"; + cfg NSHost = "mla1.std01.ryzomcore.local"; cfgFile ../cfg/02_shard_type_std_mainland.cfg define shard_exe_set_std01_mainland01_be01 use exe_set_std_mainland_be01 - host mla1.std01.ryzomcore.org + host mla1.std01.ryzomcore.local define shard_exe_set_std01_mainland01_be02 use exe_set_std_mainland_be02 - host mla2.std01.ryzomcore.org + host mla2.std01.ryzomcore.local define shard_exe_set_std01_mainland01_be03 use exe_set_std_mainland_be03 - host mla3.std01.ryzomcore.org + host mla3.std01.ryzomcore.local define shard_exe_set_std01_mainland01_fe01 use exe_set_std_mainland_fe - host mla4.std01.ryzomcore.org - cfg FSListenHost = "mla4.std01.ryzomcore.org"; + host mla4.std01.ryzomcore.local + cfg FSListenHost = "mla4.std01.ryzomcore.local"; define shard_exe_set_std01_mainland01_fe02 use exe_set_std_mainland_fe - host mla5.std01.ryzomcore.org - cfg FSListenHost = "mla5.std01.ryzomcore.org"; + host mla5.std01.ryzomcore.local + cfg FSListenHost = "mla5.std01.ryzomcore.local"; // shard mainland02 ---------------- @@ -144,30 +144,30 @@ define shard_std01_mainland02 cfg ShardId = 102; cfg BasePort = 51100; cfg SaveFilesDirectory="std01_mainland02/"; - cfg NSHost = "mlb1.std01.ryzomcore.org"; + cfg NSHost = "mlb1.std01.ryzomcore.local"; cfgFile ../cfg/02_shard_type_std_mainland.cfg define shard_exe_set_std01_mainland02_be01 use exe_set_std_mainland_be01 - host mlb1.std01.ryzomcore.org + host mlb1.std01.ryzomcore.local define shard_exe_set_std01_mainland02_be02 use exe_set_std_mainland_be02 - host mlb2.std01.ryzomcore.org + host mlb2.std01.ryzomcore.local define shard_exe_set_std01_mainland02_be03 use exe_set_std_mainland_be03 - host mlb3.std01.ryzomcore.org + host mlb3.std01.ryzomcore.local define shard_exe_set_std01_mainland02_fe01 use exe_set_std_mainland_fe - host mlb4.std01.ryzomcore.org - cfg FSListenHost = "mlb4.std01.ryzomcore.org"; + host mlb4.std01.ryzomcore.local + cfg FSListenHost = "mlb4.std01.ryzomcore.local"; define shard_exe_set_std01_mainland02_fe02 use exe_set_std_mainland_fe - host mlb5.std01.ryzomcore.org - cfg FSListenHost = "mlb5.std01.ryzomcore.org"; + host mlb5.std01.ryzomcore.local + cfg FSListenHost = "mlb5.std01.ryzomcore.local"; // shard ring01 -------------------- @@ -179,17 +179,17 @@ define shard_std01_ring01 cfg ShardId = 201; cfg BasePort = 51400; cfg SaveFilesDirectory="std01_ring01/"; - cfg NSHost = "rra1.std01.ryzomcore.org"; + cfg NSHost = "rra1.std01.ryzomcore.local"; cfgFile ../cfg/02_shard_type_std_ring.cfg define shard_exe_set_std01_ring01_be use exe_set_std_ring_be - host rra1.std01.ryzomcore.org + host rra1.std01.ryzomcore.local define shard_exe_set_std01_ring01_fe use exe_set_std_ring_fe - host rra2.std01.ryzomcore.org - cfg FSListenHost = "rra2.std01.ryzomcore.org"; + host rra2.std01.ryzomcore.local + cfg FSListenHost = "rra2.std01.ryzomcore.local"; // shard ring02 -------------------- @@ -201,17 +201,17 @@ define shard_std01_ring02 cfg ShardId = 202; cfg BasePort = 51500; cfg SaveFilesDirectory="std01_ring02/"; - cfg NSHost = "rrb1.std01.ryzomcore.org"; + cfg NSHost = "rrb1.std01.ryzomcore.local"; cfgFile ../cfg/02_shard_type_std_ring.cfg define shard_exe_set_std01_ring02_be use exe_set_std_ring_be - host rrb1.std01.ryzomcore.org + host rrb1.std01.ryzomcore.local define shard_exe_set_std01_ring02_fe use exe_set_std_ring_fe - host rrb2.std01.ryzomcore.org - cfg FSListenHost = "rrb2.std01.ryzomcore.org"; + host rrb2.std01.ryzomcore.local + cfg FSListenHost = "rrb2.std01.ryzomcore.local"; // the std01 backup domain ---------- @@ -260,7 +260,7 @@ define shard_std01_backup_ras shard std01_backup_ras cfg ShardId = 100; use ras - host ep1.std01.ryzomcore.org + host ep1.std01.ryzomcore.local // the main backup pair ------------ @@ -273,15 +273,15 @@ define shard_std01_backup define shard_exe_set_std01_backup_master name bs_master use exe_set_std_backup_master - host pd1.std01.ryzomcore.org + host pd1.std01.ryzomcore.local define shard_exe_set_std01_backup_slave name bs_slave // hack to workaround bug in backup service // use exe_set_std_backup_slave use exe_set_std01_backup_slave - host pd2.std01.ryzomcore.org - cfgAfter MasterBSHost = "pd1.std01.ryzomcore.org:49990"; + host pd2.std01.ryzomcore.local + cfgAfter MasterBSHost = "pd1.std01.ryzomcore.local:49990"; // hack to workaround bug in backup service define exe_set_std01_backup_slave @@ -312,27 +312,27 @@ define shard_std01_lgs cfg L3SlaveLGSPort = 49993; cfg LGSBSPort = 49994; cfg L3LGSBSPort = 49995; - cfg MasterLGSHost = "pd3.std01.ryzomcore.org"; - cfg SlaveLGSHost = "pd4.std01.ryzomcore.org"; - cfg LGSBSHost = "csr.core.ryzomcore.org"; + cfg MasterLGSHost = "pd3.std01.ryzomcore.local"; + cfg SlaveLGSHost = "pd4.std01.ryzomcore.local"; + cfg LGSBSHost = "csr.core.ryzomcore.local"; define shard_exe_set_std01_lgs_primary name lgs_primary use raes use exe_set_std_lgs_master - host pd3.std01.ryzomcore.org + host pd3.std01.ryzomcore.local define shard_exe_set_std01_lgs_secondary name lgs_secondary use raes use exe_set_std_lgs_slave - host pd4.std01.ryzomcore.org + host pd4.std01.ryzomcore.local define shard_exe_set_std01_lgs_bs name lgs_bs use raes use backup_lgs - host csr.core.ryzomcore.org + host csr.core.ryzomcore.local // the std01 las domain ------------- @@ -365,7 +365,7 @@ define shard_std01_las_ras shard std01_las_ras cfg ShardId = 100; use ras - host ep1.std01.ryzomcore.org + host ep1.std01.ryzomcore.local // master las ---------------------- @@ -378,7 +378,7 @@ define shard_std01_las_master use las_mainland02 use las_ring01 use las_ring02 - host pd3.std01.ryzomcore.org + host pd3.std01.ryzomcore.local define las_mainland01 cfgAfter StartCommands += {"PDRootDirectory /srv/core/backup01/save_shard_pd/std01_mainland01/pds"}; @@ -415,7 +415,7 @@ define shard_std01_las_slave use las_mainland02_slave use las_ring01_slave use las_ring02_slave - host pd4.std01.ryzomcore.org + host pd4.std01.ryzomcore.local define las_mainland01_slave cfgAfter StartCommands += {"PDRootDirectory /srv/core/backup01/save_shard_pd/std01_mainland01/pds"}; diff --git a/code/ryzom/server/patchman_cfg/terminal_mini01/patchman_service.cfg b/code/ryzom/server/patchman_cfg/terminal_mini01/patchman_service.cfg index 351a8614a..c6a336c02 100644 --- a/code/ryzom/server/patchman_cfg/terminal_mini01/patchman_service.cfg +++ b/code/ryzom/server/patchman_cfg/terminal_mini01/patchman_service.cfg @@ -41,12 +41,12 @@ StartCommands += // bridge gateway // "moduleManager.createModule StandardGateway gw1", // "gw1.transportAdd L3Client l3client", -// "gw1.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44748)", +// "gw1.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44748)", // ats spm gateway "moduleManager.createModule StandardGateway gw2", "gw2.transportAdd L3Client l3client", - "gw2.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.org:44751)", + "gw2.transportCmd l3client(connect addr=ep1.mini01.ryzomcore.local:44751)", //------------------------------------------------------------------------------ diff --git a/code/ryzom/server/patchman_cfg/terminal_mini01/terminal_mini01.bat b/code/ryzom/server/patchman_cfg/terminal_mini01/terminal_mini01.bat index 7f61bfa59..90e11d5d6 100644 --- a/code/ryzom/server/patchman_cfg/terminal_mini01/terminal_mini01.bat +++ b/code/ryzom/server/patchman_cfg/terminal_mini01/terminal_mini01.bat @@ -1,2 +1,2 @@ @echo off -start S:\devw_x86\bin\Release\ryzom_patchman_service.exe --nolog -C. -L. \ No newline at end of file +start R:\build\bin\Release\ryzom_patchman_service.exe --nolog -C. -L. \ No newline at end of file diff --git a/code/ryzom/server/src/ai_data_service/pacs_scan.cpp b/code/ryzom/server/src/ai_data_service/pacs_scan.cpp index 5fc1ed6b5..28e55559c 100644 --- a/code/ryzom/server/src/ai_data_service/pacs_scan.cpp +++ b/code/ryzom/server/src/ai_data_service/pacs_scan.cpp @@ -48,7 +48,7 @@ // Server share -#include "server_share/bmp4image.h" +#include "game_share/bmp4image.h" #include "server_share/continent_container.h" diff --git a/code/ryzom/server/src/ai_service/sheets.cpp b/code/ryzom/server/src/ai_service/sheets.cpp index bc7ece4fa..8369023e0 100644 --- a/code/ryzom/server/src/ai_service/sheets.cpp +++ b/code/ryzom/server/src/ai_service/sheets.cpp @@ -581,7 +581,7 @@ void AISHEETS::CCreature::readGeorges(NLMISC::CSmartPtr const& } if (item.getValueByName(s, "Basics.FameForGuardAttack") && !s.empty()) { - double tmp; + float tmp; sscanf(s.c_str(), "%f", &tmp); _FameForGuardAttack = (sint32)tmp; } diff --git a/code/ryzom/server/src/entities_game_service/creature_manager/harvestable.h b/code/ryzom/server/src/entities_game_service/creature_manager/harvestable.h index cd1ecfd06..f966e6cb0 100644 --- a/code/ryzom/server/src/entities_game_service/creature_manager/harvestable.h +++ b/code/ryzom/server/src/entities_game_service/creature_manager/harvestable.h @@ -188,7 +188,7 @@ protected: /// the harvestable Mps (4 per entity) std::vector< CCreatureRawMaterial> _Mps; - /// pointer on the harverting character + /// pointer on the harvesting character TDataSetRow _HarvesterRowId; /// skill used to harvest this creature diff --git a/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.cpp b/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.cpp index f36fe91ab..42517c190 100644 --- a/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.cpp +++ b/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.cpp @@ -237,24 +237,12 @@ void SItemSpecialEffects::serial(class NLMISC::IStream &f) //-------------------------------------------------------------- // init() //-------------------------------------------------------------- -void CStaticItem::init() +void CStaticItem::init(bool doDelete) { Family = ITEMFAMILY::UNDEFINED; Type = ITEM_TYPE::UNDEFINED; - Armor = NULL; - MeleeWeapon = NULL; - RangeWeapon = NULL; - Ammo = NULL; - Shield = NULL; - TamingTool = NULL; - Mp = NULL; - GuildOption = NULL; - Cosmetics = NULL; - ItemServiceData = NULL; - ConsumableItem = NULL; - XpCatalyser = NULL; - CommandTicket = NULL; + clearPtrs(doDelete); Skill = SKILLS::unknown; MinSkill = 0; @@ -287,16 +275,54 @@ void CStaticItem::init() RequiredCharacQualityFactor = 0.0f; RequiredCharacQualityOffset = 0; - ItemSpecialEffects = NULL; } // init // +// *************************************************************************** +void CStaticItem::clearPtrs(bool doDelete) +{ + if (doDelete) + { + delete Armor; + delete MeleeWeapon; + delete RangeWeapon; + delete Ammo; + delete Shield; + delete TamingTool; + delete Mp; + delete GuildOption; + delete Cosmetics; + delete ItemServiceData; + delete ConsumableItem; + delete XpCatalyser; + delete CommandTicket; + delete ItemSpecialEffects; + } + + Armor = NULL; + MeleeWeapon = NULL; + RangeWeapon = NULL; + Ammo = NULL; + Shield = NULL; + TamingTool = NULL; + Mp = NULL; + GuildOption = NULL; + Cosmetics = NULL; + ItemServiceData = NULL; + ConsumableItem = NULL; + XpCatalyser = NULL; + CommandTicket = NULL; + ItemSpecialEffects = NULL; +} + //-------------------------------------------------------------- // copy constructor //-------------------------------------------------------------- CStaticItem::CStaticItem( const CStaticItem& itm ) { + clearPtrs(false); + *this = itm; if(itm.Armor) { @@ -1443,6 +1469,9 @@ void CStaticItem::readGeorges (const NLMISC::CSmartPtr &form, if (form == NULL) return; + // Clear pointers to previous data + clearPtrs(true); + // Get the root node, always exist UFormElm &root = form->getRootNode (); @@ -1993,37 +2022,6 @@ float CStaticItem::getBaseWeight() const } #endif -// *************************************************************************** -void CStaticItem::clearPtrs(bool doDelete) -{ - if(doDelete) - { - if (Ammo != NULL ) delete Ammo; - if (Armor != NULL ) delete Armor; - if (MeleeWeapon != NULL ) delete MeleeWeapon; - if (RangeWeapon != NULL ) delete RangeWeapon; - if (Cosmetics != NULL ) delete Cosmetics; - if (Mp != NULL ) delete Mp; - if (GuildOption != NULL ) delete GuildOption; - if (Shield != NULL ) delete Shield; - if (TamingTool != NULL) delete TamingTool; - if (ItemServiceData != NULL) delete ItemServiceData; - if (CommandTicket != NULL) delete CommandTicket; - } - - Ammo = NULL; - Armor = NULL; - MeleeWeapon = NULL; - RangeWeapon = NULL; - Cosmetics = NULL; - Mp = NULL; - GuildOption = NULL; - Shield = NULL; - TamingTool = NULL; - ItemServiceData = NULL; - CommandTicket = NULL; -} - uint32 CStaticItem::getMaxStackSize() const { diff --git a/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.h b/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.h index ddea7be9c..96aae2e98 100644 --- a/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.h +++ b/code/ryzom/server/src/entities_game_service/egs_sheets/egs_static_game_item.h @@ -812,13 +812,13 @@ public: public: /// Constructor - CStaticItem() { init(); } + CStaticItem() { init(false); } /// copy constructor CStaticItem( const CStaticItem& itm ); /// init method - void init(); + void init(bool doDelete = true); /// destructor virtual ~CStaticItem(); diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp b/code/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp index 010176023..f2fc03eb0 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp @@ -1509,7 +1509,7 @@ NLMISC_DYNVARIABLE( uint32, RyzomSeason, "Get season number (0=Spring)" ) #ifdef DEPOSIT_MAP_GENERATION -#include "server_share/bmp4image.h" +#include "game_share/bmp4image.h" #include typedef std::map< std::string, pair< pair< float, float >, uint > > CSUMap; diff --git a/code/ryzom/server/src/entities_game_service/phrase_manager/sabrina_area_debug.h b/code/ryzom/server/src/entities_game_service/phrase_manager/sabrina_area_debug.h index 4964b78e1..a87c0a092 100644 --- a/code/ryzom/server/src/entities_game_service/phrase_manager/sabrina_area_debug.h +++ b/code/ryzom/server/src/entities_game_service/phrase_manager/sabrina_area_debug.h @@ -23,7 +23,7 @@ #include "egs_mirror.h" #include "area_geometry.h" -#include "server_share/bmp4image.h" +#include "game_share/bmp4image.h" diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character.cpp b/code/ryzom/server/src/entities_game_service/player_manager/character.cpp index 4a9096232..3c72995ea 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character.cpp +++ b/code/ryzom/server/src/entities_game_service/player_manager/character.cpp @@ -14167,7 +14167,7 @@ void CCharacter::sendCloseTempInventoryImpulsion() BOMB_IF(isRecursing,"CCharacter::sendCloseTempInventoryImpulsion is recursing!",return); // **** Temp Fix 2/4 **** // isRecursing= true; // **** Temp Fix 3/4 **** // - getAllTempInventoryItems(); + getAllTempInventoryItems(false); CMessage msgout( "IMPULSION_ID" ); msgout.serial( _Id ); diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character.h b/code/ryzom/server/src/entities_game_service/player_manager/character.h index 3f97c6b3e..de6d3f110 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character.h +++ b/code/ryzom/server/src/entities_game_service/player_manager/character.h @@ -2623,13 +2623,13 @@ public: CGameItemPtr createItemInInventoryFreeSlot(INVENTORIES::TInventory invId, uint16 obtainedQuality, uint32 quantity, const NLMISC::CSheetId & obtainedItem, const NLMISC::CEntityId & creatorId = NLMISC::CEntityId::Unknown, const std::string * phraseId = NULL); /// action on an item in the temp inventory (move it to bag) - void itemTempInventoryToBag(uint32 scrSlot); + void itemTempInventoryToBag(uint32 scrSlot, bool sendCloseTempImpulsion = true); /// clear temp inventory void clearTempInventory(); /// get all items in temp inventory - void getAllTempInventoryItems(); + void getAllTempInventoryItems(bool sendCloseTempImpulsion = true); /// return true if temp inventory is empty bool tempInventoryEmpty(); diff --git a/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp b/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp index 2ce09282c..139cf1b4e 100644 --- a/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp +++ b/code/ryzom/server/src/entities_game_service/player_manager/character_inventory_manipulation.cpp @@ -1841,7 +1841,7 @@ CGameItemPtr CCharacter::createItemInInventoryFreeSlot(INVENTORIES::TInventory i } // **************************************************************************** -void CCharacter::itemTempInventoryToBag(uint32 srcSlot) +void CCharacter::itemTempInventoryToBag(uint32 srcSlot, bool sendCloseTempImpulsion) { H_AUTO(CCharacter_itemTempInventoryToBag); @@ -2015,7 +2015,7 @@ void CCharacter::itemTempInventoryToBag(uint32 srcSlot) CWorldInstances::instance().msgToAIInstance(getInstanceNumber(), msg); } - endHarvest(); + endHarvest(sendCloseTempImpulsion); leaveTempInventoryMode(); } @@ -2108,12 +2108,12 @@ void CCharacter::itemTempInventoryToBag(uint32 srcSlot) } // **************************************************************************** -void CCharacter::getAllTempInventoryItems() +void CCharacter::getAllTempInventoryItems(bool sendCloseTempImpulsion) { H_AUTO(CCharacter_getAllTempInventoryItems); for (uint i = 0 ; i < INVENTORIES::NbTempInvSlots; ++i) - itemTempInventoryToBag(i); + itemTempInventoryToBag(i, sendCloseTempImpulsion); } // **************************************************************************** diff --git a/code/ryzom/server/src/monitor_service/service_main.cpp b/code/ryzom/server/src/monitor_service/service_main.cpp index a0e577269..84bbcbe86 100644 --- a/code/ryzom/server/src/monitor_service/service_main.cpp +++ b/code/ryzom/server/src/monitor_service/service_main.cpp @@ -392,7 +392,15 @@ void clientAuthentication(CMessage &msgin, TSockId from, CCallbackNetBase &netba { if (strlen(row[0]) > 2) { - std::string salt = std::string(row[0], row[0] + 2); + std::string salt; + if (row[0][0] == '$') + { + salt = std::string(row[0], row[0] + 19); + } + else + { + salt = std::string(row[0], row[0] + 2); + } std::string cryptedVersion = CCrypt::crypt(password, salt); if (cryptedVersion == row[0]) { diff --git a/code/ryzom/tools/CMakeLists.txt b/code/ryzom/tools/CMakeLists.txt index 0bf9fb632..041ba210e 100644 --- a/code/ryzom/tools/CMakeLists.txt +++ b/code/ryzom/tools/CMakeLists.txt @@ -23,9 +23,7 @@ IF(WITH_LIGO AND WITH_NET) ADD_SUBDIRECTORY(sheets_packer) ENDIF(WITH_LIGO AND WITH_NET) -IF(WITH_RYZOM_CLIENT) - ADD_SUBDIRECTORY(client) -ENDIF(WITH_RYZOM_CLIENT) +ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(server) diff --git a/code/ryzom/tools/client/CMakeLists.txt b/code/ryzom/tools/client/CMakeLists.txt index ff7516ccc..aabc3142c 100644 --- a/code/ryzom/tools/client/CMakeLists.txt +++ b/code/ryzom/tools/client/CMakeLists.txt @@ -1,5 +1,10 @@ -ADD_SUBDIRECTORY( client_patcher ) -IF( WITH_QT ) -ADD_SUBDIRECTORY( client_config_qt ) -ENDIF( WITH_QT ) +IF(WITH_RYZOM_CLIENT) + ADD_SUBDIRECTORY( client_patcher ) + + IF( WITH_QT ) + ADD_SUBDIRECTORY( client_config_qt ) + ENDIF( WITH_QT ) +ENDIF(WITH_RYZOM_CLIENT) + +ADD_SUBDIRECTORY( r2_islands_textures ) diff --git a/code/ryzom/tools/client/r2_islands_textures/CMakeLists.txt b/code/ryzom/tools/client/r2_islands_textures/CMakeLists.txt new file mode 100644 index 000000000..0fc6c65a2 --- /dev/null +++ b/code/ryzom/tools/client/r2_islands_textures/CMakeLists.txt @@ -0,0 +1,17 @@ +FILE(GLOB SRC *.cpp *.h) + +ADD_EXECUTABLE(r2_islands_textures ${SRC}) + +INCLUDE_DIRECTORIES(${RZ_SERVER_SRC_DIR} ${LIBXML2_INCLUDE_DIR}) +TARGET_LINK_LIBRARIES(r2_islands_textures + ryzom_gameshare + ryzom_aishare + ${LIBXML2_LIBRARIES} + nelmisc + nel3d) +ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) + +NL_DEFAULT_PROPS(r2_islands_textures "Ryzom, Tools, Server: R2 Islands Textures") +NL_ADD_RUNTIME_FLAGS(r2_islands_textures) + +INSTALL(TARGETS r2_islands_textures RUNTIME DESTINATION ${RYZOM_BIN_PREFIX} COMPONENT tools) diff --git a/code/nel/src/misc/keyboard_device.cpp b/code/ryzom/tools/client/r2_islands_textures/main.cpp similarity index 68% rename from code/nel/src/misc/keyboard_device.cpp rename to code/ryzom/tools/client/r2_islands_textures/main.cpp index 4c7f353bc..cbde8b9d4 100644 --- a/code/nel/src/misc/keyboard_device.cpp +++ b/code/ryzom/tools/client/r2_islands_textures/main.cpp @@ -1,4 +1,4 @@ -// NeL - MMORPG Framework +// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify @@ -14,23 +14,16 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -#include "stdmisc.h" +#include +#include "screenshot_islands.h" -//#include "nel/3d/u_keyboard_device.h" +using namespace NLMISC; +using namespace R2; -#ifdef DEBUG_NEW - #define new DEBUG_NEW -#endif - -namespace NL3D { - - -/* - * Constructor - */ -/*UKeyboardDevice::UKeyboardDevice() +int main(int argc, char **argv) { -}*/ + CScreenshotIslands screenshotIslands = CScreenshotIslands::getInstance(); + screenshotIslands.buildScreenshots(); - -} // NL3D + return 0; +} diff --git a/code/ryzom/tools/client/r2_islands_textures/screenshot_islands.cpp b/code/ryzom/tools/client/r2_islands_textures/screenshot_islands.cpp new file mode 100644 index 000000000..4f167ea9c --- /dev/null +++ b/code/ryzom/tools/client/r2_islands_textures/screenshot_islands.cpp @@ -0,0 +1,2351 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "screenshot_islands.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// AI share +#include + +#include + +#include + +using namespace NLMISC; +using namespace NL3D; +using namespace std; +using namespace EGSPD; +using namespace NLGEORGES; +using namespace RYAI_MAP_CRUNCH; + + +// The 3d driver +UDriver *driver = NULL; +CLandscapeIGManager LandscapeIGManager; + +uint ScreenShotWidth; +uint ScreenShotHeight; + +UMaterial sceneMaterial; + +namespace R2 +{ + +const TBufferEntry InteriorValue= (TBufferEntry)(~0u-1); +const TBufferEntry ValueBorder= (TBufferEntry)(~0u-2); +const uint32 BigValue= 15*5; +const float limitValue = 200.0; + +//------------------------------------------------------------------------------------------------- +CScreenshotIslands::CScreenshotIslands() +{ + _BackColor = CRGBA(255, 255, 255, 255); +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::init() +{ + // Create a driver + driver = UDriver::createDriver(0, true); + nlassert(driver); + + sceneMaterial = driver->createMaterial(); + sceneMaterial.getObjectPtr()->setLighting(true); + sceneMaterial.getObjectPtr()->setSpecular(CRGBA(255, 255, 255, 255)); + sceneMaterial.getObjectPtr()->setShininess(50); + sceneMaterial.getObjectPtr()->setDiffuse(CRGBA(100, 100, 100, 255)); + sceneMaterial.getObjectPtr()->setEmissive(CRGBA(25, 25, 25, 255)); + + // load and parse the configfile + CConfigFile cf; + cf.load("island_screenshots.cfg"); + + // get the value of searchPaths + CConfigFile::CVar * searchPaths = cf.getVarPtr("SearchPaths"); + if(searchPaths) + { + for(int i = 0; i < searchPaths->size(); i++) + { + CPath::addSearchPath(searchPaths->asString(i).c_str(), true, false); + } + } + CPath::remapExtension("dds", "tga", true); + CPath::remapExtension("dds", "png", true); + + // get the scenario entry points file + CConfigFile::CVar * epFile = cf.getVarPtr("CompleteIslandsFile"); + if(epFile) + { + _CompleteIslandsFile = epFile->asString(); + } + + // get the out directory path + CConfigFile::CVar * outDir = cf.getVarPtr("OutDir"); + if(outDir) + { + _OutDirectory = outDir->asString(); + } + + // get the vegetation option + CConfigFile::CVar * veget = cf.getVarPtr("Vegetation"); + if(veget) + { + _Vegetation = veget->asBool(); + } + + // get the vegetation option + CConfigFile::CVar * inverseZTest = cf.getVarPtr("InverseZTest"); + if(inverseZTest) + { + _InverseZTest = inverseZTest->asBool(); + } + + // get list of continents + CConfigFile::CVar * continents = cf.getVarPtr("Continents"); + vector continentsName(continents->size()); + for(int i = 0; i < continents->size(); i++) + { + continentsName[i] = continents->asString(i); + } + + // get continents data (light, coarseMesh,...) + UFormLoader * formLoader; + for(uint i=0; i form = formLoader->loadForm(CPath::lookup(georgeFileName).c_str()); + if(form) + { + CContinentData continentData; + + UFormElm &formRoot = form->getRootNode(); + + const UFormElm *elm; + if(formRoot.getNodeByName(&elm, "LightLandscapeDay") && elm) + { + CDirLightSetup landscapeLightDay; + landscapeLightDay.build(*elm); + continentData.Ambiant = landscapeLightDay.Ambiant; + continentData.Diffuse = landscapeLightDay.Diffuse; + + if(continentsName[i]=="r2_jungle" || continentsName[i]=="r2_forest" || continentsName[i]=="r2_roots") + { + continentData.Ambiant = CRGBA(255, 255, 255, 255); + continentData.Diffuse = CRGBA(255, 255, 255, 255); + } + } + + formRoot.getValueByName(continentData.IGFile, "LandscapeIG"); + string zoneMin, zoneMax; + formRoot.getValueByName(zoneMin, "ZoneMin"); + formRoot.getValueByName(zoneMax, "ZoneMax"); + + getPosFromZoneName(zoneMin, continentData.ZoneMin); + getPosFromZoneName(zoneMax, continentData.ZoneMax); + + string filename; + if(formRoot.getValueByName(filename, "Ecosystem")) + { + UFormLoader *formLoaderEco = UFormLoader::createLoader(); + if(formLoaderEco) + { + // Load the form + CSmartPtr formEco = formLoaderEco->loadForm(filename.c_str()); + + if(formEco) + { + // Root node + UFormElm &formRootEco = formEco->getRootNode(); + + // Small bank. + formRootEco.getValueByName(continentData.SmallBank, "SmallBank"); + + // Far bank. + formRootEco.getValueByName(continentData.FarBank, "FarBank"); + + // Coarse mesh texture. + formRootEco.getValueByName(continentData.CoarseMeshMap, "CoarseMeshMap"); + } + else + { + nlwarning("CScreenshotIslands::init : Can't load form %s.", filename.c_str()); + } + UFormLoader::releaseLoader(formLoaderEco); + } + } + + _ContinentsData[continentsName[i]] = continentData; + } + UFormLoader::releaseLoader(formLoader); + } + + + // load islands + loadIslands(); + + searchIslandsBorders(); + + // get seasons + CConfigFile::CVar * seasonSuffixes = cf.getVarPtr("SeasonSuffixes"); + if(seasonSuffixes) + { + for(uint i = 0; i < (uint)seasonSuffixes->size(); i++) + { + _SeasonSuffixes.push_back(seasonSuffixes->asString(i)); + } + } + + // get the meter size in pixels + CConfigFile::CVar * meterSize = cf.getVarPtr("MeterPixelSize"); + if(meterSize) + { + _MeterPixelSize = meterSize->asInt(); + } +} + +//------------------------------------------------------------------------------------------------- +bool CScreenshotIslands::getPosFromZoneName(const std::string &name, NLMISC::CVector2f &dest) +{ + if(name.empty()) + { + nlwarning ("getPosFromZoneName(): empty name, can't getPosFromZoneName"); + return false; + } + + static std::string zoneName; + static string xStr, yStr; + xStr.clear(); + yStr.clear(); + zoneName = CFile::getFilenameWithoutExtension(name); + uint32 i = 0; + while(zoneName[i] != '_') + { + if(!::isdigit(zoneName[i])) return false; + yStr += zoneName[i]; ++i; + if(i == zoneName.size()) + return false; + } + ++i; + while(i < zoneName.size()) + { + if(!::isalpha(zoneName[i])) return false; + xStr += (char) ::toupper(zoneName[i]); ++i; + } + if(xStr.size() != 2) return false; + dest.x = 160.f * ((xStr[0] - 'A') * 26 + (xStr[1] - 'A')); + dest.y = 160.f * -atoi(yStr.c_str()); + return true; +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::searchIslandsBorders() +{ + vector filenames; + list zonelFiles; + + map< CVector2f, bool> islandsMap; + + TContinentsData::iterator itCont(_ContinentsData.begin()), lastCont(_ContinentsData.end()); + for( ; itCont != lastCont ; ++itCont) + { + // for each continent we recover a map of zonel files whith position of + // left/bottom point of each zone for keys + filenames.clear(); + zonelFiles.clear(); + + string bnpFileName = itCont->first + ".bnp"; + CBigFile::getInstance().list(bnpFileName.c_str(), filenames); + + for(uint i=0; i::iterator itZonel(zonelFiles.begin()), lastZonel(zonelFiles.end()); + for( ; itZonel != lastZonel ; ++itZonel) + { + CVector2f position; + getPosFromZoneName(*itZonel, position); + + islandsMap[position] = true; + } + + // search for island borders + CContinentData & continent = itCont->second; + list< string >::const_iterator itIsland(continent.Islands.begin()), lastIsland(continent.Islands.end()); + for( ; itIsland != lastIsland ; ++itIsland) + { + if(_IslandsData.find(itIsland->c_str()) != _IslandsData.end()) + { + const CProximityZone & islandData = _IslandsData[itIsland->c_str()]; + + sint32 xmin = islandData.getBoundXMin(); + sint32 xmax = islandData.getBoundXMax(); + sint32 ymin = islandData.getBoundYMin(); + sint32 ymax = islandData.getBoundYMax(); + + sint32 width = xmax-xmin; + sint32 height = ymax-ymin; + + sint32 zonelXMin = ((uint)(xmin/160)) * 160; + sint32 zonelYMin = ((uint)(ymin/160) - 1) * 160; + sint32 zonelXMax = ((uint)(xmax/160)) * 160; + sint32 zonelYMax = ((uint)(ymax/160) - 1) * 160; + + list< CVector2f > leftBorders, rightBorders, bottomBorders, topBorders; + + // search for left and right borders on lines + for(sint32 y = zonelYMin; y<=zonelYMax; y+=160 ) + { + sint32 x=zonelXMin; + CVector2f vec((float)x, (float)y); + bool lastZoneFull = (islandsMap.find(vec) != islandsMap.end()); + bool currentZoneFull; + + while(x<=zonelXMax) + { + vec = CVector2f((float)x, (float)y); + currentZoneFull = (islandsMap.find(vec) != islandsMap.end()); + + if(lastZoneFull && !currentZoneFull && vec.x-1 >= xmin) + { + rightBorders.push_back(CVector2f(vec.x-1, vec.y)); + } + else if(!lastZoneFull && currentZoneFull) + { + leftBorders.push_back(vec); + } + x += 160; + lastZoneFull = currentZoneFull; + } + } + + // search for bottom and top borders on columns + for(sint32 x = zonelXMin; x<=zonelXMax; x+=160 ) + { + sint32 y=zonelYMin; + CVector2f vec((float)x, (float)y); + bool lastZoneFull = (islandsMap.find(vec) != islandsMap.end()); + bool currentZoneFull; + + while(y<=zonelYMax) + { + vec = CVector2f((float)x, (float)y); + currentZoneFull = (islandsMap.find(vec) != islandsMap.end()); + + if(lastZoneFull && !currentZoneFull && vec.y-1 >= ymin) + { + topBorders.push_back(CVector2f(vec.x, vec.y-1)); + } + else if(!lastZoneFull && currentZoneFull) + { + bottomBorders.push_back(vec); + } + y += 160; + lastZoneFull = currentZoneFull; + } + } + + _BorderIslands[*itIsland + "/right"] = rightBorders; + _BorderIslands[*itIsland + "/left"] = leftBorders; + _BorderIslands[*itIsland + "/bottom"] = bottomBorders; + _BorderIslands[*itIsland + "/top"] = topBorders; + } + } + } +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::attenuateIslandBorders(const std::string & islandName, CBitmap & islandBitmap, + const CProximityZone & islandData) +{ + list< CVector2f > leftBorders, rightBorders, bottomBorders, topBorders; + rightBorders = _BorderIslands[islandName + "/right"]; + leftBorders = _BorderIslands[islandName + "/left"]; + bottomBorders = _BorderIslands[islandName + "/bottom"]; + topBorders = _BorderIslands[islandName + "/top"]; + + sint32 xmin = islandData.getBoundXMin(); + sint32 xmax = islandData.getBoundXMax(); + sint32 ymin = islandData.getBoundYMin(); + sint32 ymax = islandData.getBoundYMax(); + + sint32 width = xmax-xmin; + sint32 height = ymax-ymin; + uint8 *dest = &(islandBitmap.getPixels(0)[0]); + + list< CVector2f >::iterator itBorder; + + for(itBorder=leftBorders.begin(); itBorder!=leftBorders.end(); itBorder++) + { + const CVector2f initPoint = *itBorder; + sint32 x = (sint32)initPoint.x - xmin; + sint32 y = (sint32)initPoint.y - ymin; + sint32 maxBorder = 160; + if(y<0) + { + maxBorder += y; + y = 0; + } + sint32 inity = y; + + while(y<(inity+maxBorder) && y<(sint32)height) + { + double noiseValue = (1+cos(((y-inity)*2*Pi)/maxBorder))*5; + double evalNoise = 10 + noiseValue; + double diffAlpha = 255/evalNoise; + + CRGBA color = islandBitmap.getPixelColor(x, height-y-1); + sint32 currentX = x-1; + + while((currentX>=x-evalNoise) && currentX>=0) + { + uint8 *pixel = &(islandBitmap.getPixels(0)[((height-y-1)*width + currentX)*4]); + uint alpha = (uint)(255-diffAlpha*(x-currentX)); + uint invAlpha = 255-alpha; + + *pixel = (uint8) (((invAlpha * *pixel) + (alpha * color.R)) >> 8); + *(pixel + 1) = (uint8) (((invAlpha * *(pixel + 1)) + (alpha * color.G)) >> 8); + *(pixel + 2) = (uint8) (((invAlpha * *(pixel + 2)) + (alpha * color.B)) >> 8); + *(pixel + 3) = (uint8) 255; + + currentX--; + } + y++; + } + } + + for(itBorder=rightBorders.begin(); itBorder!=rightBorders.end(); itBorder++) + { + const CVector2f initPoint = *itBorder; + sint32 x = (sint32)initPoint.x - xmin; + sint32 y = (sint32)initPoint.y - ymin; + sint32 maxBorder = 160; + if(y<0) + { + maxBorder += y; + y = 0; + } + sint32 inity = y; + + while(y<(inity+maxBorder) && y<(sint32)height) + { + double noiseValue = (1+cos(((y-inity)*2*Pi)/maxBorder))*5; + double evalNoise = 10 + noiseValue; + double diffAlpha = 255/evalNoise; + + CRGBA color = islandBitmap.getPixelColor(x, height-y-1); + sint32 currentX = x+1; + + while((currentX<=x+evalNoise) && currentX> 8); + *(pixel + 1) = (uint8) (((invAlpha * *(pixel + 1)) + (alpha * color.G)) >> 8); + *(pixel + 2) = (uint8) (((invAlpha * *(pixel + 2)) + (alpha * color.B)) >> 8); + *(pixel + 3) = (uint8) 255; + + currentX++; + } + + y++; + } + } + + for(itBorder=bottomBorders.begin(); itBorder!=bottomBorders.end(); itBorder++) + { + const CVector2f initPoint = *itBorder; + sint32 x = (sint32)initPoint.x - xmin; + sint32 y = (sint32)initPoint.y - ymin; + sint32 maxBorder = 160; + if(x<0) + { + maxBorder += x; + x = 0; + } + sint32 initx = x; + + while(x<(initx+maxBorder) && x<(sint32)width) + { + double noiseValue = (1+cos(((x-initx)*2*Pi)/maxBorder))*5; + double evalNoise = 10 + noiseValue; + double diffAlpha = 255/evalNoise; + + CRGBA color = islandBitmap.getPixelColor(x, height-y-1); + sint32 currentY = y-1; + + while((currentY>=y-evalNoise) && currentY>=0) + { + uint8 *pixel = &(islandBitmap.getPixels(0)[((height-currentY-1)*width + x)*4]); + uint alpha = (uint)(255-diffAlpha*(y-currentY)); + uint invAlpha = 255-alpha; + + *pixel = (uint8) (((invAlpha * *pixel) + (alpha * color.R)) >> 8); + *(pixel + 1) = (uint8) (((invAlpha * *(pixel + 1)) + (alpha * color.G)) >> 8); + *(pixel + 2) = (uint8) (((invAlpha * *(pixel + 2)) + (alpha * color.B)) >> 8); + *(pixel + 3) = (uint8) 255; + + currentY--; + } + + x++; + } + } + + for(itBorder=topBorders.begin(); itBorder!=topBorders.end(); itBorder++) + { + const CVector2f initPoint = *itBorder; + sint32 x = (sint32)initPoint.x - xmin; + sint32 y = (sint32)initPoint.y - ymin; + sint32 maxBorder = 160; + if(x<0) + { + maxBorder += x; + x = 0; + } + sint32 initx = x; + + while(x<(initx+maxBorder) && x<(sint32)width) + { + double noiseValue = (1+cos(((x-initx)*2*Pi)/maxBorder))*5; + double evalNoise = 10 + noiseValue; + double diffAlpha = 255/evalNoise; + + CRGBA color = islandBitmap.getPixelColor(x, height-y-1); + sint32 currentY = y+1; + + while((currentY<=y+evalNoise) && currentY> 8); + *(pixel + 1) = (uint8) (((invAlpha * *(pixel + 1)) + (alpha * color.G)) >> 8); + *(pixel + 2) = (uint8) (((invAlpha * *(pixel + 2)) + (alpha * color.B)) >> 8); + *(pixel + 3) = (uint8) 255; + + currentY++; + } + + x++; + } + } +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::buildScreenshots() +{ + init(); + buildIslandsTextures(); +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::writeProximityBufferToTgaFile(const std::string& fileName,const TBuffer& buffer,uint32 scanWidth,uint32 scanHeight) +{ + uint imageWidth = (scanWidth); // (scanWidth+15)&~15; + uint imageHeight = (scanHeight); + + CTGAImageGrey tgaImage; + tgaImage.setup((uint16)imageWidth, (uint16)imageHeight, fileName, 0, 0); + for (uint32 y=0;y255*5)?255:value/5); + } + tgaImage.writeLine(); + } +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::processProximityBuffer(TBuffer & inputBuffer, uint32 lineLength, TBuffer& resultBuffer) +{ + // a couple of constants to control the range over which our degressive filter is to be applied + const uint32 smallValue= 2*5; + + float a = 5*((255.0 - limitValue)/(float(100-BigValue))); + float b = (float)(limitValue*5 - a*BigValue); + + // determine numer of lines in the buffer... + uint32 numLines= inputBuffer.size()/ lineLength; + + // clear out the result buffer and reset all values to 5*255, remembering that this is the correct value for the image edges + resultBuffer.clear(); + resultBuffer.resize(inputBuffer.size(),(TBufferEntry)5*255); + + for (uint32 y=1;yBigValue) value=5*255; + else value= (uint32)(((1.0-cos(Pi*(float(value-smallValue)/(float)(BigValue-smallValue))))/2.0)*float(5*255)); + */ + + if (value==ValueBorder); + else if ((value>=0) && (valueBigValue) + { + if(value==InteriorValue) + { + value = (uint)(5*limitValue); + } + else + { + value = (uint)(a*value+b); + if(value > 5*255) value = 5*255; + } + } + else if((value>=smallValue) && (value<=BigValue)) + { + value= (uint32)(((1.0-cos(Pi*(float(value-smallValue)/(float)(BigValue-smallValue))))/2.0)*float(5*limitValue)); + } + + // store the value into the result buffer + resultBuffer[offset]= (TBufferEntry)value; + } + } + + // modify inputBuffer to store "bigValue" limit + for (uint32 y=1;y0) + { + uint16 nextValue = resultBuffer[offset-1]; + uint16 prevValue = (TBufferEntry)(5*limitValue); + if(nextValue!=(TBufferEntry)(5*limitValue)) + { + uint32 count = x-1; + while((count>x-7) && (count>0) && ((nextValue=resultBuffer[lineOffset+count])!=0) + && nextValue!=(TBufferEntry)(5*limitValue) && (nextValue!=ValueBorder)) + { + uint16 newValue = (TBufferEntry)(prevValue+5*7); + if(newValue < nextValue) + { + resultBuffer[lineOffset+count] = newValue; + } + + prevValue = newValue; + count--; + } + } + } + } + } + } + + //columns + for (uint32 x=0;x=startOffset) + { + uint16 nextValue = resultBuffer[offset-lineLength]; + uint16 prevValue = (TBufferEntry)(5*limitValue); + if(nextValue!=(TBufferEntry)(5*limitValue)) + { + uint32 count = offset-lineLength; + while((count>offset-7*lineLength) && (count>=startOffset) && + ((nextValue=resultBuffer[count])!=0) && nextValue!=(TBufferEntry)(5*limitValue) && (nextValue!=ValueBorder)) + { + uint16 newValue = (TBufferEntry)(prevValue+5*7); + if(newValue < nextValue) + { + resultBuffer[count] = newValue; + } + + prevValue = newValue; + count -= lineLength; + } + } + } + } + } + } + */ + + //----------------------------------------------------------------------------- + // search for pixels of borders + map< CVector2f, bool > bordersPixels; + for (uint32 y=0;y leftBorders, rightBorders, bottomBorders, topBorders; + for (uint32 y=0;y0) + { + for(uint32 xc=(uint32)firstPixelBorder.x; xc<(uint32)(firstPixelBorder.x+nbPixelsBorder); xc++) + { + if(resultBuffer[(y-1)*lineLength+xc]==(TBufferEntry)(5*255)) + { + bottom = true; + break; + } + } + } + + if(y+10) + { + for(uint32 yc=(uint32)firstPixelBorder.y; yc<(uint32)(firstPixelBorder.y+nbPixelsBorder); yc++) + { + if(resultBuffer[yc*lineLength+x-1]==(TBufferEntry)(5*255)) + { + left = true; + break; + } + } + } + + if(x+1=(uint32)(y-evalNoise)) && yc>=0) + { + uint16 newValue = (TBufferEntry)(5*(limitValue + diffAlpha*(y-yc))); + uint16 currentValue = (TBufferEntry)resultBuffer[yc*lineLength+xc]; + if(newValue=(uint32)(x-evalNoise)) && xc>=0) + { + uint16 newValue = (TBufferEntry)(5*(limitValue + diffAlpha*(x-xc))); + uint16 currentValue = (TBufferEntry)resultBuffer[yc*lineLength+xc]; + if(newValue islands; + CScenarioEntryPoints scenarioEntryPoints = CScenarioEntryPoints::getInstance(); + + scenarioEntryPoints.loadFromFile(); + const CScenarioEntryPoints::TEntryPoints& entryPoints = scenarioEntryPoints.getEntryPoints(); + + CScenarioEntryPoints::TEntryPoints::const_iterator entry(entryPoints.begin()), entryPoint(entryPoints.end()); + for( ; entry != entryPoint ; ++entry) + { + islands[entry->Island] = CVector2f((float)entry->X, (float)entry->Y); + } + + // search islands of each continent + map< string, CVector2f >::iterator itIsland(islands.begin()), lastIsland(islands.end()); + for( ; itIsland != lastIsland ; ++itIsland) + { + const CVector2f & entryPoint = itIsland->second; + + // search continent of this island + TContinentsData::iterator itCont(_ContinentsData.begin()), lastCont(_ContinentsData.end()); + for( ; itCont != lastCont ; ++itCont) + { + CContinentData & continent = itCont->second; + CVector2f zoneMax = continent.ZoneMax; + CVector2f zoneMin = continent.ZoneMin; + + if((zoneMin.x <= entryPoint.x) && (entryPoint.x <= zoneMax.x) + && (zoneMax.y <= entryPoint.y) && (entryPoint.y <= zoneMin.y)) + { + continent.Islands.push_back(itIsland->first); + break; + } + } + } + + // search data of each island + TContinentsData::iterator itCont(_ContinentsData.begin()), lastCont(_ContinentsData.end()); + for( ; itCont != lastCont ; ++itCont) + { + string aiFileName = itCont->first+"_0.cwmap2"; + + const CContinentData & continent = itCont->second; + + CProximityMapBuffer continentBuffer; + continentBuffer.load(CPath::lookup(aiFileName)); + + CProximityMapBuffer::TZones zones; + continentBuffer.calculateZones(zones); + + for (uint32 i=0;i::const_iterator itIsland(continent.Islands.begin()), lastIsland(continent.Islands.end()); + for( ; itIsland != lastIsland ; ++itIsland) + { + const CVector2f & entryPoint = islands[*itIsland]; + sint32 xmin = zones[i].getBoundXMin(); + sint32 xmax = zones[i].getBoundXMax(); + sint32 ymin = zones[i].getBoundYMin(); + sint32 ymax = zones[i].getBoundYMax(); + + if((xmin <= entryPoint.x) && (entryPoint.x <= xmax) + && (ymin <= entryPoint.y) && (entryPoint.y <= ymax)) + { + fileName = _OutDirectory + "/" + *itIsland + "_prox.tga"; + _IslandsData[*itIsland] = zones[i]; + break; + } + } + + // write the processed proximity map to an output file + if(fileName != "") + { + writeProximityBufferToTgaFile(fileName, cleanBuffer, zones[i].getZoneWidth(), zones[i].getZoneHeight()); + _TempFileNames.push_back(fileName); + + fileName = _OutDirectory + "/" + *itIsland + "_limit.tga"; + writeProximityBufferToTgaFile(fileName, zoneBuffer, zones[i].getZoneWidth(), zones[i].getZoneHeight()); + _TempFileNames.push_back(fileName); + } + else + { + nlinfo("Zone of island not found, tga not build"); + } + } + } + + + CScenarioEntryPoints::TCompleteIslands completeIslands(entryPoints.size()); + + uint completeIslandsNb = 0; + for(uint e=0; e::const_iterator itIsland(itCont->second.Islands.begin()), lastIsland(itCont->second.Islands.end()); + for( ; itIsland != lastIsland ; ++itIsland) + { + if(*itIsland == entry.Island) + { + completeIsland.Continent = CSString(itCont->first); + if(_IslandsData.find(entry.Island)!=_IslandsData.end()) + { + completeIsland.XMin = _IslandsData[entry.Island].getBoundXMin(); + completeIsland.YMin = _IslandsData[entry.Island].getBoundYMin(); + completeIsland.XMax = _IslandsData[entry.Island].getBoundXMax(); + completeIsland.YMax = _IslandsData[entry.Island].getBoundYMax(); + completeIslands[completeIslandsNb] = completeIsland; + completeIslandsNb++; + } + break; + } + } + } + } + completeIslands.resize(completeIslandsNb); + + CScenarioEntryPoints::getInstance().saveXMLFile(completeIslands, _CompleteIslandsFile); +} + +//-------------------------------------------------------------------------------- + +void CScreenshotIslands::getBuffer(UScene * scene, ULandscape * landscape, CBitmap &btm) +{ + // + if (ScreenShotWidth && ScreenShotHeight) + { + UCamera camera = scene->getCam(); + + // Destination image + CBitmap dest; + btm.resize(ScreenShotWidth, ScreenShotHeight, CBitmap::RGBA); + + uint windowWidth = driver->getWindowWidth(); + uint windowHeight = driver->getWindowHeight(); + + uint top; + uint bottom = min(windowHeight, ScreenShotHeight); + for (top=0; topclearBuffers(_BackColor); + + // store initial frustum and viewport + CFrustum Frustum = scene->getCam().getFrustum(); + CViewport Viewport = scene->getViewport(); + + // Build a new frustum + CFrustum frustumPart; + frustumPart.Left = Frustum.Left+(Frustum.Right-Frustum.Left)*((float)left/(float)ScreenShotWidth); + frustumPart.Right = Frustum.Left+(Frustum.Right-Frustum.Left)*((float)right/(float)ScreenShotWidth); + frustumPart.Top = ceil(Frustum.Top+(Frustum.Bottom-Frustum.Top)*((float)top/(float)ScreenShotHeight)); + frustumPart.Bottom = ceil(Frustum.Top+(Frustum.Bottom-Frustum.Top)*((float)bottom/(float)ScreenShotHeight)); + frustumPart.Near = Frustum.Near; + frustumPart.Far = Frustum.Far; + frustumPart.Perspective = Frustum.Perspective; + + // Build a new viewport + CViewport viewport; + viewport.init(0, 0, (float)(right-left)/windowWidth, + (float)(bottom-top)/windowHeight); + + // Activate all this + scene->getCam().setFrustum(frustumPart); + scene->setViewport(viewport); + + scene->setMaxSkeletonsInNotCLodForm(1000000); + scene->setPolygonBalancingMode(UScene::PolygonBalancingOff); + + if(_InverseZTest) + { + // render scene with inversed ZBuffer test (keep greater distances) + driver->setColorMask(false, false, false, false); + sceneMaterial.setZFunc(UMaterial::less); + + // initialize ZBuffer with leak value + driver->setMatrixMode2D11(); + CQuad quad; + quad.V0 = CVector(0.0, 0.0, 0.0); + quad.V1 = CVector(1.0, 0.0, 0.0); + quad.V2 = CVector(1.0, 1.0, 0.0); + quad.V3 = CVector(0.0, 1.0, 0.0); + + driver->drawQuad(quad, sceneMaterial); + driver->setMatrixMode3D(camera); + driver->setColorMask(true, true, true, true); + + scene->enableElementRender(UScene::FilterWater, false); + } + + scene->render(); + + // display vegetables with normal ZBuffer test + if(_InverseZTest && _Vegetation) + { + scene->enableElementRender(UScene::FilterWater, false); + scene->enableElementRender(UScene::FilterLandscape, false); + scene->enableElementRender(UScene::FilterWater, true); + scene->render(); + scene->enableElementRender(UScene::FilterLandscape, true); + } + + // Get the bitmap + driver->getBuffer(dest); + btm.blit(dest, 0, windowHeight-(bottom-top), right-left, bottom-top, left, top); + + // restore camera + scene->getCam().setFrustum(Frustum); + scene->setViewport(Viewport); + + driver->flush(); + driver->swapBuffers(); + + // Next + right = std::min(right+windowWidth, ScreenShotWidth); + } + + // Next + bottom = std::min(bottom+windowHeight, ScreenShotHeight); + } + } + else + { + driver->getBuffer(btm); + } +} + + + +void CScreenshotIslands::buildIslandsTextures() +{ + int loop = 0; + int maxLoop = 6; + + // Create the window with config file values + driver->setDisplay(UDriver::CMode(512, 512, 32, true)); + + // Create a scene + UScene * scene = driver->createScene(true); + scene->animate(CTime::ticksToSecond(CTime::getPerformanceTime())); + scene->setMaxSkeletonsInNotCLodForm(1000000); + scene->setPolygonBalancingMode(UScene::PolygonBalancingOff); + + // Create a camera + UCamera camera = scene->getCam(); + camera.setTransformMode(UTransformable::DirectMatrix); + + // Create and load landscape + ULandscape * landscape = scene->createLandscape(); + landscape->setThreshold(0.0005); + if(_InverseZTest) + { + landscape->setZFunc(UMaterial::greaterequal); + } + else + { + landscape->setZFunc(UMaterial::less); + } + + //Iteration on seasons + list< string >::iterator itSeason(_SeasonSuffixes.begin()), lastSeason(_SeasonSuffixes.end()); + for( ; itSeason != lastSeason ; ++itSeason) + { + string seasonSuffix = *itSeason; + + int season; + if(seasonSuffix=="_sp") season = CSeason::Spring; + else if(seasonSuffix=="_su") season = CSeason::Summer; + else if(seasonSuffix=="_au") season = CSeason::Autumn; + else if(seasonSuffix=="_wi") season = CSeason::Winter; + + // Iterations on Continents + TContinentsData::iterator itCont(_ContinentsData.begin()), lastCont(_ContinentsData.end()); + for( ; itCont != lastCont ; ++itCont) + { + const CContinentData & continent = itCont->second; + + // Light init + landscape->setupStaticLight(continent.Diffuse, continent.Ambiant, 1.0f); + + string coarseMeshFile = continent.CoarseMeshMap; + string coarseMeshWithoutExt = CFile::getFilenameWithoutExtension(coarseMeshFile); + string coarseMeshExt = CFile::getExtension(coarseMeshFile); + coarseMeshFile = coarseMeshWithoutExt + seasonSuffix + "." + coarseMeshExt; + nldebug("Coarse mesh texture: '%s'", coarseMeshFile.c_str()); + scene->setCoarseMeshManagerTexture(coarseMeshFile.c_str()); + + // Load the landscape + string farBank = continent.FarBank; + string farBankWithoutExt = CFile::getFilenameWithoutExtension(farBank); + string farBankExt = CFile::getExtension(farBank); + farBank = farBankWithoutExt + seasonSuffix + "." + farBankExt; + landscape->loadBankFiles(continent.SmallBank, farBank); + + // Load vegatables + LandscapeIGManager.initIG(scene, continent.IGFile, driver, season, NULL); + + // Iterations on Islands + list< string >::const_iterator itIsland(continent.Islands.begin()), lastIsland(continent.Islands.end()); + for( ; itIsland != lastIsland ; ++itIsland) + { + loop = 0; + + if(_IslandsData.find(itIsland->c_str()) != _IslandsData.end()) + { + const CProximityZone & islandData = _IslandsData[itIsland->c_str()]; + + sint32 xmin = islandData.getBoundXMin(); + sint32 xmax = islandData.getBoundXMax(); + sint32 ymin = islandData.getBoundYMin(); + sint32 ymax = islandData.getBoundYMax(); + + float width = (float)(xmax-xmin); + float height = (float)(ymax-ymin); + ScreenShotWidth = (uint)(width*_MeterPixelSize); + ScreenShotHeight = (uint)(height*_MeterPixelSize); + + // position in island center + float posx = ((float)(xmax+xmin))/2; + float posy = ((float)(ymax+ymin))/2; + CVector entryPos(posx, posy, 400); + + // Setup camera + CMatrix startCamMatrix; + startCamMatrix.setPos(entryPos); + startCamMatrix.rotateX(-(float)Pi/2); + camera.setMatrix(startCamMatrix); + camera.setFrustum(width, height, -10000.0f, 10000.0f, false); + + // init lanscape + landscape->postfixTileFilename(seasonSuffix.c_str()); + + while(loop zonesAdded; + vector zonesRemoved; + IProgressCallback progress; + landscape->refreshAllZonesAround(camera.getMatrix().getPos(), 1000, zonesAdded, zonesRemoved, progress); + if(_Vegetation) + { + LandscapeIGManager.unloadArrayZoneIG(zonesRemoved); + LandscapeIGManager.loadArrayZoneIG(zonesAdded); + + vector::iterator itName(zonesAdded.begin()), lastName(zonesAdded.end()); + for( ; itName != lastName ; ++itName) + { + UInstanceGroup * instanceGr = LandscapeIGManager.getIG(*itName); + if(instanceGr) + { + uint nbInst = instanceGr->getNumInstance(); + for(uint i=0; igetNumInstance(); i++) + { + instanceGr->setCoarseMeshDist(i, 100000); + instanceGr->setDistMax(i, 100000); + } + } + } + } + scene->animate(CTime::ticksToSecond(CTime::getPerformanceTime())); + + // Clear all buffers + driver->clearBuffers(_BackColor); + + if(_InverseZTest) + { + // render scene with inversed ZBuffer test (keep greater distances) + driver->setColorMask(false, false, false, false); + sceneMaterial.setZFunc(UMaterial::less); + + // initialize ZBuffer with leak value + driver->setMatrixMode2D11(); + CQuad quad; + quad.V0 = CVector(0.0, 0.0, 0.0); + quad.V1 = CVector(1.0, 0.0, 0.0); + quad.V2 = CVector(1.0, 1.0, 0.0); + quad.V3 = CVector(0.0, 1.0, 0.0); + + driver->drawQuad(quad, sceneMaterial); + driver->setMatrixMode3D(camera); + driver->setColorMask(true, true, true, true); + + scene->enableElementRender(UScene::FilterWater, false); + } + + scene->render(); + + // display vegetables with normal ZBuffer test + if(_InverseZTest && _Vegetation) + { + scene->enableElementRender(UScene::FilterLandscape, false); + scene->enableElementRender(UScene::FilterWater, true); + scene->render(); + scene->enableElementRender(UScene::FilterLandscape, true); + } + + // Swap 3d buffers + driver->flush(); + driver->swapBuffers(); + + // Pump user input messages + driver->EventServer.pump(); + + loop += 1; + + // Screenshot + if(loop==maxLoop-1) + { + CBitmap islandBitmap; + getBuffer(scene, landscape, islandBitmap); + + buildBackTextureHLS(*itIsland, islandBitmap); + } + if(loop==maxLoop) + { + // create srcennshot bitmap of full island + CBitmap islandBitmap; + getBuffer(scene, landscape, islandBitmap); + + attenuateIslandBorders(*itIsland, islandBitmap, islandData); + + // load proximity bitmap + CBitmap proxBitmap; + std::string proxFileName = _OutDirectory + "/" + *itIsland + "_prox.tga"; + CIFile proxFS(proxFileName.c_str()); + proxBitmap.load(proxFS); + + + // resize proximity bitmap + CBitmap tempBitmap; + int newWidth = islandBitmap.getWidth(); + int newHeight = islandBitmap.getHeight(); + tempBitmap.resize(newWidth, newHeight, islandBitmap.PixelFormat); + // blit src bitmap + //tempBitmap.blit(proxBitmap, 0, 0, newWidth, newHeight, 0, 0); + { + const uint8 *prox = &(proxBitmap.getPixels(0)[0]); + uint8 *temp = &(tempBitmap.getPixels(0)[0]); + for (uint y = 0; y < newHeight; ++y) + for (uint x = 0; x < newWidth; ++x) + { + uint ys = (y * proxBitmap.getHeight()) / newHeight; + uint xs = (x * proxBitmap.getWidth()) / newWidth; + uint addr = ((y * newWidth) + x) * 4; + uint addrs = ((ys * proxBitmap.getWidth()) + xs) * 4; + temp[addr] = prox[addrs]; + temp[addr+1] = prox[addrs+1]; + temp[addr+2] = prox[addrs+2]; + temp[addr+3] = prox[addrs+3]; + } + } + + // swap them + proxBitmap.resize(newWidth, newHeight, proxBitmap.PixelFormat); + proxBitmap.swap(tempBitmap); + + //proxBitmap.resample(newWidth, newHeight); + + + // create final bitmap + CBitmap bitmapDest; + bitmapDest.resize(islandBitmap.getWidth(), islandBitmap.getHeight(), islandBitmap.PixelFormat); + + + // mix black and full island bitmaps with blend factor of proximity bitmap pixels + uint numPix = islandBitmap.getWidth() * islandBitmap.getHeight(); + + const uint8 *alphaProx = &(proxBitmap.getPixels(0)[0]); + const uint8 *srcIsland = &(islandBitmap.getPixels(0)[0]); + uint8 *dest = &(bitmapDest.getPixels(0)[0]); + + + const uint8 *srcBack = &(_BackBitmap.getPixels(0)[0]); + + uint8 *endDest = dest + (numPix << 2); + + do + { + uint invblendFact = (uint) alphaProx[0]; + uint blendFact = 256 - invblendFact; + + // blend 4 component at each pass + *dest = (uint8) (((blendFact * *srcIsland) + (invblendFact * *srcBack)) >> 8); + *(dest + 1) = (uint8) (((blendFact * *(srcIsland + 1)) + (invblendFact * *(srcBack + 1))) >> 8); + *(dest + 2) = (uint8) (((blendFact * *(srcIsland + 2)) + (invblendFact * *(srcBack + 2))) >> 8); + *(dest + 3) = (uint8) 255; + + alphaProx = alphaProx + 4; + srcIsland = srcIsland + 4; + dest = dest + 4; + + srcBack = srcBack + 4; + } + while(dest != endDest); + + + // create tga file of avoidable place in island + string textureName = _OutDirectory + "/" + *itIsland + seasonSuffix + ".tga"; + + CBitmap bitmapLittle; + bitmapLittle.resize(bitmapDest.getWidth(), bitmapDest.getHeight(), bitmapDest.PixelFormat); + bitmapLittle = bitmapDest; + if(!isPowerOf2(bitmapDest.getWidth()) || !isPowerOf2(bitmapDest.getHeight()) ) + { + uint pow2w = NLMISC::raiseToNextPowerOf2(bitmapDest.getWidth()); + uint pow2h = NLMISC::raiseToNextPowerOf2(bitmapDest.getHeight()); + CBitmap enlargedBitmap; + enlargedBitmap.resize(pow2w, pow2h, bitmapDest.PixelFormat); + // blit src bitmap + enlargedBitmap.blit(&bitmapDest, 0, 0); + // swap them + bitmapDest.swap(enlargedBitmap); + } + + COFile fsDest(textureName.c_str()); + bitmapDest.writeTGA(fsDest,32); + + + // little tga + bitmapLittle.resample(bitmapLittle.getWidth()/10, bitmapLittle.getHeight()/10); + if(!isPowerOf2(bitmapLittle.getWidth()) || !isPowerOf2(bitmapLittle.getHeight()) ) + { + uint pow2w = NLMISC::raiseToNextPowerOf2(bitmapLittle.getWidth()); + uint pow2h = NLMISC::raiseToNextPowerOf2(bitmapLittle.getHeight()); + CBitmap enlargedBitmap; + enlargedBitmap.resize(pow2w, pow2h, bitmapLittle.PixelFormat); + // blit src bitmap + enlargedBitmap.blit(&bitmapLittle, 0, 0); + // swap them + bitmapLittle.swap(enlargedBitmap); + } + + textureName = _OutDirectory + "/" + *itIsland + seasonSuffix + "_little.tga"; + COFile fsLittle(textureName.c_str()); + bitmapLittle.writeTGA(fsLittle,32); + + _BackColor = CRGBA(255, 255, 255, 255); + } + } + } + } + + LandscapeIGManager.reset(); + landscape->removeAllZones(); + } + } + + // remove proximity tga + list::iterator itProx(_TempFileNames.begin()), lastProx(_TempFileNames.end()); + for( ; itProx != lastProx ; ++itProx) + { + CFile::deleteFile(*itProx); + }; +} + +//-------------------------------------------------------------------------------- +inline bool RGB2HSV(const CRGBA & rgba, uint & Hue, uint & Sat, uint & Val) +{ + double Min_, Max_, Delta, H, S, V; + + H = 0.0; + Min_ = min(min(rgba.R, rgba.G), rgba.B); + Max_ = max(max(rgba.R, rgba.G), rgba.B); + Delta = ( Max_ - Min_); + V = Max_; + + if(Max_ != 0.0) + { + S = 255.0*Delta/Max_; + } + else + { + S = 0.0; + H = -1; + return false; + } + + if(rgba.R == Max_) + { + H = (rgba.G - rgba.B) / Delta; + } + else if(rgba.G == Max_) + { + H = 2.0 + (rgba.B - rgba.R) / Delta; + } + else + { + H = 4.0 + (rgba.R - rgba.G) / Delta; + } + + H = H * 60; + if(H < 0.0) + { + H = H + 360.0; + } + + Hue = (uint)H ; // Hue -> 0..360 + Sat = (uint)S * 100 / 255; // Saturation -> 0..100 % + Val = (uint)V * 100 / 255; // Value - > 0..100 % + + return true; +} + +//------------------------------------------------------------------------------------------------- +inline bool infHLS(const CRGBA & rgba1, const CRGBA & rgba2) +{ + uint h1, s1, v1, h2, s2, v2; + RGB2HSV(rgba1, h1, s1, v1); + RGB2HSV(rgba2, h2, s2, v2); + + if(h1 != h2) + { + return (h1 < h2); + } + else if(s1 != s2) + { + return (s1 < s2); + } + else + { + return (v1 < v2); + } +} + +//------------------------------------------------------------------------------------------------- +void CScreenshotIslands::buildBackTextureHLS(const std::string & islandName, const CBitmap & islandBitmap) +{ + // load limit bitmap + CBitmap limBitmap; + std::string limFileName = _OutDirectory + "/" + islandName + "_limit.tga"; + + CIFile limFS(limFileName.c_str()); + limBitmap.load(limFS); + + list< CRGBA > limitPixels; + + // search for colors of limit pixels + for(uint x=0; x sortedHLS; + list< CRGBA >::iterator itCol, itHLS; + bool inserted = false; + for(itCol=limitPixels.begin(); itCol!=limitPixels.end(); itCol++) + { + inserted = false; + for(itHLS=sortedHLS.begin(); itHLS!=sortedHLS.end(); ++itHLS) + { + if(infHLS(*itCol, *itHLS)) + { + sortedHLS.insert(itHLS, *itCol); + inserted = true; + break; + } + } + if(inserted==false) sortedHLS.push_back(*itCol); + } + + + // keep more filled eighth of circle + nlassert(!sortedHLS.empty()); // If it crashes here, you may be missing .zonel's. + itHLS = sortedHLS.begin(); + uint h, s, v; + RGB2HSV(*itHLS, h, s, v); + list< CRGBA > currentList, maxList; + + for(uint i=0; i<8; i++) + { + while(itHLS!=sortedHLS.end() && h maxList.size()) + { + maxList.clear(); + maxList = currentList; + currentList.clear(); + } + } + + vector< CRGBA > sortedColors(maxList.size()); + uint colorsNb = 0; + CRGBA lastColor(0, 0, 0, 0); + CRGBA maxColor; + uint maxColorNb = 0; + uint currentColorNb = 0; + for(itHLS=maxList.begin(); itHLS!=maxList.end(); ++itHLS) + { + if(lastColor==*itHLS) + { + currentColorNb++; + } + else + { + currentColorNb = 1; + } + + if(currentColorNb>maxColorNb) + { + maxColorNb = currentColorNb; + maxColor = *itHLS; + } + + lastColor = *itHLS; + + RGB2HSV(*itHLS, h, s, v); + if(v>25 && v<75 && s>25 && s<75) + { + sortedColors[colorsNb] = *itHLS; + colorsNb++; + } + } + + if(colorsNb < 5) + { + colorsNb = 0; + for(itHLS=maxList.begin(); itHLS!=maxList.end(); ++itHLS) + { + sortedColors[colorsNb] = *itHLS; + colorsNb++; + } + } + + sortedColors.resize(colorsNb); + + _BackBitmap.resize(islandBitmap.getWidth(), islandBitmap.getHeight(), islandBitmap.PixelFormat); + + if(sortedColors.size()!=0) + { + _BackColor = maxColor; + + CRandom randomGenerator; + + uint8 * backPixels = &(_BackBitmap.getPixels(0)[0]); + + for(uint x=0; x<_BackBitmap.getWidth(); x++) + { + for(uint y=0; y<_BackBitmap.getHeight(); y++) + { + sint32 randomVal = randomGenerator.rand(colorsNb-1); + const CRGBA & color = sortedColors[randomVal]; + + *backPixels = (uint8) color.R; + *(backPixels + 1) = (uint8) color.G; + *(backPixels + 2) = (uint8) color.B; + *(backPixels + 3) = (uint8) 255; + + backPixels = backPixels+4; + } + } + } + + /* + //TEST + CBitmap HLSBitmap; + HLSBitmap.resize(640, sortedColors.size()*4, islandBitmap.PixelFormat); + + uint8 * hlsPixels = &(HLSBitmap.getPixels(0)[0]); + + for(uint i=0; i < sortedColors.size(); i++) + { + uint count = 0; + while(count<640*4) + { + *hlsPixels = (uint8) sortedColors[i].R; + *(hlsPixels + 1) = (uint8) sortedColors[i].G; + *(hlsPixels + 2) = (uint8) sortedColors[i].B; + *(hlsPixels + 3) = (uint8) sortedColors[i].A; + + hlsPixels = hlsPixels+4; + count++; + } + } + + + string textureName = _OutDirectory + "/" + islandName + "_HLS2.tga"; + COFile fsHLS(textureName.c_str()); + HLSBitmap.writeTGA(fsHLS,32); + */ +} + + +//-------------------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------- +// methods CProximityMapBuffer +//------------------------------------------------------------------------------------------------- + +void CProximityMapBuffer::load(const std::string& name) +{ + // load the AI collision map file + CWorldMap worldMap; + CIFile f(name); + f.serial(worldMap); + + // lookup the map bounds + CMapPosition min, max; + worldMap.getBounds(min, max); + + // calculate a handful of constants relating to the bounds of the image... + _ScanWidth = max.x()-min.x(); + _ScanHeight = max.y()-min.y(); + _XOffset= min.x(); + _YOffset= (sint16)min.y(); + + // redimension buffer to correct size + _Buffer.resize(_ScanWidth*_ScanHeight); + + // setup a position variable to mark the start point of each line + CMapPosition scanpos(min.x(),min.y()); + + // iterate over the scan area looking for points that are accessible + for (uint32 y=0; y<_ScanHeight; ++y, scanpos = scanpos.getStepN()) + { + CMapPosition pos(scanpos); + + // scan a line of the map + for (uint32 x=0; x<_ScanWidth; ++x, pos = pos.getStepE()) + { + bool isAccessible= false; + // if the cell pointer is NULL it means that the 16x16 cell in question is inaccessible + if (worldMap.getRootCellCst(pos) != NULL) + { + // run through the surfaces in the cell looking for a match for this position (may be as many as 3 surfaces per cell max) + for (uint32 ns=0; ns<3; ++ns) + { + isAccessible |= worldMap.getSafeWorldPosition(pos, CSlot(ns)).isValid(); + } + } + // setup the next pixel in the output buffers... + _Buffer[y*_ScanWidth+x]= (isAccessible? 0: (TBufferEntry)~0u); + } + } +} + +//------------------------------------------------------------------------------------------------- +void CProximityMapBuffer::calculateZones(TZones& zones) +{ + // clear out the result buffer before starting work + zones.clear(); + + // setup a container to hold the accessible points within this buffer + typedef std::set TAccessiblePoints; + TAccessiblePoints accessiblePoints; + + // start by building the set of all accessible points + for (uint32 i=0;i<_Buffer.size();++i) + { + if (_Buffer[i]==0) + accessiblePoints.insert(i); + } + + // while there are still points remaining in the set we must have another zone to process + while (!accessiblePoints.empty()) + { + // append a new zone to the zones vector and get a refference to it + zones.push_back( CProximityZone(_ScanWidth,_ScanHeight,_XOffset,_YOffset) ); + CProximityZone& theZone= zones.back(); + + // setup a todo list representing points that are part of the surface that we are dealing with + // that haven't yet been treated to check for neighbours, etc + std::vector todo; + + // get hold of the first point in the accessilbe points set and push it onto the todo list + todo.push_back(*accessiblePoints.begin()); + accessiblePoints.erase(todo.back()); + + // while we have more points to deal with ... + while (!todo.empty()) + { + // pop the next point off the todo list + uint32 thePoint= todo.back(); + todo.pop_back(); + + // add the point to the zone + theZone.add(thePoint); + + // a little macro for the code to perform for each movement test... + #define TEST_MOVE(xoffs,yoffs)\ + {\ + TAccessiblePoints::iterator it= accessiblePoints.find(thePoint+xoffs+_ScanWidth*yoffs);\ + if (it!=accessiblePoints.end())\ + {\ + todo.push_back(*it);\ + accessiblePoints.erase(it);\ + }\ + } + + // N, S, W, E moves + TEST_MOVE( 0, 1); + TEST_MOVE( 0,-1); + TEST_MOVE( 1, 0); + TEST_MOVE(-1, 0); + + // NW, NE, WS, SE moves + TEST_MOVE( 1, 1); + TEST_MOVE(-1, 1); + TEST_MOVE( 1,-1); + TEST_MOVE(-1,-1); + + #undef TEST_MOVE + } + } + + nlinfo("Found %u zones",zones.size()); +} + +//------------------------------------------------------------------------------------------------- +void CProximityMapBuffer::_prepareBufferForZoneProximityMap(const CProximityZone& zone,TBuffer& zoneBuffer,TOffsetsVector& accessiblePoints) +{ + // the length of runs that we consider too short to deal with... + const uint32 shortRunLength=5; + + // redimention and initialise the zone buffer + uint32 zoneWidth= zone.getZoneWidth(); + uint32 zoneHeight= zone.getZoneHeight(); + zoneBuffer.clear(); + zoneBuffer.resize(zoneWidth*zoneHeight,(TBufferEntry)~0u); + + // setup the buffer's accessible points and prime vects[0] with the set of accessible points in the zone buffer + for (uint32 i=0;istartOffset && zoneBuffer[endOffset]!=0; endOffset-= zoneWidth) {} + + for (uint32 offset=startOffset, marker=startOffset;offset<=endOffset;offset+=zoneWidth) + { + // see if this is an accessible position + if (zoneBuffer[offset]!=0) + { + zoneBuffer[offset]= InteriorValue; + + if(offset-1>=startOffset && zoneBuffer[offset-1]==(TBufferEntry)~0u) + { + zoneBuffer[offset-1] = ValueBorder; + } + if(offset+1<=endOffset && zoneBuffer[offset+1]==(TBufferEntry)~0u) + { + zoneBuffer[offset+1] = ValueBorder; + } + } + } + } + + // continue by dealing with all points that belong to a short run in the x direction + for (uint32 i=0;istartOffset && zoneBuffer[endOffset]!=0; --endOffset) {} + + for (uint32 offset=startOffset, marker=startOffset;offset<=endOffset;++offset) + { + // see if this is an accessible position + if (zoneBuffer[offset]!=0) + { + zoneBuffer[offset]= InteriorValue; + + if(offset>zoneWidth && zoneBuffer[offset-zoneWidth]==(TBufferEntry)~0u) + { + zoneBuffer[offset-zoneWidth] = ValueBorder; + } + if(offset+zoneWidth BigValue) + || (zoneBuffer[val]==ValueBorder && dist > BigValue)) + continue; + + // write the new distance into this buffer entry + zoneBuffer[val]=dist; + + // decompose into x and y in order to manage identification of neighbour cells correctly + uint32 x= val% zoneWidth; + uint32 y= val/ zoneWidth; + + #define TEST_MOVE(xoffs,yoffs,newDist)\ + {\ + if (((uint32)(x+(xoffs)) BigValue) || (zoneBuffer[newVal]==ValueBorder && newDist > BigValue));\ + if (zoneBuffer[newVal]>(newDist) && !isInterior)\ + {\ + zoneBuffer[newVal]=(newDist);\ + vects[(newDist)&15].push_back(newVal);\ + ++entriesToTreat;\ + }\ + }\ + } + + // N, S, W, E moves + TEST_MOVE( 0, 1,dist+5); + TEST_MOVE( 0,-1,dist+5); + TEST_MOVE( 1, 0,dist+5); + TEST_MOVE(-1, 0,dist+5); + + // NW, NE, WS, SE moves + TEST_MOVE( 1, 1,dist+7); + TEST_MOVE(-1, 1,dist+7); + TEST_MOVE( 1,-1,dist+7); + TEST_MOVE(-1,-1,dist+7); + + // NNW, NNE, SSW, SSE moves + TEST_MOVE( 1, 2,dist+11); + TEST_MOVE(-1, 2,dist+11); + TEST_MOVE( 1,-2,dist+11); + TEST_MOVE(-1,-2,dist+11); + + // WNW, WSW, ENE, ESE moves + TEST_MOVE( 2, 1,dist+11); + TEST_MOVE(-2, 1,dist+11); + TEST_MOVE( 2,-1,dist+11); + TEST_MOVE(-2,-1,dist+11); + + #undef TEST_MOVE + } + + // clear out the vector + entriesToTreat-= vect.size(); + vect.clear(); + } +} + +//------------------------------------------------------------------------------------------------- +const TBuffer& CProximityMapBuffer::getBuffer() const +{ + return _Buffer; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityMapBuffer::getScanHeight() const +{ + return _ScanHeight; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityMapBuffer::getScanWidth() const +{ + return _ScanWidth; +} + +//----------------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------- +// methods CProximityZone +//------------------------------------------------------------------------------------------------- + +CProximityZone::CProximityZone(uint32 scanWidth,uint32 scanHeight,sint32 xOffset, sint32 yOffset) +{ + _ScanWidth = scanWidth; + _ScanHeight = scanHeight; + _XOffset = xOffset; + _YOffset = yOffset; + + _MaxOffset = scanWidth * scanHeight -1; + + _XMin = ~0u; + _YMin = ~0u; + _XMax = 0; + _YMax = 0; + + _BorderPixels = 30; +} + +//------------------------------------------------------------------------------------------------- +bool CProximityZone::add(uint32 offset) +{ + // make sure the requested point is in the zone + if (offset>_MaxOffset) + return false; + + // calculate the x and y coordinates of the point + uint32 y= offset/ _ScanWidth; + uint32 x= offset% _ScanWidth; + + // update the bounding coordinates for this zone + if (x<_XMin) _XMin= x; + if (x>_XMax) _XMax= x; + if (y<_YMin) _YMin= y; + if (y>_YMax) _YMax= y; + + // add the point to the vector of points + _Offsets.push_back(offset); + return true; +} + +//------------------------------------------------------------------------------------------------- +const CProximityZone::TOffsets& CProximityZone::getOffsets() const +{ + return _Offsets; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getZoneWidth() const +{ + return getZoneXMax()- getZoneXMin() +1; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getZoneHeight() const +{ + return getZoneYMax()- getZoneYMin() +1; +} + +//------------------------------------------------------------------------------------------------- +sint32 CProximityZone::getZoneXMin() const +{ + return _XMin-_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +sint32 CProximityZone::getZoneYMin() const +{ + return _YMin-_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getZoneXMax() const +{ + return _XMax+_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getZoneYMax() const +{ + return _YMax+_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getBoundXMin() const +{ + return _XMin+_XOffset-_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getBoundYMin() const +{ + return _YMin+_YOffset-_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getBoundXMax() const +{ + return _XMax+_XOffset+_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::getBoundYMax() const +{ + return _YMax+_YOffset+_BorderPixels; +} + +//------------------------------------------------------------------------------------------------- +uint32 CProximityZone::remapOffset(uint32 bufferOffset) const +{ + // decompose input coordinates into x and y parts + uint32 bufferX= bufferOffset% _ScanWidth; + uint32 bufferY= bufferOffset/ _ScanWidth; + + // remap the offset from a _Buffer-relative offset to a zone-relative offset + return bufferX-getZoneXMin()+ (bufferY-getZoneYMin())*getZoneWidth(); +} + +} + diff --git a/code/ryzom/tools/client/r2_islands_textures/screenshot_islands.h b/code/ryzom/tools/client/r2_islands_textures/screenshot_islands.h new file mode 100644 index 000000000..7d47fa3e7 --- /dev/null +++ b/code/ryzom/tools/client/r2_islands_textures/screenshot_islands.h @@ -0,0 +1,241 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_SCRRENSHOT_ISLANDS_H +#define CL_SCRRENSHOT_ISLANDS_H + +// Misc +#include "nel/misc/singleton.h" +#include "nel/misc/vector_2f.h" +#include "nel/misc/rgba.h" +#include "nel/misc/bitmap.h" + +#include + +namespace NL3D +{ + class UScene; + class ULandscape; +} + +namespace R2 +{ + class CProximityZone; + +typedef uint16 TBufferEntry; +typedef std::vector TBuffer; +typedef std::vector TOffsetsVector; + +//----------------------------------------------------------------------------- +// class CScreenshotIslands +//----------------------------------------------------------------------------- +struct CIslandData +{ + NLMISC::CVector2f EntryPoint; + NLMISC::CVector2f Max; + NLMISC::CVector2f Min; + + CIslandData() + { + EntryPoint = NLMISC::CVector2f(0, 0); + Max = NLMISC::CVector2f(0, 0); + Min = NLMISC::CVector2f(0, 0); + } + + CIslandData(float x, float y) + { + EntryPoint = NLMISC::CVector2f(x, y); + Max = NLMISC::CVector2f(0, 0); + Min = NLMISC::CVector2f(0, 0); + } +}; + +struct CContinentData +{ + std::string SmallBank; + std::string FarBank; + std::string IGFile; + std::string CoarseMeshMap; + NLMISC::CVector2f ZoneMin; + NLMISC::CVector2f ZoneMax; + std::list< std::string > Islands; + NLMISC::CRGBA Ambiant; + NLMISC::CRGBA Diffuse; + + CContinentData() {} +}; + +typedef std::map< const std::string, CProximityZone> TIslandsData; +typedef std::map< NLMISC::CVector2f, bool > TIslandsMap; +typedef std::map< const std::string, CContinentData > TContinentsData; +typedef std::map< std::string, std::list< NLMISC::CVector2f > > TIslandsBordersMap; + +class CScreenshotIslands : public NLMISC::CSingleton +{ + +public: + + CScreenshotIslands(); + + void buildScreenshots(); + +private: + + void init(); + + void loadIslands(); + + void buildIslandsTextures(); + + void getBuffer(NL3D::UScene * scene, NL3D::ULandscape * landscape, NLMISC::CBitmap &btm); + + bool getPosFromZoneName(const std::string &name, NLMISC::CVector2f &dest); + + void writeProximityBufferToTgaFile(const std::string& fileName,const TBuffer& buffer, + uint32 scanWidth,uint32 scanHeight); + + void processProximityBuffer(TBuffer& inputBuffer, uint32 lineLength, TBuffer& resultBuffer); + + void buildBackTextureHLS(const std::string & islandName, const NLMISC::CBitmap & islandBitmap); + + void searchIslandsBorders(); + + void attenuateIslandBorders(const std::string & islandName, NLMISC::CBitmap & islandBitmap, const CProximityZone & islandData); + + TIslandsData _IslandsData; + TIslandsMap _IslandsMap; + TContinentsData _ContinentsData; + std::list< std::string > _SeasonSuffixes; + int _MeterPixelSize; + std::string _OutDirectory; + std::list< std::string > _TempFileNames; + TIslandsBordersMap _BorderIslands; + bool _Vegetation; + bool _InverseZTest; + + NLMISC::CRGBA _BackColor; + NLMISC::CBitmap _BackBitmap; + std::string _CompleteIslandsFile; +}; + + + + + + +class CProximityZone +{ +public: + typedef std::vector TOffsets; + + // ctor + // scanWidth and scanHeight define the dimentions of the buffer that this zone is being extracted from + // xOffset and yOffset are for re-mapping coordinates from buffer-relative to absolute ryzom world coordinates + CProximityZone(uint32 scanWidth=0,uint32 scanHeight=0,sint32 xOffset=0, sint32 yOffset=0); + + // add an 'accessible position' to a zone (offset is y*scanWidth+x) + bool add(uint32 offset); + + // zone dimention accessors (note that zone dimentions line up with 160x160 world zones) + // note that this means that the zone bounds may extend outside the scan area + uint32 getZoneWidth() const; + uint32 getZoneHeight() const; + sint32 getZoneXMin() const; + sint32 getZoneYMin() const; + uint32 getZoneXMax() const; + uint32 getZoneYMax() const; + + // read accessors for the bounding limits that define the area occupied by the accessible points + uint32 getBoundXMin() const; + uint32 getBoundYMin() const; + uint32 getBoundXMax() const; + uint32 getBoundYMax() const; + + // read accessor for the _Offsets vector + // this is a vector of offsets into the scan area. It needs to be remapped to zone offsets + // via the remapOffset() routine in order to be used to index into a zone buffer + const TOffsets& getOffsets() const; + + // remap a scan buffer offset to a zone offset by decomposing into x and y parts and + // subtracting getZoneXMin() and getZoneYMin() + uint32 remapOffset(uint32 bufferOffset) const; + +private: + // parameters setup at construction time, giving info on the context that we're in + uint32 _ScanWidth; + uint32 _ScanHeight; + sint32 _XOffset; + sint32 _YOffset; + uint32 _MaxOffset; + + // the vector of points that are part of this zone + TOffsets _Offsets; + + // the min and max coords of the points that are part of this zone + uint32 _XMax; + uint32 _XMin; + uint32 _YMax; + uint32 _YMin; + + // border add to bouding zone (pixels number) + int _BorderPixels; +}; + +//------------------------------------------------------------------------------------------------- +// class CProximityMapBuffer +//------------------------------------------------------------------------------------------------- + +class CProximityMapBuffer +{ +public: + typedef std::vector TZones; + + // load a cwmap2 file and setup this object from its contents + // the 'name' parameter is the full file name of the file to load with path and extension + void load(const std::string& name); + + // scan the buffer to generate the set of non-connecting zones that it contains + void calculateZones(TZones& zones); + + // generate the proximity map for a given zone + void generateZoneProximityMap(const CProximityZone& zone,TBuffer& zoneBuffer); + + // read accessors... + const TBuffer& getBuffer() const; + uint32 getScanHeight() const; + uint32 getScanWidth() const; + + // buffer coordinate to world coordinate offsets... + sint32 _XOffset; + sint32 _YOffset; + +private: + // private routine used by generateZoneProximityMap() to setup the zoneBuffer with the accessible points set + void _prepareBufferForZoneProximityMap(const CProximityZone& zone,TBuffer& zoneBuffer,TOffsetsVector& accessiblePoints); + +private: + // the width and heilght of the scan zone (ie the dimentions of the buffer) + uint32 _ScanWidth; + uint32 _ScanHeight; + + // vector representing 2d array of points [_ScanHeight][_ScanWidth] + TBuffer _Buffer; +}; + + +} + +#endif \ No newline at end of file diff --git a/code/ryzom/tools/leveldesign/world_editor/world_editor/display.cpp b/code/ryzom/tools/leveldesign/world_editor/world_editor/display.cpp index dd2a17d82..09763d27c 100644 --- a/code/ryzom/tools/leveldesign/world_editor/world_editor/display.cpp +++ b/code/ryzom/tools/leveldesign/world_editor/world_editor/display.cpp @@ -309,6 +309,7 @@ void CDisplay::init (CMainFrame *pMF) _TextContext->setFontGenerator(NLMISC::CPath::getWindowsDirectory() + "Fonts\\arial.ttf"); _TextContext->setKeep800x600Ratio(true); _TextContext->setShaded(true); + _TextContext->setShadeOutline(false); _TextContext->setShadeColor(NLMISC::CRGBA::Black); } catch(...) diff --git a/code/ryzom/tools/server/ai_build_wmap/build_proximity_maps.cpp b/code/ryzom/tools/server/ai_build_wmap/build_proximity_maps.cpp index 5cb7c6922..a15f8c6d3 100644 --- a/code/ryzom/tools/server/ai_build_wmap/build_proximity_maps.cpp +++ b/code/ryzom/tools/server/ai_build_wmap/build_proximity_maps.cpp @@ -27,7 +27,7 @@ #include "nel/misc/file.h" // Game share -#include "server_share/bmp4image.h" +#include "game_share/bmp4image.h" // AI share #include "ai_share/world_map.h" diff --git a/code/ryzom/tools/server/build_world_packed_col/build_world_packed_col.cpp b/code/ryzom/tools/server/build_world_packed_col/build_world_packed_col.cpp index a9d1daa9e..f03489196 100644 --- a/code/ryzom/tools/server/build_world_packed_col/build_world_packed_col.cpp +++ b/code/ryzom/tools/server/build_world_packed_col/build_world_packed_col.cpp @@ -111,6 +111,7 @@ int main(int argc, char* argv[]) CPath::addSearchPath(builderConfig.SearchPaths[k], true, false); } CPath::remapExtension("dds", "tga", true); + CPath::remapExtension("dds", "png", true); // R2::CScenarioEntryPoints &sep = R2::CScenarioEntryPoints::getInstance(); try @@ -210,7 +211,7 @@ int main(int argc, char* argv[]) catch(const EStream &) { mustRebuild = true; // damaged file or bad version ? -> force rebuild - delete packedIsland; // remove whatever was serialized + // delete packedIsland; // remove whatever was serialized // NOPE. smart pointer packedIsland = new CPackedWorldHolder; } } diff --git a/code/snowballs2/client/src/camera.cpp b/code/snowballs2/client/src/camera.cpp index 9d9a5f777..0b7971192 100644 --- a/code/snowballs2/client/src/camera.cpp +++ b/code/snowballs2/client/src/camera.cpp @@ -128,6 +128,7 @@ void initCamera() StereoHMD->setScale(3.0f); // snowballs is about 4 units per meter } StereoDisplay->setDriver(Driver); // move after driver creation, move stereodisplay before driver creation + StereoDisplay->attachToDisplay(); } } } diff --git a/code/snowballs2/client/src/commands.cpp b/code/snowballs2/client/src/commands.cpp index 41faeab1e..d1929ab49 100644 --- a/code/snowballs2/client/src/commands.cpp +++ b/code/snowballs2/client/src/commands.cpp @@ -296,7 +296,7 @@ void initCommands() CommandsMaterial.setBlend(true); #if SBCLIENT_DEV_PIXEL_PROGRAM - CommandsMaterial.getObjectPtr()->setShader(NL3D::CMaterial::PostProcessing); + CommandsMaterial.getObjectPtr()->setShader(NL3D::CMaterial::Program); a_NelLogo = Driver->createTextureFile("nel128.tga"); CommandsMaterial.setTexture(dynamic_cast(a_NelLogo)); static const char *program_arbfp1 = @@ -340,7 +340,24 @@ void initCommands() "mov oC0.xzw, c0.xyyx\n" "texld oC0.y, v0, s0\n"; NL3D::IDriver *d = dynamic_cast(Driver)->getDriver(); - if (d->supportPixelProgram(CPixelProgram::fp40)) + a_DevPixelProgram = new CPixelProgram(); + // arbfp1 + { + IProgram::CSource *source = new IProgram::CSource(); + source->Features.MaterialFlags = CProgramFeatures::TextureStages; + source->Profile = IProgram::arbfp1; + source->setSourcePtr(program_arbfp1); + a_DevPixelProgram->addSource(source); + } + // ps_2_0 + { + IProgram::CSource *source = new IProgram::CSource(); + source->Features.MaterialFlags = CProgramFeatures::TextureStages; + source->Profile = IProgram::ps_2_0; + source->setSourcePtr(program_ps_2_0); + a_DevPixelProgram->addSource(source); + } + /*if (d->supportPixelProgram(CPixelProgram::fp40)) { nldebug("fp40"); a_DevPixelProgram = new CPixelProgram(program_fp40); @@ -349,14 +366,14 @@ void initCommands() { nldebug("arbfp1"); a_DevPixelProgram = new CPixelProgram(program_arbfp1); - } + }*/ /*else if (d->supportPixelProgram(CPixelProgram::ps_3_0)) { nldebug("ps_3_0"); a_DevPixelProgram = new CPixelProgram(program_ps_3_0); // Textures do not seem to work with ps_3_0... }*/ - else if (d->supportPixelProgram(CPixelProgram::ps_2_0)) + /*else if (d->supportPixelProgram(CPixelProgram::ps_2_0)) { nldebug("ps_2_0"); a_DevPixelProgram = new CPixelProgram(program_ps_2_0); @@ -365,7 +382,7 @@ void initCommands() { nldebug("ps_1_1"); a_DevPixelProgram = new CPixelProgram(program_ps_1_1); - } + }*/ #endif } @@ -385,17 +402,6 @@ void updateCommands() float CommandsBoxHeight = ((float)(sint32)((CommandsNbLines + 1) * CommandsLineHeight * width)) / width; float CommandsBoxBorderX = ((float)(sint32)(SBCLIENT::CommandsBoxBorder * width)) / width; float CommandsBoxBorderY = ((float)(sint32)(SBCLIENT::CommandsBoxBorder * height)) / height; - if (StereoHMD) - { - float xshift, yshift; - StereoHMD->getInterface2DShift(0, xshift, yshift, 4.f); - // snap to pixels - xshift = ((float)(sint32)(xshift * width)) / width; - yshift = ((float)(sint32)(yshift * height)) / height; - // adjust - CommandsBoxX += xshift; - CommandsBoxY += yshift; - } // Display the background Driver->setMatrixMode2D11 (); diff --git a/code/snowballs2/client/src/compass.cpp b/code/snowballs2/client/src/compass.cpp index 27e0e27f1..1c36d1f6b 100644 --- a/code/snowballs2/client/src/compass.cpp +++ b/code/snowballs2/client/src/compass.cpp @@ -95,13 +95,6 @@ void updateCompass () { float x = CompassPosX; float y = CompassPosY; - if (StereoHMD) - { - float xshift, yshift; - StereoHMD->getInterface2DShift(0, xshift, yshift, 4.f); - x += xshift; - y += yshift; - } float radius = CompassRadius; // tri @@ -117,8 +110,7 @@ void updateCompass () quad.V2.set ( radius, radius, 0); quad.V3.set (-radius, radius, 0); - if (StereoHMD) Driver->setMatrixMode2D11(); - else Driver->setMatrixMode2D43(); + Driver->setMatrixMode2D43(); CMatrix mtx; @@ -161,7 +153,7 @@ void updateCompass () Driver->setModelMatrix (mtx); Driver->drawQuad (quad, CompassMaterial); - if (!StereoHMD) x *= 3.0/4.0f; + x *= 3.0/4.0f; // Print position TextContext->setHotSpot(UTextContext::MiddleTop); diff --git a/code/snowballs2/client/src/snowballs_client.cpp b/code/snowballs2/client/src/snowballs_client.cpp index b401d80bc..7e019412b 100644 --- a/code/snowballs2/client/src/snowballs_client.cpp +++ b/code/snowballs2/client/src/snowballs_client.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #if SBCLIENT_DEV_STEREO # include #endif /* #if SBCLIENT_DEV_STEREO */ @@ -153,6 +154,7 @@ static IStereoRender *_StereoRender = NULL; #endif /* #if SBCLIENT_DEV_STEREO */ static bool s_EnableBloom = false; +static CFXAA *s_FXAA = NULL; // // Prototypes @@ -185,6 +187,7 @@ void cbGraphicsDriver(CConfigFile::CVar &var); void cbSquareBloom(CConfigFile::CVar &var); void cbDensityBloom(CConfigFile::CVar &var); void cbEnableBloom(CConfigFile::CVar &var); +void cbEnableFXAA(CConfigFile::CVar &var); // // Functions @@ -324,6 +327,7 @@ void initCore() ConfigFile->getVar("ScreenFull").asInt()==0)); TextContext = Driver->createTextContext(CPath::lookup(ConfigFile->getVar("FontName").asString())); TextContext->setShaded(true); + TextContext->setShadeOutline(false); TextContext->setKeep800x600Ratio(false); // You can't call displayLoadingState() before init the loading state system displayLoadingState("Initialize Loading"); @@ -373,10 +377,11 @@ void initIngame() // initialize bloom effect CBloomEffect::instance().setDriver(Driver); CBloomEffect::instance().setScene(Scene); - CBloomEffect::instance().init(ConfigFile->getVar("OpenGL").asInt() == 1); + CBloomEffect::instance().init(); CConfiguration::setAndCallback("SquareBloom", cbSquareBloom); CConfiguration::setAndCallback("DensityBloom", cbDensityBloom); CConfiguration::setAndCallback("EnableBloom", cbEnableBloom); + CConfiguration::setAndCallback("EnableFXAA", cbEnableFXAA); // Init the landscape using the previously created UScene displayLoadingState("Initialize Landscape"); initLandscape(); @@ -740,7 +745,19 @@ void loopIngame() else { uint i = 0; - uint bloomStage = 0; + bool effectRender = false; + CTextureUser *effectRenderTarget = NULL; + bool haveEffects = Driver->getPolygonMode() == UDriver::Filled + && (s_EnableBloom || s_FXAA); + bool defaultRenderTarget = false; + if (haveEffects) + { + if (!StereoDisplay) + { + Driver->beginDefaultRenderTarget(); + defaultRenderTarget = true; + } + } while ((!StereoDisplay && i == 0) || (StereoDisplay && StereoDisplay->nextPass())) { ++i; @@ -762,13 +779,7 @@ void loopIngame() if (!StereoDisplay || StereoDisplay->wantClear()) { - - if (s_EnableBloom) - { - nlassert(bloomStage == 0); - CBloomEffect::instance().initBloom(); // start bloom effect (just before the first scene element render) - bloomStage = 1; - } + effectRender = haveEffects; // 01. Render Driver (background color) Driver->clearBuffers(CRGBA(0, 0, 127)); // clear all buffers, if you see this blue there's a problem with scene rendering @@ -788,13 +799,16 @@ void loopIngame() if (!StereoDisplay || StereoDisplay->wantInterface3D()) { - if (s_EnableBloom && bloomStage == 1) + if (effectRender) { - // End the actual bloom effect visible in the scene. if (StereoDisplay) Driver->setViewport(NL3D::CViewport()); - CBloomEffect::instance().endBloom(); + UCamera pCam = Scene->getCam(); + Driver->setMatrixMode2D11(); + if (s_FXAA) s_FXAA->applyEffect(); + if (s_EnableBloom) CBloomEffect::instance().applyBloom(); + Driver->setMatrixMode3D(pCam); if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport()); - bloomStage = 2; + effectRender = false; } // 06. Render Interface 3D (player names) @@ -803,15 +817,6 @@ void loopIngame() if (!StereoDisplay || StereoDisplay->wantInterface2D()) { - if (s_EnableBloom && bloomStage == 2) - { - // End bloom effect system after drawing the 3d interface (z buffer related). - if (StereoDisplay) Driver->setViewport(NL3D::CViewport()); - CBloomEffect::instance().endInterfacesDisplayBloom(); - if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport()); - bloomStage = 0; - } - // 07. Render Interface 2D (chatboxes etc, optionally does have 3d) updateCompass(); // Update the compass updateRadar(); // Update the radar @@ -833,6 +838,11 @@ void loopIngame() } // 09. Render Buffer + if (defaultRenderTarget) + { + // draw final result to backbuffer + Driver->endDefaultRenderTarget(Scene); + } Driver->swapBuffers(); } @@ -965,6 +975,22 @@ void cbEnableBloom(CConfigFile::CVar &var) s_EnableBloom = var.asBool(); } +void cbEnableFXAA(CConfigFile::CVar &var) +{ + bool enable = var.asBool(); + if (enable != (s_FXAA != NULL)) + { + if (enable) + { + s_FXAA = new CFXAA(Driver); + } + else + { + delete s_FXAA; + } + } +} + // // Loading state procedure // diff --git a/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.cpp b/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.cpp index dc0bb858b..bc83b5d78 100644 --- a/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.cpp +++ b/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.cpp @@ -14,7 +14,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - #include "nel3d_widget.h" #include "nel/3d/u_driver.h" #include "nel/3d/text_context.h" @@ -29,7 +28,7 @@ #include Nel3DWidget::Nel3DWidget( QWidget *parent ) : -QWidget( parent ) +NEL3DWIDGET( parent ) { driver = NULL; textContext = NULL; diff --git a/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.h b/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.h index 059e1b738..254001b25 100644 --- a/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.h +++ b/code/studio/src/plugins/core/Nel3DWidget/nel3d_widget.h @@ -18,10 +18,22 @@ #ifndef NEL3D_WIDGET_H #define NEL3D_WIDGET_H -#include #include "nel/misc/types_nl.h" #include +#ifdef NEL3DWIDGET +#undef NEL3DWIDGET +#endif + +#ifdef NL_OS_WINDOWS +#include +#define NEL3DWIDGET QWidget +#else +#include +#define NEL3DWIDGET QGLWidget +#endif + + #include "../core_global.h" namespace NL3D @@ -31,7 +43,7 @@ namespace NL3D } /// Nel 3D interface to Qt -class CORE_EXPORT Nel3DWidget : public QWidget +class CORE_EXPORT Nel3DWidget : public NEL3DWIDGET { Q_OBJECT public: diff --git a/code/studio/src/plugins/core/context_manager.cpp b/code/studio/src/plugins/core/context_manager.cpp index 3b02b411c..203738faf 100644 --- a/code/studio/src/plugins/core/context_manager.cpp +++ b/code/studio/src/plugins/core/context_manager.cpp @@ -143,6 +143,8 @@ void ContextManager::currentTabChanged(int index) if (index >= 0) { IContext *context = d->m_contexts.at(index); + context->onActivated(); + Q_EMIT currentContextChanged(context); } } @@ -158,4 +160,4 @@ int ContextManager::indexOf(const QString &id) const return -1; } -} /* namespace Core */ \ No newline at end of file +} /* namespace Core */ diff --git a/code/studio/src/plugins/core/icontext.h b/code/studio/src/plugins/core/icontext.h index d2cbb412c..616e0db14 100644 --- a/code/studio/src/plugins/core/icontext.h +++ b/code/studio/src/plugins/core/icontext.h @@ -69,6 +69,8 @@ public: virtual void newDocument(){} virtual void close(){} + + virtual void onActivated(){} }; } // namespace Core diff --git a/code/studio/src/plugins/core/main_window.cpp b/code/studio/src/plugins/core/main_window.cpp index 4ccd32564..c181376e8 100644 --- a/code/studio/src/plugins/core/main_window.cpp +++ b/code/studio/src/plugins/core/main_window.cpp @@ -108,8 +108,14 @@ void MainWindow::extensionsInitialized() readSettings(); connect(m_contextManager, SIGNAL(currentContextChanged(Core::IContext *)), this, SLOT(updateContext(Core::IContext *))); - if (m_contextManager->currentContext() != NULL) - updateContext(m_contextManager->currentContext()); + + Core::IContext *context = m_contextManager->currentContext(); + if (context != NULL) + { + updateContext(context); + context->onActivated(); + } + show(); } diff --git a/code/studio/src/plugins/gui_editor/CMakeLists.txt b/code/studio/src/plugins/gui_editor/CMakeLists.txt index 4b50ec8d1..e1e8b38be 100644 --- a/code/studio/src/plugins/gui_editor/CMakeLists.txt +++ b/code/studio/src/plugins/gui_editor/CMakeLists.txt @@ -34,6 +34,9 @@ SET(OVQT_PLUGIN_GUI_EDITOR_HDR texture_chooser.h action_property_manager.h texture_property_manager.h + expression_editor.h + expr_link_dlg.h + new_gui_dlg.h ) SET(OVQT_PLUGIN_GUI_EDITOR_UIS @@ -51,6 +54,9 @@ SET(OVQT_PLUGIN_GUI_EDITOR_UIS add_widget_widget.ui action_list.ui texture_chooser.ui + expression_editor.ui + expr_link_dlg.ui + new_gui_dlg.ui ) SET(QT_USE_QTGUI TRUE) diff --git a/code/studio/src/plugins/gui_editor/editor_message_processor.cpp b/code/studio/src/plugins/gui_editor/editor_message_processor.cpp index 691dbdead..ef99c87fc 100644 --- a/code/studio/src/plugins/gui_editor/editor_message_processor.cpp +++ b/code/studio/src/plugins/gui_editor/editor_message_processor.cpp @@ -25,35 +25,40 @@ namespace GUIEditor { void CEditorMessageProcessor::onDelete() { - std::string selection = CWidgetManager::getInstance()->getCurrentEditorSelection(); + std::vector< std::string > selection; + + CWidgetManager::getInstance()->getEditorSelection( selection ); if( selection.empty() ) return; QMessageBox::StandardButton r = QMessageBox::question( NULL, tr( "Deleting widget" ), - tr( "Are you sure you want to delete %1?" ).arg( selection.c_str() ), + tr( "Are you sure you want to delete these?" ), QMessageBox::Yes | QMessageBox::No ); if( r != QMessageBox::Yes ) return; - CInterfaceElement *e = - CWidgetManager::getInstance()->getElementFromId( selection ); - if( e == NULL ) - return; - - CInterfaceElement *p = e->getParent(); - if( p == NULL ) - return; - - CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( p ); - if( g == NULL ) - return; - - if( g->delElement( e ) ) + for( int i = 0; i < selection.size(); i++ ) { - CWidgetManager::getInstance()->setCurrentEditorSelection( "" ); + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( selection[ i ] ); + if( e == NULL ) + continue; + + CInterfaceElement *p = e->getParent(); + if( p == NULL ) + continue; + + CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( p ); + if( g == NULL ) + continue; + + g->delElement( e ); + } + + + CWidgetManager::getInstance()->clearEditorSelection(); } void CEditorMessageProcessor::onAdd( const QString &parentGroup, const QString &widgetType, const QString &name ) @@ -130,5 +135,32 @@ namespace GUIEditor e->setActive( false ); e->setActive( true ); } + + void CEditorMessageProcessor::onSetGroupSelection( bool b ) + { + CWidgetManager::getInstance()->setGroupSelection( b ); + } + + void CEditorMessageProcessor::onGroup() + { + CWidgetManager::getInstance()->groupSelection(); + } + + void CEditorMessageProcessor::onUngroup() + { + bool ok = CWidgetManager::getInstance()->unGroupSelection(); + + if( !ok ) + { + QMessageBox::critical( NULL, + tr( "Ungrouping widgets" ), + tr( "Couldn't ungroup widgets." ) ); + } + } + + void CEditorMessageProcessor::onSetMultiSelection( bool b ) + { + CWidgetManager::getInstance()->setMultiSelection( b ); + } } diff --git a/code/studio/src/plugins/gui_editor/editor_message_processor.h b/code/studio/src/plugins/gui_editor/editor_message_processor.h index 5c19a03c2..ee55fcda7 100644 --- a/code/studio/src/plugins/gui_editor/editor_message_processor.h +++ b/code/studio/src/plugins/gui_editor/editor_message_processor.h @@ -38,6 +38,10 @@ namespace GUIEditor public Q_SLOTS: void onDelete(); void onAdd( const QString &parentGroup, const QString &widgetType, const QString &name ); + void onSetGroupSelection( bool b ); + void onGroup(); + void onUngroup(); + void onSetMultiSelection( bool b ); private: CWidgetInfoTree *tree; diff --git a/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp b/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp index ee3a079ad..7647c8abb 100644 --- a/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp +++ b/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp @@ -18,9 +18,9 @@ namespace GUIEditor { - void CEditorSelectionWatcher::selectionChanged( std::string &newSelection ) + void CEditorSelectionWatcher::selectionChanged() { - Q_EMIT sgnSelectionChanged( newSelection ); + Q_EMIT sgnSelectionChanged(); } } diff --git a/code/studio/src/plugins/gui_editor/editor_selection_watcher.h b/code/studio/src/plugins/gui_editor/editor_selection_watcher.h index 61218c0cd..2eab68310 100644 --- a/code/studio/src/plugins/gui_editor/editor_selection_watcher.h +++ b/code/studio/src/plugins/gui_editor/editor_selection_watcher.h @@ -27,10 +27,10 @@ namespace GUIEditor public: CEditorSelectionWatcher() : QObject( NULL ){} - void selectionChanged( std::string &newSelection ); + void selectionChanged(); Q_SIGNALS: - void sgnSelectionChanged( std::string &id ); + void sgnSelectionChanged(); }; } diff --git a/code/studio/src/plugins/gui_editor/expr_link_dlg.cpp b/code/studio/src/plugins/gui_editor/expr_link_dlg.cpp new file mode 100644 index 000000000..e8d01af85 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expr_link_dlg.cpp @@ -0,0 +1,124 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#include "expr_link_dlg.h" +#include + +ExprLinkDlg::ExprLinkDlg( QWidget *parent ) : +QDialog( parent ) +{ + m_ui.setupUi( this ); + + connect( m_ui.okButton, SIGNAL( clicked( bool ) ), this, SLOT( onOKClicked() ) ); + connect( m_ui.cancelButton, SIGNAL( clicked( bool ) ), this, SLOT( onCancelClicked() ) ); +} + +ExprLinkDlg::~ExprLinkDlg() +{ +} + +void ExprLinkDlg::load( const QList< SlotInfo > &a, const QList< SlotInfo > &b, const QString &aname, const QString &bname ) +{ + QListIterator< SlotInfo > itra( a ); + QListIterator< SlotInfo > itrb( b ); + + while( itra.hasNext() ) + { + const SlotInfo &info = itra.next(); + + QListWidgetItem *item = new QListWidgetItem(); + item->setText( info.name ); + item->setData( Qt::UserRole, info.slot ); + + m_ui.list1->addItem( item ); + } + + while( itrb.hasNext() ) + { + const SlotInfo &info = itrb.next(); + + QListWidgetItem *item = new QListWidgetItem(); + item->setText( info.name ); + item->setData( Qt::UserRole, info.slot ); + + m_ui.list2->addItem( item ); + } + + m_ui.groupBox1->setTitle( aname ); + m_ui.groupBox2->setTitle( bname ); +} + +int ExprLinkDlg::getSlotA() const +{ + QListWidgetItem *item = m_ui.list1->currentItem(); + if( item == NULL ) + return -1; + + int slot = item->data( Qt::UserRole ).toInt(); + return slot; +} + +int ExprLinkDlg::getSlotB() const +{ + QListWidgetItem *item = m_ui.list2->currentItem(); + if( item == NULL ) + return -1; + + int slot = item->data( Qt::UserRole ).toInt(); + return slot; +} + +void ExprLinkDlg::onOKClicked() +{ + int slotA = getSlotA(); + int slotB = getSlotB(); + + if( ( slotA == -1 ) || ( slotB == -1 ) ) + { + QMessageBox::information( this, + tr( "No slots selected" ), + tr( "You need to select a slot on both sides." ) ); + return; + } + + if( ( slotA == 0 ) && ( slotB == 0 ) ) + { + QMessageBox::information( this, + tr( "Wrong slots selected" ), + tr( "You can only select the 'Out' slot on one of the sides." ) ); + return; + } + + if( ( slotA != 0 ) && ( slotB != 0 ) ) + { + QMessageBox::information( this, + tr( "Wrong slots selected" ), + tr( "One of the slots selected must be the 'Out' slot!" ) ); + return; + } + + accept(); +} + +void ExprLinkDlg::onCancelClicked() +{ + reject(); +} + + diff --git a/code/studio/src/plugins/gui_editor/expr_link_dlg.h b/code/studio/src/plugins/gui_editor/expr_link_dlg.h new file mode 100644 index 000000000..3f3ba97c0 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expr_link_dlg.h @@ -0,0 +1,49 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef EXPR_LINK_DLG +#define EXPR_LINK_DLG + +#include +#include +#include "ui_expr_link_dlg.h" +#include "expr_slot_info.h" + +class ExprLinkDlg : public QDialog +{ + Q_OBJECT +public: + ExprLinkDlg( QWidget *parent = NULL ); + ~ExprLinkDlg(); + + void load( const QList< SlotInfo > &a, const QList< SlotInfo > &b, const QString &aname, const QString &bname ); + + int getSlotA() const; + int getSlotB() const; + +private Q_SLOTS: + void onOKClicked(); + void onCancelClicked(); + +private: + Ui::ExprLinkDialog m_ui; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expr_link_dlg.ui b/code/studio/src/plugins/gui_editor/expr_link_dlg.ui new file mode 100644 index 000000000..d6fdf9d7d --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expr_link_dlg.ui @@ -0,0 +1,76 @@ + + + ExprLinkDialog + + + + 0 + 0 + 641 + 334 + + + + Linking nodes + + + + + + + + GroupBox + + + + + + + + + + + + GroupBox + + + + + + + + + + + + + + Qt::Horizontal + + + + 398 + 20 + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + diff --git a/code/nel/src/misc/game_device.cpp b/code/studio/src/plugins/gui_editor/expr_slot_info.h similarity index 73% rename from code/nel/src/misc/game_device.cpp rename to code/studio/src/plugins/gui_editor/expr_slot_info.h index 2ba49367f..470edf68d 100644 --- a/code/nel/src/misc/game_device.cpp +++ b/code/studio/src/plugins/gui_editor/expr_slot_info.h @@ -1,5 +1,7 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as @@ -14,15 +16,17 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -#include "stdmisc.h" -#include "nel/misc/game_device.h" -#ifdef DEBUG_NEW - #define new DEBUG_NEW +#ifndef EXPR_SLOT_INFO +#define EXPR_SLOT_INFO + +#include + +struct SlotInfo +{ + QString name; + int slot; +}; + #endif -namespace NLMISC { - - - -} // NLMISC diff --git a/code/studio/src/plugins/gui_editor/expression_editor.cpp b/code/studio/src/plugins/gui_editor/expression_editor.cpp new file mode 100644 index 000000000..858c63c9c --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_editor.cpp @@ -0,0 +1,380 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#include "expression_editor.h" +#include +#include +#include +#include + +#include "expression_node.h" +#include "expression_link.h" +#include "expr_link_dlg.h" +#include "expression_store.h" +#include "expression_info.h" + +#include +#include + +class ExpressionEditorPvt +{ +public: + + ExpressionEditorPvt() + { + m_root = NULL; + } + + ExpressionStore store; + ExpressionNode *m_root; +}; + +ExpressionEditor::ExpressionEditor( QWidget *parent ) : +QMainWindow( parent ) +{ + m_ui.setupUi( this ); + + m_pvt = new ExpressionEditorPvt(); + + m_selectionCount = 0; + + m_scene = new QGraphicsScene( this ); + m_ui.view->setScene( m_scene ); + + connect( m_scene, SIGNAL( selectionChanged() ), this, SLOT( onSelectionChanged() ) ); + connect( m_ui.tree, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( onItemDblClicked( QTreeWidgetItem* ) ) ); + + m_nodeCount = 0; +} + +ExpressionEditor::~ExpressionEditor() +{ + delete m_pvt; + m_pvt = NULL; + m_scene = NULL; +} + +void ExpressionEditor::load() +{ + m_pvt->store.load(); + + QList< const ExpressionInfo* > l; + m_pvt->store.getExpressions( l ); + + QListIterator< const ExpressionInfo* > itr( l ); + while( itr.hasNext() ) + { + addExpression( itr.next() ); + } + + l.clear(); +} + +void ExpressionEditor::contextMenuEvent( QContextMenuEvent *e ) +{ + QMenu menu; + QAction *a = NULL; + + if( m_selectionCount > 0 ) + { + a = menu.addAction( "Remove" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onDeleteSelection() ) ); + + if( m_selectionCount == 1 ) + { + QList< QGraphicsItem* > l = m_scene->selectedItems(); + ExpressionNode *node = dynamic_cast< ExpressionNode* >( l[ 0 ] ); + if( node != NULL ) + { + if( node->variable() ) + { + a = menu.addAction( "Change slot count" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onChangeSlotCount() ) ); + } + else + if( node->isValue() ) + { + a = menu.addAction( "Change value" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onChangeValue() ) ); + } + + a = menu.addAction( "Set as root" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onSetRoot() ) ); + } + } + else + if( m_selectionCount == 2 ) + { + a = menu.addAction( "Link" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onLinkItems() ) ); + } + + a = menu.addAction( "Unlink" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onUnLinkItems() ) ); + } + else + { + a = menu.addAction( "Build expression" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onBuildExpression() ) ); + + a = menu.addAction( "Save" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onSave() ) ); + + a = menu.addAction( "Clear" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onClear() ) ); + } + + menu.exec( e->globalPos() ); +} + +void ExpressionEditor::closeEvent( QCloseEvent *e ) +{ + QMainWindow::closeEvent( e ); + + Q_EMIT closing(); +} + +void ExpressionEditor::onDeleteSelection() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + QListIterator< QGraphicsItem* > itr( l ); + while( itr.hasNext() ) + { + QGraphicsItem *item = itr.next(); + + ExpressionNode *node = dynamic_cast< ExpressionNode* >( item ); + if( node != NULL ) + { + ExpressionLink *link = NULL; + + int c = node->slotCount(); + for( int i = 0; i < c; i++ ) + { + link = node->link( i ); + if( link != NULL ) + { + link->unlink(); + m_scene->removeItem( link ); + delete link; + } + } + } + + if( item == m_pvt->m_root ) + m_pvt->m_root = NULL; + + m_scene->removeItem( item ); + delete item; + } +} + +void ExpressionEditor::onSelectionChanged() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + m_selectionCount = l.count(); +} + +void ExpressionEditor::onLinkItems() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + ExpressionNode *from = static_cast< ExpressionNode* >( l[ 0 ] ); + ExpressionNode *to = static_cast< ExpressionNode* >( l[ 1 ] ); + + QList< SlotInfo > froml; + QList< SlotInfo > tol; + + from->getSlots( froml ); + to->getSlots( tol ); + + // If there are no free slots, or both "Out" slots are taken we can't link + if( froml.isEmpty() || tol.isEmpty() || ( !from->slotEmpty( 0 ) && !to->slotEmpty( 0 ) ) ) + { + QMessageBox::information( this, + tr( "Failed to link nodes" ), + tr( "Unfortunately those nodes are full." ) ); + return; + } + + ExprLinkDlg d; + d.load( froml, tol, from->name(), to->name() ); + int result = d.exec(); + if( result == QDialog::Rejected ) + return; + + int slotA = d.getSlotA(); + int slotB = d.getSlotB(); + + ExpressionLink *link = new ExpressionLink(); + link->link( from, to, slotA, slotB ); + + m_scene->addItem( link ); +} + +void ExpressionEditor::onUnLinkItems() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + + for( int i = 0; i < l.count(); i++ ) + { + ExpressionNode *node = dynamic_cast< ExpressionNode* >( l[ i ] ); + if( node == NULL ) + continue; + + node->clearLinks(); + } +} + +void ExpressionEditor::onItemDblClicked( QTreeWidgetItem *item ) +{ + QString name = item->text( 0 ); + + const ExpressionInfo *info = m_pvt->store.getInfo( name ); + + QString n = name; + n += " #"; + n += QString::number( m_nodeCount ); + m_nodeCount++; + + ExpressionNode *node = new ExpressionNode( n, info->slotNames.count() ); + node->setSlotNames( info->slotNames ); + node->setVariable( info->variable ); + node->setIsValue( info->value ); + if( node->isValue() ) + { + node->setValue( "Value" ); + } + m_scene->addItem( node ); +} + +void ExpressionEditor::onChangeSlotCount() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + ExpressionNode *node = static_cast< ExpressionNode* >( l[ 0 ] ); + int oldc = node->slotCount(); + + int c = QInputDialog::getInt( this, + tr( "Change slot count" ), + tr( "Enter new slot count" ), + oldc, + 1, + 26 ); + + if( oldc == c ) + return; + + node->changeSlotCount( c ); +} + +void ExpressionEditor::onChangeValue() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + ExpressionNode *node = static_cast< ExpressionNode* >( l[ 0 ] ); + + QString oldValue = node->getValue(); + + QString newValue = QInputDialog::getText( this, + tr( "Change value" ), + tr( "Enter new value" ), + QLineEdit::Normal, + oldValue ); + + if( newValue.isEmpty() ) + return; + if( newValue == oldValue ) + return; + + node->setValue( newValue ); +} + +void ExpressionEditor::onSetRoot() +{ + QList< QGraphicsItem* > l = m_scene->selectedItems(); + ExpressionNode *node = static_cast< ExpressionNode* >( l[ 0 ] ); + + if( m_pvt->m_root != NULL ) + m_pvt->m_root->setRoot( false ); + + m_pvt->m_root = node; + node->setRoot( true ); +} + +void ExpressionEditor::onBuildExpression() +{ + if( m_pvt->m_root == NULL ) + { + QMessageBox::information( this, + tr( "Building expression" ), + tr( "Failed to build expression: You must set a root node." ) ); + return; + } + + QString result = m_pvt->m_root->build(); + QMessageBox::information( this, + tr( "Building expression" ), + tr( "The result is\n" ) + result ); +} + +void ExpressionEditor::onSave() +{ + if( m_pvt->m_root != NULL ) + { + m_result = m_pvt->m_root->build(); + } + + close(); +} + +void ExpressionEditor::onClear() +{ + m_scene->clear(); + m_pvt->m_root = NULL; + m_nodeCount = 0; + m_selectionCount = 0; + m_result = ""; +} + + +void ExpressionEditor::addExpression( const ExpressionInfo *info ) +{ + QTreeWidgetItem *item = findTopLevelItem( info->category ); + if( item == NULL ) + { + item = new QTreeWidgetItem(); + item->setText( 0, info->category ); + m_ui.tree->addTopLevelItem( item ); + } + + QTreeWidgetItem *citem = new QTreeWidgetItem(); + citem->setText( 0, info->name ); + item->addChild( citem ); +} + +QTreeWidgetItem* ExpressionEditor::findTopLevelItem( const QString &text ) +{ + int c = m_ui.tree->topLevelItemCount(); + for( int i = 0; i < c; i++ ) + { + QTreeWidgetItem *item = m_ui.tree->topLevelItem( i ); + if( item->text( 0 ) == text ) + return item; + } + + return NULL; +} + diff --git a/code/studio/src/plugins/gui_editor/expression_editor.h b/code/studio/src/plugins/gui_editor/expression_editor.h new file mode 100644 index 000000000..92cc959bd --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_editor.h @@ -0,0 +1,75 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef EXPRESSION_EDITOR +#define EXPRESSION_EDITOR + +#include "ui_expression_editor.h" + +class QGraphicsScene; +class QGraphicsItem; +class ExpressionEditorPvt; +class ExpressionInfo; + +class ExpressionEditor : public QMainWindow +{ + Q_OBJECT +public: + ExpressionEditor( QWidget *parent = NULL ); + ~ExpressionEditor(); + + void load(); + QString result() const{ return m_result; } + +Q_SIGNALS: + void closing(); + +protected: + void contextMenuEvent( QContextMenuEvent *e ); + void closeEvent( QCloseEvent *e ); + +private Q_SLOTS: + void onDeleteSelection(); + void onSelectionChanged(); + void onLinkItems(); + void onUnLinkItems(); + void onItemDblClicked( QTreeWidgetItem *item ); + void onChangeSlotCount(); + void onChangeValue(); + void onSetRoot(); + void onBuildExpression(); + void onSave(); + void onClear(); + +private: + void addExpression( const ExpressionInfo *info ); + QTreeWidgetItem* findTopLevelItem( const QString &text ); + + Ui::ExpressionEditor m_ui; + QGraphicsScene *m_scene; + + int m_selectionCount; + int m_nodeCount; + + ExpressionEditorPvt *m_pvt; + QString m_result; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expression_editor.ui b/code/studio/src/plugins/gui_editor/expression_editor.ui new file mode 100644 index 000000000..fa21420a2 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_editor.ui @@ -0,0 +1,58 @@ + + + ExpressionEditor + + + Qt::ApplicationModal + + + + 0 + 0 + 800 + 600 + + + + Expression Editor + + + + + + + + + + + + 0 + 0 + 800 + 21 + + + + + + + 1 + + + + + + + + Expressions + + + + + + + + + + + diff --git a/code/studio/src/plugins/gui_editor/expression_info.h b/code/studio/src/plugins/gui_editor/expression_info.h new file mode 100644 index 000000000..86218b6af --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_info.h @@ -0,0 +1,41 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef EXPRESSION_INFO +#define EXPRESSION_INFO + +#include +#include + +struct ExpressionInfo +{ + QString name; + bool value; + QString category; + bool variable; + QStringList slotNames; + + ExpressionInfo() + { + value = false; + variable = false; + } +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expression_link.cpp b/code/studio/src/plugins/gui_editor/expression_link.cpp new file mode 100644 index 000000000..54c7734b0 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_link.cpp @@ -0,0 +1,78 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "expression_link.h" +#include "expression_node.h" +#include +#include + +ExpressionLink::ExpressionLink( QGraphicsItem *parent ) : +QGraphicsLineItem( parent ) +{ + m_from = NULL; + m_to = NULL; +} + +ExpressionLink::~ExpressionLink() +{ + unlink(); +} + +void ExpressionLink::link( ExpressionNode *from, ExpressionNode *to, int fromSlot, int toSlot ) +{ + m_from = from; + m_to = to; + m_from->setLink( this, fromSlot ); + m_to->setLink( this, toSlot ); + + m_fromSlot = fromSlot; + m_toSlot = toSlot; + + nodeMoved(); +} + +void ExpressionLink::unlink() +{ + if( m_from == NULL ) + return; + + m_from->setLink( NULL, m_fromSlot ); + m_to->setLink( NULL, m_toSlot ); + + m_from = NULL; + m_to = NULL; + + delete this; +} + +void ExpressionLink::nodeMoved() +{ + setLine( QLineF( m_from->slotPos( m_fromSlot ), m_to->slotPos( m_toSlot ) ) ); +} + +void ExpressionLink::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ) +{ + QPen p; + p.setColor( Qt::black ); + p.setWidth( 5 ); + setPen( p ); + + QGraphicsLineItem::paint( painter, option, widget ); +} + + diff --git a/code/studio/src/plugins/gui_editor/expression_link.h b/code/studio/src/plugins/gui_editor/expression_link.h new file mode 100644 index 000000000..a0e699451 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_link.h @@ -0,0 +1,51 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef EXPRESSION_LINK +#define EXPRESSION_LINK + +#include + +class ExpressionNode; + +class ExpressionLink : public QGraphicsLineItem +{ +public: + ExpressionLink( QGraphicsItem *parent = NULL ); + ~ExpressionLink(); + + void link( ExpressionNode *from, ExpressionNode *to, int fromSlot, int toSlot ); + void unlink(); + + void nodeMoved(); + + void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ); + + ExpressionNode* from() const{ return m_from; } + ExpressionNode* to() const{ return m_to; } + +private: + ExpressionNode *m_from; + ExpressionNode *m_to; + + int m_fromSlot; + int m_toSlot; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expression_loader.cpp b/code/studio/src/plugins/gui_editor/expression_loader.cpp new file mode 100644 index 000000000..07db432e0 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_loader.cpp @@ -0,0 +1,220 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "expression_loader.h" +#include "expression_info.h" + +#include +#include + +class ExpressionLoaderPvt +{ +public: + + bool parseName() + { + QString text = reader.readElementText( QXmlStreamReader::ErrorOnUnexpectedElement ); + if( reader.hasError() ) + return false; + + m_info->name = text; + + return true; + } + + bool parseValue() + { + QString text = reader.readElementText( QXmlStreamReader::ErrorOnUnexpectedElement ); + if( reader.hasError() ) + return false; + + if( text.toLower() == "true" ) + m_info->value = true; + else + m_info->value = false; + + return true; + } + + bool parseCategory() + { + QString text = reader.readElementText( QXmlStreamReader::ErrorOnUnexpectedElement ); + if( reader.hasError() ) + return false; + + m_info->category = text; + + return true; + } + + bool parseVariable() + { + QString text = reader.readElementText( QXmlStreamReader::ErrorOnUnexpectedElement ); + if( reader.hasError() ) + return false; + + if( text.toLower() == "true" ) + m_info->variable = true; + else + m_info->variable = false; + + return true; + } + + bool parseSlot() + { + QString text = reader.readElementText( QXmlStreamReader::ErrorOnUnexpectedElement ); + if( reader.hasError() ) + return false; + + m_info->slotNames.push_back( text ); + + return true; + } + + bool parseSlots() + { + bool error = false; + + while( !reader.atEnd() ) + { + reader.readNext(); + + if( reader.isStartElement() ) + { + QString name = reader.name().toString(); + if( name == "slot" ) + error = !parseSlot(); + } + else + if( reader.isEndElement() ) + { + if( reader.name() == "slots" ) + break; + } + } + + if( reader.atEnd() ) + return false; + + return true; + } + + bool load( QFile *f ) + { + reader.clear(); + reader.setDevice( f ); + + bool error = false; + + // start of document + reader.readNext(); + if( reader.atEnd() ) + return false; + + // root node + reader.readNext(); + if( reader.atEnd() ) + return false; + + if( reader.isStartElement() ) + { + // Not an expression file? + if( reader.name() != "expression" ) + return false; + } + + while( !reader.atEnd() ) + { + reader.readNext(); + + if( reader.isStartElement() ) + { + QString name = reader.name().toString(); + + if( name == "name" ) + error = !parseName(); + else + if( name == "value" ) + error = !parseValue(); + else + if( name == "category" ) + error = !parseCategory(); + else + if( name == "variable" ) + error = !parseVariable(); + else + if( name == "slots" ) + error = !parseSlots(); + } + + if( error ) + break; + } + + if( error || reader.hasError() ) + { + return false; + } + + return true; + } + + void setInfo( ExpressionInfo *info ){ m_info = info; } + +private: + QXmlStreamReader reader; + ExpressionInfo *m_info; +}; + +ExpressionLoader::ExpressionLoader() +{ + m_pvt = new ExpressionLoaderPvt; +} + +ExpressionLoader::~ExpressionLoader() +{ + delete m_pvt; + m_pvt = NULL; +} + +ExpressionInfo* ExpressionLoader::load( const QString &filename ) +{ + ExpressionInfo *info = NULL; + bool ok = false; + + QFile f( filename ); + if( !f.open( QIODevice::ReadOnly | QIODevice::Text ) ) + return NULL; + + info = new ExpressionInfo(); + m_pvt->setInfo( info ); + ok = m_pvt->load( &f ); + + f.close(); + + if( !ok ) + { + delete info; + info = NULL; + } + + return info; +} + + diff --git a/code/studio/src/plugins/gui_editor/expression_loader.h b/code/studio/src/plugins/gui_editor/expression_loader.h new file mode 100644 index 000000000..f315fcdcd --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_loader.h @@ -0,0 +1,39 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef EXPRESSION_LOADER +#define EXPRESSION_LOADER + +struct ExpressionInfo; +class QString; +class ExpressionLoaderPvt; + +class ExpressionLoader +{ +public: + ExpressionLoader(); + ~ExpressionLoader(); + + ExpressionInfo* load( const QString &filename ); + +private: + ExpressionLoaderPvt *m_pvt; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expression_node.cpp b/code/studio/src/plugins/gui_editor/expression_node.cpp new file mode 100644 index 000000000..80ef571e2 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_node.cpp @@ -0,0 +1,417 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#include "expression_node.h" +#include "expression_link.h" +#include +#include + +struct NodeSlotInfo +{ + // top-left + QPoint tl; + + // text top-left + QPoint ttl; + + // The text displayed + QString text; + + // text width + qreal tw; + + // text height + qreal th; + + // width-height of the box + qreal wh; +}; + +class NodeSlot +{ +public: + NodeSlot( const NodeSlotInfo &info ) + { + m_info = info; + } + + ~NodeSlot() + { + } + + QPointF pos() const{ + QPointF p; + p.setX( m_info.tl.x() + m_info.wh / 2.0 ); + p.setY( m_info.tl.y() + m_info.wh / 2.0 ); + + return p; + } + + void paint( QPainter *painter ) + { + QBrush boxBrush; + QPen p; + + boxBrush.setColor( Qt::black ); + boxBrush.setStyle( Qt::SolidPattern ); + p.setColor( Qt::black ); + painter->setPen( p ); + + QRectF box; + QRectF tbox; + + box.setTopLeft( m_info.tl ); + box.setHeight( m_info.wh ); + box.setWidth( m_info.wh ); + + painter->fillRect( box, boxBrush ); + + tbox.setTopLeft( m_info.ttl ); + tbox.setHeight( m_info.th ); + tbox.setWidth( m_info.tw ); + + painter->drawText( tbox, Qt::AlignRight, m_info.text ); + } + + QString text() const{ return m_info.text; } + void setText( const QString &text ){ m_info.text = text; } + +private: + NodeSlotInfo m_info; +}; + + + +ExpressionNode::ExpressionNode( const QString &name, int slotCount, QGraphicsItem *parent ) : +QGraphicsItem( parent ) +{ + setFlags( QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsScenePositionChanges ); + + m_w = 100; + m_h = 100; + m_hh = 20.0; + + m_variable = false; + m_isValue = false; + m_isRoot = false; + + m_name = name; + + if( slotCount > 3 ) + m_h = m_h + 20.0 * ( slotCount - 3 ); + + createSlots( slotCount ); +} + +ExpressionNode::~ExpressionNode() +{ + clearLinks(); + clearSlots(); +} + +QRectF ExpressionNode::boundingRect() const +{ + return QRectF( 0, 0, m_w, m_h ); +} + +void ExpressionNode::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ) +{ + QBrush br; + QBrush boxBrush; + QPen p; + QColor c; + + QRectF rect = boundingRect(); + QRectF header = rect; + header.setHeight( m_hh ); + + // Draw filled rectangle, header + if( !m_isRoot ) + { + c.setRed( 44 ); + c.setGreen( 169 ); + c.setBlue( 232 ); + } + else + { + c.setRed( 255 ); + c.setGreen( 0 ); + c.setBlue( 0 ); + } + br.setColor( c ); + br.setStyle( Qt::SolidPattern ); + p.setColor( c ); + painter->setPen( p ); + painter->fillRect( header, br ); + + // Draw header text + p.setColor( Qt::black ); + painter->setPen( p ); + painter->drawText( header, Qt::AlignCenter, m_name ); + + // Draw value if applicable + if( m_isValue ) + { + QRectF vbox; + vbox.setTopLeft( QPoint( 0.0, 20.0 ) ); + vbox.setWidth( header.width() ); + vbox.setHeight( header.height() ); + QPen vpen; + vpen.setColor( Qt::red ); + painter->setPen( vpen ); + painter->drawText( vbox, Qt::AlignCenter, m_value ); + painter->setPen( p ); + } + + if( option->state & QStyle::State_Selected ) + { + p.setStyle( Qt::DotLine ); + p.setColor( Qt::red ); + } + + // Draw outline of the entire thing + header + painter->setPen( p ); + painter->drawRect( rect ); + painter->drawRect( header ); + + paintSlots( painter ); +} + + +QPointF ExpressionNode::slotPos( int slot ) const +{ + const NodeSlot *s = m_slots[ slot ]; + QPointF sp = s->pos(); + QPointF mp = pos(); + + mp += sp; + return mp; +} + +void ExpressionNode::changeSlotCount( int count ) +{ + clearSlots(); + clearLinks(); + m_links.clear(); + + if( count <= 3 ) + m_h = 100.0; + else + m_h = 100.0 + 20.0 * ( count - 3 ); + + createSlots( count ); + + update(); +} + +void ExpressionNode::clearSlots() +{ + qDeleteAll( m_slots ); + m_slots.clear(); +} + +bool ExpressionNode::slotEmpty( int slot ) const +{ + if( m_links[ 0 ] == NULL ) + return true; + else + return false; +} + +void ExpressionNode::getSlots( QList< SlotInfo > &l ) +{ + SlotInfo info; + + for( int i = 0; i < m_slots.count(); i++ ) + { + if( m_links[ i ] != NULL ) + continue; + + info.name = m_slots[ i ]->text(); + info.slot = i; + l.push_back( info ); + } +} + +void ExpressionNode::setLink( ExpressionLink *link, int slot ) +{ + m_links[ slot ] = link; +} + +ExpressionLink* ExpressionNode::link( int slot ) const +{ + return m_links[ slot ]; +} + +void ExpressionNode::setSlotNames( const QList< QString > &l ) +{ + int c = l.count(); + for( int i = 0; i < c; i++ ) + { + // "Out" slot is at position 0, so set the names with an offset of 1 + m_slots[ i + 1 ]->setText( l[ i ] ); + } +} + +void ExpressionNode::setValue( const QString &value ) +{ + m_value = value; + + int c = m_value.count(); + if( c < 15 ) + m_w = 100.0; + else + m_w = m_w + ( 100.0 / 15.0 ) * ( c - 15.0 ); + + update(); +} + +void ExpressionNode::setRoot( bool b ) +{ + m_isRoot = b; + update(); +} + +QString ExpressionNode::build() const +{ + QString result; + + if( isValue() ) + return m_value; + + QStringList l = m_name.split( ' ' ); + result = l[ 0 ]; + + int c = m_links.count(); + if( c == 1 ) + { + result += "()"; + return result; + } + + result += "( "; + + for( int i = 1; i < c; i++ ) + { + ExpressionLink *link = m_links[ i ]; + if( link == NULL ) + continue; + + ExpressionNode *node = NULL; + + if( link->from() == this ) + node = link->to(); + else + node = link->from(); + + result += node->build(); + + if( i != ( c - 1 ) ) + result += ", "; + } + + result += " )"; + return result; +} + +QVariant ExpressionNode::itemChange( GraphicsItemChange change, const QVariant &value ) +{ + if( change == ItemScenePositionHasChanged ) + { + onNodeMove(); + } + + return QGraphicsItem::itemChange( change, value ); +} + +void ExpressionNode::onNodeMove() +{ + for( int i = 0; i < m_links.count(); i++ ) + { + ExpressionLink *link = m_links[ i ]; + if( link == NULL ) + continue; + + link->nodeMoved(); + } +} + +void ExpressionNode::createSlots( int count) +{ + // Out nodes + m_links.push_back( NULL ); + + for( int i = 0; i < count; i++ ) + m_links.push_back( NULL ); + + // First create the "Out" slot + NodeSlotInfo info; + info.tw = 25.0; + info.th = 12.0; + info.wh = 10.0; + + qreal x = 0.0; + qreal y = m_h * 0.5; + qreal tx = info.wh; + qreal ty = m_h * 0.5 - 2; + + info.tl = QPoint( x, y ); + info.ttl = QPoint( tx, ty ); + info.text = "Out"; + + m_slots.push_back( new NodeSlot( info ) ); + + // Then the rest of them + for( int i = 0; i < count; i++ ) + { + x = m_w - info.wh; + y = 30 + i * 20.0; + tx = x - 5 - info.tw; + ty = y - 2; + + info.tl = QPoint( x, y ); + info.ttl = QPoint( tx, ty ); + info.text = QString( 'A' + i ); + + m_slots.push_back( new NodeSlot( info ) ); + } +} + +void ExpressionNode::paintSlots( QPainter *painter ) +{ + for( int i = 0; i < m_slots.count(); i++ ) + { + NodeSlot *slot = m_slots[ i ]; + slot->paint( painter ); + } +} + + +void ExpressionNode::clearLinks() +{ + for( int i = 0; i < m_links.count(); i++ ) + { + ExpressionLink *link = m_links[ i ]; + if( link == NULL ) + continue; + + link->unlink(); + } +} + diff --git a/code/studio/src/plugins/gui_editor/expression_node.h b/code/studio/src/plugins/gui_editor/expression_node.h new file mode 100644 index 000000000..1e0290344 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_node.h @@ -0,0 +1,95 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef EXPRESSION_NODE +#define EXPRESSION_NODE + +#include +#include +#include "expr_slot_info.h" + +class ExpressionLink; +class NodeSlot; + +class ExpressionNode : public QGraphicsItem +{ +public: + ExpressionNode( const QString &name, int slotCount = 3, QGraphicsItem *parent = NULL ); + ~ExpressionNode(); + + QRectF boundingRect() const; + void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ); + + void setLink( ExpressionLink *link, int slot ); + ExpressionLink* link( int slot ) const; + + QPointF slotPos( int slot ) const; + + int slotCount() const{ return m_slots.count(); } + void changeSlotCount( int count ); + void clearSlots(); + + bool slotEmpty( int slot ) const; + + void getSlots( QList< SlotInfo > &l ); + + void clearLinks(); + + QString name() const{ return m_name; } + + void setSlotNames( const QList< QString > &l ); + + void setVariable( bool b ){ m_variable = b; } + bool variable() const{ return m_variable; } + + void setValue( const QString &value ); + QString getValue() const{ return m_value; } + + bool isValue() const{ return m_isValue; } + void setIsValue( bool b ){ m_isValue = b; } + void setRoot( bool b ); + + QString build() const; + +protected: + QVariant itemChange( GraphicsItemChange change, const QVariant &value ); + +private: + void onNodeMove(); + void createSlots( int count = 3 ); + void paintSlots( QPainter *painter ); + + qreal m_w; // node width + qreal m_h; // node height + qreal m_hh; // header height + + QList< NodeSlot* > m_slots; + QList< ExpressionLink* > m_links; + + QString m_name; + + bool m_variable; + + QString m_value; + bool m_isValue; + bool m_isRoot; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expression_store.cpp b/code/studio/src/plugins/gui_editor/expression_store.cpp new file mode 100644 index 000000000..9f2218b4e --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_store.cpp @@ -0,0 +1,105 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "expression_store.h" +#include "expression_info.h" +#include "expression_loader.h" +#include +#include + +class ExpressionStorePvt +{ +public: + + ~ExpressionStorePvt() + { + qDeleteAll( expressions ); + expressions.clear(); + } + + + QMap< QString, ExpressionInfo* > expressions; +}; + +ExpressionStore::ExpressionStore() +{ + m_pvt = new ExpressionStorePvt(); +} + +ExpressionStore::~ExpressionStore() +{ + delete m_pvt; + m_pvt = NULL; +} + + +bool ExpressionStore::load() +{ + QDir d( "expressions" ); + if( !d.exists() ) + return false; + + QFileInfoList l = d.entryInfoList(); + QListIterator< QFileInfo > itr( l ); + if( !itr.hasNext() ) + return false; + + ExpressionLoader loader; + + while( itr.hasNext() ) + { + const QFileInfo &info = itr.next(); + if( !info.isFile() ) + continue; + + if( info.suffix() != "xml" ) + continue; + + ExpressionInfo *expr = loader.load( info.absoluteFilePath() ); + if( expr == NULL ) + continue; + + m_pvt->expressions[ expr->name ] = expr; + } + + return false; +} + +void ExpressionStore::getExpressions( QList< const ExpressionInfo* > &l ) const +{ + l.clear(); + + QMap< QString, ExpressionInfo* >::const_iterator itr = m_pvt->expressions.constBegin(); + while( itr != m_pvt->expressions.constEnd() ) + { + l.push_back( itr.value() ); + ++itr; + } +} + +const ExpressionInfo* ExpressionStore::getInfo( const QString &name ) +{ + QMap< QString, ExpressionInfo* >::const_iterator itr = m_pvt->expressions.find( name ); + if( itr == m_pvt->expressions.end() ) + return NULL; + else + return itr.value(); +} + + + diff --git a/code/studio/src/plugins/gui_editor/expression_store.h b/code/studio/src/plugins/gui_editor/expression_store.h new file mode 100644 index 000000000..9c29fa0f6 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expression_store.h @@ -0,0 +1,46 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef EXPRESSION_STORE +#define EXPRESSION_STORE + +#include +#include +#include "expression_info.h" + +//struct ExpressionInfo; +class ExpressionStorePvt; + +class ExpressionStore +{ +public: + ExpressionStore(); + ~ExpressionStore(); + + bool load(); + + void getExpressions( QList< const ExpressionInfo* > &l ) const; + + const ExpressionInfo* getInfo( const QString &name ); + +private: + ExpressionStorePvt *m_pvt; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/expressions/abs.xml b/code/studio/src/plugins/gui_editor/expressions/abs.xml new file mode 100644 index 000000000..5a5fe2c70 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/abs.xml @@ -0,0 +1,8 @@ + +Mathematical +abs +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/add.xml b/code/studio/src/plugins/gui_editor/expressions/add.xml new file mode 100644 index 000000000..62cec88af --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/add.xml @@ -0,0 +1,9 @@ + +Mathematical +add +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/and.xml b/code/studio/src/plugins/gui_editor/expressions/and.xml new file mode 100644 index 000000000..cc8c05c6e --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/and.xml @@ -0,0 +1,9 @@ + +Logical +and +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/band.xml b/code/studio/src/plugins/gui_editor/expressions/band.xml new file mode 100644 index 000000000..1ce1534ec --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/band.xml @@ -0,0 +1,9 @@ + +Bits +band +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/bnot.xml b/code/studio/src/plugins/gui_editor/expressions/bnot.xml new file mode 100644 index 000000000..bde93f6e7 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/bnot.xml @@ -0,0 +1,8 @@ + +Bits +bnot +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/bor.xml b/code/studio/src/plugins/gui_editor/expressions/bor.xml new file mode 100644 index 000000000..906678bc2 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/bor.xml @@ -0,0 +1,9 @@ + +Bits +bor +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/bxor.xml b/code/studio/src/plugins/gui_editor/expressions/bxor.xml new file mode 100644 index 000000000..2bfedb167 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/bxor.xml @@ -0,0 +1,9 @@ + +Bits +bxor +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/dbcount.xml b/code/studio/src/plugins/gui_editor/expressions/dbcount.xml new file mode 100644 index 000000000..df8e0aac6 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/dbcount.xml @@ -0,0 +1,8 @@ + +Database +dbcount +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/depends.xml b/code/studio/src/plugins/gui_editor/expressions/depends.xml new file mode 100644 index 000000000..225d48dd6 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/depends.xml @@ -0,0 +1,8 @@ + +Logical +depends +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/div.xml b/code/studio/src/plugins/gui_editor/expressions/div.xml new file mode 100644 index 000000000..aba3faffc --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/div.xml @@ -0,0 +1,9 @@ + +Mathematical +div +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/eq.xml b/code/studio/src/plugins/gui_editor/expressions/eq.xml new file mode 100644 index 000000000..77b7041cc --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/eq.xml @@ -0,0 +1,9 @@ + +Logical +eq +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/extSign11To64.xml b/code/studio/src/plugins/gui_editor/expressions/extSign11To64.xml new file mode 100644 index 000000000..e227fc8cb --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/extSign11To64.xml @@ -0,0 +1,8 @@ + +Bits +extSign11To64 +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/extSign8To64.xml b/code/studio/src/plugins/gui_editor/expressions/extSign8To64.xml new file mode 100644 index 000000000..f029c15fc --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/extSign8To64.xml @@ -0,0 +1,8 @@ + +Bits +extSign8To64 +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/getAlpha.xml b/code/studio/src/plugins/gui_editor/expressions/getAlpha.xml new file mode 100644 index 000000000..acdc5e322 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/getAlpha.xml @@ -0,0 +1,8 @@ + +Color +getAlpha +false + +Color + + diff --git a/code/studio/src/plugins/gui_editor/expressions/getBlue.xml b/code/studio/src/plugins/gui_editor/expressions/getBlue.xml new file mode 100644 index 000000000..be35a6c17 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/getBlue.xml @@ -0,0 +1,8 @@ + +Color +getBlue +false + +Color + + diff --git a/code/studio/src/plugins/gui_editor/expressions/getGreen.xml b/code/studio/src/plugins/gui_editor/expressions/getGreen.xml new file mode 100644 index 000000000..da8e16bc4 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/getGreen.xml @@ -0,0 +1,8 @@ + +Color +getGreen +false + +Color + + diff --git a/code/studio/src/plugins/gui_editor/expressions/getRed.xml b/code/studio/src/plugins/gui_editor/expressions/getRed.xml new file mode 100644 index 000000000..3a918857b --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/getRed.xml @@ -0,0 +1,8 @@ + +Color +getRed +false + +Color + + diff --git a/code/studio/src/plugins/gui_editor/expressions/getbit.xml b/code/studio/src/plugins/gui_editor/expressions/getbit.xml new file mode 100644 index 000000000..6cc08e10b --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/getbit.xml @@ -0,0 +1,9 @@ + +Bits +getbit +false + +Integer +Bit + + diff --git a/code/studio/src/plugins/gui_editor/expressions/getprop.xml b/code/studio/src/plugins/gui_editor/expressions/getprop.xml new file mode 100644 index 000000000..1098635aa --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/getprop.xml @@ -0,0 +1,8 @@ + +Database +getprop +false + +property + + diff --git a/code/studio/src/plugins/gui_editor/expressions/identity.xml b/code/studio/src/plugins/gui_editor/expressions/identity.xml new file mode 100644 index 000000000..cd36facd6 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/identity.xml @@ -0,0 +1,8 @@ + +Mathematical +identity +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/ifthenelse.xml b/code/studio/src/plugins/gui_editor/expressions/ifthenelse.xml new file mode 100644 index 000000000..248a68332 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/ifthenelse.xml @@ -0,0 +1,10 @@ + +Logical +ifthenelse +false + +if +then +else + + diff --git a/code/studio/src/plugins/gui_editor/expressions/ilinear.xml b/code/studio/src/plugins/gui_editor/expressions/ilinear.xml new file mode 100644 index 000000000..9284b4e82 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/ilinear.xml @@ -0,0 +1,10 @@ + +Mathematical +ilinear +false + +Interpolant +Start +End + + diff --git a/code/studio/src/plugins/gui_editor/expressions/int.xml b/code/studio/src/plugins/gui_editor/expressions/int.xml new file mode 100644 index 000000000..117225b6b --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/int.xml @@ -0,0 +1,8 @@ + +Mathematical +int +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/intToColor.xml b/code/studio/src/plugins/gui_editor/expressions/intToColor.xml new file mode 100644 index 000000000..2993365d7 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/intToColor.xml @@ -0,0 +1,8 @@ + +Color +intToColor +false + +Integer + + diff --git a/code/studio/src/plugins/gui_editor/expressions/isFinalVersion.xml b/code/studio/src/plugins/gui_editor/expressions/isFinalVersion.xml new file mode 100644 index 000000000..3c9ddc64c --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/isFinalVersion.xml @@ -0,0 +1,5 @@ + +Nel +isFinalVersion +false + diff --git a/code/studio/src/plugins/gui_editor/expressions/localize.xml b/code/studio/src/plugins/gui_editor/expressions/localize.xml new file mode 100644 index 000000000..f8d3f0f4e --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/localize.xml @@ -0,0 +1,8 @@ + +Localization +localize +false + +String + + diff --git a/code/studio/src/plugins/gui_editor/expressions/makeRGB.xml b/code/studio/src/plugins/gui_editor/expressions/makeRGB.xml new file mode 100644 index 000000000..a2cb2d352 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/makeRGB.xml @@ -0,0 +1,11 @@ + +Color +makeRGB +false + +R +G +B +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/max.xml b/code/studio/src/plugins/gui_editor/expressions/max.xml new file mode 100644 index 000000000..6592aecd7 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/max.xml @@ -0,0 +1,9 @@ + +Mathematical +max +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/min.xml b/code/studio/src/plugins/gui_editor/expressions/min.xml new file mode 100644 index 000000000..753955ed9 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/min.xml @@ -0,0 +1,9 @@ + +Mathematical +min +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/mod.xml b/code/studio/src/plugins/gui_editor/expressions/mod.xml new file mode 100644 index 000000000..d306f3371 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/mod.xml @@ -0,0 +1,9 @@ + +Mathematical +mod +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/mul.xml b/code/studio/src/plugins/gui_editor/expressions/mul.xml new file mode 100644 index 000000000..54d03b025 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/mul.xml @@ -0,0 +1,9 @@ + +Mathematical +mul +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/ne.xml b/code/studio/src/plugins/gui_editor/expressions/ne.xml new file mode 100644 index 000000000..31d62af02 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/ne.xml @@ -0,0 +1,9 @@ + +Logical +ne +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/not.xml b/code/studio/src/plugins/gui_editor/expressions/not.xml new file mode 100644 index 000000000..872b9b7a4 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/not.xml @@ -0,0 +1,8 @@ + +Logical +not +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/oldvalue.xml b/code/studio/src/plugins/gui_editor/expressions/oldvalue.xml new file mode 100644 index 000000000..299706c79 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/oldvalue.xml @@ -0,0 +1,8 @@ + +Database +oldvalue +false + +property + + diff --git a/code/studio/src/plugins/gui_editor/expressions/or.xml b/code/studio/src/plugins/gui_editor/expressions/or.xml new file mode 100644 index 000000000..2d977267c --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/or.xml @@ -0,0 +1,9 @@ + +Logical +or +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/rand.xml b/code/studio/src/plugins/gui_editor/expressions/rand.xml new file mode 100644 index 000000000..b284dc241 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/rand.xml @@ -0,0 +1,5 @@ + +Mathematical +rand +false + diff --git a/code/studio/src/plugins/gui_editor/expressions/sal.xml b/code/studio/src/plugins/gui_editor/expressions/sal.xml new file mode 100644 index 000000000..3190f4420 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/sal.xml @@ -0,0 +1,9 @@ + +Bits +sal +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/sar.xml b/code/studio/src/plugins/gui_editor/expressions/sar.xml new file mode 100644 index 000000000..75fcd57d7 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/sar.xml @@ -0,0 +1,9 @@ + +Bits +sar +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/secondsToTimeString.xml b/code/studio/src/plugins/gui_editor/expressions/secondsToTimeString.xml new file mode 100644 index 000000000..fda7dd1c8 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/secondsToTimeString.xml @@ -0,0 +1,8 @@ + +Time +secondsToTimeString +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/secondsToTimeStringShort.xml b/code/studio/src/plugins/gui_editor/expressions/secondsToTimeStringShort.xml new file mode 100644 index 000000000..042cf06de --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/secondsToTimeStringShort.xml @@ -0,0 +1,8 @@ + +Time +secondsToTimeStringShort +false + +A + + diff --git a/code/studio/src/plugins/gui_editor/expressions/shl.xml b/code/studio/src/plugins/gui_editor/expressions/shl.xml new file mode 100644 index 000000000..653a142a6 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/shl.xml @@ -0,0 +1,9 @@ + +Bits +shl +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/shr.xml b/code/studio/src/plugins/gui_editor/expressions/shr.xml new file mode 100644 index 000000000..435816f6e --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/shr.xml @@ -0,0 +1,9 @@ + +Bits +shr +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/str.xml b/code/studio/src/plugins/gui_editor/expressions/str.xml new file mode 100644 index 000000000..c98ae89eb --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/str.xml @@ -0,0 +1,9 @@ + +String +str +true + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/sub.xml b/code/studio/src/plugins/gui_editor/expressions/sub.xml new file mode 100644 index 000000000..5f35c2895 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/sub.xml @@ -0,0 +1,9 @@ + +Mathematical +sub +false + +A +B + + diff --git a/code/studio/src/plugins/gui_editor/expressions/switch.xml b/code/studio/src/plugins/gui_editor/expressions/switch.xml new file mode 100644 index 000000000..19f94f9d3 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/switch.xml @@ -0,0 +1,10 @@ + +Logical +switch +true + +A +B +C + + diff --git a/code/studio/src/plugins/gui_editor/expressions/value.xml b/code/studio/src/plugins/gui_editor/expressions/value.xml new file mode 100644 index 000000000..9bd57fc95 --- /dev/null +++ b/code/studio/src/plugins/gui_editor/expressions/value.xml @@ -0,0 +1,6 @@ + +Value +value +true +false + diff --git a/code/studio/src/plugins/gui_editor/gui_editor_window.cpp b/code/studio/src/plugins/gui_editor/gui_editor_window.cpp index 3f4e318db..002002abd 100644 --- a/code/studio/src/plugins/gui_editor/gui_editor_window.cpp +++ b/code/studio/src/plugins/gui_editor/gui_editor_window.cpp @@ -44,7 +44,7 @@ #include "editor_selection_watcher.h" #include "editor_message_processor.h" #include "add_widget_widget.h" -#include "texture_chooser.h" +#include "new_gui_dlg.h" namespace GUIEditor { @@ -71,8 +71,6 @@ namespace GUIEditor widgetInfoTree = new CWidgetInfoTree; - tc = new TextureChooser(); - createMenus(); readSettings(); @@ -118,9 +116,6 @@ namespace GUIEditor removeMenus(); - delete tc; - tc = NULL; - delete messageProcessor; messageProcessor = NULL; @@ -187,6 +182,8 @@ namespace GUIEditor currentProject = projectFiles.projectName.c_str(); currentProjectFile = fileName; projectWindow->setupFiles( projectFiles ); + GUICtrl->setWorkDir( _lastDir ); + if( GUICtrl->parse( projectFiles ) ) { hierarchyView->buildHierarchy( projectFiles.masterGroup ); @@ -203,6 +200,85 @@ namespace GUIEditor void GUIEditorWindow::newDocument() { + NewGUIDlg d; + int result = d.exec(); + + if( result == QDialog::Rejected ) + return; + + close(); + + std::string proj = d.getProjectName().toUtf8().constData(); + std::string wnd = d.getWindowName().toUtf8().constData(); + std::string mg = std::string( "ui:" ) + proj; + std::string dir = d.getProjectDirectory().toUtf8().constData(); + _lastDir = dir.c_str(); + std::string uiFile = "ui_" + proj + ".xml"; + + QList< QString > mapList; + d.getMapList( mapList ); + + bool b = GUICtrl->createNewGUI( proj, wnd ); + if( !b ) + { + QMessageBox::information( this, + tr( "Creating new GUI project" ), + tr( "Failed to create new GUI project :(" ) ); + reset(); + return; + } + + hierarchyView->buildHierarchy( mg ); + + projectFiles.projectName = proj; + projectFiles.masterGroup = mg; + projectFiles.activeGroup = std::string( "ui:" ) + proj + ":" + wnd; + projectFiles.version = SProjectFiles::NEW; + projectFiles.guiFiles.push_back( uiFile ); + + for( int i = 0; i < mapList.size(); i++ ) + { + projectFiles.mapFiles.push_back( mapList[ i ].toUtf8().constData() ); + } + + b = GUICtrl->loadMapFiles( projectFiles.mapFiles ); + if( !b ) + { + QMessageBox::information( this, + tr( "Creating new GUI project" ), + tr( "Failed to create new GUI project: Couldn't load map files. " ) ); + reset(); + return; + } + + projectWindow->setupFiles( projectFiles ); + + currentProject = proj.c_str(); + currentProjectFile = std::string( dir + "/" + proj + ".xml" ).c_str(); + + + // Save the project file + CProjectFileSerializer serializer; + serializer.setFile( currentProjectFile.toUtf8().constData() ); + if( !serializer.serialize( projectFiles ) ) + { + QMessageBox::critical( this, + tr( "Failed to save project" ), + tr( "There was an error while trying to save the project." ) ); + return; + } + + // Save the GUI file + WidgetSerializer widgetSerializer; + widgetSerializer.setFile( dir + "/" + uiFile ); + widgetSerializer.setActiveGroup( projectFiles.activeGroup ); + if( !widgetSerializer.serialize( projectFiles.masterGroup ) ) + { + QMessageBox::critical( this, + tr( "Failed to save project" ), + tr( "There was an error while trying to save the project." ) ); + return; + } } void GUIEditorWindow::save() @@ -223,8 +299,23 @@ namespace GUIEditor // Can't save old projects any further, since the widgets are in multiple files in them // using templates, styles and whatnot. There's no way to restore the original XML structure // after it's loaded - if( projectParser.getProjectVersion() == OLD ) + if( projectFiles.version == SProjectFiles::OLD ) return; + + std::string f = _lastDir.toUtf8().constData(); + f += "/"; + f += projectFiles.guiFiles[ 0 ]; + + WidgetSerializer widgetSerializer; + widgetSerializer.setFile( f ); + widgetSerializer.setActiveGroup( projectFiles.activeGroup ); + if( !widgetSerializer.serialize( projectFiles.masterGroup ) ) + { + QMessageBox::critical( this, + tr( "Failed to save project" ), + tr( "There was an error while trying to save the project." ) ); + return; + } } void GUIEditorWindow::saveAs() @@ -237,42 +328,36 @@ namespace GUIEditor if( dir.isEmpty() ) return; + _lastDir = dir; - projectFiles.guiFiles.clear(); - projectFiles.guiFiles.push_back( "ui_" + projectFiles.projectName + ".xml" ); - projectFiles.version = NEW; - - QString newFile = - dir + "/" + projectFiles.projectName.c_str() + ".xml"; - - CProjectFileSerializer serializer; - serializer.setFile( newFile.toUtf8().constData() ); - if( !serializer.serialize( projectFiles ) ) + if( projectFiles.version == SProjectFiles::OLD ) { - QMessageBox::critical( this, - tr( "Failed to save project" ), - tr( "There was an error while trying to save the project." ) ); - return; + projectFiles.guiFiles.clear(); + projectFiles.guiFiles.push_back( "ui_" + projectFiles.projectName + ".xml" ); + projectFiles.version = SProjectFiles::NEW; + } - std::string guiFile = - std::string( dir.toUtf8().constData() ) + "/" + "ui_" + projectFiles.projectName + ".xml"; + currentProjectFile = _lastDir; + currentProjectFile += "/"; + currentProjectFile += projectFiles.projectName.c_str(); + currentProjectFile += ".xml"; - WidgetSerializer widgetSerializer; - widgetSerializer.setFile( guiFile ); - widgetSerializer.setActiveGroup( projectFiles.activeGroup ); - if( !widgetSerializer.serialize( projectFiles.masterGroup ) ) - { - QMessageBox::critical( this, - tr( "Failed to save project" ), - tr( "There was an error while trying to save the project." ) ); - return; - } - - QMessageBox::information( this, - tr( "Save successful" ), - tr( "Project saved successfully!" ) ); + save(); + } + void GUIEditorWindow::reset() + { + projectFiles.clearAll(); + projectWindow->clear(); + hierarchyView->clearHierarchy(); + GUICtrl->reset(); + browserCtrl.clear(); + linkList->clear(); + procList->clear(); + currentProject = ""; + currentProjectFile = ""; + projectParser.clear(); } bool GUIEditorWindow::close() @@ -289,19 +374,10 @@ namespace GUIEditor CEditorSelectionWatcher *w = GUICtrl->getWatcher(); - disconnect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), hierarchyView, SLOT( onSelectionChanged( std::string& ) ) ); - disconnect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + disconnect( w, SIGNAL( sgnSelectionChanged() ), hierarchyView, SLOT( onSelectionChanged() ) ); + disconnect( w, SIGNAL( sgnSelectionChanged() ), &browserCtrl, SLOT( onSelectionChanged() ) ); - projectFiles.clearAll(); - projectWindow->clear(); - hierarchyView->clearHierarchy(); - GUICtrl->reset(); - browserCtrl.clear(); - linkList->clear(); - procList->clear(); - currentProject = ""; - currentProjectFile = ""; - projectParser.clear(); + reset(); return true; } @@ -328,8 +404,8 @@ namespace GUIEditor linkList->onGUILoaded(); CEditorSelectionWatcher *w = GUICtrl->getWatcher(); - connect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), hierarchyView, SLOT( onSelectionChanged( std::string& ) ) ); - connect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + connect( w, SIGNAL( sgnSelectionChanged() ), hierarchyView, SLOT( onSelectionChanged() ) ); + connect( w, SIGNAL( sgnSelectionChanged() ), &browserCtrl, SLOT( onSelectionChanged() ) ); } void GUIEditorWindow::onAddWidgetClicked() @@ -359,23 +435,17 @@ namespace GUIEditor GUICtrl->show(); } - void GUIEditorWindow::onTCClicked() - { - tc->load(); - tc->exec(); - } - void GUIEditorWindow::createMenus() { Core::MenuManager *mm = Core::ICore::instance()->menuManager(); - //QAction *newAction = mm->action( Core::Constants::NEW ); + QAction *newAction = mm->action( Core::Constants::NEW ); QAction *saveAction = mm->action( Core::Constants::SAVE ); QAction *saveAsAction = mm->action( Core::Constants::SAVE_AS ); QAction *closeAction = mm->action( Core::Constants::CLOSE ); QAction *delAction = mm->action( Core::Constants::DEL ); - //if( newAction != NULL ) - // newAction->setEnabled( true ); + if( newAction != NULL ) + newAction->setEnabled( true ); if( saveAction != NULL ) saveAction->setEnabled( true ); if( saveAsAction != NULL ) @@ -411,8 +481,28 @@ namespace GUIEditor connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onAddWidgetClicked() ) ); m->addAction( a ); - a = new QAction( "Texture Chooser", this ); - connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onTCClicked() ) ); + a = new QAction( "Group", this ); + connect( a, SIGNAL( triggered() ), messageProcessor, SLOT( onGroup() ) ); + m->addAction( a ); + + a = new QAction( "Ungroup", this ); + connect( a, SIGNAL( triggered() ), messageProcessor, SLOT( onUngroup() ) ); + m->addAction( a ); + + + // ---------------------------------------------------------------------------------- + m->addSeparator(); + + a = new QAction( "Select groups", this ); + a->setCheckable( true ); + a->setChecked( false ); + connect( a, SIGNAL( triggered( bool ) ), messageProcessor, SLOT( onSetGroupSelection( bool ) ) ); + m->addAction( a ); + + a = new QAction( "Multiselect", this ); + a->setCheckable( true ); + a->setChecked( false ); + connect( a, SIGNAL( triggered( bool ) ), messageProcessor, SLOT( onSetMultiSelection( bool ) ) ); m->addAction( a ); menu = m; diff --git a/code/studio/src/plugins/gui_editor/gui_editor_window.h b/code/studio/src/plugins/gui_editor/gui_editor_window.h index d18a24813..4a0a919a4 100644 --- a/code/studio/src/plugins/gui_editor/gui_editor_window.h +++ b/code/studio/src/plugins/gui_editor/gui_editor_window.h @@ -25,11 +25,8 @@ #include "property_browser_ctrl.h" class QtTreePropertyBrowser; - class QMenu; -class TextureChooser; - namespace GUIEditor { @@ -67,14 +64,13 @@ private Q_SLOTS: void onGUILoaded(); void onAddWidgetClicked(); void onTreeChanged(); - void onTCClicked(); - protected: void hideEvent( QHideEvent *evnt ); void showEvent( QShowEvent *evnt ); private: + void reset(); void createMenus(); void removeMenus(); @@ -101,8 +97,6 @@ private: QString currentProjectFile; QMenu *menu; - - TextureChooser *tc; }; } diff --git a/code/studio/src/plugins/gui_editor/link_editor.cpp b/code/studio/src/plugins/gui_editor/link_editor.cpp index c57a6cd09..3cb49f37a 100644 --- a/code/studio/src/plugins/gui_editor/link_editor.cpp +++ b/code/studio/src/plugins/gui_editor/link_editor.cpp @@ -18,20 +18,49 @@ #include "link_editor.h" #include "nel/gui/interface_group.h" #include "nel/gui/widget_manager.h" +#include "expression_editor.h" +#include namespace GUIEditor { + class LinkEditorPvt + { + public: + + LinkEditorPvt() + { + ee = new ExpressionEditor(); + ee->load(); + } + + ~LinkEditorPvt() + { + delete ee; + ee = NULL; + } + + ExpressionEditor *ee; + }; + + LinkEditor::LinkEditor( QWidget *parent ) : QWidget( parent ) { setupUi( this ); setup(); + + m_pvt = new LinkEditorPvt(); + connect( okButton, SIGNAL( clicked( bool ) ), this, SLOT( onOKButtonClicked() ) ); connect( cancelButton, SIGNAL( clicked( bool ) ), this, SLOT( hide() ) ); + connect( expressionEdit, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( onTextEditContextMenu( const QPoint& ) ) ); + connect( m_pvt->ee, SIGNAL( closing() ), this, SLOT( onEEClosing() ) ); } LinkEditor::~LinkEditor() { + delete m_pvt; + m_pvt = NULL; } void LinkEditor::setup() @@ -89,4 +118,23 @@ namespace GUIEditor hide(); } + + void LinkEditor::onTextEditContextMenu( const QPoint &pos ) + { + QMenu *menu = expressionEdit->createStandardContextMenu(); + QAction *a = menu->addAction( "Expression Editor" ); + connect( a, SIGNAL( triggered() ), this, SLOT( onEE() ) ); + + menu->exec( mapToGlobal( pos ) ); + } + + void LinkEditor::onEE() + { + m_pvt->ee->show(); + } + + void LinkEditor::onEEClosing() + { + expressionEdit->setPlainText( m_pvt->ee->result() ); + } } diff --git a/code/studio/src/plugins/gui_editor/link_editor.h b/code/studio/src/plugins/gui_editor/link_editor.h index b70019d20..f5617982e 100644 --- a/code/studio/src/plugins/gui_editor/link_editor.h +++ b/code/studio/src/plugins/gui_editor/link_editor.h @@ -23,6 +23,8 @@ namespace GUIEditor { + class LinkEditorPvt; + class LinkEditor : public QWidget, public Ui::LinkEditor { Q_OBJECT @@ -35,12 +37,16 @@ namespace GUIEditor Q_SIGNALS: void okClicked(); - + private Q_SLOTS: void onOKButtonClicked(); + void onTextEditContextMenu( const QPoint &pos ); + void onEE(); + void onEEClosing(); private: uint32 currentLinkId; + LinkEditorPvt *m_pvt; }; } diff --git a/code/studio/src/plugins/gui_editor/link_editor.ui b/code/studio/src/plugins/gui_editor/link_editor.ui index 13a6e7d7e..657b0eabc 100644 --- a/code/studio/src/plugins/gui_editor/link_editor.ui +++ b/code/studio/src/plugins/gui_editor/link_editor.ui @@ -26,6 +26,9 @@ + + Qt::CustomContextMenu + diff --git a/code/studio/src/plugins/gui_editor/nelgui_ctrl.cpp b/code/studio/src/plugins/gui_editor/nelgui_ctrl.cpp index 03f784944..e9712ce4e 100644 --- a/code/studio/src/plugins/gui_editor/nelgui_ctrl.cpp +++ b/code/studio/src/plugins/gui_editor/nelgui_ctrl.cpp @@ -89,20 +89,8 @@ namespace GUIEditor reset(); IParser *parser = CWidgetManager::getInstance()->getParser(); - std::vector< std::string >::iterator itr; - for( itr = files.mapFiles.begin(); itr != files.mapFiles.end(); ++itr ) - { - std::string &file = *itr; - std::string::size_type i = file.find_last_of( '.' ); - std::string mapFile = file.substr( 0, i ); - mapFile.append( ".txt" ); - - if( !CViewRenderer::getInstance()->loadTextures( file, mapFile, false ) ) - { - CViewRenderer::getInstance()->reset(); - return false; - } - } + if( !loadMapFiles( files.mapFiles ) ) + return false; if( !parser->parseInterface( files.guiFiles, false ) ) return false; @@ -114,11 +102,49 @@ namespace GUIEditor if( e != NULL ) e->setActive( true ); - timerID = startTimer( 200 ); - guiLoaded = true; - Q_EMIT guiLoadComplete(); + onGUILoaded(); - CWidgetManager::getInstance()->registerSelectionWatcher( watcher ); + return true; + } + + bool NelGUICtrl::loadMapFiles( const std::vector< std::string > &v ) + { + std::vector< std::string >::const_iterator itr; + for( itr = v.begin(); itr != v.end(); ++itr ) + { + const std::string &file = *itr; + std::string::size_type i = file.find_last_of( '.' ); + std::string mapFile = file.substr( 0, i ); + mapFile.append( ".txt" ); + + if( !CViewRenderer::getInstance()->loadTextures( file, mapFile, false ) ) + { + CViewRenderer::getInstance()->reset(); + return false; + } + } + + return true; + } + + bool NelGUICtrl::createNewGUI( const std::string &project, const std::string &window ) + { + reset(); + bool ok = CWidgetManager::getInstance()->createNewGUI( project, window ); + if( !ok ) + return false; + + std::string mg = std::string( "ui:" ) + project; + std::string ag = mg + ":" + window; + + CWidgetManager::getInstance()->updateAllLocalisedElements(); + CWidgetManager::getInstance()->activateMasterGroup( mg, true ); + + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( ag ); + if( e != NULL ) + e->setActive( true ); + + onGUILoaded(); return true; } @@ -160,6 +186,15 @@ namespace GUIEditor } } + void NelGUICtrl::onGUILoaded() + { + timerID = startTimer( 200 ); + guiLoaded = true; + Q_EMIT guiLoadComplete(); + + CWidgetManager::getInstance()->registerSelectionWatcher( watcher ); + } + void NelGUICtrl::show() { if( timerID == 0 ) @@ -187,6 +222,12 @@ namespace GUIEditor } } + void NelGUICtrl::setWorkDir( const QString &dir ) + { + IParser *parser = CWidgetManager::getInstance()->getParser(); + parser->setWorkDir( std::string( dir.toUtf8().constData() ) ); + } + QWidget* NelGUICtrl::getViewPort() { return w; diff --git a/code/studio/src/plugins/gui_editor/nelgui_ctrl.h b/code/studio/src/plugins/gui_editor/nelgui_ctrl.h index b3c68ff32..d54c78c7a 100644 --- a/code/studio/src/plugins/gui_editor/nelgui_ctrl.h +++ b/code/studio/src/plugins/gui_editor/nelgui_ctrl.h @@ -43,6 +43,8 @@ namespace GUIEditor void init(); bool parse( SProjectFiles &files ); + bool loadMapFiles( const std::vector< std::string > &v ); + bool createNewGUI( const std::string &project, const std::string &window ); void draw(); void reset(); CEditorSelectionWatcher* getWatcher(){ return watcher; } @@ -52,6 +54,8 @@ namespace GUIEditor void show(); void hide(); + void setWorkDir( const QString &dir ); + Q_SIGNALS: void guiLoadComplete(); @@ -59,6 +63,8 @@ Q_SIGNALS: void timerEvent( QTimerEvent *evnt ); private: + void onGUILoaded(); + int timerID; bool guiLoaded; CEditorSelectionWatcher *watcher; diff --git a/code/studio/src/plugins/gui_editor/new_gui_dlg.cpp b/code/studio/src/plugins/gui_editor/new_gui_dlg.cpp new file mode 100644 index 000000000..3c9208dfc --- /dev/null +++ b/code/studio/src/plugins/gui_editor/new_gui_dlg.cpp @@ -0,0 +1,135 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "new_gui_dlg.h" +#include +#include + +NewGUIDlg::NewGUIDlg( QWidget *parent ) : +QDialog( parent ) +{ + m_ui.setupUi( this ); + + connect( m_ui.okButton, SIGNAL( clicked( bool ) ), this, SLOT( onOKClicked() ) ); + connect( m_ui.cancelButton, SIGNAL( clicked( bool ) ), this, SLOT( onCancelClicked() ) ); + connect( m_ui.projectDirTB, SIGNAL( clicked( bool ) ), this, SLOT( onProjectDirTBClicked() ) ); + connect( m_ui.addButton, SIGNAL( clicked( bool ) ), this, SLOT( onAddClicked() ) ); + connect( m_ui.removeButton, SIGNAL( clicked( bool ) ), this, SLOT( onRemoveClicked() ) ); + +} + +NewGUIDlg::~NewGUIDlg() +{ +} + +QString NewGUIDlg::getProjectName() const +{ + return m_ui.projectEdit->text(); +} + +QString NewGUIDlg::getWindowName() const +{ + return m_ui.windowEdit->text(); +} + +QString NewGUIDlg::getProjectDirectory() const +{ + return m_ui.projectDirEdit->text(); +} + +void NewGUIDlg::getMapList( QList< QString > &l ) +{ + l.clear(); + + for( int i = 0; i < m_ui.mapList->count(); i++ ) + { + l.push_back( m_ui.mapList->item( i )->text() ); + } +} + +void NewGUIDlg::onOKClicked() +{ + if( m_ui.projectEdit->text().isEmpty() ) + { + QMessageBox::information( this, + tr( "New project" ), + tr( "You must specify a project name!" ) ); + return; + } + + if( m_ui.windowEdit->text().isEmpty() ) + { + QMessageBox::information( this, + tr( "New project" ), + tr( "You must specify a window name!" ) ); + return; + } + + if( m_ui.projectDirEdit->text().isEmpty() ) + { + QMessageBox::information( this, + tr( "New project" ), + tr( "You must specify a project directory!" ) ); + return; + } + + accept(); +} + +void NewGUIDlg::onCancelClicked() +{ + reject(); +} + +void NewGUIDlg::onProjectDirTBClicked() +{ + QString dir = QFileDialog::getExistingDirectory( this, + tr( "Specify project directory" ), + "." ); + if( dir.isEmpty() ) + return; + + m_ui.projectDirEdit->setText( dir ); +} + +void NewGUIDlg::onAddClicked() +{ + if( m_ui.mapEdit->text().isEmpty() ) + return; + + QList< QListWidgetItem* > l = m_ui.mapList->findItems( m_ui.mapEdit->text(), Qt::MatchContains ); + if( !l.isEmpty() ) + { + return; + } + + m_ui.mapList->addItem( m_ui.mapEdit->text() ); + m_ui.mapEdit->clear(); +} + +void NewGUIDlg::onRemoveClicked() +{ + QListWidgetItem *item = m_ui.mapList->currentItem(); + if( item == NULL ) + return; + + delete item; +} + + + diff --git a/code/studio/src/plugins/gui_editor/new_gui_dlg.h b/code/studio/src/plugins/gui_editor/new_gui_dlg.h new file mode 100644 index 000000000..0d878461c --- /dev/null +++ b/code/studio/src/plugins/gui_editor/new_gui_dlg.h @@ -0,0 +1,50 @@ +// Ryzom Core Studio - GUI Editor Plugin +// +// Copyright (C) 2014 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef NEW_GUI_DLG_H +#define NEW_GUI_DLG_H + +#include "ui_new_gui_dlg.h" +#include + +class NewGUIDlg : public QDialog +{ + Q_OBJECT + +public: + NewGUIDlg( QWidget *parent = NULL ); + ~NewGUIDlg(); + + QString getProjectName() const; + QString getWindowName() const; + QString getProjectDirectory() const; + void getMapList( QList< QString > &l ); + +private Q_SLOTS: + void onOKClicked(); + void onCancelClicked(); + void onProjectDirTBClicked(); + void onAddClicked(); + void onRemoveClicked(); + +private: + Ui::NewGUIDialog m_ui; +}; + +#endif + diff --git a/code/studio/src/plugins/gui_editor/new_gui_dlg.ui b/code/studio/src/plugins/gui_editor/new_gui_dlg.ui new file mode 100644 index 000000000..bf22e8c6b --- /dev/null +++ b/code/studio/src/plugins/gui_editor/new_gui_dlg.ui @@ -0,0 +1,130 @@ + + + NewGUIDialog + + + + 0 + 0 + 399 + 354 + + + + New GUI + + + + + + Project name + + + + + + + + + + Window name + + + + + + + + + + Project directory + + + + + + + + + + ... + + + + + + + Map files + + + + + + Add + + + + + + + + + + Remove + + + + + + + + + + + + + Qt::Horizontal + + + + 107 + 20 + + + + + + + + + + + 0 + 0 + + + + OK + + + + + + + + 0 + 0 + + + + Cancel + + + + + + + + + + diff --git a/code/studio/src/plugins/gui_editor/project_file_parser.cpp b/code/studio/src/plugins/gui_editor/project_file_parser.cpp index 7213b332a..856b3c164 100644 --- a/code/studio/src/plugins/gui_editor/project_file_parser.cpp +++ b/code/studio/src/plugins/gui_editor/project_file_parser.cpp @@ -16,6 +16,7 @@ #include "project_file_parser.h" +#include "nel/misc/debug.h" namespace GUIEditor { @@ -57,12 +58,13 @@ namespace GUIEditor projectFiles.projectName = files.projectName; projectFiles.masterGroup = files.masterGroup; projectFiles.activeGroup = files.activeGroup; + projectFiles.version = files.version; } unsigned long CProjectFileParser::getProjectVersion() const { if( !loaded ) - return OLD; + return SProjectFiles::OLD; return files.version; } @@ -70,7 +72,7 @@ namespace GUIEditor void CProjectFileParser::clear() { files.projectName = ""; - files.version = OLD; + files.version = SProjectFiles::OLD; files.activeGroup = ""; files.guiFiles.clear(); files.mapFiles.clear(); @@ -208,7 +210,9 @@ namespace GUIEditor reader.readNext(); } if( files.mapFiles.empty() ) - return false; + { + nlinfo( "No map file(s) specified in project file." ); + } return true; } diff --git a/code/studio/src/plugins/gui_editor/project_file_serializer.cpp b/code/studio/src/plugins/gui_editor/project_file_serializer.cpp index 4eb442d3f..0b34f511b 100644 --- a/code/studio/src/plugins/gui_editor/project_file_serializer.cpp +++ b/code/studio/src/plugins/gui_editor/project_file_serializer.cpp @@ -25,7 +25,7 @@ namespace GUIEditor if( fileName.empty() ) return false; - if( project.version >= MAX_PROJECTFILE_VERSION ) + if( project.version >= SProjectFiles::MAX_PROJECTFILE_VERSION ) return false; out.open( fileName.c_str() ); diff --git a/code/studio/src/plugins/gui_editor/project_files.h b/code/studio/src/plugins/gui_editor/project_files.h index 4ae58493b..786bd22e4 100644 --- a/code/studio/src/plugins/gui_editor/project_files.h +++ b/code/studio/src/plugins/gui_editor/project_files.h @@ -23,16 +23,17 @@ namespace GUIEditor { - enum ProjectVersion - { - OLD = 0, - NEW = 1, - MAX_PROJECTFILE_VERSION - }; - struct SProjectFiles { public: + + enum ProjectVersion + { + OLD = 0, + NEW = 1, + MAX_PROJECTFILE_VERSION + }; + std::string projectName; unsigned long version; std::string masterGroup; diff --git a/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp b/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp index bd73fb7fa..6db5423a3 100644 --- a/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp +++ b/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp @@ -436,7 +436,7 @@ namespace GUIEditor browser->clear(); } - void CPropBrowserCtrl::onSelectionChanged( std::string &id ) + void CPropBrowserCtrl::onSelectionChanged() { if( browser == NULL ) return; @@ -444,14 +444,20 @@ namespace GUIEditor disablePropertyWatchers(); browser->clear(); - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( id ); + std::vector< std::string > selection; + CWidgetManager::getInstance()->getEditorSelection( selection ); + + if( selection.size() != 1 ) + return; + + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( selection[ 0 ] ); if( e == NULL ) { enablePropertyWatchers(); return; } - currentElement = id; + currentElement = selection[ 0 ]; std::string n = e->getClassName(); @@ -493,6 +499,10 @@ namespace GUIEditor if( e == NULL ) return; e->setProperty( propName.toUtf8().constData(), propValue.toUtf8().constData() ); + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); // Make sure the changes are applied @@ -514,13 +524,12 @@ namespace GUIEditor return; std::string type = itr->second; + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); + if( e == NULL ) + return; if( type == "button_type" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v; v = NelButtonType::toString( value ); if( v.empty() ) @@ -531,10 +540,6 @@ namespace GUIEditor else if( type == "text_justification" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v; v = NelTxtJustification::toString( value ); if( v.empty() ) @@ -545,10 +550,6 @@ namespace GUIEditor else if( type == "posref" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelPosRef::toString( value ); if( v.empty() ) return; @@ -558,10 +559,6 @@ namespace GUIEditor else if( type == "posreftt" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelPosRefTT::toString( value ); if( v.empty() ) return; @@ -608,10 +605,6 @@ namespace GUIEditor else if( type == "tooltip_parent" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelTTParent::toString( value ); if( v.empty() ) return; @@ -621,16 +614,18 @@ namespace GUIEditor else if( type == "bitmap_align" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelBMAlign::toString( value ); if( v.empty() ) return; e->setProperty( propName.toUtf8().constData(), v ); } + + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); + } @@ -643,6 +638,10 @@ namespace GUIEditor return; e->setProperty( propName.toUtf8().constData(), v.toUtf8().constData() ); + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); } void CPropBrowserCtrl::onTexturePropertyChanged( QtProperty *p, const QString &v ) @@ -654,6 +653,10 @@ namespace GUIEditor return; e->setProperty( propName.toUtf8().constData(), v.toUtf8().constData() ); + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); } void CPropBrowserCtrl::enablePropertyWatchers() @@ -710,9 +713,6 @@ namespace GUIEditor { std::string j = element->getProperty( prop.propName ); - if( j.empty() ) - return; - QtProperty *pp = textureMgr->addProperty( prop.propName.c_str() ); if( pp == NULL ) return; @@ -725,9 +725,6 @@ namespace GUIEditor { std::string j = element->getProperty( prop.propName ); - if( j.empty() ) - return; - QtProperty *pp = actionMgr->addProperty( prop.propName.c_str() ); if( pp == NULL ) return; diff --git a/code/studio/src/plugins/gui_editor/property_browser_ctrl.h b/code/studio/src/plugins/gui_editor/property_browser_ctrl.h index abf80d7de..3d72d92ba 100644 --- a/code/studio/src/plugins/gui_editor/property_browser_ctrl.h +++ b/code/studio/src/plugins/gui_editor/property_browser_ctrl.h @@ -59,7 +59,7 @@ namespace GUIEditor void clear(); public Q_SLOTS: - void onSelectionChanged( std::string &id ); + void onSelectionChanged(); private Q_SLOTS: void onPropertyChanged( QtProperty *prop, const QVariant &v ); diff --git a/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp b/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp index 24208f4a3..343d8efd8 100644 --- a/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp +++ b/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp @@ -18,7 +18,6 @@ #include "widget_hierarchy.h" #include "nel/gui/interface_group.h" #include "nel/gui/widget_manager.h" -#include "nel/gui/widget_addition_watcher.h" namespace { @@ -76,18 +75,24 @@ namespace GUIEditor::WidgetHierarchy *h; }; - class CWidgetAdditionWatcher : public IWidgetAdditionWatcher + class CWidgetWatcher : public CWidgetManager::IWidgetWatcher { public: - CWidgetAdditionWatcher(){ h = NULL; } - ~CWidgetAdditionWatcher(){} + CWidgetWatcher(){ h = NULL; } + ~CWidgetWatcher(){} - void widgetAdded( const std::string &name ) + void onWidgetAdded( const std::string &name ) { if( h != NULL ) h->onWidgetAdded( name ); } - + + void onWidgetMoved( const std::string &oldid, const std::string &newid ) + { + if( h != NULL ) + h->onWidgetMoved( oldid, newid ); + } + void setWidgetHierarchy( GUIEditor::WidgetHierarchy *h ){ this->h = h; } private: @@ -95,7 +100,7 @@ namespace }; CWidgetDeletionWatcher deletionWatcher; - CWidgetAdditionWatcher additionWatcher; + CWidgetWatcher widgetwatcher; } namespace GUIEditor @@ -107,7 +112,7 @@ namespace GUIEditor connect( widgetHT, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( onItemDblClicked( QTreeWidgetItem* ) ) ); deletionWatcher.setWidgetHierarchy( this ); - additionWatcher.setWidgetHierarchy( this ); + widgetwatcher.setWidgetHierarchy( this ); } WidgetHierarchy::~WidgetHierarchy() @@ -117,7 +122,7 @@ namespace GUIEditor void WidgetHierarchy::clearHierarchy() { CInterfaceElement::unregisterDeletionWatcher( &deletionWatcher ); - CWidgetManager::getInstance()->unregisterAdditionWatcher( &additionWatcher ); + CWidgetManager::getInstance()->unregisterWidgetWatcher( &widgetwatcher ); widgetHT->clear(); widgetHierarchyMap.clear(); } @@ -126,7 +131,7 @@ namespace GUIEditor { clearHierarchy(); CInterfaceElement::registerDeletionWatcher( &deletionWatcher ); - CWidgetManager::getInstance()->registerAdditionWatcher( &additionWatcher ); + CWidgetManager::getInstance()->registerWidgetWatcher( &widgetwatcher ); CInterfaceGroup *mg = CWidgetManager::getInstance()->getMasterGroupFromId( masterGroup ); if( mg != NULL ) @@ -177,6 +182,27 @@ namespace GUIEditor } } + QTreeWidgetItem* WidgetHierarchy::findItem( const std::string &id ) + { + std::map< std::string, QTreeWidgetItem* >::iterator itr + = widgetHierarchyMap.find( id ); + if( itr == widgetHierarchyMap.end() ) + return NULL; + else + return itr->second; + } + + QTreeWidgetItem* WidgetHierarchy::findParent( const std::string &id ) + { + // Get the parent's name + std::string::size_type p = id.find_last_of( ':' ); + if( p == std::string::npos ) + return NULL; + std::string parentId = id.substr( 0, p ); + + return findItem( parentId ); + } + void WidgetHierarchy::onWidgetDeleted( const std::string &id ) { std::map< std::string, QTreeWidgetItem* >::iterator itr @@ -231,16 +257,62 @@ namespace GUIEditor widgetHierarchyMap[ id ] = item; } + void WidgetHierarchy::onWidgetMoved( const std::string &oldid, const std::string &newid ) + { + QTreeWidgetItem *newParent = NULL; + QTreeWidgetItem *item = NULL; + QString id; + + newParent = findParent( newid ); + item = findItem( oldid ); + + if( ( newParent == NULL ) || ( item == NULL ) ) + return; + + // Remove item from old parent + QTreeWidgetItem *p = item->parent(); + if( p != NULL ) + p->setExpanded( false ); + p->removeChild( item ); + + // Remove reference to old item + widgetHierarchyMap.erase( oldid ); + + // Add item to new parent + newParent->addChild( item ); + + // Add reference to new item + widgetHierarchyMap[ newid ] = item; + + selectItem( item ); + } + + void WidgetHierarchy::selectItem( QTreeWidgetItem *item ) + { + widgetHT->collapseAll(); + + QTreeWidgetItem *currItem = item; + while( currItem != NULL ) + { + currItem->setExpanded( true ); + currItem = currItem->parent(); + } + + widgetHT->setCurrentItem( item ); + item->setSelected( true ); + } + void WidgetHierarchy::getCurrentGroup( QString &g ) { - std::string s = CWidgetManager::getInstance()->getCurrentEditorSelection(); - if( s.empty() ) + std::vector< std::string > selection; + CWidgetManager::getInstance()->getEditorSelection( selection ); + if( selection.size() != 1 ) { g = ""; return; } - NLGUI::CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( s ); + NLGUI::CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( selection[ 0 ] ); if( e == NULL ) { g = ""; @@ -271,8 +343,16 @@ namespace GUIEditor currentSelection.clear(); } - void WidgetHierarchy::onSelectionChanged( std::string &newSelection ) + void WidgetHierarchy::onSelectionChanged() { + std::vector< std::string > selection; + CWidgetManager::getInstance()->getEditorSelection( selection ); + + if( selection.size() != 1 ) + return; + + std::string newSelection = selection[ 0 ]; + if( newSelection == currentSelection ) return; @@ -288,18 +368,11 @@ namespace GUIEditor if( widgetHT->currentItem() != NULL ) widgetHT->currentItem()->setSelected( false ); - // expand the tree items, so that we can see the selected item - QTreeWidgetItem *item = itr->second; - QTreeWidgetItem *currItem = item; - while( currItem != NULL ) - { - currItem->setExpanded( true ); - currItem = currItem->parent(); - } + widgetHT->collapseAll(); // select the current item - item->setSelected( true ); - widgetHT->setCurrentItem( item ); + QTreeWidgetItem *item = itr->second; + selectItem( item ); currentSelection = newSelection; } @@ -307,9 +380,11 @@ namespace GUIEditor { if( item->parent() == NULL ) return; + + selectItem( item ); std::string n = item->text( 0 ).toUtf8().constData(); currentSelection = makeFullName( item, n ); - CWidgetManager::getInstance()->setCurrentEditorSelection( currentSelection ); + CWidgetManager::getInstance()->selectWidget( currentSelection ); } } diff --git a/code/studio/src/plugins/gui_editor/widget_hierarchy.h b/code/studio/src/plugins/gui_editor/widget_hierarchy.h index 4641c8ce8..cdfc9a741 100644 --- a/code/studio/src/plugins/gui_editor/widget_hierarchy.h +++ b/code/studio/src/plugins/gui_editor/widget_hierarchy.h @@ -44,15 +44,19 @@ namespace GUIEditor void onWidgetDeleted( const std::string &id ); void onWidgetAdded( const std::string &id ); + void onWidgetMoved( const std::string &oldid, const std::string &newid ); void getCurrentGroup( QString &g ); private: void buildHierarchy( QTreeWidgetItem *parent, NLGUI::CInterfaceGroup *group ); + QTreeWidgetItem* findItem( const std::string &id ); + QTreeWidgetItem* findParent( const std::string &id ); + void selectItem( QTreeWidgetItem *item ); public Q_SLOTS: void onGUILoaded(); - void onSelectionChanged( std::string &newSelection ); + void onSelectionChanged(); private Q_SLOTS: void onItemDblClicked( QTreeWidgetItem *item ); diff --git a/code/studio/src/plugins/gui_editor/widget_serializer.cpp b/code/studio/src/plugins/gui_editor/widget_serializer.cpp index fd4e7cfbe..8006a6b50 100644 --- a/code/studio/src/plugins/gui_editor/widget_serializer.cpp +++ b/code/studio/src/plugins/gui_editor/widget_serializer.cpp @@ -93,8 +93,6 @@ namespace GUIEditor return false; } - ag->setActive( false ); - if( mg->serializeSubGroups( root ) == NULL ) { ag->setActive( true ); @@ -103,8 +101,6 @@ namespace GUIEditor return false; } - ag->setActive( true ); - if( !mg->serializeLinks( root ) ) { xmlFreeNode( root ); diff --git a/code/studio/src/plugins/gui_editor/widgets/CtrlButton.xml b/code/studio/src/plugins/gui_editor/widgets/CtrlButton.xml index 12b82e7f6..c081f3dae 100644 --- a/code/studio/src/plugins/gui_editor/widgets/CtrlButton.xml +++ b/code/studio/src/plugins/gui_editor/widgets/CtrlButton.xml @@ -2,6 +2,7 @@
CtrlButton CCtrlButton + button CtrlBaseButton false diff --git a/code/studio/src/plugins/gui_editor/widgets/CtrlColPick.xml b/code/studio/src/plugins/gui_editor/widgets/CtrlColPick.xml index ea2ba6171..7ab3e2f48 100644 --- a/code/studio/src/plugins/gui_editor/widgets/CtrlColPick.xml +++ b/code/studio/src/plugins/gui_editor/widgets/CtrlColPick.xml @@ -2,6 +2,7 @@
CtrlColPick CCtrlColPick + colpick CtrlBase false diff --git a/code/studio/src/plugins/gui_editor/widgets/CtrlScroll.xml b/code/studio/src/plugins/gui_editor/widgets/CtrlScroll.xml index 1ad970f31..9f5fcfc60 100644 --- a/code/studio/src/plugins/gui_editor/widgets/CtrlScroll.xml +++ b/code/studio/src/plugins/gui_editor/widgets/CtrlScroll.xml @@ -2,6 +2,7 @@
CtrlScroll CCtrlScroll + scroll CtrlBase false diff --git a/code/studio/src/plugins/gui_editor/widgets/CtrlTextButton.xml b/code/studio/src/plugins/gui_editor/widgets/CtrlTextButton.xml index ca66dbd62..6afd06cdf 100644 --- a/code/studio/src/plugins/gui_editor/widgets/CtrlTextButton.xml +++ b/code/studio/src/plugins/gui_editor/widgets/CtrlTextButton.xml @@ -2,6 +2,7 @@
CtrlTextButton CCtrlTextButton + text_button CtrlBaseButton false @@ -11,22 +12,22 @@ tx_normal string - + but tx_pushed string - + but tx_over string - + but_over hardtext string - + push me wmargin @@ -156,7 +157,7 @@ line_maxw int - 0 + 100 multi_line_space diff --git a/code/studio/src/plugins/gui_editor/widgets/DBGroupSelectNumber.xml b/code/studio/src/plugins/gui_editor/widgets/DBGroupSelectNumber.xml index 624ded887..7d78fc6b9 100644 --- a/code/studio/src/plugins/gui_editor/widgets/DBGroupSelectNumber.xml +++ b/code/studio/src/plugins/gui_editor/widgets/DBGroupSelectNumber.xml @@ -2,6 +2,7 @@
DBGroupSelectNumber CDBGroupSelectNumber + select_number InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/DBViewBar.xml b/code/studio/src/plugins/gui_editor/widgets/DBViewBar.xml index c7f644fa4..878f9b563 100644 --- a/code/studio/src/plugins/gui_editor/widgets/DBViewBar.xml +++ b/code/studio/src/plugins/gui_editor/widgets/DBViewBar.xml @@ -2,6 +2,7 @@
DBViewBar CDBViewBar + bar ViewBitmap false diff --git a/code/studio/src/plugins/gui_editor/widgets/DBViewBar3.xml b/code/studio/src/plugins/gui_editor/widgets/DBViewBar3.xml index 8295c5f30..db635eb27 100644 --- a/code/studio/src/plugins/gui_editor/widgets/DBViewBar3.xml +++ b/code/studio/src/plugins/gui_editor/widgets/DBViewBar3.xml @@ -2,6 +2,7 @@
DBViewBar3 CDBViewBar3 + bar3 ViewBitmap false diff --git a/code/studio/src/plugins/gui_editor/widgets/DBViewDigit.xml b/code/studio/src/plugins/gui_editor/widgets/DBViewDigit.xml index 0c12445f9..1a659fd91 100644 --- a/code/studio/src/plugins/gui_editor/widgets/DBViewDigit.xml +++ b/code/studio/src/plugins/gui_editor/widgets/DBViewDigit.xml @@ -2,6 +2,7 @@
DBViewDigit CDBViewDigit + digit CtrlBase false diff --git a/code/studio/src/plugins/gui_editor/widgets/DBViewNumber.xml b/code/studio/src/plugins/gui_editor/widgets/DBViewNumber.xml index c1861df61..36a7d23ce 100644 --- a/code/studio/src/plugins/gui_editor/widgets/DBViewNumber.xml +++ b/code/studio/src/plugins/gui_editor/widgets/DBViewNumber.xml @@ -2,6 +2,7 @@
DBViewNumber CDBViewNumber + text_number ViewText false diff --git a/code/studio/src/plugins/gui_editor/widgets/DBViewQuantity.xml b/code/studio/src/plugins/gui_editor/widgets/DBViewQuantity.xml index c24379c96..c11c1a4cc 100644 --- a/code/studio/src/plugins/gui_editor/widgets/DBViewQuantity.xml +++ b/code/studio/src/plugins/gui_editor/widgets/DBViewQuantity.xml @@ -2,6 +2,7 @@
DBViewQuantity CDBViewQuantity + text_quantity ViewText false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupContainer.xml b/code/studio/src/plugins/gui_editor/widgets/GroupContainer.xml index 3d879a150..a3c9aade7 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupContainer.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupContainer.xml @@ -2,6 +2,7 @@
GroupContainer CGroupContainer + container InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupEditBox.xml b/code/studio/src/plugins/gui_editor/widgets/GroupEditBox.xml index 31ca205c7..578262a20 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupEditBox.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupEditBox.xml @@ -2,6 +2,7 @@
GroupEditBox CGroupEditBox + edit_box InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupHTML.xml b/code/studio/src/plugins/gui_editor/widgets/GroupHTML.xml index 5f0521be8..894580734 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupHTML.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupHTML.xml @@ -2,6 +2,7 @@
GroupHTML CGroupHTML + html GroupScrollText false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupHeader.xml b/code/studio/src/plugins/gui_editor/widgets/GroupHeader.xml index cc96fd742..91dd73e36 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupHeader.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupHeader.xml @@ -2,6 +2,7 @@
GroupHeader CGroupHeader + header GroupList false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupList.xml b/code/studio/src/plugins/gui_editor/widgets/GroupList.xml index 3ca2db95c..569aa8d9d 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupList.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupList.xml @@ -2,6 +2,7 @@
GroupList CGroupList + list InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupMenu.xml b/code/studio/src/plugins/gui_editor/widgets/GroupMenu.xml index cdd42ba95..3bd0c5506 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupMenu.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupMenu.xml @@ -2,6 +2,7 @@
GroupMenu CGroupMenu + menu GroupModal false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupModal.xml b/code/studio/src/plugins/gui_editor/widgets/GroupModal.xml index 034e3025e..33bd6fd08 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupModal.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupModal.xml @@ -2,6 +2,7 @@
GroupModal CGroupModal + modal GroupFrame false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupScrollText.xml b/code/studio/src/plugins/gui_editor/widgets/GroupScrollText.xml index 95719398d..53092a456 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupScrollText.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupScrollText.xml @@ -2,6 +2,7 @@
GroupScrollText CGroupScrollText + scroll_text InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupTab.xml b/code/studio/src/plugins/gui_editor/widgets/GroupTab.xml index df148a0a3..e2e1a8bf1 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupTab.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupTab.xml @@ -2,6 +2,7 @@
GroupTab CGroupTab + tab InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupTable.xml b/code/studio/src/plugins/gui_editor/widgets/GroupTable.xml index 9fa957741..dfbc4e2a8 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupTable.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupTable.xml @@ -2,6 +2,7 @@
GroupTable CGroupTable + table InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/GroupTree.xml b/code/studio/src/plugins/gui_editor/widgets/GroupTree.xml index 73b1dea3b..b20c74733 100644 --- a/code/studio/src/plugins/gui_editor/widgets/GroupTree.xml +++ b/code/studio/src/plugins/gui_editor/widgets/GroupTree.xml @@ -2,6 +2,7 @@
GroupTree CGroupTree + tree InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/InterfaceGroup.xml b/code/studio/src/plugins/gui_editor/widgets/InterfaceGroup.xml index ddcdf01e6..50f7c3e83 100644 --- a/code/studio/src/plugins/gui_editor/widgets/InterfaceGroup.xml +++ b/code/studio/src/plugins/gui_editor/widgets/InterfaceGroup.xml @@ -2,6 +2,7 @@
InterfaceGroup CInterfaceGroup + interface_group CtrlBase false diff --git a/code/studio/src/plugins/gui_editor/widgets/InterfaceGroupWheel.xml b/code/studio/src/plugins/gui_editor/widgets/InterfaceGroupWheel.xml index b095ecac5..6a35671cd 100644 --- a/code/studio/src/plugins/gui_editor/widgets/InterfaceGroupWheel.xml +++ b/code/studio/src/plugins/gui_editor/widgets/InterfaceGroupWheel.xml @@ -2,6 +2,7 @@
InterfaceGroupWheel CInterfaceGroupWheel + group_wheel InterfaceGroup false diff --git a/code/studio/src/plugins/gui_editor/widgets/ViewBitmap.xml b/code/studio/src/plugins/gui_editor/widgets/ViewBitmap.xml index 21ef7daff..7d78f6c40 100644 --- a/code/studio/src/plugins/gui_editor/widgets/ViewBitmap.xml +++ b/code/studio/src/plugins/gui_editor/widgets/ViewBitmap.xml @@ -2,6 +2,7 @@
ViewBitmap CViewBitmap + bitmap CtrlBase false diff --git a/code/studio/src/plugins/gui_editor/widgets/ViewBitmapCombo.xml b/code/studio/src/plugins/gui_editor/widgets/ViewBitmapCombo.xml index 8fc579675..461f69c55 100644 --- a/code/studio/src/plugins/gui_editor/widgets/ViewBitmapCombo.xml +++ b/code/studio/src/plugins/gui_editor/widgets/ViewBitmapCombo.xml @@ -2,6 +2,7 @@
ViewBitmapCombo CViewBitmapCombo + bitmap_combo CtrlBase false diff --git a/code/studio/src/plugins/gui_editor/widgets/ViewText.xml b/code/studio/src/plugins/gui_editor/widgets/ViewText.xml index 415c3167e..4862517aa 100644 --- a/code/studio/src/plugins/gui_editor/widgets/ViewText.xml +++ b/code/studio/src/plugins/gui_editor/widgets/ViewText.xml @@ -2,6 +2,7 @@
ViewText CViewText + text InterfaceElement false @@ -46,7 +47,7 @@ line_maxw int - 0 + 100 multi_line_space @@ -101,7 +102,7 @@ hardtext string - + Some text hardtext_format diff --git a/code/studio/src/plugins/gui_editor/widgets/ViewTextFormated.xml b/code/studio/src/plugins/gui_editor/widgets/ViewTextFormated.xml index cabd081f0..36aa68102 100644 --- a/code/studio/src/plugins/gui_editor/widgets/ViewTextFormated.xml +++ b/code/studio/src/plugins/gui_editor/widgets/ViewTextFormated.xml @@ -2,6 +2,7 @@
ViewTextFormated CViewTextFormated + text_formated ViewText false diff --git a/code/studio/src/plugins/gui_editor/widgets/ViewTextID.xml b/code/studio/src/plugins/gui_editor/widgets/ViewTextID.xml index 52e010ec6..43ac442c0 100644 --- a/code/studio/src/plugins/gui_editor/widgets/ViewTextID.xml +++ b/code/studio/src/plugins/gui_editor/widgets/ViewTextID.xml @@ -2,6 +2,7 @@
ViewTextID CViewTextID + text_id ViewText false diff --git a/code/studio/src/plugins/gui_editor/widgets/ViewTextIDFormated.xml b/code/studio/src/plugins/gui_editor/widgets/ViewTextIDFormated.xml index af8dd54eb..32b08f156 100644 --- a/code/studio/src/plugins/gui_editor/widgets/ViewTextIDFormated.xml +++ b/code/studio/src/plugins/gui_editor/widgets/ViewTextIDFormated.xml @@ -2,6 +2,7 @@
ViewTextIDFormated CViewTextIDFormated + text_id_formated ViewTextID false diff --git a/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.cpp b/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.cpp index 10985aa38..efadd3949 100644 --- a/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.cpp +++ b/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.cpp @@ -484,6 +484,11 @@ void MissionCompilerMainWindow::saveConfig() { settings->sync(); } +void MissionCompilerMainWindow::onActivated() +{ + NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &m_ligoConfig; +} + void MissionCompilerMainWindow::handleChangedSettings() { QStringList servers; diff --git a/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.h b/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.h index dc19db1c6..3d59e206a 100644 --- a/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.h +++ b/code/studio/src/plugins/mission_compiler/mission_compiler_main_window.h @@ -31,6 +31,8 @@ public: void saveConfig(); QUndoStack *getUndoStack() { return m_undoStack; } + void onActivated(); + typedef std::map TMissionContainer; public Q_SLOTS: diff --git a/code/studio/src/plugins/mission_compiler/mission_compiler_plugin.h b/code/studio/src/plugins/mission_compiler/mission_compiler_plugin.h index 2ad92b40f..cc2cac47c 100644 --- a/code/studio/src/plugins/mission_compiler/mission_compiler_plugin.h +++ b/code/studio/src/plugins/mission_compiler/mission_compiler_plugin.h @@ -83,6 +83,12 @@ public: virtual void open() {} + void onActivated() + { + m_missionCompilerMainWindow->onActivated(); + } + + MissionCompilerMainWindow *m_missionCompilerMainWindow; }; diff --git a/code/studio/src/plugins/object_viewer/graphics_viewport.h b/code/studio/src/plugins/object_viewer/graphics_viewport.h index 9bbad9806..a11081ffd 100644 --- a/code/studio/src/plugins/object_viewer/graphics_viewport.h +++ b/code/studio/src/plugins/object_viewer/graphics_viewport.h @@ -63,7 +63,6 @@ private Q_SLOTS: void setBackgroundColor(); void submitEvents(NLMISC::CEventServer &server, bool allWindows) { } - void emulateMouseRawMode(bool) { } void onResize( int width, int height ); diff --git a/code/studio/src/plugins/object_viewer/object_viewer.cpp b/code/studio/src/plugins/object_viewer/object_viewer.cpp index 566869e84..240a0d9e9 100644 --- a/code/studio/src/plugins/object_viewer/object_viewer.cpp +++ b/code/studio/src/plugins/object_viewer/object_viewer.cpp @@ -120,7 +120,7 @@ void CObjectViewer::init( NL3D::UDriver *driver ) NL3D::CBloomEffect::instance().setDriver(_Driver); NL3D::CBloomEffect::instance().setScene(_Scene); - NL3D::CBloomEffect::instance().init(!_Direct3D); + NL3D::CBloomEffect::instance().init(); NL3D::CBloomEffect::instance().setDensityBloom(uint8(_BloomDensity)); NL3D::CBloomEffect::instance().setSquareBloom(_BloomSquare); @@ -172,7 +172,7 @@ void CObjectViewer::renderDriver() // Render the scene. if((NL3D::CBloomEffect::instance().getDriver() != 0) && (_BloomEffect)) { - NL3D::CBloomEffect::instance().initBloom(); + NL3D::CBloomEffect::instance().init(); } _Driver->clearBuffers(_BackgroundColor); } @@ -184,8 +184,7 @@ void CObjectViewer::renderScene() if((NL3D::CBloomEffect::instance().getDriver() != 0) && (_BloomEffect)) { - NL3D::CBloomEffect::instance().endBloom(); - NL3D::CBloomEffect::instance().endInterfacesDisplayBloom(); + NL3D::CBloomEffect::instance().applyBloom(); } } diff --git a/code/studio/src/plugins/world_editor/world_editor_plugin.cpp b/code/studio/src/plugins/world_editor/world_editor_plugin.cpp index 3170bce60..9b9622d00 100644 --- a/code/studio/src/plugins/world_editor/world_editor_plugin.cpp +++ b/code/studio/src/plugins/world_editor/world_editor_plugin.cpp @@ -54,36 +54,6 @@ bool WorldEditorPlugin::initialize(ExtensionSystem::IPluginManager *pluginManage WorldEditorSettingsPage *weSettings = new WorldEditorSettingsPage(this); addAutoReleasedObject(weSettings); - - QSettings *settings = Core::ICore::instance()->settings(); - settings->beginGroup(Constants::WORLD_EDITOR_SECTION); - m_ligoConfig.CellSize = settings->value(Constants::WORLD_EDITOR_CELL_SIZE, "160").toFloat(); - m_ligoConfig.Snap = settings->value(Constants::WORLD_EDITOR_SNAP, "1").toFloat(); - m_ligoConfig.ZoneSnapShotRes = settings->value(Constants::ZONE_SNAPSHOT_RES, "128").toUInt(); - QString fileName = settings->value(Constants::PRIMITIVE_CLASS_FILENAME, "world_editor_classes.xml").toString(); - settings->endGroup(); - try - { - // Search path of file world_editor_classes.xml - std::string ligoPath = NLMISC::CPath::lookup(fileName.toUtf8().constData()); - // Init LIGO - m_ligoConfig.readPrimitiveClass(ligoPath.c_str(), true); - NLLIGO::Register(); - NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &m_ligoConfig; - } - catch (NLMISC::Exception &e) - { - *errorString = tr("(%1)").arg(e.what()); - return false; - } - - // Reset - m_ligoConfig.resetPrimitiveConfiguration (); - - // TODO: get file names! from settings - m_ligoConfig.readPrimitiveClass("world_editor_primitive_configuration.xml", true); - - addAutoReleasedObject(new WorldEditorContext(this)); return true; } @@ -116,6 +86,33 @@ WorldEditorContext::WorldEditorContext(QObject *parent) : IContext(parent), m_worldEditorWindow(0) { + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup(Constants::WORLD_EDITOR_SECTION); + m_ligoConfig.CellSize = settings->value(Constants::WORLD_EDITOR_CELL_SIZE, "160").toFloat(); + m_ligoConfig.Snap = settings->value(Constants::WORLD_EDITOR_SNAP, "1").toFloat(); + m_ligoConfig.ZoneSnapShotRes = settings->value(Constants::ZONE_SNAPSHOT_RES, "128").toUInt(); + QString fileName = settings->value(Constants::PRIMITIVE_CLASS_FILENAME, "world_editor_classes.xml").toString(); + settings->endGroup(); + try + { + // Search path of file world_editor_classes.xml + std::string ligoPath = NLMISC::CPath::lookup(fileName.toUtf8().constData()); + // Init LIGO + m_ligoConfig.readPrimitiveClass(ligoPath.c_str(), true); + NLLIGO::Register(); + NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &m_ligoConfig; + } + catch (NLMISC::Exception &e) + { + nlinfo( "Error starting LIGO." ); + } + + // Reset + m_ligoConfig.resetPrimitiveConfiguration (); + + // TODO: get file names! from settings + m_ligoConfig.readPrimitiveClass("world_editor_primitive_configuration.xml", true); + m_worldEditorWindow = new WorldEditorWindow(); } @@ -124,6 +121,11 @@ QUndoStack *WorldEditorContext::undoStack() return m_worldEditorWindow->undoStack(); } +void WorldEditorContext::onActivated() +{ + NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &m_ligoConfig; +} + void WorldEditorContext::open() { m_worldEditorWindow->open(); @@ -136,4 +138,4 @@ QWidget *WorldEditorContext::widget() } -Q_EXPORT_PLUGIN(WorldEditor::WorldEditorPlugin) \ No newline at end of file +Q_EXPORT_PLUGIN(WorldEditor::WorldEditorPlugin) diff --git a/code/studio/src/plugins/world_editor/world_editor_plugin.h b/code/studio/src/plugins/world_editor/world_editor_plugin.h index 686b87e14..cfb5448e3 100644 --- a/code/studio/src/plugins/world_editor/world_editor_plugin.h +++ b/code/studio/src/plugins/world_editor/world_editor_plugin.h @@ -59,7 +59,6 @@ protected: NLMISC::CLibraryContext *m_libContext; private: - NLLIGO::CLigoConfig m_ligoConfig; ExtensionSystem::IPluginManager *m_plugMan; QList m_autoReleaseObjects; }; @@ -88,9 +87,14 @@ public: virtual QUndoStack *undoStack(); + void onActivated(); + virtual QWidget *widget(); WorldEditorWindow *m_worldEditorWindow; + +private: + NLLIGO::CLigoConfig m_ligoConfig; }; } // namespace WorldEditor diff --git a/code/studio/src/plugins/world_editor/world_editor_window.h b/code/studio/src/plugins/world_editor/world_editor_window.h index 60a6a988a..9080187f9 100644 --- a/code/studio/src/plugins/world_editor/world_editor_window.h +++ b/code/studio/src/plugins/world_editor/world_editor_window.h @@ -46,6 +46,7 @@ public: ~WorldEditorWindow(); QUndoStack *undoStack() const; + void onActivated(); void maybeSave(); Q_SIGNALS: diff --git a/code/web/private_php/ams/autoload/dblayer.php b/code/web/private_php/ams/autoload/dblayer.php index d14e48e84..f7871ebcb 100644 --- a/code/web/private_php/ams/autoload/dblayer.php +++ b/code/web/private_php/ams/autoload/dblayer.php @@ -214,7 +214,7 @@ class DBLayer { } $field_option_values = ltrim($field_option_values, ','); try { - $sth = $this->PDO->prepare("UPDATE $tb_name SET $field_option_values WHERE $where "); + $sth = $this->PDO->prepare("UPDATE `$tb_name` SET $field_option_values WHERE $where "); foreach ($data as $key => $value) { $sth->bindValue(":$key", $value); diff --git a/code/web/private_php/ams/autoload/helpers.php b/code/web/private_php/ams/autoload/helpers.php index 0ebc6d8fc..28e4ce036 100644 --- a/code/web/private_php/ams/autoload/helpers.php +++ b/code/web/private_php/ams/autoload/helpers.php @@ -18,12 +18,14 @@ class Helpers { */ public static function loadTemplate( $template, $vars = array (), $returnHTML = false ) { + //error_log(print_r($_GET,true)); + //error_log(print_r($_POST,true)); global $AMS_LIB; global $SITEBASE; global $AMS_TRANS; global $INGAME_LAYOUT; global $AMS_CACHEDIR; - global $AMS_PLUGINS; + global $AMS_PLUGINS; // define('SMARTY_SPL_AUTOLOAD',1); require_once $AMS_LIB . '/smarty/libs/Smarty.class.php'; @@ -89,6 +91,14 @@ class Helpers { $id = session_id(); $smarty -> assign( "sessionid", $id ); + + $dbl = new DBLayer("lib"); + $statement = $dbl->executeWithoutParams("SELECT * FROM settings"); + $rows = $statement->fetchAll(); + + foreach ($rows as &$value) { + $smarty -> assign( $value['Setting'], $value['Value'] ); + } // smarty inheritance for loading the matching wrapper layout (with the matching menu bar) if ( isset( $vars['permission'] ) && $vars['permission'] == 3 ) { diff --git a/code/web/private_php/ams/autoload/users.php b/code/web/private_php/ams/autoload/users.php index cde30cf63..67ed9af88 100644 --- a/code/web/private_php/ams/autoload/users.php +++ b/code/web/private_php/ams/autoload/users.php @@ -252,8 +252,8 @@ class Users{ * @param $length the length of the SALT which is by default 2 * @return a random salt of 2 chars */ - public static function generateSALT( $length = 2 ) - { + public static function generateSALT( $length = 16 ) + { // start with a blank salt $salt = ""; // define possible characters - any character in this string can be @@ -282,6 +282,10 @@ class Users{ } } // done! + if ($length > 2) + { + $salt = '$6$'.$salt; + } return $salt; } @@ -336,12 +340,32 @@ class Users{ $dbs = new DBLayer("shard"); $sth = $dbs->selectWithParameter("UId", "user", $values, "Login= :username"); $result = $sth->fetchAll(); - /*foreach ($result as $UId) { - $ins_values = array('UId' => $UId['UId'], 'clientApplication' => 'r2', 'AccessPrivilege' => 'OPEN'); + $dbl = new DBLayer("lib"); + + $UId = $result['0']['UId']; + + $statement = $dbl->execute("SELECT * FROM `settings` WHERE `Setting` = :setting", Array('setting' => 'Domain_Auto_Add')); + $json = $statement->fetch(); + $json = json_decode($json['Value'],true); + + $db = new DBLayer( 'shard' ); + + // get all domains + $statement = $db -> executeWithoutParams( "SELECT * FROM domain" ); + $rows = $statement -> fetchAll(); + + //error_log(print_r($rows,true)); + //error_log(print_r($result,true)); + //error_log(print_r($json,true)); + foreach ($json as $key => $value) { + //error_log(print_r($key,true)); + //error_log(print_r($value,true)); + + $ins_values = array('UId' => $UId, 'DomainId' => $key, 'AccessPrivilege' => $value['1']); + error_log(print_r($ins_values,true)); + $dbs = new DBLayer("shard"); $dbs->insert("permission", $ins_values); - $ins_values['clientApplication'] = 'ryzom_open'; - $dbs->insert("permission", $ins_values); - }*/ // FIXME: GARBAGE + } } catch (PDOException $e) { //oh noooz, the shard is offline! Put it in query queue at ams_lib db! diff --git a/code/web/private_php/ams/ingame_templates/register.tpl b/code/web/private_php/ams/ingame_templates/register.tpl index 9fa8fef32..7f34e8639 100644 --- a/code/web/private_php/ams/ingame_templates/register.tpl +++ b/code/web/private_php/ams/ingame_templates/register.tpl @@ -7,6 +7,8 @@ {$welcome_message} + {if $userRegistration == '0'|| $userRegistration == '1'} +
@@ -89,6 +91,8 @@
+ + {/if}
on which request is to be made * appkey --> app key for authentication * host --> host from which request have been sent - * + * * @return $domain_management_return_set global array returns the template data */ function domain_management_hook_call_rest() { global $domain_management_return_set; - global $WEBPATH; - - $domain_management_return_set['path'] = $WEBPATH; + global $WEBPATH; - } + $domain_management_return_set['path'] = $WEBPATH; + + } /** * Global Hook to return global variables which contains - * the content to use in the smarty templates extracted from + * the content to use in the smarty templates extracted from * the database - * + * * @return $domain_management_return_set global array returns the template data */ function domain_management_hook_get_db() { global $domain_management_return_set; - - try { - - $db = new DBLayer( 'shard' ); - - //get all domains - $statement = $db->executeWithoutParams("SELECT * FROM domain"); - $rows = $statement->fetchAll(); - $domain_management_return_set['domains'] = $rows; - if (isset($_GET['edit_domain'])){ - //get permissions - $statement = $db->executeWithoutParams("SELECT * FROM `domain` WHERE `domain_id` = '".$_GET['edit_domain']."'"); - $rows = $statement->fetchAll(); - $domain_management_return_set['domains'] = $rows; + if ( isset( $_GET['ModifyDomain'] ) && $_GET['ModifyDomain'] = '1' && isset($_POST['domain_name'])) { + try { + + $dbs = new DBLayer( 'shard' ); + $dbs->update("domain", Array( 'domain_name' => $_POST['domain_name'], 'status' => $_POST['status'], 'patch_version' => $_POST['patch_version'],'backup_patch_url' => $_POST['backup_patch_url'],'patch_urls' => $_POST['patch_urls'],'login_address' => $_POST['login_address'],'session_manager_address' => $_POST['session_manager_address'],'ring_db_name' => $_POST['ring_db_name'],'web_host' => $_POST['web_host'],'web_host_php' => $_POST['web_host_php'],'description' => $_POST['description'],),'`domain_id` = '.$_GET['edit_domain']); + + } + catch ( Exception $e ) { + return null; + } + } - $statement = $db->executeWithoutParams("SELECT * FROM `permission` WHERE `DomainId` = '".$_GET['edit_domain']."'"); - $rows = $statement->fetchAll(); - $domain_management_return_set['permissions'] = $rows; - - //get all users - $pagination = new Pagination(WebUsers::getAllUsersQuery(),"web",10,"WebUsers"); - $domain_management_return_set['userlist'] = Gui_Elements::make_table($pagination->getElements() , Array("getUId","getUsername","getEmail"), Array("id","username","email")); + if ( isset( $_GET['ModifyPermission'] ) && $_GET['ModifyPermission'] = '1' && isset($_POST['user'])) { + try { + $dbl = new DBLayer("lib"); + + $statement = $dbl->execute("SELECT * FROM `settings` WHERE `Setting` = :setting", Array('setting' => 'Domain_Auto_Add')); + $json = $statement->fetch(); + $json = json_decode($json['Value'],true); + + $json[$_GET['edit_domain']]['1'] = $_POST['user']; + $json[$_GET['edit_domain']]['2'] = $_POST['moderator']; + $json[$_GET['edit_domain']]['3'] = $_POST['admin']; + + $update = json_encode($json); + + $dbl->update("settings", Array( 'Value' => $update),"`Setting` = 'Domain_Auto_Add'"); + + } + catch ( Exception $e ) { + return null; + } } + + try { + + $db = new DBLayer( 'shard' ); + + // get all domains + $statement = $db -> executeWithoutParams( "SELECT * FROM domain" ); + $rows = $statement -> fetchAll(); + $domain_management_return_set['domains'] = $rows; + + if ( isset( $_GET['edit_domain'] ) ) { + // get permissions + $statement = $db -> executeWithoutParams( "SELECT * FROM `domain` WHERE `domain_id` = '" . $_GET['edit_domain'] . "'" ); + $rows = $statement -> fetchAll(); + $domain_management_return_set['domains'] = $rows; + + $statement = $db -> executeWithoutParams( "SELECT * FROM `permission` WHERE `DomainId` = '" . $_GET['edit_domain'] . "'" ); + $rows = $statement -> fetchAll(); + $domain_management_return_set['permissions'] = $rows; + + // get all users + $pagination = new Pagination( WebUsers :: getAllUsersQuery(), "web", 10, "WebUsers" ); + $domain_management_return_set['userlist'] = Gui_Elements :: make_table( $pagination -> getElements() , Array( "getUId", "getUsername", "getEmail" ), Array( "id", "username", "email" ) ); + + $dbl = new DBLayer("lib"); + $statement = $dbl->execute("SELECT * FROM `settings` WHERE `Setting` = :setting", Array('setting' => 'Domain_Auto_Add')); + $json = $statement->fetch(); + $json = json_decode($json['Value'],true); + + $domain_management_return_set['Domain_Auto_Add'] = $json[$_GET['edit_domain']]; + + } + return $rows; - - } catch (Exception $e) { + + } + catch ( Exception $e ) { return null; - } - } + } + } /** * Global Hook to return global variables which contains * the content to use in the smarty templates - * + * * @return $domain_management_return_set global array returns the template data */ function domain_management_hook_return_global() @@ -110,3 +154,15 @@ function domain_management_hook_return_global() global $domain_management_return_set; return $domain_management_return_set; } + + +function api_key_management_hook_activate() + { + $dbl = new DBLayer( "lib" ); + $sql = "INSERT INTO `settings` (Setting) + SELECT 'Domain_Auto_Add' FROM DUAL + WHERE NOT EXISTS + (SELECT Setting FROM settings WHERE Setting='Domain_Auto_Add');"; + + $dbl -> executeWithoutParams( $sql ); + } \ No newline at end of file diff --git a/code/web/private_php/ams/plugins/Domain_Management/templates/index.tpl b/code/web/private_php/ams/plugins/Domain_Management/templates/index.tpl index 2e818591c..803d1133e 100644 --- a/code/web/private_php/ams/plugins/Domain_Management/templates/index.tpl +++ b/code/web/private_php/ams/plugins/Domain_Management/templates/index.tpl @@ -52,15 +52,15 @@
-
+
-
+
Modify Domain Settings
-
-
+
+
-
+ Domain Settings of '{$hook_info['Domain_Management']['domains']['0']['domain_name']}' @@ -80,19 +80,19 @@
-
+
- -
- -
-
+ +
+ +
+
@@ -194,6 +194,84 @@
+
+
+ +
+
+
+ Permission Settings +
+
+
+ + + + Permission Settings of '{$hook_info['Domain_Management']['domains']['0']['domain_name']}' +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+ + + {if isset($RESULT_OF_MODIFYING) and $RESULT_OF_MODIFYING eq "SUCCESS"} +
+ {$modify_mail_of_group_success} +
+ {/if} + + +
+
+
+
{else} diff --git a/code/web/private_php/setup/sql/nel_00004.sql b/code/web/private_php/setup/sql/nel_00004.sql new file mode 100644 index 000000000..8d48a4c8c --- /dev/null +++ b/code/web/private_php/setup/sql/nel_00004.sql @@ -0,0 +1 @@ +ALTER TABLE `user` MODIFY `Password` VARCHAR(106); diff --git a/code/web/private_php/setup/sql/nel_ams_00002.sql b/code/web/private_php/setup/sql/nel_ams_00002.sql new file mode 100644 index 000000000..b1a9c9df4 --- /dev/null +++ b/code/web/private_php/setup/sql/nel_ams_00002.sql @@ -0,0 +1 @@ +ALTER TABLE `ams_user` MODIFY `Password` VARCHAR(106); diff --git a/code/web/private_php/setup/sql/nel_ams_lib_00006.sql b/code/web/private_php/setup/sql/nel_ams_lib_00006.sql new file mode 100644 index 000000000..f4c632bad --- /dev/null +++ b/code/web/private_php/setup/sql/nel_ams_lib_00006.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS `settings` ( +`idSettings` int(11) NOT NULL, + `Setting` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `Value` varchar(256) COLLATE utf8_unicode_ci NOT NULL +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +INSERT INTO `settings` (`idSettings`, `Setting`, `Value`) VALUES +(1, 'userRegistration', '0'); + +ALTER TABLE `settings` + ADD PRIMARY KEY (`idSettings`), ADD UNIQUE KEY `idSettings` (`idSettings`), ADD KEY `idSettings_2` (`idSettings`); + +ALTER TABLE `settings` +MODIFY `idSettings` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=2; \ No newline at end of file diff --git a/code/web/public_php/admin/nel/nel_message.php b/code/web/public_php/admin/nel/nel_message.php index 5e704bff1..42dd91cbe 100644 --- a/code/web/public_php/admin/nel/nel_message.php +++ b/code/web/public_php/admin/nel/nel_message.php @@ -91,9 +91,10 @@ } else { - $this->serialUInt32(strlen($val)); + $valLen = strlen($val); + $this->serialUInt32($valLen); $this->Buffer .= $val; - $this->Pos += strlen($val); + $this->Pos += $valLen; debug(sprintf ("write string '%s' %d
\n", $val, $this->Pos)); } } diff --git a/code/web/public_php/admin/smarty/Config_File.class.php b/code/web/public_php/admin/smarty/Config_File.class.php index a7f61c9da..c25f2a0ea 100644 --- a/code/web/public_php/admin/smarty/Config_File.class.php +++ b/code/web/public_php/admin/smarty/Config_File.class.php @@ -1,389 +1,393 @@ - - * @access public - * @package Smarty - */ - -/* $Id: Config_File.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */ - -/** - * Config file reading class - * @package Smarty - */ -class Config_File { - /**#@+ - * Options - * @var boolean - */ - /** - * Controls whether variables with the same name overwrite each other. - */ - var $overwrite = true; - - /** - * Controls whether config values of on/true/yes and off/false/no get - * converted to boolean values automatically. - */ - var $booleanize = true; - - /** - * Controls whether hidden config sections/vars are read from the file. - */ - var $read_hidden = true; - - /** - * Controls whether or not to fix mac or dos formatted newlines. - * If set to true, \r or \r\n will be changed to \n. - */ - var $fix_newlines = true; - /**#@-*/ - - /** @access private */ - var $_config_path = ""; - var $_config_data = array(); - /**#@-*/ - - /** - * Constructs a new config file class. - * - * @param string $config_path (optional) path to the config files - */ - function Config_File($config_path = NULL) - { - if (isset($config_path)) - $this->set_path($config_path); - } - - - /** - * Set the path where configuration files can be found. - * - * @param string $config_path path to the config files - */ - function set_path($config_path) - { - if (!empty($config_path)) { - if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { - $this->_trigger_error_msg("Bad config file path '$config_path'"); - return; - } - if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { - $config_path .= DIRECTORY_SEPARATOR; - } - - $this->_config_path = $config_path; - } - } - - - /** - * Retrieves config info based on the file, section, and variable name. - * - * @param string $file_name config file to get info for - * @param string $section_name (optional) section to get info for - * @param string $var_name (optional) variable to get info for - * @return string|array a value or array of values - */ - function &get($file_name, $section_name = NULL, $var_name = NULL) - { - if (empty($file_name)) { - $this->_trigger_error_msg('Empty config file name'); - return; - } else { - $file_name = $this->_config_path . $file_name; - if (!isset($this->_config_data[$file_name])) - $this->load_file($file_name, false); - } - - if (!empty($var_name)) { - if (empty($section_name)) { - return $this->_config_data[$file_name]["vars"][$var_name]; - } else { - if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) - return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; - else - return array(); - } - } else { - if (empty($section_name)) { - return (array)$this->_config_data[$file_name]["vars"]; - } else { - if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) - return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; - else - return array(); - } - } - } - - - /** - * Retrieves config info based on the key. - * - * @param $file_name string config key (filename/section/var) - * @return string|array same as get() - * @uses get() retrieves information from config file and returns it - */ - function &get_key($config_key) - { - list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); - $result = &$this->get($file_name, $section_name, $var_name); - return $result; - } - - /** - * Get all loaded config file names. - * - * @return array an array of loaded config file names - */ - function get_file_names() - { - return array_keys($this->_config_data); - } - - - /** - * Get all section names from a loaded file. - * - * @param string $file_name config file to get section names from - * @return array an array of section names from the specified file - */ - function get_section_names($file_name) - { - $file_name = $this->_config_path . $file_name; - if (!isset($this->_config_data[$file_name])) { - $this->_trigger_error_msg("Unknown config file '$file_name'"); - return; - } - - return array_keys($this->_config_data[$file_name]["sections"]); - } - - - /** - * Get all global or section variable names. - * - * @param string $file_name config file to get info for - * @param string $section_name (optional) section to get info for - * @return array an array of variables names from the specified file/section - */ - function get_var_names($file_name, $section = NULL) - { - if (empty($file_name)) { - $this->_trigger_error_msg('Empty config file name'); - return; - } else if (!isset($this->_config_data[$file_name])) { - $this->_trigger_error_msg("Unknown config file '$file_name'"); - return; - } - - if (empty($section)) - return array_keys($this->_config_data[$file_name]["vars"]); - else - return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); - } - - - /** - * Clear loaded config data for a certain file or all files. - * - * @param string $file_name file to clear config data for - */ - function clear($file_name = NULL) - { - if ($file_name === NULL) - $this->_config_data = array(); - else if (isset($this->_config_data[$file_name])) - $this->_config_data[$file_name] = array(); - } - - - /** - * Load a configuration file manually. - * - * @param string $file_name file name to load - * @param boolean $prepend_path whether current config path should be - * prepended to the filename - */ - function load_file($file_name, $prepend_path = true) - { - if ($prepend_path && $this->_config_path != "") - $config_file = $this->_config_path . $file_name; - else - $config_file = $file_name; - - ini_set('track_errors', true); - $fp = @fopen($config_file, "r"); - if (!is_resource($fp)) { - $this->_trigger_error_msg("Could not open config file '$config_file'"); - return false; - } - - $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; - fclose($fp); - - $this->_config_data[$config_file] = $this->parse_contents($contents); - return true; - } - - /** - * Store the contents of a file manually. - * - * @param string $config_file file name of the related contents - * @param string $contents the file-contents to parse - */ - function set_file_contents($config_file, $contents) - { - $this->_config_data[$config_file] = $this->parse_contents($contents); - return true; - } - - /** - * parse the source of a configuration file manually. - * - * @param string $contents the file-contents to parse - */ - function parse_contents($contents) - { - if($this->fix_newlines) { - // fix mac/dos formatted newlines - $contents = preg_replace('!\r\n?!', "\n", $contents); - } - - $config_data = array(); - $config_data['sections'] = array(); - $config_data['vars'] = array(); - - /* reference to fill with data */ - $vars =& $config_data['vars']; - - /* parse file line by line */ - preg_match_all('!^.*\r?\n?!m', $contents, $match); - $lines = $match[0]; - for ($i=0, $count=count($lines); $i<$count; $i++) { - $line = $lines[$i]; - if (empty($line)) continue; - - if ( $line{0} == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { - /* section found */ - if ($match[1]{0} == '.') { - /* hidden section */ - if ($this->read_hidden) { - $section_name = substr($match[1], 1); - } else { - /* break reference to $vars to ignore hidden section */ - unset($vars); - $vars = array(); - continue; - } - } else { - $section_name = $match[1]; - } - if (!isset($config_data['sections'][$section_name])) - $config_data['sections'][$section_name] = array('vars' => array()); - $vars =& $config_data['sections'][$section_name]['vars']; - continue; - } - - if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { - /* variable found */ - $var_name = rtrim($match[1]); - if (strpos($match[2], '"""') === 0) { - /* handle multiline-value */ - $lines[$i] = substr($match[2], 3); - $var_value = ''; - while ($i<$count) { - if (($pos = strpos($lines[$i], '"""')) === false) { - $var_value .= $lines[$i++]; - } else { - /* end of multiline-value */ - $var_value .= substr($lines[$i], 0, $pos); - break; - } - } - $booleanize = false; - - } else { - /* handle simple value */ - $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); - $booleanize = $this->booleanize; - - } - $this->_set_config_var($vars, $var_name, $var_value, $booleanize); - } - /* else unparsable line / means it is a comment / means ignore it */ - } - return $config_data; - } - - /**#@+ @access private */ - /** - * @param array &$container - * @param string $var_name - * @param mixed $var_value - * @param boolean $booleanize determines whether $var_value is converted to - * to true/false - */ - function _set_config_var(&$container, $var_name, $var_value, $booleanize) - { - if ($var_name{0} == '.') { - if (!$this->read_hidden) - return; - else - $var_name = substr($var_name, 1); - } - - if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { - $this->_trigger_error_msg("Bad variable name '$var_name'"); - return; - } - - if ($booleanize) { - if (preg_match("/^(on|true|yes)$/i", $var_value)) - $var_value = true; - else if (preg_match("/^(off|false|no)$/i", $var_value)) - $var_value = false; - } - - if (!isset($container[$var_name]) || $this->overwrite) - $container[$var_name] = $var_value; - else { - settype($container[$var_name], 'array'); - $container[$var_name][] = $var_value; - } - } - - /** - * @uses trigger_error() creates a PHP warning/error - * @param string $error_msg - * @param integer $error_type one of - */ - function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) - { - trigger_error("Config_File error: $error_msg", $error_type); - } - /**#@-*/ -} - -?> + + * @access public + * @package Smarty + */ + +/* $Id: Config_File.class.php 3149 2009-05-23 20:59:25Z monte.ohrt $ */ + +/** + * Config file reading class + * @package Smarty + */ +class Config_File { + /**#@+ + * Options + * @var boolean + */ + /** + * Controls whether variables with the same name overwrite each other. + */ + var $overwrite = true; + + /** + * Controls whether config values of on/true/yes and off/false/no get + * converted to boolean values automatically. + */ + var $booleanize = true; + + /** + * Controls whether hidden config sections/vars are read from the file. + */ + var $read_hidden = true; + + /** + * Controls whether or not to fix mac or dos formatted newlines. + * If set to true, \r or \r\n will be changed to \n. + */ + var $fix_newlines = true; + /**#@-*/ + + /** @access private */ + var $_config_path = ""; + var $_config_data = array(); + /**#@-*/ + + /** + * Constructs a new config file class. + * + * @param string $config_path (optional) path to the config files + */ + function Config_File($config_path = NULL) + { + if (isset($config_path)) + $this->set_path($config_path); + } + + + /** + * Set the path where configuration files can be found. + * + * @param string $config_path path to the config files + */ + function set_path($config_path) + { + if (!empty($config_path)) { + if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { + $this->_trigger_error_msg("Bad config file path '$config_path'"); + return; + } + if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { + $config_path .= DIRECTORY_SEPARATOR; + } + + $this->_config_path = $config_path; + } + } + + + /** + * Retrieves config info based on the file, section, and variable name. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @param string $var_name (optional) variable to get info for + * @return string|array a value or array of values + */ + function get($file_name, $section_name = NULL, $var_name = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) + $this->load_file($file_name, false); + } + + if (!empty($var_name)) { + if (empty($section_name)) { + return $this->_config_data[$file_name]["vars"][$var_name]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) + return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; + else + return array(); + } + } else { + if (empty($section_name)) { + return (array)$this->_config_data[$file_name]["vars"]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) + return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; + else + return array(); + } + } + } + + + /** + * Retrieves config info based on the key. + * + * @param $file_name string config key (filename/section/var) + * @return string|array same as get() + * @uses get() retrieves information from config file and returns it + */ + function &get_key($config_key) + { + list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); + $result = &$this->get($file_name, $section_name, $var_name); + return $result; + } + + /** + * Get all loaded config file names. + * + * @return array an array of loaded config file names + */ + function get_file_names() + { + return array_keys($this->_config_data); + } + + + /** + * Get all section names from a loaded file. + * + * @param string $file_name config file to get section names from + * @return array an array of section names from the specified file + */ + function get_section_names($file_name) + { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + return array_keys($this->_config_data[$file_name]["sections"]); + } + + + /** + * Get all global or section variable names. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @return array an array of variables names from the specified file/section + */ + function get_var_names($file_name, $section = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + if (empty($section)) + return array_keys($this->_config_data[$file_name]["vars"]); + else + return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); + } + + + /** + * Clear loaded config data for a certain file or all files. + * + * @param string $file_name file to clear config data for + */ + function clear($file_name = NULL) + { + if ($file_name === NULL) + $this->_config_data = array(); + else if (isset($this->_config_data[$file_name])) + $this->_config_data[$file_name] = array(); + } + + + /** + * Load a configuration file manually. + * + * @param string $file_name file name to load + * @param boolean $prepend_path whether current config path should be + * prepended to the filename + */ + function load_file($file_name, $prepend_path = true) + { + if ($prepend_path && $this->_config_path != "") + $config_file = $this->_config_path . $file_name; + else + $config_file = $file_name; + + ini_set('track_errors', true); + $fp = @fopen($config_file, "r"); + if (!is_resource($fp)) { + $this->_trigger_error_msg("Could not open config file '$config_file'"); + return false; + } + + $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; + fclose($fp); + + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * Store the contents of a file manually. + * + * @param string $config_file file name of the related contents + * @param string $contents the file-contents to parse + */ + function set_file_contents($config_file, $contents) + { + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * parse the source of a configuration file manually. + * + * @param string $contents the file-contents to parse + */ + function parse_contents($contents) + { + if($this->fix_newlines) { + // fix mac/dos formatted newlines + $contents = preg_replace('!\r\n?!', "\n", $contents); + } + + $config_data = array(); + $config_data['sections'] = array(); + $config_data['vars'] = array(); + + /* reference to fill with data */ + $vars =& $config_data['vars']; + + /* parse file line by line */ + preg_match_all('!^.*\r?\n?!m', $contents, $match); + $lines = $match[0]; + for ($i=0, $count=count($lines); $i<$count; $i++) { + $line = $lines[$i]; + if (empty($line)) continue; + + if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { + /* section found */ + if (substr($match[1], 0, 1) == '.') { + /* hidden section */ + if ($this->read_hidden) { + $section_name = substr($match[1], 1); + } else { + /* break reference to $vars to ignore hidden section */ + unset($vars); + $vars = array(); + continue; + } + } else { + $section_name = $match[1]; + } + if (!isset($config_data['sections'][$section_name])) + $config_data['sections'][$section_name] = array('vars' => array()); + $vars =& $config_data['sections'][$section_name]['vars']; + continue; + } + + if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { + /* variable found */ + $var_name = rtrim($match[1]); + if (strpos($match[2], '"""') === 0) { + /* handle multiline-value */ + $lines[$i] = substr($match[2], 3); + $var_value = ''; + while ($i<$count) { + if (($pos = strpos($lines[$i], '"""')) === false) { + $var_value .= $lines[$i++]; + } else { + /* end of multiline-value */ + $var_value .= substr($lines[$i], 0, $pos); + break; + } + } + $booleanize = false; + + } else { + /* handle simple value */ + $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); + $booleanize = $this->booleanize; + + } + $this->_set_config_var($vars, $var_name, $var_value, $booleanize); + } + /* else unparsable line / means it is a comment / means ignore it */ + } + return $config_data; + } + + /**#@+ @access private */ + /** + * @param array &$container + * @param string $var_name + * @param mixed $var_value + * @param boolean $booleanize determines whether $var_value is converted to + * to true/false + */ + function _set_config_var(&$container, $var_name, $var_value, $booleanize) + { + if (substr($var_name, 0, 1) == '.') { + if (!$this->read_hidden) + return; + else + $var_name = substr($var_name, 1); + } + + if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { + $this->_trigger_error_msg("Bad variable name '$var_name'"); + return; + } + + if ($booleanize) { + if (preg_match("/^(on|true|yes)$/i", $var_value)) + $var_value = true; + else if (preg_match("/^(off|false|no)$/i", $var_value)) + $var_value = false; + } + + if (!isset($container[$var_name]) || $this->overwrite) + $container[$var_name] = $var_value; + else { + settype($container[$var_name], 'array'); + $container[$var_name][] = $var_value; + } + } + + /** + * @uses trigger_error() creates a PHP warning/error + * @param string $error_msg + * @param integer $error_type one of + */ + function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Config_File error: $error_msg", $error_type); + } + /**#@-*/ +} + +?> diff --git a/code/web/public_php/admin/smarty/Smarty.class.php b/code/web/public_php/admin/smarty/Smarty.class.php index 40248fbd0..39eed5fc5 100644 --- a/code/web/public_php/admin/smarty/Smarty.class.php +++ b/code/web/public_php/admin/smarty/Smarty.class.php @@ -1,1934 +1,1962 @@ - - * @author Andrei Zmievski - * @package Smarty - * @version 2.6.9 - */ - -/* $Id: Smarty.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */ - -/** - * DIR_SEP isn't used anymore, but third party apps might - */ -if(!defined('DIR_SEP')) { - define('DIR_SEP', DIRECTORY_SEPARATOR); -} - -/** - * set SMARTY_DIR to absolute path to Smarty library files. - * if not defined, include_path will be used. Sets SMARTY_DIR only if user - * application has not already defined it. - */ - -if (!defined('SMARTY_DIR')) { - define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); -} - -if (!defined('SMARTY_CORE_DIR')) { - define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); -} - -define('SMARTY_PHP_PASSTHRU', 0); -define('SMARTY_PHP_QUOTE', 1); -define('SMARTY_PHP_REMOVE', 2); -define('SMARTY_PHP_ALLOW', 3); - -/** - * @package Smarty - */ -class Smarty -{ - /**#@+ - * Smarty Configuration Section - */ - - /** - * The name of the directory where templates are located. - * - * @var string - */ - var $template_dir = 'templates'; - - /** - * The directory where compiled templates are located. - * - * @var string - */ - var $compile_dir = 'templates_c'; - - /** - * The directory where config files are located. - * - * @var string - */ - var $config_dir = 'configs'; - - /** - * An array of directories searched for plugins. - * - * @var array - */ - var $plugins_dir = array('plugins'); - - /** - * If debugging is enabled, a debug console window will display - * when the page loads (make sure your browser allows unrequested - * popup windows) - * - * @var boolean - */ - var $debugging = false; - - /** - * When set, smarty does uses this value as error_reporting-level. - * - * @var boolean - */ - var $error_reporting = null; - - /** - * This is the path to the debug console template. If not set, - * the default one will be used. - * - * @var string - */ - var $debug_tpl = ''; - - /** - * This determines if debugging is enable-able from the browser. - *
    - *
  • NONE => no debugging control allowed
  • - *
  • URL => enable debugging when SMARTY_DEBUG is found in the URL.
  • - *
- * @link http://www.foo.dom/index.php?SMARTY_DEBUG - * @var string - */ - var $debugging_ctrl = 'NONE'; - - /** - * This tells Smarty whether to check for recompiling or not. Recompiling - * does not need to happen unless a template or config file is changed. - * Typically you enable this during development, and disable for - * production. - * - * @var boolean - */ - var $compile_check = true; - - /** - * This forces templates to compile every time. Useful for development - * or debugging. - * - * @var boolean - */ - var $force_compile = false; - - /** - * This enables template caching. - *
    - *
  • 0 = no caching
  • - *
  • 1 = use class cache_lifetime value
  • - *
  • 2 = use cache_lifetime in cache file
  • - *
- * @var integer - */ - var $caching = 0; - - /** - * The name of the directory for cache files. - * - * @var string - */ - var $cache_dir = 'cache'; - - /** - * This is the number of seconds cached content will persist. - *
    - *
  • 0 = always regenerate cache
  • - *
  • -1 = never expires
  • - *
- * - * @var integer - */ - var $cache_lifetime = 3600; - - /** - * Only used when $caching is enabled. If true, then If-Modified-Since headers - * are respected with cached content, and appropriate HTTP headers are sent. - * This way repeated hits to a cached page do not send the entire page to the - * client every time. - * - * @var boolean - */ - var $cache_modified_check = false; - - /** - * This determines how Smarty handles "" tags in templates. - * possible values: - *
    - *
  • SMARTY_PHP_PASSTHRU -> print tags as plain text
  • - *
  • SMARTY_PHP_QUOTE -> escape tags as entities
  • - *
  • SMARTY_PHP_REMOVE -> remove php tags
  • - *
  • SMARTY_PHP_ALLOW -> execute php tags
  • - *
- * - * @var integer - */ - var $php_handling = SMARTY_PHP_PASSTHRU; - - /** - * This enables template security. When enabled, many things are restricted - * in the templates that normally would go unchecked. This is useful when - * untrusted parties are editing templates and you want a reasonable level - * of security. (no direct execution of PHP in templates for example) - * - * @var boolean - */ - var $security = false; - - /** - * This is the list of template directories that are considered secure. This - * is used only if {@link $security} is enabled. One directory per array - * element. {@link $template_dir} is in this list implicitly. - * - * @var array - */ - var $secure_dir = array(); - - /** - * These are the security settings for Smarty. They are used only when - * {@link $security} is enabled. - * - * @var array - */ - var $security_settings = array( - 'PHP_HANDLING' => false, - 'IF_FUNCS' => array('array', 'list', - 'isset', 'empty', - 'count', 'sizeof', - 'in_array', 'is_array', - 'true', 'false', 'null'), - 'INCLUDE_ANY' => false, - 'PHP_TAGS' => false, - 'MODIFIER_FUNCS' => array('count'), - 'ALLOW_CONSTANTS' => false - ); - - /** - * This is an array of directories where trusted php scripts reside. - * {@link $security} is disabled during their inclusion/execution. - * - * @var array - */ - var $trusted_dir = array(); - - /** - * The left delimiter used for the template tags. - * - * @var string - */ - var $left_delimiter = '{'; - - /** - * The right delimiter used for the template tags. - * - * @var string - */ - var $right_delimiter = '}'; - - /** - * The order in which request variables are registered, similar to - * variables_order in php.ini E = Environment, G = GET, P = POST, - * C = Cookies, S = Server - * - * @var string - */ - var $request_vars_order = 'EGPCS'; - - /** - * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) - * are uses as request-vars or $_*[]-vars. note: if - * request_use_auto_globals is true, then $request_vars_order has - * no effect, but the php-ini-value "gpc_order" - * - * @var boolean - */ - var $request_use_auto_globals = true; - - /** - * Set this if you want different sets of compiled files for the same - * templates. This is useful for things like different languages. - * Instead of creating separate sets of templates per language, you - * set different compile_ids like 'en' and 'de'. - * - * @var string - */ - var $compile_id = null; - - /** - * This tells Smarty whether or not to use sub dirs in the cache/ and - * templates_c/ directories. sub directories better organized, but - * may not work well with PHP safe mode enabled. - * - * @var boolean - * - */ - var $use_sub_dirs = false; - - /** - * This is a list of the modifiers to apply to all template variables. - * Put each modifier in a separate array element in the order you want - * them applied. example: array('escape:"htmlall"'); - * - * @var array - */ - var $default_modifiers = array(); - - /** - * This is the resource type to be used when not specified - * at the beginning of the resource path. examples: - * $smarty->display('file:index.tpl'); - * $smarty->display('db:index.tpl'); - * $smarty->display('index.tpl'); // will use default resource type - * {include file="file:index.tpl"} - * {include file="db:index.tpl"} - * {include file="index.tpl"} {* will use default resource type *} - * - * @var array - */ - var $default_resource_type = 'file'; - - /** - * The function used for cache file handling. If not set, built-in caching is used. - * - * @var null|string function name - */ - var $cache_handler_func = null; - - /** - * This indicates which filters are automatically loaded into Smarty. - * - * @var array array of filter names - */ - var $autoload_filters = array(); - - /**#@+ - * @var boolean - */ - /** - * This tells if config file vars of the same name overwrite each other or not. - * if disabled, same name variables are accumulated in an array. - */ - var $config_overwrite = true; - - /** - * This tells whether or not to automatically booleanize config file variables. - * If enabled, then the strings "on", "true", and "yes" are treated as boolean - * true, and "off", "false" and "no" are treated as boolean false. - */ - var $config_booleanize = true; - - /** - * This tells whether hidden sections [.foobar] are readable from the - * tempalates or not. Normally you would never allow this since that is - * the point behind hidden sections: the application can access them, but - * the templates cannot. - */ - var $config_read_hidden = false; - - /** - * This tells whether or not automatically fix newlines in config files. - * It basically converts \r (mac) or \r\n (dos) to \n - */ - var $config_fix_newlines = true; - /**#@-*/ - - /** - * If a template cannot be found, this PHP function will be executed. - * Useful for creating templates on-the-fly or other special action. - * - * @var string function name - */ - var $default_template_handler_func = ''; - - /** - * The file that contains the compiler class. This can a full - * pathname, or relative to the php_include path. - * - * @var string - */ - var $compiler_file = 'Smarty_Compiler.class.php'; - - /** - * The class used for compiling templates. - * - * @var string - */ - var $compiler_class = 'Smarty_Compiler'; - - /** - * The class used to load config vars. - * - * @var string - */ - var $config_class = 'Config_File'; - -/**#@+ - * END Smarty Configuration Section - * There should be no need to touch anything below this line. - * @access private - */ - /** - * where assigned template vars are kept - * - * @var array - */ - var $_tpl_vars = array(); - - /** - * stores run-time $smarty.* vars - * - * @var null|array - */ - var $_smarty_vars = null; - - /** - * keeps track of sections - * - * @var array - */ - var $_sections = array(); - - /** - * keeps track of foreach blocks - * - * @var array - */ - var $_foreach = array(); - - /** - * keeps track of tag hierarchy - * - * @var array - */ - var $_tag_stack = array(); - - /** - * configuration object - * - * @var Config_file - */ - var $_conf_obj = null; - - /** - * loaded configuration settings - * - * @var array - */ - var $_config = array(array('vars' => array(), 'files' => array())); - - /** - * md5 checksum of the string 'Smarty' - * - * @var string - */ - var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; - - /** - * Smarty version number - * - * @var string - */ - var $_version = '2.6.9'; - - /** - * current template inclusion depth - * - * @var integer - */ - var $_inclusion_depth = 0; - - /** - * for different compiled templates - * - * @var string - */ - var $_compile_id = null; - - /** - * text in URL to enable debug mode - * - * @var string - */ - var $_smarty_debug_id = 'SMARTY_DEBUG'; - - /** - * debugging information for debug console - * - * @var array - */ - var $_smarty_debug_info = array(); - - /** - * info that makes up a cache file - * - * @var array - */ - var $_cache_info = array(); - - /** - * default file permissions - * - * @var integer - */ - var $_file_perms = 0644; - - /** - * default dir permissions - * - * @var integer - */ - var $_dir_perms = 0771; - - /** - * registered objects - * - * @var array - */ - var $_reg_objects = array(); - - /** - * table keeping track of plugins - * - * @var array - */ - var $_plugins = array( - 'modifier' => array(), - 'function' => array(), - 'block' => array(), - 'compiler' => array(), - 'prefilter' => array(), - 'postfilter' => array(), - 'outputfilter' => array(), - 'resource' => array(), - 'insert' => array()); - - - /** - * cache serials - * - * @var array - */ - var $_cache_serials = array(); - - /** - * name of optional cache include file - * - * @var string - */ - var $_cache_include = null; - - /** - * indicate if the current code is used in a compiled - * include - * - * @var string - */ - var $_cache_including = false; - - /**#@-*/ - /** - * The class constructor. - */ - function Smarty() - { - $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] - : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); - } - - /** - * assigns values to template variables - * - * @param array|string $tpl_var the template variable name(s) - * @param mixed $value the value to assign - */ - function assign($tpl_var, $value = null) - { - if (is_array($tpl_var)){ - foreach ($tpl_var as $key => $val) { - if ($key != '') { - $this->_tpl_vars[$key] = $val; - } - } - } else { - if ($tpl_var != '') - $this->_tpl_vars[$tpl_var] = $value; - } - } - - /** - * assigns values to template variables by reference - * - * @param string $tpl_var the template variable name - * @param mixed $value the referenced value to assign - */ - function assign_by_ref($tpl_var, &$value) - { - if ($tpl_var != '') - $this->_tpl_vars[$tpl_var] = &$value; - } - - /** - * appends values to template variables - * - * @param array|string $tpl_var the template variable name(s) - * @param mixed $value the value to append - */ - function append($tpl_var, $value=null, $merge=false) - { - if (is_array($tpl_var)) { - // $tpl_var is an array, ignore $value - foreach ($tpl_var as $_key => $_val) { - if ($_key != '') { - if(!@is_array($this->_tpl_vars[$_key])) { - settype($this->_tpl_vars[$_key],'array'); - } - if($merge && is_array($_val)) { - foreach($_val as $_mkey => $_mval) { - $this->_tpl_vars[$_key][$_mkey] = $_mval; - } - } else { - $this->_tpl_vars[$_key][] = $_val; - } - } - } - } else { - if ($tpl_var != '' && isset($value)) { - if(!@is_array($this->_tpl_vars[$tpl_var])) { - settype($this->_tpl_vars[$tpl_var],'array'); - } - if($merge && is_array($value)) { - foreach($value as $_mkey => $_mval) { - $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; - } - } else { - $this->_tpl_vars[$tpl_var][] = $value; - } - } - } - } - - /** - * appends values to template variables by reference - * - * @param string $tpl_var the template variable name - * @param mixed $value the referenced value to append - */ - function append_by_ref($tpl_var, &$value, $merge=false) - { - if ($tpl_var != '' && isset($value)) { - if(!@is_array($this->_tpl_vars[$tpl_var])) { - settype($this->_tpl_vars[$tpl_var],'array'); - } - if ($merge && is_array($value)) { - foreach($value as $_key => $_val) { - $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; - } - } else { - $this->_tpl_vars[$tpl_var][] = &$value; - } - } - } - - - /** - * clear the given assigned template variable. - * - * @param string $tpl_var the template variable to clear - */ - function clear_assign($tpl_var) - { - if (is_array($tpl_var)) - foreach ($tpl_var as $curr_var) - unset($this->_tpl_vars[$curr_var]); - else - unset($this->_tpl_vars[$tpl_var]); - } - - - /** - * Registers custom function to be used in templates - * - * @param string $function the name of the template function - * @param string $function_impl the name of the PHP function to register - */ - function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) - { - $this->_plugins['function'][$function] = - array($function_impl, null, null, false, $cacheable, $cache_attrs); - - } - - /** - * Unregisters custom function - * - * @param string $function name of template function - */ - function unregister_function($function) - { - unset($this->_plugins['function'][$function]); - } - - /** - * Registers object to be used in templates - * - * @param string $object name of template object - * @param object &$object_impl the referenced PHP object to register - * @param null|array $allowed list of allowed methods (empty = all) - * @param boolean $smarty_args smarty argument format, else traditional - * @param null|array $block_functs list of methods that are block format - */ - function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) - { - settype($allowed, 'array'); - settype($smarty_args, 'boolean'); - $this->_reg_objects[$object] = - array(&$object_impl, $allowed, $smarty_args, $block_methods); - } - - /** - * Unregisters object - * - * @param string $object name of template object - */ - function unregister_object($object) - { - unset($this->_reg_objects[$object]); - } - - - /** - * Registers block function to be used in templates - * - * @param string $block name of template block - * @param string $block_impl PHP function to register - */ - function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) - { - $this->_plugins['block'][$block] = - array($block_impl, null, null, false, $cacheable, $cache_attrs); - } - - /** - * Unregisters block function - * - * @param string $block name of template function - */ - function unregister_block($block) - { - unset($this->_plugins['block'][$block]); - } - - /** - * Registers compiler function - * - * @param string $function name of template function - * @param string $function_impl name of PHP function to register - */ - function register_compiler_function($function, $function_impl, $cacheable=true) - { - $this->_plugins['compiler'][$function] = - array($function_impl, null, null, false, $cacheable); - } - - /** - * Unregisters compiler function - * - * @param string $function name of template function - */ - function unregister_compiler_function($function) - { - unset($this->_plugins['compiler'][$function]); - } - - /** - * Registers modifier to be used in templates - * - * @param string $modifier name of template modifier - * @param string $modifier_impl name of PHP function to register - */ - function register_modifier($modifier, $modifier_impl) - { - $this->_plugins['modifier'][$modifier] = - array($modifier_impl, null, null, false); - } - - /** - * Unregisters modifier - * - * @param string $modifier name of template modifier - */ - function unregister_modifier($modifier) - { - unset($this->_plugins['modifier'][$modifier]); - } - - /** - * Registers a resource to fetch a template - * - * @param string $type name of resource - * @param array $functions array of functions to handle resource - */ - function register_resource($type, $functions) - { - if (count($functions)==4) { - $this->_plugins['resource'][$type] = - array($functions, false); - - } elseif (count($functions)==5) { - $this->_plugins['resource'][$type] = - array(array(array(&$functions[0], $functions[1]) - ,array(&$functions[0], $functions[2]) - ,array(&$functions[0], $functions[3]) - ,array(&$functions[0], $functions[4])) - ,false); - - } else { - $this->trigger_error("malformed function-list for '$type' in register_resource"); - - } - } - - /** - * Unregisters a resource - * - * @param string $type name of resource - */ - function unregister_resource($type) - { - unset($this->_plugins['resource'][$type]); - } - - /** - * Registers a prefilter function to apply - * to a template before compiling - * - * @param string $function name of PHP function to register - */ - function register_prefilter($function) - { - $_name = (is_array($function)) ? $function[1] : $function; - $this->_plugins['prefilter'][$_name] - = array($function, null, null, false); - } - - /** - * Unregisters a prefilter function - * - * @param string $function name of PHP function - */ - function unregister_prefilter($function) - { - unset($this->_plugins['prefilter'][$function]); - } - - /** - * Registers a postfilter function to apply - * to a compiled template after compilation - * - * @param string $function name of PHP function to register - */ - function register_postfilter($function) - { - $_name = (is_array($function)) ? $function[1] : $function; - $this->_plugins['postfilter'][$_name] - = array($function, null, null, false); - } - - /** - * Unregisters a postfilter function - * - * @param string $function name of PHP function - */ - function unregister_postfilter($function) - { - unset($this->_plugins['postfilter'][$function]); - } - - /** - * Registers an output filter function to apply - * to a template output - * - * @param string $function name of PHP function - */ - function register_outputfilter($function) - { - $_name = (is_array($function)) ? $function[1] : $function; - $this->_plugins['outputfilter'][$_name] - = array($function, null, null, false); - } - - /** - * Unregisters an outputfilter function - * - * @param string $function name of PHP function - */ - function unregister_outputfilter($function) - { - unset($this->_plugins['outputfilter'][$function]); - } - - /** - * load a filter of specified type and name - * - * @param string $type filter type - * @param string $name filter name - */ - function load_filter($type, $name) - { - switch ($type) { - case 'output': - $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); - require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); - smarty_core_load_plugins($_params, $this); - break; - - case 'pre': - case 'post': - if (!isset($this->_plugins[$type . 'filter'][$name])) - $this->_plugins[$type . 'filter'][$name] = false; - break; - } - } - - /** - * clear cached content for the given template and cache id - * - * @param string $tpl_file name of template file - * @param string $cache_id name of cache_id - * @param string $compile_id name of compile_id - * @param string $exp_time expiration time - * @return boolean - */ - function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) - { - - if (!isset($compile_id)) - $compile_id = $this->compile_id; - - if (!isset($tpl_file)) - $compile_id = null; - - $_auto_id = $this->_get_auto_id($cache_id, $compile_id); - - if (!empty($this->cache_handler_func)) { - return call_user_func_array($this->cache_handler_func, - array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); - } else { - $_params = array('auto_base' => $this->cache_dir, - 'auto_source' => $tpl_file, - 'auto_id' => $_auto_id, - 'exp_time' => $exp_time); - require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); - return smarty_core_rm_auto($_params, $this); - } - - } - - - /** - * clear the entire contents of cache (all templates) - * - * @param string $exp_time expire time - * @return boolean results of {@link smarty_core_rm_auto()} - */ - function clear_all_cache($exp_time = null) - { - return $this->clear_cache(null, null, null, $exp_time); - } - - - /** - * test to see if valid cache exists for this template - * - * @param string $tpl_file name of template file - * @param string $cache_id - * @param string $compile_id - * @return string|false results of {@link _read_cache_file()} - */ - function is_cached($tpl_file, $cache_id = null, $compile_id = null) - { - if (!$this->caching) - return false; - - if (!isset($compile_id)) - $compile_id = $this->compile_id; - - $_params = array( - 'tpl_file' => $tpl_file, - 'cache_id' => $cache_id, - 'compile_id' => $compile_id - ); - require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); - return smarty_core_read_cache_file($_params, $this); - } - - - /** - * clear all the assigned template variables. - * - */ - function clear_all_assign() - { - $this->_tpl_vars = array(); - } - - /** - * clears compiled version of specified template resource, - * or all compiled template files if one is not specified. - * This function is for advanced use only, not normally needed. - * - * @param string $tpl_file - * @param string $compile_id - * @param string $exp_time - * @return boolean results of {@link smarty_core_rm_auto()} - */ - function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) - { - if (!isset($compile_id)) { - $compile_id = $this->compile_id; - } - $_params = array('auto_base' => $this->compile_dir, - 'auto_source' => $tpl_file, - 'auto_id' => $compile_id, - 'exp_time' => $exp_time, - 'extensions' => array('.inc', '.php')); - require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); - return smarty_core_rm_auto($_params, $this); - } - - /** - * Checks whether requested template exists. - * - * @param string $tpl_file - * @return boolean - */ - function template_exists($tpl_file) - { - $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); - return $this->_fetch_resource_info($_params); - } - - /** - * Returns an array containing template variables - * - * @param string $name - * @param string $type - * @return array - */ - function &get_template_vars($name=null) - { - if(!isset($name)) { - return $this->_tpl_vars; - } - if(isset($this->_tpl_vars[$name])) { - return $this->_tpl_vars[$name]; - } - } - - /** - * Returns an array containing config variables - * - * @param string $name - * @param string $type - * @return array - */ - function &get_config_vars($name=null) - { - if(!isset($name) && is_array($this->_config[0])) { - return $this->_config[0]['vars']; - } else if(isset($this->_config[0]['vars'][$name])) { - return $this->_config[0]['vars'][$name]; - } - } - - /** - * trigger Smarty error - * - * @param string $error_msg - * @param integer $error_type - */ - function trigger_error($error_msg, $error_type = E_USER_WARNING) - { - trigger_error("Smarty error: $error_msg", $error_type); - } - - - /** - * executes & displays the template results - * - * @param string $resource_name - * @param string $cache_id - * @param string $compile_id - */ - function display($resource_name, $cache_id = null, $compile_id = null) - { - $this->fetch($resource_name, $cache_id, $compile_id, true); - } - - /** - * executes & returns or displays the template results - * - * @param string $resource_name - * @param string $cache_id - * @param string $compile_id - * @param boolean $display - */ - function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) - { - static $_cache_info = array(); - - $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) - ? $this->error_reporting : error_reporting() & ~E_NOTICE); - - if (!$this->debugging && $this->debugging_ctrl == 'URL') { - $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; - if (@strstr($_query_string, $this->_smarty_debug_id)) { - if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { - // enable debugging for this browser session - @setcookie('SMARTY_DEBUG', true); - $this->debugging = true; - } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { - // disable debugging for this browser session - @setcookie('SMARTY_DEBUG', false); - $this->debugging = false; - } else { - // enable debugging for this page - $this->debugging = true; - } - } else { - $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); - } - } - - if ($this->debugging) { - // capture time for debugging info - $_params = array(); - require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); - $_debug_start_time = smarty_core_get_microtime($_params, $this); - $this->_smarty_debug_info[] = array('type' => 'template', - 'filename' => $resource_name, - 'depth' => 0); - $_included_tpls_idx = count($this->_smarty_debug_info) - 1; - } - - if (!isset($compile_id)) { - $compile_id = $this->compile_id; - } - - $this->_compile_id = $compile_id; - $this->_inclusion_depth = 0; - - if ($this->caching) { - // save old cache_info, initialize cache_info - array_push($_cache_info, $this->_cache_info); - $this->_cache_info = array(); - $_params = array( - 'tpl_file' => $resource_name, - 'cache_id' => $cache_id, - 'compile_id' => $compile_id, - 'results' => null - ); - require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); - if (smarty_core_read_cache_file($_params, $this)) { - $_smarty_results = $_params['results']; - if (!empty($this->_cache_info['insert_tags'])) { - $_params = array('plugins' => $this->_cache_info['insert_tags']); - require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); - smarty_core_load_plugins($_params, $this); - $_params = array('results' => $_smarty_results); - require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); - $_smarty_results = smarty_core_process_cached_inserts($_params, $this); - } - if (!empty($this->_cache_info['cache_serials'])) { - $_params = array('results' => $_smarty_results); - require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); - $_smarty_results = smarty_core_process_compiled_include($_params, $this); - } - - - if ($display) { - if ($this->debugging) - { - // capture time for debugging info - $_params = array(); - require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); - $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; - require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); - $_smarty_results .= smarty_core_display_debug_console($_params, $this); - } - if ($this->cache_modified_check) { - $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; - $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); - $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; - if (@count($this->_cache_info['insert_tags']) == 0 - && !$this->_cache_serials - && $_gmt_mtime == $_last_modified_date) { - if (php_sapi_name()=='cgi') - header('Status: 304 Not Modified'); - else - header('HTTP/1.1 304 Not Modified'); - - } else { - header('Last-Modified: '.$_gmt_mtime); - echo $_smarty_results; - } - } else { - echo $_smarty_results; - } - error_reporting($_smarty_old_error_level); - // restore initial cache_info - $this->_cache_info = array_pop($_cache_info); - return true; - } else { - error_reporting($_smarty_old_error_level); - // restore initial cache_info - $this->_cache_info = array_pop($_cache_info); - return $_smarty_results; - } - } else { - $this->_cache_info['template'][$resource_name] = true; - if ($this->cache_modified_check && $display) { - header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); - } - } - } - - // load filters that are marked as autoload - if (count($this->autoload_filters)) { - foreach ($this->autoload_filters as $_filter_type => $_filters) { - foreach ($_filters as $_filter) { - $this->load_filter($_filter_type, $_filter); - } - } - } - - $_smarty_compile_path = $this->_get_compile_path($resource_name); - - // if we just need to display the results, don't perform output - // buffering - for speed - $_cache_including = $this->_cache_including; - $this->_cache_including = false; - if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { - if ($this->_is_compiled($resource_name, $_smarty_compile_path) - || $this->_compile_resource($resource_name, $_smarty_compile_path)) - { - include($_smarty_compile_path); - } - } else { - ob_start(); - if ($this->_is_compiled($resource_name, $_smarty_compile_path) - || $this->_compile_resource($resource_name, $_smarty_compile_path)) - { - include($_smarty_compile_path); - } - $_smarty_results = ob_get_contents(); - ob_end_clean(); - - foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { - $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); - } - } - - if ($this->caching) { - $_params = array('tpl_file' => $resource_name, - 'cache_id' => $cache_id, - 'compile_id' => $compile_id, - 'results' => $_smarty_results); - require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); - smarty_core_write_cache_file($_params, $this); - require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); - $_smarty_results = smarty_core_process_cached_inserts($_params, $this); - - if ($this->_cache_serials) { - // strip nocache-tags from output - $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' - ,'' - ,$_smarty_results); - } - // restore initial cache_info - $this->_cache_info = array_pop($_cache_info); - } - $this->_cache_including = $_cache_including; - - if ($display) { - if (isset($_smarty_results)) { echo $_smarty_results; } - if ($this->debugging) { - // capture time for debugging info - $_params = array(); - require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); - $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); - require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); - echo smarty_core_display_debug_console($_params, $this); - } - error_reporting($_smarty_old_error_level); - return; - } else { - error_reporting($_smarty_old_error_level); - if (isset($_smarty_results)) { return $_smarty_results; } - } - } - - /** - * load configuration values - * - * @param string $file - * @param string $section - * @param string $scope - */ - function config_load($file, $section = null, $scope = 'global') - { - require_once($this->_get_plugin_filepath('function', 'config_load')); - smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); - } - - /** - * return a reference to a registered object - * - * @param string $name - * @return object - */ - function &get_registered_object($name) { - if (!isset($this->_reg_objects[$name])) - $this->_trigger_fatal_error("'$name' is not a registered object"); - - if (!is_object($this->_reg_objects[$name][0])) - $this->_trigger_fatal_error("registered '$name' is not an object"); - - return $this->_reg_objects[$name][0]; - } - - /** - * clear configuration values - * - * @param string $var - */ - function clear_config($var = null) - { - if(!isset($var)) { - // clear all values - $this->_config = array(array('vars' => array(), - 'files' => array())); - } else { - unset($this->_config[0]['vars'][$var]); - } - } - - /** - * get filepath of requested plugin - * - * @param string $type - * @param string $name - * @return string|false - */ - function _get_plugin_filepath($type, $name) - { - $_params = array('type' => $type, 'name' => $name); - require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); - return smarty_core_assemble_plugin_filepath($_params, $this); - } - - /** - * test if resource needs compiling - * - * @param string $resource_name - * @param string $compile_path - * @return boolean - */ - function _is_compiled($resource_name, $compile_path) - { - if (!$this->force_compile && file_exists($compile_path)) { - if (!$this->compile_check) { - // no need to check compiled file - return true; - } else { - // get file source and timestamp - $_params = array('resource_name' => $resource_name, 'get_source'=>false); - if (!$this->_fetch_resource_info($_params)) { - return false; - } - if ($_params['resource_timestamp'] <= filemtime($compile_path)) { - // template not expired, no recompile - return true; - } else { - // compile template - return false; - } - } - } else { - // compiled template does not exist, or forced compile - return false; - } - } - - /** - * compile the template - * - * @param string $resource_name - * @param string $compile_path - * @return boolean - */ - function _compile_resource($resource_name, $compile_path) - { - - $_params = array('resource_name' => $resource_name); - if (!$this->_fetch_resource_info($_params)) { - return false; - } - - $_source_content = $_params['source_content']; - $_cache_include = substr($compile_path, 0, -4).'.inc'; - - if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { - // if a _cache_serial was set, we also have to write an include-file: - if ($this->_cache_include_info) { - require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); - smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); - } - - $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); - require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); - smarty_core_write_compiled_resource($_params, $this); - - return true; - } else { - return false; - } - - } - - /** - * compile the given source - * - * @param string $resource_name - * @param string $source_content - * @param string $compiled_content - * @return boolean - */ - function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) - { - if (file_exists(SMARTY_DIR . $this->compiler_file)) { - require_once(SMARTY_DIR . $this->compiler_file); - } else { - // use include_path - require_once($this->compiler_file); - } - - - $smarty_compiler = new $this->compiler_class; - - $smarty_compiler->template_dir = $this->template_dir; - $smarty_compiler->compile_dir = $this->compile_dir; - $smarty_compiler->plugins_dir = $this->plugins_dir; - $smarty_compiler->config_dir = $this->config_dir; - $smarty_compiler->force_compile = $this->force_compile; - $smarty_compiler->caching = $this->caching; - $smarty_compiler->php_handling = $this->php_handling; - $smarty_compiler->left_delimiter = $this->left_delimiter; - $smarty_compiler->right_delimiter = $this->right_delimiter; - $smarty_compiler->_version = $this->_version; - $smarty_compiler->security = $this->security; - $smarty_compiler->secure_dir = $this->secure_dir; - $smarty_compiler->security_settings = $this->security_settings; - $smarty_compiler->trusted_dir = $this->trusted_dir; - $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; - $smarty_compiler->_reg_objects = &$this->_reg_objects; - $smarty_compiler->_plugins = &$this->_plugins; - $smarty_compiler->_tpl_vars = &$this->_tpl_vars; - $smarty_compiler->default_modifiers = $this->default_modifiers; - $smarty_compiler->compile_id = $this->_compile_id; - $smarty_compiler->_config = $this->_config; - $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; - - if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { - $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; - } - $smarty_compiler->_cache_include = $cache_include_path; - - - $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); - - if ($smarty_compiler->_cache_serial) { - $this->_cache_include_info = array( - 'cache_serial'=>$smarty_compiler->_cache_serial - ,'plugins_code'=>$smarty_compiler->_plugins_code - ,'include_file_path' => $cache_include_path); - - } else { - $this->_cache_include_info = null; - - } - - return $_results; - } - - /** - * Get the compile path for this resource - * - * @param string $resource_name - * @return string results of {@link _get_auto_filename()} - */ - function _get_compile_path($resource_name) - { - return $this->_get_auto_filename($this->compile_dir, $resource_name, - $this->_compile_id) . '.php'; - } - - /** - * fetch the template info. Gets timestamp, and source - * if get_source is true - * - * sets $source_content to the source of the template, and - * $resource_timestamp to its time stamp - * @param string $resource_name - * @param string $source_content - * @param integer $resource_timestamp - * @param boolean $get_source - * @param boolean $quiet - * @return boolean - */ - - function _fetch_resource_info(&$params) - { - if(!isset($params['get_source'])) { $params['get_source'] = true; } - if(!isset($params['quiet'])) { $params['quiet'] = false; } - - $_return = false; - $_params = array('resource_name' => $params['resource_name']) ; - if (isset($params['resource_base_path'])) - $_params['resource_base_path'] = $params['resource_base_path']; - else - $_params['resource_base_path'] = $this->template_dir; - - if ($this->_parse_resource_name($_params)) { - $_resource_type = $_params['resource_type']; - $_resource_name = $_params['resource_name']; - switch ($_resource_type) { - case 'file': - if ($params['get_source']) { - $params['source_content'] = $this->_read_file($_resource_name); - } - $params['resource_timestamp'] = filemtime($_resource_name); - $_return = is_file($_resource_name); - break; - - default: - // call resource functions to fetch the template source and timestamp - if ($params['get_source']) { - $_source_return = isset($this->_plugins['resource'][$_resource_type]) && - call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], - array($_resource_name, &$params['source_content'], &$this)); - } else { - $_source_return = true; - } - - $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && - call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], - array($_resource_name, &$params['resource_timestamp'], &$this)); - - $_return = $_source_return && $_timestamp_return; - break; - } - } - - if (!$_return) { - // see if we can get a template with the default template handler - if (!empty($this->default_template_handler_func)) { - if (!is_callable($this->default_template_handler_func)) { - $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); - } else { - $_return = call_user_func_array( - $this->default_template_handler_func, - array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); - } - } - } - - if (!$_return) { - if (!$params['quiet']) { - $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); - } - } else if ($_return && $this->security) { - require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); - if (!smarty_core_is_secure($_params, $this)) { - if (!$params['quiet']) - $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); - $params['source_content'] = null; - $params['resource_timestamp'] = null; - return false; - } - } - return $_return; - } - - - /** - * parse out the type and name from the resource - * - * @param string $resource_base_path - * @param string $resource_name - * @param string $resource_type - * @param string $resource_name - * @return boolean - */ - - function _parse_resource_name(&$params) - { - - // split tpl_path by the first colon - $_resource_name_parts = explode(':', $params['resource_name'], 2); - - if (count($_resource_name_parts) == 1) { - // no resource type given - $params['resource_type'] = $this->default_resource_type; - $params['resource_name'] = $_resource_name_parts[0]; - } else { - if(strlen($_resource_name_parts[0]) == 1) { - // 1 char is not resource type, but part of filepath - $params['resource_type'] = $this->default_resource_type; - $params['resource_name'] = $params['resource_name']; - } else { - $params['resource_type'] = $_resource_name_parts[0]; - $params['resource_name'] = $_resource_name_parts[1]; - } - } - - if ($params['resource_type'] == 'file') { - if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { - // relative pathname to $params['resource_base_path'] - // use the first directory where the file is found - foreach ((array)$params['resource_base_path'] as $_curr_path) { - $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; - if (file_exists($_fullpath) && is_file($_fullpath)) { - $params['resource_name'] = $_fullpath; - return true; - } - // didn't find the file, try include_path - $_params = array('file_path' => $_fullpath); - require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); - if(smarty_core_get_include_path($_params, $this)) { - $params['resource_name'] = $_params['new_file_path']; - return true; - } - } - return false; - } else { - /* absolute path */ - return file_exists($params['resource_name']); - } - } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { - $_params = array('type' => $params['resource_type']); - require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); - smarty_core_load_resource_plugin($_params, $this); - } - - return true; - } - - - /** - * Handle modifiers - * - * @param string|null $modifier_name - * @param array|null $map_array - * @return string result of modifiers - */ - function _run_mod_handler() - { - $_args = func_get_args(); - list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); - list($_func_name, $_tpl_file, $_tpl_line) = - $this->_plugins['modifier'][$_modifier_name]; - - $_var = $_args[0]; - foreach ($_var as $_key => $_val) { - $_args[0] = $_val; - $_var[$_key] = call_user_func_array($_func_name, $_args); - } - return $_var; - } - - /** - * Remove starting and ending quotes from the string - * - * @param string $string - * @return string - */ - function _dequote($string) - { - if (($string{0} == "'" || $string{0} == '"') && - $string{strlen($string)-1} == $string{0}) - return substr($string, 1, -1); - else - return $string; - } - - - /** - * read in a file - * - * @param string $filename - * @return string - */ - function _read_file($filename) - { - if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) { - $contents = ($size = filesize($filename)) ? fread($fd, $size) : ''; - fclose($fd); - return $contents; - } else { - return false; - } - } - - /** - * get a concrete filename for automagically created content - * - * @param string $auto_base - * @param string $auto_source - * @param string $auto_id - * @return string - * @staticvar string|null - * @staticvar string|null - */ - function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) - { - $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; - $_return = $auto_base . DIRECTORY_SEPARATOR; - - if(isset($auto_id)) { - // make auto_id safe for directory names - $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); - // split into separate directories - $_return .= $auto_id . $_compile_dir_sep; - } - - if(isset($auto_source)) { - // make source name safe for filename - $_filename = urlencode(basename($auto_source)); - $_crc32 = sprintf('%08X', crc32($auto_source)); - // prepend %% to avoid name conflicts with - // with $params['auto_id'] names - $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . - substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; - $_return .= '%%' . $_crc32 . '%%' . $_filename; - } - - return $_return; - } - - /** - * unlink a file, possibly using expiration time - * - * @param string $resource - * @param integer $exp_time - */ - function _unlink($resource, $exp_time = null) - { - if(isset($exp_time)) { - if(time() - @filemtime($resource) >= $exp_time) { - return @unlink($resource); - } - } else { - return @unlink($resource); - } - } - - /** - * returns an auto_id for auto-file-functions - * - * @param string $cache_id - * @param string $compile_id - * @return string|null - */ - function _get_auto_id($cache_id=null, $compile_id=null) { - if (isset($cache_id)) - return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; - elseif(isset($compile_id)) - return $compile_id; - else - return null; - } - - /** - * trigger Smarty plugin error - * - * @param string $error_msg - * @param string $tpl_file - * @param integer $tpl_line - * @param string $file - * @param integer $line - * @param integer $error_type - */ - function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, - $file = null, $line = null, $error_type = E_USER_ERROR) - { - if(isset($file) && isset($line)) { - $info = ' ('.basename($file).", line $line)"; - } else { - $info = ''; - } - if (isset($tpl_line) && isset($tpl_file)) { - $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); - } else { - $this->trigger_error($error_msg . $info, $error_type); - } - } - - - /** - * callback function for preg_replace, to call a non-cacheable block - * @return string - */ - function _process_compiled_include_callback($match) { - $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; - ob_start(); - $_func($this); - $_ret = ob_get_contents(); - ob_end_clean(); - return $_ret; - } - - - /** - * called for included templates - * - * @param string $_smarty_include_tpl_file - * @param string $_smarty_include_vars - */ - - // $_smarty_include_tpl_file, $_smarty_include_vars - - function _smarty_include($params) - { - if ($this->debugging) { - $_params = array(); - require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); - $debug_start_time = smarty_core_get_microtime($_params, $this); - $this->_smarty_debug_info[] = array('type' => 'template', - 'filename' => $params['smarty_include_tpl_file'], - 'depth' => ++$this->_inclusion_depth); - $included_tpls_idx = count($this->_smarty_debug_info) - 1; - } - - $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); - - // config vars are treated as local, so push a copy of the - // current ones onto the front of the stack - array_unshift($this->_config, $this->_config[0]); - - $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); - - - if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) - || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) - { - include($_smarty_compile_path); - } - - // pop the local vars off the front of the stack - array_shift($this->_config); - - $this->_inclusion_depth--; - - if ($this->debugging) { - // capture time for debugging info - $_params = array(); - require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); - $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; - } - - if ($this->caching) { - $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; - } - } - - - /** - * get or set an array of cached attributes for function that is - * not cacheable - * @return array - */ - function &_smarty_cache_attrs($cache_serial, $count) { - $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; - - if ($this->_cache_including) { - /* return next set of cache_attrs */ - $_return =& current($_cache_attrs); - next($_cache_attrs); - return $_return; - - } else { - /* add a reference to a new set of cache_attrs */ - $_cache_attrs[] = array(); - return $_cache_attrs[count($_cache_attrs)-1]; - - } - - } - - - /** - * wrapper for include() retaining $this - * @return mixed - */ - function _include($filename, $once=false, $params=null) - { - if ($once) { - return include_once($filename); - } else { - return include($filename); - } - } - - - /** - * wrapper for eval() retaining $this - * @return mixed - */ - function _eval($code, $params=null) - { - return eval($code); - } - /**#@-*/ - -} - -/* vim: set expandtab: */ - -?> + + * @author Andrei Zmievski + * @package Smarty + * @version 2.6.28 + */ + +/* $Id: Smarty.class.php 4660 2012-09-24 20:05:15Z uwe.tews@googlemail.com $ */ + +/** + * DIR_SEP isn't used anymore, but third party apps might + */ +if(!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * if not defined, include_path will be used. Sets SMARTY_DIR only if user + * application has not already defined it. + */ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +if (!defined('SMARTY_CORE_DIR')) { + define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); +} + +define('SMARTY_PHP_PASSTHRU', 0); +define('SMARTY_PHP_QUOTE', 1); +define('SMARTY_PHP_REMOVE', 2); +define('SMARTY_PHP_ALLOW', 3); + +/** + * @package Smarty + */ +class Smarty +{ + /**#@+ + * Smarty Configuration Section + */ + + /** + * The name of the directory where templates are located. + * + * @var string + */ + var $template_dir = 'templates'; + + /** + * The directory where compiled templates are located. + * + * @var string + */ + var $compile_dir = 'templates_c'; + + /** + * The directory where config files are located. + * + * @var string + */ + var $config_dir = 'configs'; + + /** + * An array of directories searched for plugins. + * + * @var array + */ + var $plugins_dir = array('plugins'); + + /** + * If debugging is enabled, a debug console window will display + * when the page loads (make sure your browser allows unrequested + * popup windows) + * + * @var boolean + */ + var $debugging = false; + + /** + * When set, smarty does uses this value as error_reporting-level. + * + * @var integer + */ + var $error_reporting = null; + + /** + * This is the path to the debug console template. If not set, + * the default one will be used. + * + * @var string + */ + var $debug_tpl = ''; + + /** + * This determines if debugging is enable-able from the browser. + *
    + *
  • NONE => no debugging control allowed
  • + *
  • URL => enable debugging when SMARTY_DEBUG is found in the URL.
  • + *
+ * @link http://www.foo.dom/index.php?SMARTY_DEBUG + * @var string + */ + var $debugging_ctrl = 'NONE'; + + /** + * This tells Smarty whether to check for recompiling or not. Recompiling + * does not need to happen unless a template or config file is changed. + * Typically you enable this during development, and disable for + * production. + * + * @var boolean + */ + var $compile_check = true; + + /** + * This forces templates to compile every time. Useful for development + * or debugging. + * + * @var boolean + */ + var $force_compile = false; + + /** + * This enables template caching. + *
    + *
  • 0 = no caching
  • + *
  • 1 = use class cache_lifetime value
  • + *
  • 2 = use cache_lifetime in cache file
  • + *
+ * @var integer + */ + var $caching = 0; + + /** + * The name of the directory for cache files. + * + * @var string + */ + var $cache_dir = 'cache'; + + /** + * This is the number of seconds cached content will persist. + *
    + *
  • 0 = always regenerate cache
  • + *
  • -1 = never expires
  • + *
+ * + * @var integer + */ + var $cache_lifetime = 3600; + + /** + * Only used when $caching is enabled. If true, then If-Modified-Since headers + * are respected with cached content, and appropriate HTTP headers are sent. + * This way repeated hits to a cached page do not send the entire page to the + * client every time. + * + * @var boolean + */ + var $cache_modified_check = false; + + /** + * This determines how Smarty handles "" tags in templates. + * possible values: + *
    + *
  • SMARTY_PHP_PASSTHRU -> print tags as plain text
  • + *
  • SMARTY_PHP_QUOTE -> escape tags as entities
  • + *
  • SMARTY_PHP_REMOVE -> remove php tags
  • + *
  • SMARTY_PHP_ALLOW -> execute php tags
  • + *
+ * + * @var integer + */ + var $php_handling = SMARTY_PHP_PASSTHRU; + + /** + * This enables template security. When enabled, many things are restricted + * in the templates that normally would go unchecked. This is useful when + * untrusted parties are editing templates and you want a reasonable level + * of security. (no direct execution of PHP in templates for example) + * + * @var boolean + */ + var $security = false; + + /** + * This is the list of template directories that are considered secure. This + * is used only if {@link $security} is enabled. One directory per array + * element. {@link $template_dir} is in this list implicitly. + * + * @var array + */ + var $secure_dir = array(); + + /** + * These are the security settings for Smarty. They are used only when + * {@link $security} is enabled. + * + * @var array + */ + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'sizeof', + 'in_array', 'is_array', + 'true', 'false', 'null'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count'), + 'ALLOW_CONSTANTS' => false, + 'ALLOW_SUPER_GLOBALS' => true + ); + + /** + * This is an array of directories where trusted php scripts reside. + * {@link $security} is disabled during their inclusion/execution. + * + * @var array + */ + var $trusted_dir = array(); + + /** + * The left delimiter used for the template tags. + * + * @var string + */ + var $left_delimiter = '{'; + + /** + * The right delimiter used for the template tags. + * + * @var string + */ + var $right_delimiter = '}'; + + /** + * The order in which request variables are registered, similar to + * variables_order in php.ini E = Environment, G = GET, P = POST, + * C = Cookies, S = Server + * + * @var string + */ + var $request_vars_order = 'EGPCS'; + + /** + * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) + * are uses as request-vars or $_*[]-vars. note: if + * request_use_auto_globals is true, then $request_vars_order has + * no effect, but the php-ini-value "gpc_order" + * + * @var boolean + */ + var $request_use_auto_globals = true; + + /** + * Set this if you want different sets of compiled files for the same + * templates. This is useful for things like different languages. + * Instead of creating separate sets of templates per language, you + * set different compile_ids like 'en' and 'de'. + * + * @var string + */ + var $compile_id = null; + + /** + * This tells Smarty whether or not to use sub dirs in the cache/ and + * templates_c/ directories. sub directories better organized, but + * may not work well with PHP safe mode enabled. + * + * @var boolean + * + */ + var $use_sub_dirs = false; + + /** + * This is a list of the modifiers to apply to all template variables. + * Put each modifier in a separate array element in the order you want + * them applied. example: array('escape:"htmlall"'); + * + * @var array + */ + var $default_modifiers = array(); + + /** + * This is the resource type to be used when not specified + * at the beginning of the resource path. examples: + * $smarty->display('file:index.tpl'); + * $smarty->display('db:index.tpl'); + * $smarty->display('index.tpl'); // will use default resource type + * {include file="file:index.tpl"} + * {include file="db:index.tpl"} + * {include file="index.tpl"} {* will use default resource type *} + * + * @var array + */ + var $default_resource_type = 'file'; + + /** + * The function used for cache file handling. If not set, built-in caching is used. + * + * @var null|string function name + */ + var $cache_handler_func = null; + + /** + * This indicates which filters are automatically loaded into Smarty. + * + * @var array array of filter names + */ + var $autoload_filters = array(); + + /**#@+ + * @var boolean + */ + /** + * This tells if config file vars of the same name overwrite each other or not. + * if disabled, same name variables are accumulated in an array. + */ + var $config_overwrite = true; + + /** + * This tells whether or not to automatically booleanize config file variables. + * If enabled, then the strings "on", "true", and "yes" are treated as boolean + * true, and "off", "false" and "no" are treated as boolean false. + */ + var $config_booleanize = true; + + /** + * This tells whether hidden sections [.foobar] are readable from the + * tempalates or not. Normally you would never allow this since that is + * the point behind hidden sections: the application can access them, but + * the templates cannot. + */ + var $config_read_hidden = false; + + /** + * This tells whether or not automatically fix newlines in config files. + * It basically converts \r (mac) or \r\n (dos) to \n + */ + var $config_fix_newlines = true; + /**#@-*/ + + /** + * If a template cannot be found, this PHP function will be executed. + * Useful for creating templates on-the-fly or other special action. + * + * @var string function name + */ + var $default_template_handler_func = ''; + + /** + * The file that contains the compiler class. This can a full + * pathname, or relative to the php_include path. + * + * @var string + */ + var $compiler_file = 'Smarty_Compiler.class.php'; + + /** + * The class used for compiling templates. + * + * @var string + */ + var $compiler_class = 'Smarty_Compiler'; + + /** + * The class used to load config vars. + * + * @var string + */ + var $config_class = 'Config_File'; + +/**#@+ + * END Smarty Configuration Section + * There should be no need to touch anything below this line. + * @access private + */ + /** + * where assigned template vars are kept + * + * @var array + */ + var $_tpl_vars = array(); + + /** + * stores run-time $smarty.* vars + * + * @var null|array + */ + var $_smarty_vars = null; + + /** + * keeps track of sections + * + * @var array + */ + var $_sections = array(); + + /** + * keeps track of foreach blocks + * + * @var array + */ + var $_foreach = array(); + + /** + * keeps track of tag hierarchy + * + * @var array + */ + var $_tag_stack = array(); + + /** + * configuration object + * + * @var Config_file + */ + var $_conf_obj = null; + + /** + * loaded configuration settings + * + * @var array + */ + var $_config = array(array('vars' => array(), 'files' => array())); + + /** + * md5 checksum of the string 'Smarty' + * + * @var string + */ + var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; + + /** + * Smarty version number + * + * @var string + */ + var $_version = '2.6.28'; + + /** + * current template inclusion depth + * + * @var integer + */ + var $_inclusion_depth = 0; + + /** + * for different compiled templates + * + * @var string + */ + var $_compile_id = null; + + /** + * text in URL to enable debug mode + * + * @var string + */ + var $_smarty_debug_id = 'SMARTY_DEBUG'; + + /** + * debugging information for debug console + * + * @var array + */ + var $_smarty_debug_info = array(); + + /** + * info that makes up a cache file + * + * @var array + */ + var $_cache_info = array(); + + /** + * default file permissions + * + * @var integer + */ + var $_file_perms = 0644; + + /** + * default dir permissions + * + * @var integer + */ + var $_dir_perms = 0771; + + /** + * registered objects + * + * @var array + */ + var $_reg_objects = array(); + + /** + * table keeping track of plugins + * + * @var array + */ + var $_plugins = array( + 'modifier' => array(), + 'function' => array(), + 'block' => array(), + 'compiler' => array(), + 'prefilter' => array(), + 'postfilter' => array(), + 'outputfilter' => array(), + 'resource' => array(), + 'insert' => array()); + + + /** + * cache serials + * + * @var array + */ + var $_cache_serials = array(); + + /** + * name of optional cache include file + * + * @var string + */ + var $_cache_include = null; + + /** + * indicate if the current code is used in a compiled + * include + * + * @var string + */ + var $_cache_including = false; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty() + { + $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] + : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); + } + + /** + * assigns values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to assign + */ + function assign($tpl_var, $value = null) + { + if (is_array($tpl_var)){ + foreach ($tpl_var as $key => $val) { + if ($key != '') { + $this->_tpl_vars[$key] = $val; + } + } + } else { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = $value; + } + } + + /** + * assigns values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to assign + */ + function assign_by_ref($tpl_var, &$value) + { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = &$value; + } + + /** + * appends values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to append + */ + function append($tpl_var, $value=null, $merge=false) + { + if (is_array($tpl_var)) { + // $tpl_var is an array, ignore $value + foreach ($tpl_var as $_key => $_val) { + if ($_key != '') { + if(!@is_array($this->_tpl_vars[$_key])) { + settype($this->_tpl_vars[$_key],'array'); + } + if($merge && is_array($_val)) { + foreach($_val as $_mkey => $_mval) { + $this->_tpl_vars[$_key][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$_key][] = $_val; + } + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if($merge && is_array($value)) { + foreach($value as $_mkey => $_mval) { + $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$tpl_var][] = $value; + } + } + } + } + + /** + * appends values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to append + */ + function append_by_ref($tpl_var, &$value, $merge=false) + { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if ($merge && is_array($value)) { + foreach($value as $_key => $_val) { + $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; + } + } else { + $this->_tpl_vars[$tpl_var][] = &$value; + } + } + } + + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + function clear_assign($tpl_var) + { + if (is_array($tpl_var)) + foreach ($tpl_var as $curr_var) + unset($this->_tpl_vars[$curr_var]); + else + unset($this->_tpl_vars[$tpl_var]); + } + + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + */ + function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['function'][$function] = + array($function_impl, null, null, false, $cacheable, $cache_attrs); + + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + function unregister_function($function) + { + unset($this->_plugins['function'][$function]); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object &$object_impl the referenced PHP object to register + * @param null|array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param null|array $block_functs list of methods that are block format + */ + function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->_reg_objects[$object] = + array(&$object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + function unregister_object($object) + { + unset($this->_reg_objects[$object]); + } + + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + */ + function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['block'][$block] = + array($block_impl, null, null, false, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + function unregister_block($block) + { + unset($this->_plugins['block'][$block]); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + */ + function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->_plugins['compiler'][$function] = + array($function_impl, null, null, false, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + function unregister_compiler_function($function) + { + unset($this->_plugins['compiler'][$function]); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + function register_modifier($modifier, $modifier_impl) + { + $this->_plugins['modifier'][$modifier] = + array($modifier_impl, null, null, false); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + function unregister_modifier($modifier) + { + unset($this->_plugins['modifier'][$modifier]); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + function register_resource($type, $functions) + { + if (count($functions)==4) { + $this->_plugins['resource'][$type] = + array($functions, false); + + } elseif (count($functions)==5) { + $this->_plugins['resource'][$type] = + array(array(array(&$functions[0], $functions[1]) + ,array(&$functions[0], $functions[2]) + ,array(&$functions[0], $functions[3]) + ,array(&$functions[0], $functions[4])) + ,false); + + } else { + $this->trigger_error("malformed function-list for '$type' in register_resource"); + + } + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + function unregister_resource($type) + { + unset($this->_plugins['resource'][$type]); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callback $function + */ + function register_prefilter($function) + { + $this->_plugins['prefilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a prefilter function + * + * @param callback $function + */ + function unregister_prefilter($function) + { + unset($this->_plugins['prefilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callback $function + */ + function register_postfilter($function) + { + $this->_plugins['postfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a postfilter function + * + * @param callback $function + */ + function unregister_postfilter($function) + { + unset($this->_plugins['postfilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callback $function + */ + function register_outputfilter($function) + { + $this->_plugins['outputfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters an outputfilter function + * + * @param callback $function + */ + function unregister_outputfilter($function) + { + unset($this->_plugins['outputfilter'][$this->_get_filter_name($function)]); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + function load_filter($type, $name) + { + switch ($type) { + case 'output': + $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + break; + + case 'pre': + case 'post': + if (!isset($this->_plugins[$type . 'filter'][$name])) + $this->_plugins[$type . 'filter'][$name] = false; + break; + } + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + if (!isset($tpl_file)) + $compile_id = null; + + $_auto_id = $this->_get_auto_id($cache_id, $compile_id); + + if (!empty($this->cache_handler_func)) { + return call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $_auto_id, + 'exp_time' => $exp_time); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + } + + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_all_cache($exp_time = null) + { + return $this->clear_cache(null, null, null, $exp_time); + } + + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + if (!$this->caching) + return false; + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + $_params = array( + 'tpl_file' => $tpl_file, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + return smarty_core_read_cache_file($_params, $this); + } + + + /** + * clear all the assigned template variables. + * + */ + function clear_all_assign() + { + $this->_tpl_vars = array(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + $_params = array('auto_base' => $this->compile_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $compile_id, + 'exp_time' => $exp_time, + 'extensions' => array('.inc', '.php')); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + function template_exists($tpl_file) + { + $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); + return $this->_fetch_resource_info($_params); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_template_vars($name=null) + { + if(!isset($name)) { + return $this->_tpl_vars; + } elseif(isset($this->_tpl_vars[$name])) { + return $this->_tpl_vars[$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_config_vars($name=null) + { + if(!isset($name) && is_array($this->_config[0])) { + return $this->_config[0]['vars']; + } else if(isset($this->_config[0]['vars'][$name])) { + return $this->_config[0]['vars'][$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + $msg = htmlentities($error_msg); + trigger_error("Smarty error: $msg", $error_type); + } + + + /** + * executes & displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + /** + * executes & returns or displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + static $_cache_info = array(); + + $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) + ? $this->error_reporting : error_reporting() & ~E_NOTICE); + + if (!$this->debugging && $this->debugging_ctrl == 'URL') { + $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + if (@strstr($_query_string, $this->_smarty_debug_id)) { + if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { + // enable debugging for this browser session + @setcookie('SMARTY_DEBUG', true); + $this->debugging = true; + } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { + // disable debugging for this browser session + @setcookie('SMARTY_DEBUG', false); + $this->debugging = false; + } else { + // enable debugging for this page + $this->debugging = true; + } + } else { + $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); + } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $resource_name, + 'depth' => 0); + $_included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + + $this->_compile_id = $compile_id; + $this->_inclusion_depth = 0; + + if ($this->caching) { + // save old cache_info, initialize cache_info + array_push($_cache_info, $this->_cache_info); + $this->_cache_info = array(); + $_params = array( + 'tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => null + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + if (smarty_core_read_cache_file($_params, $this)) { + $_smarty_results = $_params['results']; + if (!empty($this->_cache_info['insert_tags'])) { + $_params = array('plugins' => $this->_cache_info['insert_tags']); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + } + if (!empty($this->_cache_info['cache_serials'])) { + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); + $_smarty_results = smarty_core_process_compiled_include($_params, $this); + } + + + if ($display) { + if ($this->debugging) + { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + $_smarty_results .= smarty_core_display_debug_console($_params, $this); + } + if ($this->cache_modified_check) { + $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); + $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; + if (@count($this->_cache_info['insert_tags']) == 0 + && !$this->_cache_serials + && $_gmt_mtime == $_last_modified_date) { + if (php_sapi_name()=='cgi') + header('Status: 304 Not Modified'); + else + header('HTTP/1.1 304 Not Modified'); + + } else { + header('Last-Modified: '.$_gmt_mtime); + echo $_smarty_results; + } + } else { + echo $_smarty_results; + } + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return true; + } else { + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return $_smarty_results; + } + } else { + $this->_cache_info['template'][$resource_name] = true; + if ($this->cache_modified_check && $display) { + header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); + } + } + } + + // load filters that are marked as autoload + if (count($this->autoload_filters)) { + foreach ($this->autoload_filters as $_filter_type => $_filters) { + foreach ($_filters as $_filter) { + $this->load_filter($_filter_type, $_filter); + } + } + } + + $_smarty_compile_path = $this->_get_compile_path($resource_name); + + // if we just need to display the results, don't perform output + // buffering - for speed + $_cache_including = $this->_cache_including; + $this->_cache_including = false; + if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + } else { + ob_start(); + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + $_smarty_results = ob_get_contents(); + ob_end_clean(); + + foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { + $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); + } + } + + if ($this->caching) { + $_params = array('tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); + smarty_core_write_cache_file($_params, $this); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + + if ($this->_cache_serials) { + // strip nocache-tags from output + $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' + ,'' + ,$_smarty_results); + } + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + } + $this->_cache_including = $_cache_including; + + if ($display) { + if (isset($_smarty_results)) { echo $_smarty_results; } + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console($_params, $this); + } + error_reporting($_smarty_old_error_level); + return; + } else { + error_reporting($_smarty_old_error_level); + if (isset($_smarty_results)) { return $_smarty_results; } + } + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + require_once($this->_get_plugin_filepath('function', 'config_load')); + smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + function &get_registered_object($name) { + if (!isset($this->_reg_objects[$name])) + $this->_trigger_fatal_error("'$name' is not a registered object"); + + if (!is_object($this->_reg_objects[$name][0])) + $this->_trigger_fatal_error("registered '$name' is not an object"); + + return $this->_reg_objects[$name][0]; + } + + /** + * clear configuration values + * + * @param string $var + */ + function clear_config($var = null) + { + if(!isset($var)) { + // clear all values + $this->_config = array(array('vars' => array(), + 'files' => array())); + } else { + unset($this->_config[0]['vars'][$var]); + } + } + + /** + * get filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ + function _get_plugin_filepath($type, $name) + { + $_params = array('type' => $type, 'name' => $name); + require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); + return smarty_core_assemble_plugin_filepath($_params, $this); + } + + /** + * test if resource needs compiling + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _is_compiled($resource_name, $compile_path) + { + if (!$this->force_compile && file_exists($compile_path)) { + if (!$this->compile_check) { + // no need to check compiled file + return true; + } else { + // get file source and timestamp + $_params = array('resource_name' => $resource_name, 'get_source'=>false); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + if ($_params['resource_timestamp'] <= filemtime($compile_path)) { + // template not expired, no recompile + return true; + } else { + // compile template + return false; + } + } + } else { + // compiled template does not exist, or forced compile + return false; + } + } + + /** + * compile the template + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _compile_resource($resource_name, $compile_path) + { + + $_params = array('resource_name' => $resource_name); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + + $_source_content = $_params['source_content']; + $_cache_include = substr($compile_path, 0, -4).'.inc'; + + if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { + // if a _cache_serial was set, we also have to write an include-file: + if ($this->_cache_include_info) { + require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); + smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); + } + + $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $this); + + return true; + } else { + return false; + } + + } + + /** + * compile the given source + * + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return boolean + */ + function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) + { + if (file_exists(SMARTY_DIR . $this->compiler_file)) { + require_once(SMARTY_DIR . $this->compiler_file); + } else { + // use include_path + require_once($this->compiler_file); + } + + + $smarty_compiler = new $this->compiler_class; + + $smarty_compiler->template_dir = $this->template_dir; + $smarty_compiler->compile_dir = $this->compile_dir; + $smarty_compiler->plugins_dir = $this->plugins_dir; + $smarty_compiler->config_dir = $this->config_dir; + $smarty_compiler->force_compile = $this->force_compile; + $smarty_compiler->caching = $this->caching; + $smarty_compiler->php_handling = $this->php_handling; + $smarty_compiler->left_delimiter = $this->left_delimiter; + $smarty_compiler->right_delimiter = $this->right_delimiter; + $smarty_compiler->_version = $this->_version; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security_settings = $this->security_settings; + $smarty_compiler->trusted_dir = $this->trusted_dir; + $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; + $smarty_compiler->_reg_objects = &$this->_reg_objects; + $smarty_compiler->_plugins = &$this->_plugins; + $smarty_compiler->_tpl_vars = &$this->_tpl_vars; + $smarty_compiler->default_modifiers = $this->default_modifiers; + $smarty_compiler->compile_id = $this->_compile_id; + $smarty_compiler->_config = $this->_config; + $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; + + if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { + $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; + } + $smarty_compiler->_cache_include = $cache_include_path; + + + $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); + + if ($smarty_compiler->_cache_serial) { + $this->_cache_include_info = array( + 'cache_serial'=>$smarty_compiler->_cache_serial + ,'plugins_code'=>$smarty_compiler->_plugins_code + ,'include_file_path' => $cache_include_path); + + } else { + $this->_cache_include_info = null; + + } + + return $_results; + } + + /** + * Get the compile path for this resource + * + * @param string $resource_name + * @return string results of {@link _get_auto_filename()} + */ + function _get_compile_path($resource_name) + { + return $this->_get_auto_filename($this->compile_dir, $resource_name, + $this->_compile_id) . '.php'; + } + + /** + * fetch the template info. Gets timestamp, and source + * if get_source is true + * + * sets $source_content to the source of the template, and + * $resource_timestamp to its time stamp + * @param string $resource_name + * @param string $source_content + * @param integer $resource_timestamp + * @param boolean $get_source + * @param boolean $quiet + * @return boolean + */ + + function _fetch_resource_info(&$params) + { + if(!isset($params['get_source'])) { $params['get_source'] = true; } + if(!isset($params['quiet'])) { $params['quiet'] = false; } + + $_return = false; + $_params = array('resource_name' => $params['resource_name']) ; + if (isset($params['resource_base_path'])) + $_params['resource_base_path'] = $params['resource_base_path']; + else + $_params['resource_base_path'] = $this->template_dir; + + if ($this->_parse_resource_name($_params)) { + $_resource_type = $_params['resource_type']; + $_resource_name = $_params['resource_name']; + switch ($_resource_type) { + case 'file': + if ($params['get_source']) { + $params['source_content'] = $this->_read_file($_resource_name); + } + $params['resource_timestamp'] = filemtime($_resource_name); + $_return = is_file($_resource_name) && is_readable($_resource_name); + break; + + default: + // call resource functions to fetch the template source and timestamp + if ($params['get_source']) { + $_source_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], + array($_resource_name, &$params['source_content'], &$this)); + } else { + $_source_return = true; + } + + $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], + array($_resource_name, &$params['resource_timestamp'], &$this)); + + $_return = $_source_return && $_timestamp_return; + break; + } + } + + if (!$_return) { + // see if we can get a template with the default template handler + if (!empty($this->default_template_handler_func)) { + if (!is_callable($this->default_template_handler_func)) { + $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); + } else { + $_return = call_user_func_array( + $this->default_template_handler_func, + array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); + } + } + } + + if (!$_return) { + if (!$params['quiet']) { + $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); + } + } else if ($_return && $this->security) { + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if (!smarty_core_is_secure($_params, $this)) { + if (!$params['quiet']) + $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); + $params['source_content'] = null; + $params['resource_timestamp'] = null; + return false; + } + } + return $_return; + } + + + /** + * parse out the type and name from the resource + * + * @param string $resource_base_path + * @param string $resource_name + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + function _parse_resource_name(&$params) + { + + // split tpl_path by the first colon + $_resource_name_parts = explode(':', $params['resource_name'], 2); + + if (count($_resource_name_parts) == 1) { + // no resource type given + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $_resource_name_parts[0]; + } else { + if(strlen($_resource_name_parts[0]) == 1) { + // 1 char is not resource type, but part of filepath + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $params['resource_name']; + } else { + $params['resource_type'] = $_resource_name_parts[0]; + $params['resource_name'] = $_resource_name_parts[1]; + } + } + + if ($params['resource_type'] == 'file') { + if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { + // relative pathname to $params['resource_base_path'] + // use the first directory where the file is found + foreach ((array)$params['resource_base_path'] as $_curr_path) { + $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; + if (file_exists($_fullpath) && is_file($_fullpath)) { + $params['resource_name'] = $_fullpath; + return true; + } + // didn't find the file, try include_path + $_params = array('file_path' => $_fullpath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $this)) { + $params['resource_name'] = $_params['new_file_path']; + return true; + } + } + return false; + } else { + /* absolute path */ + return file_exists($params['resource_name']); + } + } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { + $_params = array('type' => $params['resource_type']); + require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); + smarty_core_load_resource_plugin($_params, $this); + } + + return true; + } + + + /** + * Handle modifiers + * + * @param string|null $modifier_name + * @param array|null $map_array + * @return string result of modifiers + */ + function _run_mod_handler() + { + $_args = func_get_args(); + list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); + list($_func_name, $_tpl_file, $_tpl_line) = + $this->_plugins['modifier'][$_modifier_name]; + + $_var = $_args[0]; + foreach ($_var as $_key => $_val) { + $_args[0] = $_val; + $_var[$_key] = call_user_func_array($_func_name, $_args); + } + return $_var; + } + + /** + * Remove starting and ending quotes from the string + * + * @param string $string + * @return string + */ + function _dequote($string) + { + if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') && + substr($string, -1) == substr($string, 0, 1)) + return substr($string, 1, -1); + else + return $string; + } + + + /** + * read in a file + * + * @param string $filename + * @return string + */ + function _read_file($filename) + { + if ( file_exists($filename) && is_readable($filename) && ($fd = @fopen($filename, 'rb')) ) { + $contents = ''; + while (!feof($fd)) { + $contents .= fread($fd, 8192); + } + fclose($fd); + return $contents; + } else { + return false; + } + } + + /** + * get a concrete filename for automagically created content + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @return string + * @staticvar string|null + * @staticvar string|null + */ + function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) + { + $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; + $_return = $auto_base . DIRECTORY_SEPARATOR; + + if(isset($auto_id)) { + // make auto_id safe for directory names + $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); + // split into separate directories + $_return .= $auto_id . $_compile_dir_sep; + } + + if(isset($auto_source)) { + // make source name safe for filename + $_filename = urlencode(basename($auto_source)); + $_crc32 = sprintf('%08X', crc32($auto_source)); + // prepend %% to avoid name conflicts with + // with $params['auto_id'] names + $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . + substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; + $_return .= '%%' . $_crc32 . '%%' . $_filename; + } + + return $_return; + } + + /** + * unlink a file, possibly using expiration time + * + * @param string $resource + * @param integer $exp_time + */ + function _unlink($resource, $exp_time = null) + { + if(isset($exp_time)) { + if(time() - @filemtime($resource) >= $exp_time) { + return @unlink($resource); + } + } else { + return @unlink($resource); + } + } + + /** + * returns an auto_id for auto-file-functions + * + * @param string $cache_id + * @param string $compile_id + * @return string|null + */ + function _get_auto_id($cache_id=null, $compile_id=null) { + if (isset($cache_id)) + return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; + elseif(isset($compile_id)) + return $compile_id; + else + return null; + } + + /** + * trigger Smarty plugin error + * + * @param string $error_msg + * @param string $tpl_file + * @param integer $tpl_line + * @param string $file + * @param integer $line + * @param integer $error_type + */ + function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, + $file = null, $line = null, $error_type = E_USER_ERROR) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = ''; + } + if (isset($tpl_line) && isset($tpl_file)) { + $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); + } else { + $this->trigger_error($error_msg . $info, $error_type); + } + } + + + /** + * callback function for preg_replace, to call a non-cacheable block + * @return string + */ + function _process_compiled_include_callback($match) { + $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; + ob_start(); + $_func($this); + $_ret = ob_get_contents(); + ob_end_clean(); + return $_ret; + } + + + /** + * called for included templates + * + * @param string $_smarty_include_tpl_file + * @param string $_smarty_include_vars + */ + + // $_smarty_include_tpl_file, $_smarty_include_vars + + function _smarty_include($params) + { + if ($this->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $params['smarty_include_tpl_file'], + 'depth' => ++$this->_inclusion_depth); + $included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); + + // config vars are treated as local, so push a copy of the + // current ones onto the front of the stack + array_unshift($this->_config, $this->_config[0]); + + $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); + + + if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) + || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + + // pop the local vars off the front of the stack + array_shift($this->_config); + + $this->_inclusion_depth--; + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; + } + + if ($this->caching) { + $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; + } + } + + + /** + * get or set an array of cached attributes for function that is + * not cacheable + * @return array + */ + function &_smarty_cache_attrs($cache_serial, $count) { + $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; + + if ($this->_cache_including) { + /* return next set of cache_attrs */ + $_return = current($_cache_attrs); + next($_cache_attrs); + return $_return; + + } else { + /* add a reference to a new set of cache_attrs */ + $_cache_attrs[] = array(); + return $_cache_attrs[count($_cache_attrs)-1]; + + } + + } + + + /** + * wrapper for include() retaining $this + * @return mixed + */ + function _include($filename, $once=false, $params=null) + { + if ($once) { + return include_once($filename); + } else { + return include($filename); + } + } + + + /** + * wrapper for eval() retaining $this + * @return mixed + */ + function _eval($code, $params=null) + { + return eval($code); + } + + /** + * Extracts the filter name from the given callback + * + * @param callback $function + * @return string + */ + function _get_filter_name($function) + { + if (is_array($function)) { + $_class_name = (is_object($function[0]) ? + get_class($function[0]) : $function[0]); + return $_class_name . '_' . $function[1]; + } + else { + return $function; + } + } + + /**#@-*/ + +} + +/* vim: set expandtab: */ + +?> diff --git a/code/web/public_php/admin/smarty/Smarty_Compiler.class.php b/code/web/public_php/admin/smarty/Smarty_Compiler.class.php index e714a6339..c1bc798d1 100644 --- a/code/web/public_php/admin/smarty/Smarty_Compiler.class.php +++ b/code/web/public_php/admin/smarty/Smarty_Compiler.class.php @@ -1,2304 +1,2365 @@ - - * @author Andrei Zmievski - * @version 2.6.9 - * @copyright 2001-2005 New Digital Group, Inc. - * @package Smarty - */ - -/* $Id: Smarty_Compiler.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */ - -/** - * Template compiling class - * @package Smarty - */ -class Smarty_Compiler extends Smarty { - - // internal vars - /**#@+ - * @access private - */ - var $_folded_blocks = array(); // keeps folded template blocks - var $_current_file = null; // the current template being compiled - var $_current_line_no = 1; // line number for error messages - var $_capture_stack = array(); // keeps track of nested capture buffers - var $_plugin_info = array(); // keeps track of plugins to load - var $_init_smarty_vars = false; - var $_permitted_tokens = array('true','false','yes','no','on','off','null'); - var $_db_qstr_regexp = null; // regexps are setup in the constructor - var $_si_qstr_regexp = null; - var $_qstr_regexp = null; - var $_func_regexp = null; - var $_reg_obj_regexp = null; - var $_var_bracket_regexp = null; - var $_num_const_regexp = null; - var $_dvar_guts_regexp = null; - var $_dvar_regexp = null; - var $_cvar_regexp = null; - var $_svar_regexp = null; - var $_avar_regexp = null; - var $_mod_regexp = null; - var $_var_regexp = null; - var $_parenth_param_regexp = null; - var $_func_call_regexp = null; - var $_obj_ext_regexp = null; - var $_obj_start_regexp = null; - var $_obj_params_regexp = null; - var $_obj_call_regexp = null; - var $_cacheable_state = 0; - var $_cache_attrs_count = 0; - var $_nocache_count = 0; - var $_cache_serial = null; - var $_cache_include = null; - - var $_strip_depth = 0; - var $_additional_newline = "\n"; - - /**#@-*/ - /** - * The class constructor. - */ - function Smarty_Compiler() - { - // matches double quoted strings: - // "foobar" - // "foo\"bar" - $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; - - // matches single quoted strings: - // 'foobar' - // 'foo\'bar' - $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; - - // matches single or double quoted strings - $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; - - // matches bracket portion of vars - // [0] - // [foo] - // [$bar] - $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; - - // matches numerical constants - // 30 - // -12 - // 13.22 - $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; - - // matches $ vars (not objects): - // $foo - // $foo.bar - // $foo.bar.foobar - // $foo[0] - // $foo[$bar] - // $foo[5][blah] - // $foo[5].bar[$foobar][4] - $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; - $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; - $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp - . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; - $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; - - // matches config vars: - // #foo# - // #foobar123_foo# - $this->_cvar_regexp = '\#\w+\#'; - - // matches section vars: - // %foo.bar% - $this->_svar_regexp = '\%\w+\.\w+\%'; - - // matches all valid variables (no quotes, no modifiers) - $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' - . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; - - // matches valid variable syntax: - // $foo - // $foo - // #foo# - // #foo# - // "text" - // "text" - $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; - - // matches valid object call (one level of object nesting allowed in parameters): - // $foo->bar - // $foo->bar() - // $foo->bar("text") - // $foo->bar($foo, $bar, "text") - // $foo->bar($foo, "foo") - // $foo->bar->foo() - // $foo->bar->foo->bar() - // $foo->bar($foo->bar) - // $foo->bar($foo->bar()) - // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) - $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; - $this->_obj_restricted_param_regexp = '(?:' - . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' - . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; - $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' - . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; - $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp - . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; - $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; - $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; - - // matches valid modifier syntax: - // |foo - // |@foo - // |foo:"bar" - // |foo:$bar - // |foo:"bar":$foobar - // |foo|bar - // |foo:$foo->bar - $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' - . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; - - // matches valid function name: - // foo123 - // _foo_bar - $this->_func_regexp = '[a-zA-Z_]\w*'; - - // matches valid registered object: - // foo->bar - $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; - - // matches valid parameter values: - // true - // $foo - // $foo|bar - // #foo# - // #foo#|bar - // "text" - // "text"|bar - // $foo->bar - $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' - . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; - - // matches valid parenthesised function parameters: - // - // "text" - // $foo, $bar, "text" - // $foo|bar, "foo"|bar, $foo->bar($foo)|bar - $this->_parenth_param_regexp = '(?:\((?:\w+|' - . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' - . $this->_param_regexp . ')))*)?\))'; - - // matches valid function call: - // foo() - // foo_bar($foo) - // _foo_bar($foo,"bar") - // foo123($foo,$foo->bar(),"foo") - $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' - . $this->_parenth_param_regexp . '))'; - } - - /** - * compile a resource - * - * sets $compiled_content to the compiled source - * @param string $resource_name - * @param string $source_content - * @param string $compiled_content - * @return true - */ - function _compile_file($resource_name, $source_content, &$compiled_content) - { - - if ($this->security) { - // do not allow php syntax to be executed unless specified - if ($this->php_handling == SMARTY_PHP_ALLOW && - !$this->security_settings['PHP_HANDLING']) { - $this->php_handling = SMARTY_PHP_PASSTHRU; - } - } - - $this->_load_filters(); - - $this->_current_file = $resource_name; - $this->_current_line_no = 1; - $ldq = preg_quote($this->left_delimiter, '~'); - $rdq = preg_quote($this->right_delimiter, '~'); - - // run template source through prefilter functions - if (count($this->_plugins['prefilter']) > 0) { - foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { - if ($prefilter === false) continue; - if ($prefilter[3] || is_callable($prefilter[0])) { - $source_content = call_user_func_array($prefilter[0], - array($source_content, &$this)); - $this->_plugins['prefilter'][$filter_name][3] = true; - } else { - $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); - } - } - } - - /* fetch all special blocks */ - $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; - - preg_match_all($search, $source_content, $match, PREG_SET_ORDER); - $this->_folded_blocks = $match; - reset($this->_folded_blocks); - - /* replace special blocks by "{php}" */ - $source_content = preg_replace($search.'e', "'" - . $this->_quote_replace($this->left_delimiter) . 'php' - . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" - . $this->_quote_replace($this->right_delimiter) - . "'" - , $source_content); - - /* Gather all template tags. */ - preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); - $template_tags = $_match[1]; - /* Split content by template tags to obtain non-template content. */ - $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); - - /* loop through text blocks */ - for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { - /* match anything resembling php tags */ - if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { - /* replace tags with placeholders to prevent recursive replacements */ - $sp_match[1] = array_unique($sp_match[1]); - usort($sp_match[1], '_smarty_sort_length'); - for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { - $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); - } - /* process each one */ - for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { - if ($this->php_handling == SMARTY_PHP_PASSTHRU) { - /* echo php contents */ - $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); - } else if ($this->php_handling == SMARTY_PHP_QUOTE) { - /* quote php tags */ - $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); - } else if ($this->php_handling == SMARTY_PHP_REMOVE) { - /* remove php tags */ - $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); - } else { - /* SMARTY_PHP_ALLOW, but echo non php starting tags */ - $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', ''."\n", $sp_match[1][$curr_sp]); - $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); - } - } - } - } - - /* Compile the template tags into PHP code. */ - $compiled_tags = array(); - for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { - $this->_current_line_no += substr_count($text_blocks[$i], "\n"); - $compiled_tags[] = $this->_compile_tag($template_tags[$i]); - $this->_current_line_no += substr_count($template_tags[$i], "\n"); - } - if (count($this->_tag_stack)>0) { - list($_open_tag, $_line_no) = end($this->_tag_stack); - $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); - return; - } - - /* Reformat $text_blocks between 'strip' and '/strip' tags, - removing spaces, tabs and newlines. */ - $strip = false; - for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { - if ($compiled_tags[$i] == '{strip}') { - $compiled_tags[$i] = ''; - $strip = true; - /* remove leading whitespaces */ - $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); - } - if ($strip) { - /* strip all $text_blocks before the next '/strip' */ - for ($j = $i + 1; $j < $for_max; $j++) { - /* remove leading and trailing whitespaces of each line */ - $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); - if ($compiled_tags[$j] == '{/strip}') { - /* remove trailing whitespaces from the last text_block */ - $text_blocks[$j] = rtrim($text_blocks[$j]); - } - $text_blocks[$j] = ""\'", "\\"=>"\\\\")) . "'; ?>"; - if ($compiled_tags[$j] == '{/strip}') { - $compiled_tags[$j] = "\n"; /* slurped by php, but necessary - if a newline is following the closing strip-tag */ - $strip = false; - $i = $j; - break; - } - } - } - } - $compiled_content = ''; - - /* Interleave the compiled contents and text blocks to get the final result. */ - for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { - if ($compiled_tags[$i] == '') { - // tag result empty, remove first newline from following text block - $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); - } - $compiled_content .= $text_blocks[$i].$compiled_tags[$i]; - } - $compiled_content .= $text_blocks[$i]; - - // remove \n from the end of the file, if any - if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) { - $compiled_content = substr($compiled_content, 0, -1); - } - - if (!empty($this->_cache_serial)) { - $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; - } - - // remove unnecessary close/open tags - $compiled_content = preg_replace('~\?>\n?<\?php~', '', $compiled_content); - - // run compiled template through postfilter functions - if (count($this->_plugins['postfilter']) > 0) { - foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { - if ($postfilter === false) continue; - if ($postfilter[3] || is_callable($postfilter[0])) { - $compiled_content = call_user_func_array($postfilter[0], - array($compiled_content, &$this)); - $this->_plugins['postfilter'][$filter_name][3] = true; - } else { - $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); - } - } - } - - // put header at the top of the compiled template - $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; - $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; - - /* Emit code to load needed plugins. */ - $this->_plugins_code = ''; - if (count($this->_plugin_info)) { - $_plugins_params = "array('plugins' => array("; - foreach ($this->_plugin_info as $plugin_type => $plugins) { - foreach ($plugins as $plugin_name => $plugin_info) { - $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; - $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; - } - } - $_plugins_params .= '))'; - $plugins_code = "\n"; - $template_header .= $plugins_code; - $this->_plugin_info = array(); - $this->_plugins_code = $plugins_code; - } - - if ($this->_init_smarty_vars) { - $template_header .= "\n"; - $this->_init_smarty_vars = false; - } - - $compiled_content = $template_header . $compiled_content; - return true; - } - - /** - * Compile a template tag - * - * @param string $template_tag - * @return string - */ - function _compile_tag($template_tag) - { - /* Matched comment. */ - if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*') - return ''; - - /* Split tag into two three parts: command, command modifiers and the arguments. */ - if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp - . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) - (?:\s+(.*))?$ - ~xs', $template_tag, $match)) { - $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); - } - - $tag_command = $match[1]; - $tag_modifier = isset($match[2]) ? $match[2] : null; - $tag_args = isset($match[3]) ? $match[3] : null; - - if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { - /* tag name is a variable or object */ - $_return = $this->_parse_var_props($tag_command . $tag_modifier); - return "" . $this->_additional_newline; - } - - /* If the tag name is a registered object, we process it. */ - if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { - return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); - } - - switch ($tag_command) { - case 'include': - return $this->_compile_include_tag($tag_args); - - case 'include_php': - return $this->_compile_include_php_tag($tag_args); - - case 'if': - $this->_push_tag('if'); - return $this->_compile_if_tag($tag_args); - - case 'else': - list($_open_tag) = end($this->_tag_stack); - if ($_open_tag != 'if' && $_open_tag != 'elseif') - $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); - else - $this->_push_tag('else'); - return ''; - - case 'elseif': - list($_open_tag) = end($this->_tag_stack); - if ($_open_tag != 'if' && $_open_tag != 'elseif') - $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); - if ($_open_tag == 'if') - $this->_push_tag('elseif'); - return $this->_compile_if_tag($tag_args, true); - - case '/if': - $this->_pop_tag('if'); - return ''; - - case 'capture': - return $this->_compile_capture_tag(true, $tag_args); - - case '/capture': - return $this->_compile_capture_tag(false); - - case 'ldelim': - return $this->left_delimiter; - - case 'rdelim': - return $this->right_delimiter; - - case 'section': - $this->_push_tag('section'); - return $this->_compile_section_start($tag_args); - - case 'sectionelse': - $this->_push_tag('sectionelse'); - return ""; - break; - - case '/section': - $_open_tag = $this->_pop_tag('section'); - if ($_open_tag == 'sectionelse') - return ""; - else - return ""; - - case 'foreach': - $this->_push_tag('foreach'); - return $this->_compile_foreach_start($tag_args); - break; - - case 'foreachelse': - $this->_push_tag('foreachelse'); - return ""; - - case '/foreach': - $_open_tag = $this->_pop_tag('foreach'); - if ($_open_tag == 'foreachelse') - return ""; - else - return ""; - break; - - case 'strip': - case '/strip': - if ($tag_command{0}=='/') { - $this->_pop_tag('strip'); - if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ - $this->_additional_newline = "\n"; - return '{' . $tag_command . '}'; - } - } else { - $this->_push_tag('strip'); - if ($this->_strip_depth++==0) { /* outermost opening {strip} */ - $this->_additional_newline = ""; - return '{' . $tag_command . '}'; - } - } - return ''; - - case 'php': - /* handle folded tags replaced by {php} */ - list(, $block) = each($this->_folded_blocks); - $this->_current_line_no += substr_count($block[0], "\n"); - /* the number of matched elements in the regexp in _compile_file() - determins the type of folded tag that was found */ - switch (count($block)) { - case 2: /* comment */ - return ''; - - case 3: /* literal */ - return ""\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; - - case 4: /* php */ - if ($this->security && !$this->security_settings['PHP_TAGS']) { - $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); - return; - } - return ''; - } - break; - - case 'insert': - return $this->_compile_insert_tag($tag_args); - - default: - if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { - return $output; - } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { - return $output; - } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { - return $output; - } else { - $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); - } - - } - } - - - /** - * compile the custom compiler tag - * - * sets $output to the compiled custom compiler tag - * @param string $tag_command - * @param string $tag_args - * @param string $output - * @return boolean - */ - function _compile_compiler_tag($tag_command, $tag_args, &$output) - { - $found = false; - $have_function = true; - - /* - * First we check if the compiler function has already been registered - * or loaded from a plugin file. - */ - if (isset($this->_plugins['compiler'][$tag_command])) { - $found = true; - $plugin_func = $this->_plugins['compiler'][$tag_command][0]; - if (!is_callable($plugin_func)) { - $message = "compiler function '$tag_command' is not implemented"; - $have_function = false; - } - } - /* - * Otherwise we need to load plugin file and look for the function - * inside it. - */ - else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { - $found = true; - - include_once $plugin_file; - - $plugin_func = 'smarty_compiler_' . $tag_command; - if (!is_callable($plugin_func)) { - $message = "plugin function $plugin_func() not found in $plugin_file\n"; - $have_function = false; - } else { - $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); - } - } - - /* - * True return value means that we either found a plugin or a - * dynamically registered function. False means that we didn't and the - * compiler should now emit code to load custom function plugin for this - * tag. - */ - if ($found) { - if ($have_function) { - $output = call_user_func_array($plugin_func, array($tag_args, &$this)); - if($output != '') { - $output = '_push_cacheable_state('compiler', $tag_command) - . $output - . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; - } - } else { - $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); - } - return true; - } else { - return false; - } - } - - - /** - * compile block function tag - * - * sets $output to compiled block function tag - * @param string $tag_command - * @param string $tag_args - * @param string $tag_modifier - * @param string $output - * @return boolean - */ - function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) - { - if ($tag_command{0} == '/') { - $start_tag = false; - $tag_command = substr($tag_command, 1); - } else - $start_tag = true; - - $found = false; - $have_function = true; - - /* - * First we check if the block function has already been registered - * or loaded from a plugin file. - */ - if (isset($this->_plugins['block'][$tag_command])) { - $found = true; - $plugin_func = $this->_plugins['block'][$tag_command][0]; - if (!is_callable($plugin_func)) { - $message = "block function '$tag_command' is not implemented"; - $have_function = false; - } - } - /* - * Otherwise we need to load plugin file and look for the function - * inside it. - */ - else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { - $found = true; - - include_once $plugin_file; - - $plugin_func = 'smarty_block_' . $tag_command; - if (!function_exists($plugin_func)) { - $message = "plugin function $plugin_func() not found in $plugin_file\n"; - $have_function = false; - } else { - $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); - - } - } - - if (!$found) { - return false; - } else if (!$have_function) { - $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); - return true; - } - - /* - * Even though we've located the plugin function, compilation - * happens only once, so the plugin will still need to be loaded - * at runtime for future requests. - */ - $this->_add_plugin('block', $tag_command); - - if ($start_tag) - $this->_push_tag($tag_command); - else - $this->_pop_tag($tag_command); - - if ($start_tag) { - $output = '_push_cacheable_state('block', $tag_command); - $attrs = $this->_parse_attrs($tag_args); - $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs=''); - $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; - $output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);'; - $output .= 'while ($_block_repeat) { ob_start(); ?>'; - } else { - $output = '_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat=false)'; - if ($tag_modifier != '') { - $this->_parse_modifiers($_out_tag_text, $tag_modifier); - } - $output .= 'echo '.$_out_tag_text.'; } '; - $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; - } - - return true; - } - - - /** - * compile custom function tag - * - * @param string $tag_command - * @param string $tag_args - * @param string $tag_modifier - * @return string - */ - function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) - { - $found = false; - $have_function = true; - - /* - * First we check if the custom function has already been registered - * or loaded from a plugin file. - */ - if (isset($this->_plugins['function'][$tag_command])) { - $found = true; - $plugin_func = $this->_plugins['function'][$tag_command][0]; - if (!is_callable($plugin_func)) { - $message = "custom function '$tag_command' is not implemented"; - $have_function = false; - } - } - /* - * Otherwise we need to load plugin file and look for the function - * inside it. - */ - else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { - $found = true; - - include_once $plugin_file; - - $plugin_func = 'smarty_function_' . $tag_command; - if (!function_exists($plugin_func)) { - $message = "plugin function $plugin_func() not found in $plugin_file\n"; - $have_function = false; - } else { - $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); - - } - } - - if (!$found) { - return false; - } else if (!$have_function) { - $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); - return true; - } - - /* declare plugin to be loaded on display of the template that - we compile right now */ - $this->_add_plugin('function', $tag_command); - - $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); - $attrs = $this->_parse_attrs($tag_args); - $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs=''); - - $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; - if($tag_modifier != '') { - $this->_parse_modifiers($output, $tag_modifier); - } - - if($output != '') { - $output = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; - } - - return true; - } - - /** - * compile a registered object tag - * - * @param string $tag_command - * @param array $attrs - * @param string $tag_modifier - * @return string - */ - function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) - { - if ($tag_command{0} == '/') { - $start_tag = false; - $tag_command = substr($tag_command, 1); - } else { - $start_tag = true; - } - - list($object, $obj_comp) = explode('->', $tag_command); - - $arg_list = array(); - if(count($attrs)) { - $_assign_var = false; - foreach ($attrs as $arg_name => $arg_value) { - if($arg_name == 'assign') { - $_assign_var = $arg_value; - unset($attrs['assign']); - continue; - } - if (is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - $arg_list[] = "'$arg_name' => $arg_value"; - } - } - - if($this->_reg_objects[$object][2]) { - // smarty object argument format - $args = "array(".implode(',', (array)$arg_list)."), \$this"; - } else { - // traditional argument format - $args = implode(',', array_values($attrs)); - if (empty($args)) { - $args = 'null'; - } - } - - $prefix = ''; - $postfix = ''; - $newline = ''; - if(!is_object($this->_reg_objects[$object][0])) { - $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); - } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { - $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); - } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { - // method - if(in_array($obj_comp, $this->_reg_objects[$object][3])) { - // block method - if ($start_tag) { - $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; - $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); "; - $prefix .= "while (\$_block_repeat) { ob_start();"; - $return = null; - $postfix = ''; - } else { - $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); "; - $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat=false)"; - $postfix = "} array_pop(\$this->_tag_stack);"; - } - } else { - // non-block method - $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; - } - } else { - // property - $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; - } - - if($return != null) { - if($tag_modifier != '') { - $this->_parse_modifiers($return, $tag_modifier); - } - - if(!empty($_assign_var)) { - $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; - } else { - $output = 'echo ' . $return . ';'; - $newline = $this->_additional_newline; - } - } else { - $output = ''; - } - - return '" . $newline; - } - - /** - * Compile {insert ...} tag - * - * @param string $tag_args - * @return string - */ - function _compile_insert_tag($tag_args) - { - $attrs = $this->_parse_attrs($tag_args); - $name = $this->_dequote($attrs['name']); - - if (empty($name)) { - $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); - } - - if (!empty($attrs['script'])) { - $delayed_loading = true; - } else { - $delayed_loading = false; - } - - foreach ($attrs as $arg_name => $arg_value) { - if (is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - $arg_list[] = "'$arg_name' => $arg_value"; - } - - $this->_add_plugin('insert', $name, $delayed_loading); - - $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; - - return "" . $this->_additional_newline; - } - - /** - * Compile {include ...} tag - * - * @param string $tag_args - * @return string - */ - function _compile_include_tag($tag_args) - { - $attrs = $this->_parse_attrs($tag_args); - $arg_list = array(); - - if (empty($attrs['file'])) { - $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); - } - - foreach ($attrs as $arg_name => $arg_value) { - if ($arg_name == 'file') { - $include_file = $arg_value; - continue; - } else if ($arg_name == 'assign') { - $assign_var = $arg_value; - continue; - } - if (is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - $arg_list[] = "'$arg_name' => $arg_value"; - } - - $output = '_tpl_vars;\n"; - - - $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; - $output .= "\$this->_smarty_include($_params);\n" . - "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . - "unset(\$_smarty_tpl_vars);\n"; - - if (isset($assign_var)) { - $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; - } - - $output .= ' ?>'; - - return $output; - - } - - /** - * Compile {include ...} tag - * - * @param string $tag_args - * @return string - */ - function _compile_include_php_tag($tag_args) - { - $attrs = $this->_parse_attrs($tag_args); - - if (empty($attrs['file'])) { - $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); - } - - $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); - $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; - - $arg_list = array(); - foreach($attrs as $arg_name => $arg_value) { - if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { - if(is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - $arg_list[] = "'$arg_name' => $arg_value"; - } - } - - $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; - - return "" . $this->_additional_newline; - } - - - /** - * Compile {section ...} tag - * - * @param string $tag_args - * @return string - */ - function _compile_section_start($tag_args) - { - $attrs = $this->_parse_attrs($tag_args); - $arg_list = array(); - - $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); - } - - $output .= "unset(\$this->_sections[$section_name]);\n"; - $section_props = "\$this->_sections[$section_name]"; - - foreach ($attrs as $attr_name => $attr_value) { - switch ($attr_name) { - case 'loop': - $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; - break; - - case 'show': - if (is_bool($attr_value)) - $show_attr_value = $attr_value ? 'true' : 'false'; - else - $show_attr_value = "(bool)$attr_value"; - $output .= "{$section_props}['show'] = $show_attr_value;\n"; - break; - - case 'name': - $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; - break; - - case 'max': - case 'start': - $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; - break; - - case 'step': - $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; - break; - - default: - $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); - break; - } - } - - if (!isset($attrs['show'])) - $output .= "{$section_props}['show'] = true;\n"; - - if (!isset($attrs['loop'])) - $output .= "{$section_props}['loop'] = 1;\n"; - - if (!isset($attrs['max'])) - $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; - else - $output .= "if ({$section_props}['max'] < 0)\n" . - " {$section_props}['max'] = {$section_props}['loop'];\n"; - - if (!isset($attrs['step'])) - $output .= "{$section_props}['step'] = 1;\n"; - - if (!isset($attrs['start'])) - $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; - else { - $output .= "if ({$section_props}['start'] < 0)\n" . - " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . - "else\n" . - " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; - } - - $output .= "if ({$section_props}['show']) {\n"; - if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { - $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; - } else { - $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; - } - $output .= " if ({$section_props}['total'] == 0)\n" . - " {$section_props}['show'] = false;\n" . - "} else\n" . - " {$section_props}['total'] = 0;\n"; - - $output .= "if ({$section_props}['show']):\n"; - $output .= " - for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; - {$section_props}['iteration'] <= {$section_props}['total']; - {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; - $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; - $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; - $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; - $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; - $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; - - $output .= "?>"; - - return $output; - } - - - /** - * Compile {foreach ...} tag. - * - * @param string $tag_args - * @return string - */ - function _compile_foreach_start($tag_args) - { - $attrs = $this->_parse_attrs($tag_args); - $arg_list = array(); - - if (empty($attrs['from'])) { - return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); - } - $from = $attrs['from']; - - if (empty($attrs['item'])) { - return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); - } - $item = $this->_dequote($attrs['item']); - if (!preg_match('~^\w+$~', $item)) { - return $this->_syntax_error("'foreach: item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); - } - - if (isset($attrs['key'])) { - $key = $this->_dequote($attrs['key']); - if (!preg_match('~^\w+$~', $key)) { - return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); - } - $key_part = "\$this->_tpl_vars['$key'] => "; - } else { - $key = null; - $key_part = ''; - } - - if (isset($attrs['name'])) { - $name = $attrs['name']; - } else { - $name = null; - } - - $output = '_foreach[$name]"; - $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; - $output .= "if ({$foreach_props}['total'] > 0):\n"; - $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; - $output .= " {$foreach_props}['iteration']++;\n"; - } else { - $output .= "if (count(\$_from)):\n"; - $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; - } - $output .= '?>'; - - return $output; - } - - - /** - * Compile {capture} .. {/capture} tags - * - * @param boolean $start true if this is the {capture} tag - * @param string $tag_args - * @return string - */ - - function _compile_capture_tag($start, $tag_args = '') - { - $attrs = $this->_parse_attrs($tag_args); - - if ($start) { - if (isset($attrs['name'])) - $buffer = $attrs['name']; - else - $buffer = "'default'"; - - if (isset($attrs['assign'])) - $assign = $attrs['assign']; - else - $assign = null; - $output = ""; - $this->_capture_stack[] = array($buffer, $assign); - } else { - list($buffer, $assign) = array_pop($this->_capture_stack); - $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; - if (isset($assign)) { - $output .= " \$this->assign($assign, ob_get_contents());"; - } - $output .= "ob_end_clean(); ?>"; - } - - return $output; - } - - /** - * Compile {if ...} tag - * - * @param string $tag_args - * @param boolean $elseif if true, uses elseif instead of if - * @return string - */ - function _compile_if_tag($tag_args, $elseif = false) - { - - /* Tokenize args for 'if' tag. */ - preg_match_all('~(?> - ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call - ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string - \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token - \b\w+\b | # valid word token - \S+ # anything else - )~x', $tag_args, $match); - - $tokens = $match[0]; - - // make sure we have balanced parenthesis - $token_count = array_count_values($tokens); - if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { - $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); - } - - $is_arg_stack = array(); - - for ($i = 0; $i < count($tokens); $i++) { - - $token = &$tokens[$i]; - - switch (strtolower($token)) { - case '!': - case '%': - case '!==': - case '==': - case '===': - case '>': - case '<': - case '!=': - case '<>': - case '<<': - case '>>': - case '<=': - case '>=': - case '&&': - case '||': - case '|': - case '^': - case '&': - case '~': - case ')': - case ',': - case '+': - case '-': - case '*': - case '/': - case '@': - break; - - case 'eq': - $token = '=='; - break; - - case 'ne': - case 'neq': - $token = '!='; - break; - - case 'lt': - $token = '<'; - break; - - case 'le': - case 'lte': - $token = '<='; - break; - - case 'gt': - $token = '>'; - break; - - case 'ge': - case 'gte': - $token = '>='; - break; - - case 'and': - $token = '&&'; - break; - - case 'or': - $token = '||'; - break; - - case 'not': - $token = '!'; - break; - - case 'mod': - $token = '%'; - break; - - case '(': - array_push($is_arg_stack, $i); - break; - - case 'is': - /* If last token was a ')', we operate on the parenthesized - expression. The start of the expression is on the stack. - Otherwise, we operate on the last encountered token. */ - if ($tokens[$i-1] == ')') - $is_arg_start = array_pop($is_arg_stack); - else - $is_arg_start = $i-1; - /* Construct the argument for 'is' expression, so it knows - what to operate on. */ - $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); - - /* Pass all tokens from next one until the end to the - 'is' expression parsing function. The function will - return modified tokens, where the first one is the result - of the 'is' expression and the rest are the tokens it - didn't touch. */ - $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); - - /* Replace the old tokens with the new ones. */ - array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); - - /* Adjust argument start so that it won't change from the - current position for the next iteration. */ - $i = $is_arg_start; - break; - - default: - if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { - // function call - if($this->security && - !in_array($token, $this->security_settings['IF_FUNCS'])) { - $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); - } - } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { - // variable function call - $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); - } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { - // object or variable - $token = $this->_parse_var_props($token); - } elseif(is_numeric($token)) { - // number, skip it - } else { - $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); - } - break; - } - } - - if ($elseif) - return ''; - else - return ''; - } - - - function _compile_arg_list($type, $name, $attrs, &$cache_code) { - $arg_list = array(); - - if (isset($type) && isset($name) - && isset($this->_plugins[$type]) - && isset($this->_plugins[$type][$name]) - && empty($this->_plugins[$type][$name][4]) - && is_array($this->_plugins[$type][$name][5]) - ) { - /* we have a list of parameters that should be cached */ - $_cache_attrs = $this->_plugins[$type][$name][5]; - $_count = $this->_cache_attrs_count++; - $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; - - } else { - /* no parameters are cached */ - $_cache_attrs = null; - } - - foreach ($attrs as $arg_name => $arg_value) { - if (is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - if (is_null($arg_value)) - $arg_value = 'null'; - if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { - $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; - } else { - $arg_list[] = "'$arg_name' => $arg_value"; - } - } - return $arg_list; - } - - /** - * Parse is expression - * - * @param string $is_arg - * @param array $tokens - * @return array - */ - function _parse_is_expr($is_arg, $tokens) - { - $expr_end = 0; - $negate_expr = false; - - if (($first_token = array_shift($tokens)) == 'not') { - $negate_expr = true; - $expr_type = array_shift($tokens); - } else - $expr_type = $first_token; - - switch ($expr_type) { - case 'even': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; - } else - $expr = "!(1 & $is_arg)"; - break; - - case 'odd': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; - } else - $expr = "(1 & $is_arg)"; - break; - - case 'div': - if (@$tokens[$expr_end] == 'by') { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; - } else { - $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); - } - break; - - default: - $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); - break; - } - - if ($negate_expr) { - $expr = "!($expr)"; - } - - array_splice($tokens, 0, $expr_end, $expr); - - return $tokens; - } - - - /** - * Parse attribute string - * - * @param string $tag_args - * @return array - */ - function _parse_attrs($tag_args) - { - - /* Tokenize tag attributes. */ - preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) - )+ | - [=] - ~x', $tag_args, $match); - $tokens = $match[0]; - - $attrs = array(); - /* Parse state: - 0 - expecting attribute name - 1 - expecting '=' - 2 - expecting attribute value (not '=') */ - $state = 0; - - foreach ($tokens as $token) { - switch ($state) { - case 0: - /* If the token is a valid identifier, we set attribute name - and go to state 1. */ - if (preg_match('~^\w+$~', $token)) { - $attr_name = $token; - $state = 1; - } else - $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); - break; - - case 1: - /* If the token is '=', then we go to state 2. */ - if ($token == '=') { - $state = 2; - } else - $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); - break; - - case 2: - /* If token is not '=', we set the attribute value and go to - state 0. */ - if ($token != '=') { - /* We booleanize the token if it's a non-quoted possible - boolean value. */ - if (preg_match('~^(on|yes|true)$~', $token)) { - $token = 'true'; - } else if (preg_match('~^(off|no|false)$~', $token)) { - $token = 'false'; - } else if ($token == 'null') { - $token = 'null'; - } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { - /* treat integer literally */ - } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { - /* treat as a string, double-quote it escaping quotes */ - $token = '"'.addslashes($token).'"'; - } - - $attrs[$attr_name] = $token; - $state = 0; - } else - $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); - break; - } - $last_token = $token; - } - - if($state != 0) { - if($state == 1) { - $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); - } else { - $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); - } - } - - $this->_parse_vars_props($attrs); - - return $attrs; - } - - /** - * compile multiple variables and section properties tokens into - * PHP code - * - * @param array $tokens - */ - function _parse_vars_props(&$tokens) - { - foreach($tokens as $key => $val) { - $tokens[$key] = $this->_parse_var_props($val); - } - } - - /** - * compile single variable and section properties token into - * PHP code - * - * @param string $val - * @param string $tag_attrs - * @return string - */ - function _parse_var_props($val) - { - $val = trim($val); - - if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { - // $ variable or object - $return = $this->_parse_var($match[1]); - $modifiers = $match[2]; - if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { - $_default_mod_string = implode('|',(array)$this->default_modifiers); - $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; - } - $this->_parse_modifiers($return, $modifiers); - return $return; - } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { - // double quoted text - preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); - $return = $this->_expand_quoted_text($match[1]); - if($match[2] != '') { - $this->_parse_modifiers($return, $match[2]); - } - return $return; - } - elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { - // numerical constant - preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); - if($match[2] != '') { - $this->_parse_modifiers($match[1], $match[2]); - return $match[1]; - } - } - elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { - // single quoted text - preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); - if($match[2] != '') { - $this->_parse_modifiers($match[1], $match[2]); - return $match[1]; - } - } - elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { - // config var - return $this->_parse_conf_var($val); - } - elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { - // section var - return $this->_parse_section_prop($val); - } - elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { - // literal string - return $this->_expand_quoted_text('"' . $val .'"'); - } - return $val; - } - - /** - * expand quoted text with embedded variables - * - * @param string $var_expr - * @return string - */ - function _expand_quoted_text($var_expr) - { - // if contains unescaped $, expand it - if(preg_match_all('~(?:\`(?_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."', $var_expr); - } - $_return = preg_replace('~\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); - - if(count($_math_vars) > 1) { - $_first_var = ""; - $_complete_var = ""; - $_output = ""; - // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) - foreach($_math_vars as $_k => $_math_var) { - $_math_var = $_math_vars[$_k]; - - if(!empty($_math_var) || is_numeric($_math_var)) { - // hit a math operator, so process the stuff which came before it - if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { - $_has_math = true; - if(!empty($_complete_var) || is_numeric($_complete_var)) { - $_output .= $this->_parse_var($_complete_var); - } - - // just output the math operator to php - $_output .= $_math_var; - - if(empty($_first_var)) - $_first_var = $_complete_var; - - $_complete_var = ""; - } else { - $_complete_var .= $_math_var; - } - } - } - if($_has_math) { - if(!empty($_complete_var) || is_numeric($_complete_var)) - $_output .= $this->_parse_var($_complete_var); - - // get the modifiers working (only the last var from math + modifier is left) - $var_expr = $_complete_var; - } - } - - // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) - if(is_numeric($var_expr{0})) - $_var_ref = $var_expr; - else - $_var_ref = substr($var_expr, 1); - - if(!$_has_math) { - - // get [foo] and .foo and ->foo and (...) pieces - preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); - - $_indexes = $match[0]; - $_var_name = array_shift($_indexes); - - /* Handle $smarty.* variable references as a special case. */ - if ($_var_name == 'smarty') { - /* - * If the reference could be compiled, use the compiled output; - * otherwise, fall back on the $smarty variable generated at - * run-time. - */ - if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { - $_output = $smarty_ref; - } else { - $_var_name = substr(array_shift($_indexes), 1); - $_output = "\$this->_smarty_vars['$_var_name']"; - } - } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) { - // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers - if(count($_indexes) > 0) - { - $_var_name .= implode("", $_indexes); - $_indexes = array(); - } - $_output = $_var_name; - } else { - $_output = "\$this->_tpl_vars['$_var_name']"; - } - - foreach ($_indexes as $_index) { - if ($_index{0} == '[') { - $_index = substr($_index, 1, -1); - if (is_numeric($_index)) { - $_output .= "[$_index]"; - } elseif ($_index{0} == '$') { - if (strpos($_index, '.') !== false) { - $_output .= '[' . $this->_parse_var($_index) . ']'; - } else { - $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; - } - } else { - $_var_parts = explode('.', $_index); - $_var_section = $_var_parts[0]; - $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; - $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; - } - } else if ($_index{0} == '.') { - if ($_index{1} == '$') - $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; - else - $_output .= "['" . substr($_index, 1) . "']"; - } else if (substr($_index,0,2) == '->') { - if(substr($_index,2,2) == '__') { - $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); - } elseif($this->security && substr($_index, 2, 1) == '_') { - $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); - } elseif ($_index{2} == '$') { - if ($this->security) { - $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); - } else { - $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; - } - } else { - $_output .= $_index; - } - } elseif ($_index{0} == '(') { - $_index = $this->_parse_parenth_args($_index); - $_output .= $_index; - } else { - $_output .= $_index; - } - } - } - - return $_output; - } - - /** - * parse arguments in function call parenthesis - * - * @param string $parenth_args - * @return string - */ - function _parse_parenth_args($parenth_args) - { - preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); - $orig_vals = $match = $match[0]; - $this->_parse_vars_props($match); - $replace = array(); - for ($i = 0, $count = count($match); $i < $count; $i++) { - $replace[$orig_vals[$i]] = $match[$i]; - } - return strtr($parenth_args, $replace); - } - - /** - * parse configuration variable expression into PHP code - * - * @param string $conf_var_expr - */ - function _parse_conf_var($conf_var_expr) - { - $parts = explode('|', $conf_var_expr, 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; - - $var_name = substr($var_ref, 1, -1); - - $output = "\$this->_config[0]['vars']['$var_name']"; - - $this->_parse_modifiers($output, $modifiers); - - return $output; - } - - /** - * parse section property expression into PHP code - * - * @param string $section_prop_expr - * @return string - */ - function _parse_section_prop($section_prop_expr) - { - $parts = explode('|', $section_prop_expr, 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; - - preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); - $section_name = $match[1]; - $prop_name = $match[2]; - - $output = "\$this->_sections['$section_name']['$prop_name']"; - - $this->_parse_modifiers($output, $modifiers); - - return $output; - } - - - /** - * parse modifier chain into PHP code - * - * sets $output to parsed modified chain - * @param string $output - * @param string $modifier_string - */ - function _parse_modifiers(&$output, $modifier_string) - { - preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); - list(, $_modifiers, $modifier_arg_strings) = $_match; - - for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { - $_modifier_name = $_modifiers[$_i]; - - if($_modifier_name == 'smarty') { - // skip smarty modifier - continue; - } - - preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); - $_modifier_args = $_match[1]; - - if ($_modifier_name{0} == '@') { - $_map_array = false; - $_modifier_name = substr($_modifier_name, 1); - } else { - $_map_array = true; - } - - if (empty($this->_plugins['modifier'][$_modifier_name]) - && !$this->_get_plugin_filepath('modifier', $_modifier_name) - && function_exists($_modifier_name)) { - if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { - $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); - } else { - $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); - } - } - $this->_add_plugin('modifier', $_modifier_name); - - $this->_parse_vars_props($_modifier_args); - - if($_modifier_name == 'default') { - // supress notifications of default modifier vars and args - if($output{0} == '$') { - $output = '@' . $output; - } - if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') { - $_modifier_args[0] = '@' . $_modifier_args[0]; - } - } - if (count($_modifier_args) > 0) - $_modifier_args = ', '.implode(', ', $_modifier_args); - else - $_modifier_args = ''; - - if ($_map_array) { - $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; - - } else { - - $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; - - } - } - } - - - /** - * add plugin - * - * @param string $type - * @param string $name - * @param boolean? $delayed_loading - */ - function _add_plugin($type, $name, $delayed_loading = null) - { - if (!isset($this->_plugin_info[$type])) { - $this->_plugin_info[$type] = array(); - } - if (!isset($this->_plugin_info[$type][$name])) { - $this->_plugin_info[$type][$name] = array($this->_current_file, - $this->_current_line_no, - $delayed_loading); - } - } - - - /** - * Compiles references of type $smarty.foo - * - * @param string $indexes - * @return string - */ - function _compile_smarty_ref(&$indexes) - { - /* Extract the reference name. */ - $_ref = substr($indexes[0], 1); - foreach($indexes as $_index_no=>$_index) { - if ($_index{0} != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { - $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); - } - } - - switch ($_ref) { - case 'now': - $compiled_ref = 'time()'; - $_max_index = 1; - break; - - case 'foreach': - array_shift($indexes); - $_var = $this->_parse_var_props(substr($indexes[0], 1)); - $_propname = substr($indexes[1], 1); - $_max_index = 1; - switch ($_propname) { - case 'index': - array_shift($indexes); - $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; - break; - - case 'first': - array_shift($indexes); - $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; - break; - - case 'last': - array_shift($indexes); - $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; - break; - - case 'show': - array_shift($indexes); - $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; - break; - - default: - unset($_max_index); - $compiled_ref = "\$this->_foreach[$_var]"; - } - break; - - case 'section': - array_shift($indexes); - $_var = $this->_parse_var_props(substr($indexes[0], 1)); - $compiled_ref = "\$this->_sections[$_var]"; - break; - - case 'get': - $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; - break; - - case 'post': - $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; - break; - - case 'cookies': - $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; - break; - - case 'env': - $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; - break; - - case 'server': - $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; - break; - - case 'session': - $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; - break; - - /* - * These cases are handled either at run-time or elsewhere in the - * compiler. - */ - case 'request': - if ($this->request_use_auto_globals) { - $compiled_ref = '$_REQUEST'; - break; - } else { - $this->_init_smarty_vars = true; - } - return null; - - case 'capture': - return null; - - case 'template': - $compiled_ref = "'$this->_current_file'"; - $_max_index = 1; - break; - - case 'version': - $compiled_ref = "'$this->_version'"; - $_max_index = 1; - break; - - case 'const': - if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { - $this->_syntax_error("(secure mode) constants not permitted", - E_USER_WARNING, __FILE__, __LINE__); - return; - } - array_shift($indexes); - if (preg_match('!^\.\w+$!', $indexes[0])) { - $compiled_ref = '@' . substr($indexes[0], 1); - } else { - $_val = $this->_parse_var_props(substr($indexes[0], 1)); - $compiled_ref = '@constant(' . $_val . ')'; - } - $_max_index = 1; - break; - - case 'config': - $compiled_ref = "\$this->_config[0]['vars']"; - $_max_index = 3; - break; - - case 'ldelim': - $compiled_ref = "'$this->left_delimiter'"; - break; - - case 'rdelim': - $compiled_ref = "'$this->right_delimiter'"; - break; - - default: - $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); - break; - } - - if (isset($_max_index) && count($indexes) > $_max_index) { - $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); - } - - array_shift($indexes); - return $compiled_ref; - } - - /** - * compiles call to plugin of type $type with name $name - * returns a string containing the function-name or method call - * without the paramter-list that would have follow to make the - * call valid php-syntax - * - * @param string $type - * @param string $name - * @return string - */ - function _compile_plugin_call($type, $name) { - if (isset($this->_plugins[$type][$name])) { - /* plugin loaded */ - if (is_array($this->_plugins[$type][$name][0])) { - return ((is_object($this->_plugins[$type][$name][0][0])) ? - "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ - : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ - ). $this->_plugins[$type][$name][0][1]; - - } else { - /* function callback */ - return $this->_plugins[$type][$name][0]; - - } - } else { - /* plugin not loaded -> auto-loadable-plugin */ - return 'smarty_'.$type.'_'.$name; - - } - } - - /** - * load pre- and post-filters - */ - function _load_filters() - { - if (count($this->_plugins['prefilter']) > 0) { - foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { - if ($prefilter === false) { - unset($this->_plugins['prefilter'][$filter_name]); - $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); - require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); - smarty_core_load_plugins($_params, $this); - } - } - } - if (count($this->_plugins['postfilter']) > 0) { - foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { - if ($postfilter === false) { - unset($this->_plugins['postfilter'][$filter_name]); - $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); - require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); - smarty_core_load_plugins($_params, $this); - } - } - } - } - - - /** - * Quote subpattern references - * - * @param string $string - * @return string - */ - function _quote_replace($string) - { - return strtr($string, array('\\' => '\\\\', '$' => '\\$')); - } - - /** - * display Smarty syntax error - * - * @param string $error_msg - * @param integer $error_type - * @param string $file - * @param integer $line - */ - function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) - { - $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); - } - - - /** - * check if the compilation changes from cacheable to - * non-cacheable state with the beginning of the current - * plugin. return php-code to reflect the transition. - * @return string - */ - function _push_cacheable_state($type, $name) { - $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; - if ($_cacheable - || 0<$this->_cacheable_state++) return ''; - if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); - $_ret = 'if ($this->caching && !$this->_cache_including) { echo \'{nocache:' - . $this->_cache_serial . '#' . $this->_nocache_count - . '}\';}'; - return $_ret; - } - - - /** - * check if the compilation changes from non-cacheable to - * cacheable state with the end of the current plugin return - * php-code to reflect the transition. - * @return string - */ - function _pop_cacheable_state($type, $name) { - $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; - if ($_cacheable - || --$this->_cacheable_state>0) return ''; - return 'if ($this->caching && !$this->_cache_including) { echo \'{/nocache:' - . $this->_cache_serial . '#' . ($this->_nocache_count++) - . '}\';}'; - } - - - /** - * push opening tag-name, file-name and line-number on the tag-stack - * @param string the opening tag's name - */ - function _push_tag($open_tag) - { - array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); - } - - /** - * pop closing tag-name - * raise an error if this stack-top doesn't match with the closing tag - * @param string the closing tag's name - * @return string the opening tag's name - */ - function _pop_tag($close_tag) - { - $message = ''; - if (count($this->_tag_stack)>0) { - list($_open_tag, $_line_no) = array_pop($this->_tag_stack); - if ($close_tag == $_open_tag) { - return $_open_tag; - } - if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { - return $this->_pop_tag($close_tag); - } - if ($close_tag == 'section' && $_open_tag == 'sectionelse') { - $this->_pop_tag($close_tag); - return $_open_tag; - } - if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { - $this->_pop_tag($close_tag); - return $_open_tag; - } - if ($_open_tag == 'else' || $_open_tag == 'elseif') { - $_open_tag = 'if'; - } elseif ($_open_tag == 'sectionelse') { - $_open_tag = 'section'; - } elseif ($_open_tag == 'foreachelse') { - $_open_tag = 'foreach'; - } - $message = " expected {/$_open_tag} (opened line $_line_no)."; - } - $this->_syntax_error("mismatched tag {/$close_tag}.$message", - E_USER_ERROR, __FILE__, __LINE__); - } - -} - -/** - * compare to values by their string length - * - * @access private - * @param string $a - * @param string $b - * @return 0|-1|1 - */ -function _smarty_sort_length($a, $b) -{ - if($a == $b) - return 0; - - if(strlen($a) == strlen($b)) - return ($a > $b) ? -1 : 1; - - return (strlen($a) > strlen($b)) ? -1 : 1; -} - - -/* vim: set et: */ - -?> + + * @author Andrei Zmievski + * @version 2.6.25-dev + * @copyright 2001-2005 New Digital Group, Inc. + * @package Smarty + */ + +/* $Id: Smarty_Compiler.class.php 4779 2013-09-30 19:14:32Z Uwe.Tews@googlemail.com $ */ + +/** + * Template compiling class + * @package Smarty + */ +class Smarty_Compiler extends Smarty { + + // internal vars + /**#@+ + * @access private + */ + var $_folded_blocks = array(); // keeps folded template blocks + var $_current_file = null; // the current template being compiled + var $_current_line_no = 1; // line number for error messages + var $_capture_stack = array(); // keeps track of nested capture buffers + var $_plugin_info = array(); // keeps track of plugins to load + var $_init_smarty_vars = false; + var $_permitted_tokens = array('true','false','yes','no','on','off','null'); + var $_db_qstr_regexp = null; // regexps are setup in the constructor + var $_si_qstr_regexp = null; + var $_qstr_regexp = null; + var $_func_regexp = null; + var $_reg_obj_regexp = null; + var $_var_bracket_regexp = null; + var $_num_const_regexp = null; + var $_dvar_guts_regexp = null; + var $_dvar_regexp = null; + var $_cvar_regexp = null; + var $_svar_regexp = null; + var $_avar_regexp = null; + var $_mod_regexp = null; + var $_var_regexp = null; + var $_parenth_param_regexp = null; + var $_func_call_regexp = null; + var $_obj_ext_regexp = null; + var $_obj_start_regexp = null; + var $_obj_params_regexp = null; + var $_obj_call_regexp = null; + var $_cacheable_state = 0; + var $_cache_attrs_count = 0; + var $_nocache_count = 0; + var $_cache_serial = null; + var $_cache_include = null; + + var $_strip_depth = 0; + var $_additional_newline = "\n"; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty_Compiler() + { + // matches double quoted strings: + // "foobar" + // "foo\"bar" + $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; + + // matches single quoted strings: + // 'foobar' + // 'foo\'bar' + $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; + + // matches single or double quoted strings + $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; + + // matches bracket portion of vars + // [0] + // [foo] + // [$bar] + $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; + + // matches numerical constants + // 30 + // -12 + // 13.22 + $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; + + // matches $ vars (not objects): + // $foo + // $foo.bar + // $foo.bar.foobar + // $foo[0] + // $foo[$bar] + // $foo[5][blah] + // $foo[5].bar[$foobar][4] + $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; + $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; + $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp + . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; + $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; + + // matches config vars: + // #foo# + // #foobar123_foo# + $this->_cvar_regexp = '\#\w+\#'; + + // matches section vars: + // %foo.bar% + $this->_svar_regexp = '\%\w+\.\w+\%'; + + // matches all valid variables (no quotes, no modifiers) + $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' + . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; + + // matches valid variable syntax: + // $foo + // $foo + // #foo# + // #foo# + // "text" + // "text" + $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; + + // matches valid object call (one level of object nesting allowed in parameters): + // $foo->bar + // $foo->bar() + // $foo->bar("text") + // $foo->bar($foo, $bar, "text") + // $foo->bar($foo, "foo") + // $foo->bar->foo() + // $foo->bar->foo->bar() + // $foo->bar($foo->bar) + // $foo->bar($foo->bar()) + // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) + $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; + $this->_obj_restricted_param_regexp = '(?:' + . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' + . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; + $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; + $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp + . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; + $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; + $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; + + // matches valid modifier syntax: + // |foo + // |@foo + // |foo:"bar" + // |foo:$bar + // |foo:"bar":$foobar + // |foo|bar + // |foo:$foo->bar + $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' + . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; + + // matches valid function name: + // foo123 + // _foo_bar + $this->_func_regexp = '[a-zA-Z_]\w*'; + + // matches valid registered object: + // foo->bar + $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; + + // matches valid parameter values: + // true + // $foo + // $foo|bar + // #foo# + // #foo#|bar + // "text" + // "text"|bar + // $foo->bar + $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' + . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; + + // matches valid parenthesised function parameters: + // + // "text" + // $foo, $bar, "text" + // $foo|bar, "foo"|bar, $foo->bar($foo)|bar + $this->_parenth_param_regexp = '(?:\((?:\w+|' + . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_param_regexp . ')))*)?\))'; + + // matches valid function call: + // foo() + // foo_bar($foo) + // _foo_bar($foo,"bar") + // foo123($foo,$foo->bar(),"foo") + $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' + . $this->_parenth_param_regexp . '))'; + } + + /** + * compile a resource + * + * sets $compiled_content to the compiled source + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return true + */ + function _compile_file($resource_name, $source_content, &$compiled_content) + { + + if ($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + + $this->_load_filters(); + + $this->_current_file = $resource_name; + $this->_current_line_no = 1; + $ldq = preg_quote($this->left_delimiter, '~'); + $rdq = preg_quote($this->right_delimiter, '~'); + + // run template source through prefilter functions + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) continue; + if ($prefilter[3] || is_callable($prefilter[0])) { + $source_content = call_user_func_array($prefilter[0], + array($source_content, &$this)); + $this->_plugins['prefilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); + } + } + } + + /* fetch all special blocks */ + $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; + + preg_match_all($search, $source_content, $match, PREG_SET_ORDER); + $this->_folded_blocks = $match; + reset($this->_folded_blocks); + + /* replace special blocks by "{php}" */ + $source_content = preg_replace_callback($search, create_function ('$matches', "return '" + . $this->_quote_replace($this->left_delimiter) . 'php' + . "' . str_repeat(\"\n\", substr_count('\$matches[1]', \"\n\")) .'" + . $this->_quote_replace($this->right_delimiter) + . "';") + , $source_content); + + /* Gather all template tags. */ + preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); + $template_tags = $_match[1]; + /* Split content by template tags to obtain non-template content. */ + $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); + + /* loop through text blocks */ + for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { + /* match anything resembling php tags */ + if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { + /* replace tags with placeholders to prevent recursive replacements */ + $sp_match[1] = array_unique($sp_match[1]); + usort($sp_match[1], '_smarty_sort_length'); + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); + } + /* process each one */ + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + if ($this->php_handling == SMARTY_PHP_PASSTHRU) { + /* echo php contents */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_QUOTE) { + /* quote php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_REMOVE) { + /* remove php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); + } else { + /* SMARTY_PHP_ALLOW, but echo non php starting tags */ + $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', ''."\n", $sp_match[1][$curr_sp]); + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); + } + } + } + } + + /* Compile the template tags into PHP code. */ + $compiled_tags = array(); + for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { + $this->_current_line_no += substr_count($text_blocks[$i], "\n"); + $compiled_tags[] = $this->_compile_tag($template_tags[$i]); + $this->_current_line_no += substr_count($template_tags[$i], "\n"); + } + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = end($this->_tag_stack); + $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); + return; + } + + /* Reformat $text_blocks between 'strip' and '/strip' tags, + removing spaces, tabs and newlines. */ + $strip = false; + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '{strip}') { + $compiled_tags[$i] = ''; + $strip = true; + /* remove leading whitespaces */ + $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); + } + if ($strip) { + /* strip all $text_blocks before the next '/strip' */ + for ($j = $i + 1; $j < $for_max; $j++) { + /* remove leading and trailing whitespaces of each line */ + $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); + if ($compiled_tags[$j] == '{/strip}') { + /* remove trailing whitespaces from the last text_block */ + $text_blocks[$j] = rtrim($text_blocks[$j]); + } + $text_blocks[$j] = ""\'", "\\"=>"\\\\")) . "'; ?>"; + if ($compiled_tags[$j] == '{/strip}') { + $compiled_tags[$j] = "\n"; /* slurped by php, but necessary + if a newline is following the closing strip-tag */ + $strip = false; + $i = $j; + break; + } + } + } + } + $compiled_content = ''; + + $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; + + /* Interleave the compiled contents and text blocks to get the final result. */ + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '') { + // tag result empty, remove first newline from following text block + $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); + } + // replace legit PHP tags with placeholder + $text_blocks[$i] = str_replace('\n", $compiled_content); + $compiled_content = preg_replace("~(?\n", $compiled_content); + + // recover legit tags + $compiled_content = str_replace($tag_guard, '_cache_serial)) { + $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; + } + + // run compiled template through postfilter functions + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) continue; + if ($postfilter[3] || is_callable($postfilter[0])) { + $compiled_content = call_user_func_array($postfilter[0], + array($compiled_content, &$this)); + $this->_plugins['postfilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); + } + } + } + + // put header at the top of the compiled template + $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; + + /* Emit code to load needed plugins. */ + $this->_plugins_code = ''; + if (count($this->_plugin_info)) { + $_plugins_params = "array('plugins' => array("; + foreach ($this->_plugin_info as $plugin_type => $plugins) { + foreach ($plugins as $plugin_name => $plugin_info) { + $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; + $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; + } + } + $_plugins_params .= '))'; + $plugins_code = "\n"; + $template_header .= $plugins_code; + $this->_plugin_info = array(); + $this->_plugins_code = $plugins_code; + } + + if ($this->_init_smarty_vars) { + $template_header .= "\n"; + $this->_init_smarty_vars = false; + } + + $compiled_content = $template_header . $compiled_content; + return true; + } + + /** + * Compile a template tag + * + * @param string $template_tag + * @return string + */ + function _compile_tag($template_tag) + { + /* Matched comment. */ + if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') + return ''; + + /* Split tag into two three parts: command, command modifiers and the arguments. */ + if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp + . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) + (?:\s+(.*))?$ + ~xs', $template_tag, $match)) { + $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $tag_command = $match[1]; + $tag_modifier = isset($match[2]) ? $match[2] : null; + $tag_args = isset($match[3]) ? $match[3] : null; + + if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { + /* tag name is a variable or object */ + $_return = $this->_parse_var_props($tag_command . $tag_modifier); + return "" . $this->_additional_newline; + } + + /* If the tag name is a registered object, we process it. */ + if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { + return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); + } + + switch ($tag_command) { + case 'include': + return $this->_compile_include_tag($tag_args); + + case 'include_php': + return $this->_compile_include_php_tag($tag_args); + + case 'if': + $this->_push_tag('if'); + return $this->_compile_if_tag($tag_args); + + case 'else': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); + else + $this->_push_tag('else'); + return ''; + + case 'elseif': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); + if ($_open_tag == 'if') + $this->_push_tag('elseif'); + return $this->_compile_if_tag($tag_args, true); + + case '/if': + $this->_pop_tag('if'); + return ''; + + case 'capture': + return $this->_compile_capture_tag(true, $tag_args); + + case '/capture': + return $this->_compile_capture_tag(false); + + case 'ldelim': + return $this->left_delimiter; + + case 'rdelim': + return $this->right_delimiter; + + case 'section': + $this->_push_tag('section'); + return $this->_compile_section_start($tag_args); + + case 'sectionelse': + $this->_push_tag('sectionelse'); + return ""; + break; + + case '/section': + $_open_tag = $this->_pop_tag('section'); + if ($_open_tag == 'sectionelse') + return ""; + else + return ""; + + case 'foreach': + $this->_push_tag('foreach'); + return $this->_compile_foreach_start($tag_args); + break; + + case 'foreachelse': + $this->_push_tag('foreachelse'); + return ""; + + case '/foreach': + $_open_tag = $this->_pop_tag('foreach'); + if ($_open_tag == 'foreachelse') + return ""; + else + return ""; + break; + + case 'strip': + case '/strip': + if (substr($tag_command, 0, 1)=='/') { + $this->_pop_tag('strip'); + if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ + $this->_additional_newline = "\n"; + return '{' . $tag_command . '}'; + } + } else { + $this->_push_tag('strip'); + if ($this->_strip_depth++==0) { /* outermost opening {strip} */ + $this->_additional_newline = ""; + return '{' . $tag_command . '}'; + } + } + return ''; + + case 'php': + /* handle folded tags replaced by {php} */ + list(, $block) = each($this->_folded_blocks); + $this->_current_line_no += substr_count($block[0], "\n"); + /* the number of matched elements in the regexp in _compile_file() + determins the type of folded tag that was found */ + switch (count($block)) { + case 2: /* comment */ + return ''; + + case 3: /* literal */ + return ""\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; + + case 4: /* php */ + if ($this->security && !$this->security_settings['PHP_TAGS']) { + $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); + return; + } + return ''; + } + break; + + case 'insert': + return $this->_compile_insert_tag($tag_args); + + default: + if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { + return $output; + } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else { + $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); + } + + } + } + + + /** + * compile the custom compiler tag + * + * sets $output to the compiled custom compiler tag + * @param string $tag_command + * @param string $tag_args + * @param string $output + * @return boolean + */ + function _compile_compiler_tag($tag_command, $tag_args, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the compiler function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['compiler'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['compiler'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "compiler function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_compiler_' . $tag_command; + if (!is_callable($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); + } + } + + /* + * True return value means that we either found a plugin or a + * dynamically registered function. False means that we didn't and the + * compiler should now emit code to load custom function plugin for this + * tag. + */ + if ($found) { + if ($have_function) { + $output = call_user_func_array($plugin_func, array($tag_args, &$this)); + if($output != '') { + $output = '_push_cacheable_state('compiler', $tag_command) + . $output + . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; + } + } else { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + } + return true; + } else { + return false; + } + } + + + /** + * compile block function tag + * + * sets $output to compiled block function tag + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @param string $output + * @return boolean + */ + function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else + $start_tag = true; + + $found = false; + $have_function = true; + + /* + * First we check if the block function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['block'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['block'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "block function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_block_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* + * Even though we've located the plugin function, compilation + * happens only once, so the plugin will still need to be loaded + * at runtime for future requests. + */ + $this->_add_plugin('block', $tag_command); + + if ($start_tag) + $this->_push_tag($tag_command); + else + $this->_pop_tag($tag_command); + + if ($start_tag) { + $output = '_push_cacheable_state('block', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs=''; + $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); + $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; + $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; + $output .= 'while ($_block_repeat) { ob_start(); ?>'; + } else { + $output = '_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; + if ($tag_modifier != '') { + $this->_parse_modifiers($_out_tag_text, $tag_modifier); + } + $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; + $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; + } + + return true; + } + + + /** + * compile custom function tag + * + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @return string + */ + function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the custom function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['function'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['function'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "custom function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_function_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* declare plugin to be loaded on display of the template that + we compile right now */ + $this->_add_plugin('function', $tag_command); + + $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs = ''; + $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); + + $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; + if($tag_modifier != '') { + $this->_parse_modifiers($output, $tag_modifier); + } + + if($output != '') { + $output = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; + } + + return true; + } + + /** + * compile a registered object tag + * + * @param string $tag_command + * @param array $attrs + * @param string $tag_modifier + * @return string + */ + function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else { + $start_tag = true; + } + + list($object, $obj_comp) = explode('->', $tag_command); + + $arg_list = array(); + if(count($attrs)) { + $_assign_var = false; + foreach ($attrs as $arg_name => $arg_value) { + if($arg_name == 'assign') { + $_assign_var = $arg_value; + unset($attrs['assign']); + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + if($this->_reg_objects[$object][2]) { + // smarty object argument format + $args = "array(".implode(',', (array)$arg_list)."), \$this"; + } else { + // traditional argument format + $args = implode(',', array_values($attrs)); + if (empty($args)) { + $args = ''; + } + } + + $prefix = ''; + $postfix = ''; + $newline = ''; + if(!is_object($this->_reg_objects[$object][0])) { + $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { + $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { + // method + if(in_array($obj_comp, $this->_reg_objects[$object][3])) { + // block method + if ($start_tag) { + $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; + $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; + $prefix .= "while (\$_block_repeat) { ob_start();"; + $return = null; + $postfix = ''; + } else { + $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; + $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; + $postfix = "} array_pop(\$this->_tag_stack);"; + } + } else { + // non-block method + $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; + } + } else { + // property + $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; + } + + if($return != null) { + if($tag_modifier != '') { + $this->_parse_modifiers($return, $tag_modifier); + } + + if(!empty($_assign_var)) { + $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; + } else { + $output = 'echo ' . $return . ';'; + $newline = $this->_additional_newline; + } + } else { + $output = ''; + } + + return '" . $newline; + } + + /** + * Compile {insert ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_insert_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $name = $this->_dequote($attrs['name']); + + if (empty($name)) { + return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!preg_match('~^\w+$~', $name)) { + return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!empty($attrs['script'])) { + $delayed_loading = true; + } else { + $delayed_loading = false; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $this->_add_plugin('insert', $name, $delayed_loading); + + $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; + + return "" . $this->_additional_newline; + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); + } + + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; + continue; + } else if ($arg_name == 'assign') { + $assign_var = $arg_value; + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $output = '_tpl_vars;\n"; + + + $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + $output .= "\$this->_smarty_include($_params);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars);\n"; + + if (isset($assign_var)) { + $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; + } + + $output .= ' ?>'; + + return $output; + + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_php_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); + $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; + + $arg_list = array(); + foreach($attrs as $arg_name => $arg_value) { + if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { + if(is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; + + return "" . $this->_additional_newline; + } + + + /** + * Compile {section ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_section_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); + } + + $output .= "unset(\$this->_sections[$section_name]);\n"; + $section_props = "\$this->_sections[$section_name]"; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'loop': + $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; + break; + + case 'show': + if (is_bool($attr_value)) + $show_attr_value = $attr_value ? 'true' : 'false'; + else + $show_attr_value = "(bool)$attr_value"; + $output .= "{$section_props}['show'] = $show_attr_value;\n"; + break; + + case 'name': + $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; + break; + + case 'max': + case 'start': + $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; + break; + + case 'step': + $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; + break; + + default: + $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + } + + if (!isset($attrs['show'])) + $output .= "{$section_props}['show'] = true;\n"; + + if (!isset($attrs['loop'])) + $output .= "{$section_props}['loop'] = 1;\n"; + + if (!isset($attrs['max'])) + $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; + else + $output .= "if ({$section_props}['max'] < 0)\n" . + " {$section_props}['max'] = {$section_props}['loop'];\n"; + + if (!isset($attrs['step'])) + $output .= "{$section_props}['step'] = 1;\n"; + + if (!isset($attrs['start'])) + $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; + else { + $output .= "if ({$section_props}['start'] < 0)\n" . + " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . + "else\n" . + " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; + } + + $output .= "if ({$section_props}['show']) {\n"; + if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { + $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; + } else { + $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; + } + $output .= " if ({$section_props}['total'] == 0)\n" . + " {$section_props}['show'] = false;\n" . + "} else\n" . + " {$section_props}['total'] = 0;\n"; + + $output .= "if ({$section_props}['show']):\n"; + $output .= " + for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; + {$section_props}['iteration'] <= {$section_props}['total']; + {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; + $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; + $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; + $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; + $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; + + $output .= "?>"; + + return $output; + } + + + /** + * Compile {foreach ...} tag. + * + * @param string $tag_args + * @return string + */ + function _compile_foreach_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['from'])) { + return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $from = $attrs['from']; + + if (empty($attrs['item'])) { + return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $item = $this->_dequote($attrs['item']); + if (!preg_match('~^\w+$~', $item)) { + return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($attrs['key'])) { + $key = $this->_dequote($attrs['key']); + if (!preg_match('~^\w+$~', $key)) { + return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + $key_part = "\$this->_tpl_vars['$key'] => "; + } else { + $key = null; + $key_part = ''; + } + + if (isset($attrs['name'])) { + $name = $attrs['name']; + } else { + $name = null; + } + + $output = '_foreach[$name]"; + $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; + $output .= "if ({$foreach_props}['total'] > 0):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + $output .= " {$foreach_props}['iteration']++;\n"; + } else { + $output .= "if (count(\$_from)):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + } + $output .= '?>'; + + return $output; + } + + + /** + * Compile {capture} .. {/capture} tags + * + * @param boolean $start true if this is the {capture} tag + * @param string $tag_args + * @return string + */ + + function _compile_capture_tag($start, $tag_args = '') + { + $attrs = $this->_parse_attrs($tag_args); + + if ($start) { + $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; + $assign = isset($attrs['assign']) ? $attrs['assign'] : null; + $append = isset($attrs['append']) ? $attrs['append'] : null; + + $output = ""; + $this->_capture_stack[] = array($buffer, $assign, $append); + } else { + list($buffer, $assign, $append) = array_pop($this->_capture_stack); + $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; + if (isset($assign)) { + $output .= " \$this->assign($assign, ob_get_contents());"; + } + if (isset($append)) { + $output .= " \$this->append($append, ob_get_contents());"; + } + $output .= "ob_end_clean(); ?>"; + } + + return $output; + } + + /** + * Compile {if ...} tag + * + * @param string $tag_args + * @param boolean $elseif if true, uses elseif instead of if + * @return string + */ + function _compile_if_tag($tag_args, $elseif = false) + { + + /* Tokenize args for 'if' tag. */ + preg_match_all('~(?> + ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call + ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string + \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token + \b\w+\b | # valid word token + \S+ # anything else + )~x', $tag_args, $match); + + $tokens = $match[0]; + + if(empty($tokens)) { + $_error_msg = $elseif ? "'elseif'" : "'if'"; + $_error_msg .= ' statement requires arguments'; + $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); + } + + + // make sure we have balanced parenthesis + $token_count = array_count_values($tokens); + if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { + $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + + $is_arg_stack = array(); + + for ($i = 0; $i < count($tokens); $i++) { + + $token = &$tokens[$i]; + + switch (strtolower($token)) { + case '!': + case '%': + case '!==': + case '==': + case '===': + case '>': + case '<': + case '!=': + case '<>': + case '<<': + case '>>': + case '<=': + case '>=': + case '&&': + case '||': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + /* If last token was a ')', we operate on the parenthesized + expression. The start of the expression is on the stack. + Otherwise, we operate on the last encountered token. */ + if ($tokens[$i-1] == ')') { + $is_arg_start = array_pop($is_arg_stack); + if ($is_arg_start != 0) { + if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) { + $is_arg_start--; + } + } + } else + $is_arg_start = $i-1; + /* Construct the argument for 'is' expression, so it knows + what to operate on. */ + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + /* Pass all tokens from next one until the end to the + 'is' expression parsing function. The function will + return modified tokens, where the first one is the result + of the 'is' expression and the rest are the tokens it + didn't touch. */ + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + /* Replace the old tokens with the new ones. */ + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + /* Adjust argument start so that it won't change from the + current position for the next iteration. */ + $i = $is_arg_start; + break; + + default: + if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { + // function call + if($this->security && + !in_array($token, $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { + // variable function call + $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { + // object or variable + $token = $this->_parse_var_props($token); + } elseif(is_numeric($token)) { + // number, skip it + } else { + $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + } + } + + if ($elseif) + return ''; + else + return ''; + } + + + function _compile_arg_list($type, $name, $attrs, &$cache_code) { + $arg_list = array(); + + if (isset($type) && isset($name) + && isset($this->_plugins[$type]) + && isset($this->_plugins[$type][$name]) + && empty($this->_plugins[$type][$name][4]) + && is_array($this->_plugins[$type][$name][5]) + ) { + /* we have a list of parameters that should be cached */ + $_cache_attrs = $this->_plugins[$type][$name][5]; + $_count = $this->_cache_attrs_count++; + $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; + + } else { + /* no parameters are cached */ + $_cache_attrs = null; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + if (is_null($arg_value)) + $arg_value = 'null'; + if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { + $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; + } else { + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + return $arg_list; + } + + /** + * Parse is expression + * + * @param string $is_arg + * @param array $tokens + * @return array + */ + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') { + $negate_expr = true; + $expr_type = array_shift($tokens); + } else + $expr_type = $first_token; + + switch ($expr_type) { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "!(1 & $is_arg)"; + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "(1 & $is_arg)"; + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; + } else { + $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + + default: + $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if ($negate_expr) { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Parse attribute string + * + * @param string $tag_args + * @return array + */ + function _parse_attrs($tag_args) + { + + /* Tokenize tag attributes. */ + preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + ~x', $tag_args, $match); + $tokens = $match[0]; + + $attrs = array(); + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('~^\w+$~', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('~^(on|yes|true)$~', $token)) { + $token = 'true'; + } else if (preg_match('~^(off|no|false)$~', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { + /* treat integer literally */ + } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; + } + + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } + + $this->_parse_vars_props($attrs); + + return $attrs; + } + + /** + * compile multiple variables and section properties tokens into + * PHP code + * + * @param array $tokens + */ + function _parse_vars_props(&$tokens) + { + foreach($tokens as $key => $val) { + $tokens[$key] = $this->_parse_var_props($val); + } + } + + /** + * compile single variable and section properties token into + * PHP code + * + * @param string $val + * @param string $tag_attrs + * @return string + */ + function _parse_var_props($val) + { + $val = trim($val); + + if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { + // $ variable or object + $return = $this->_parse_var($match[1]); + $modifiers = $match[2]; + if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { + $_default_mod_string = implode('|',(array)$this->default_modifiers); + $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; + } + $this->_parse_modifiers($return, $modifiers); + return $return; + } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // double quoted text + preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + $return = $this->_expand_quoted_text($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // numerical constant + preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // single quoted text + preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // config var + return $this->_parse_conf_var($val); + } + elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // section var + return $this->_parse_section_prop($val); + } + elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { + // literal string + return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); + } + return $val; + } + + /** + * expand quoted text with embedded variables + * + * @param string $var_expr + * @return string + */ + function _expand_quoted_text($var_expr) + { + // if contains unescaped $, expand it + if(preg_match_all('~(?:\`(?_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."'; + } + $var_expr = strtr($var_expr, $_replace); + $_return = preg_replace('~\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); + + if(count($_math_vars) > 1) { + $_first_var = ""; + $_complete_var = ""; + $_output = ""; + // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) + foreach($_math_vars as $_k => $_math_var) { + $_math_var = $_math_vars[$_k]; + + if(!empty($_math_var) || is_numeric($_math_var)) { + // hit a math operator, so process the stuff which came before it + if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { + $_has_math = true; + if(!empty($_complete_var) || is_numeric($_complete_var)) { + $_output .= $this->_parse_var($_complete_var); + } + + // just output the math operator to php + $_output .= $_math_var; + + if(empty($_first_var)) + $_first_var = $_complete_var; + + $_complete_var = ""; + } else { + $_complete_var .= $_math_var; + } + } + } + if($_has_math) { + if(!empty($_complete_var) || is_numeric($_complete_var)) + $_output .= $this->_parse_var($_complete_var); + + // get the modifiers working (only the last var from math + modifier is left) + $var_expr = $_complete_var; + } + } + + // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) + if(is_numeric(substr($var_expr, 0, 1))) + $_var_ref = $var_expr; + else + $_var_ref = substr($var_expr, 1); + + if(!$_has_math) { + + // get [foo] and .foo and ->foo and (...) pieces + preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); + + $_indexes = $match[0]; + $_var_name = array_shift($_indexes); + + /* Handle $smarty.* variable references as a special case. */ + if ($_var_name == 'smarty') { + /* + * If the reference could be compiled, use the compiled output; + * otherwise, fall back on the $smarty variable generated at + * run-time. + */ + if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { + $_output = $smarty_ref; + } else { + $_var_name = substr(array_shift($_indexes), 1); + $_output = "\$this->_smarty_vars['$_var_name']"; + } + } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { + // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers + if(count($_indexes) > 0) + { + $_var_name .= implode("", $_indexes); + $_indexes = array(); + } + $_output = $_var_name; + } else { + $_output = "\$this->_tpl_vars['$_var_name']"; + } + + foreach ($_indexes as $_index) { + if (substr($_index, 0, 1) == '[') { + $_index = substr($_index, 1, -1); + if (is_numeric($_index)) { + $_output .= "[$_index]"; + } elseif (substr($_index, 0, 1) == '$') { + if (strpos($_index, '.') !== false) { + $_output .= '[' . $this->_parse_var($_index) . ']'; + } else { + $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; + } + } else { + $_var_parts = explode('.', $_index); + $_var_section = $_var_parts[0]; + $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; + $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; + } + } else if (substr($_index, 0, 1) == '.') { + if (substr($_index, 1, 1) == '$') + $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; + else + $_output .= "['" . substr($_index, 1) . "']"; + } else if (substr($_index,0,2) == '->') { + if(substr($_index,2,2) == '__') { + $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif($this->security && substr($_index, 2, 1) == '_') { + $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif (substr($_index, 2, 1) == '$') { + if ($this->security) { + $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } else { + $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; + } + } else { + $_output .= $_index; + } + } elseif (substr($_index, 0, 1) == '(') { + $_index = $this->_parse_parenth_args($_index); + $_output .= $_index; + } else { + $_output .= $_index; + } + } + } + + return $_output; + } + + /** + * parse arguments in function call parenthesis + * + * @param string $parenth_args + * @return string + */ + function _parse_parenth_args($parenth_args) + { + preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); + $orig_vals = $match = $match[0]; + $this->_parse_vars_props($match); + $replace = array(); + for ($i = 0, $count = count($match); $i < $count; $i++) { + $replace[$orig_vals[$i]] = $match[$i]; + } + return strtr($parenth_args, $replace); + } + + /** + * parse configuration variable expression into PHP code + * + * @param string $conf_var_expr + */ + function _parse_conf_var($conf_var_expr) + { + $parts = explode('|', $conf_var_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + $var_name = substr($var_ref, 1, -1); + + $output = "\$this->_config[0]['vars']['$var_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + /** + * parse section property expression into PHP code + * + * @param string $section_prop_expr + * @return string + */ + function _parse_section_prop($section_prop_expr) + { + $parts = explode('|', $section_prop_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); + $section_name = $match[1]; + $prop_name = $match[2]; + + $output = "\$this->_sections['$section_name']['$prop_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + + /** + * parse modifier chain into PHP code + * + * sets $output to parsed modified chain + * @param string $output + * @param string $modifier_string + */ + function _parse_modifiers(&$output, $modifier_string) + { + preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); + list(, $_modifiers, $modifier_arg_strings) = $_match; + + for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { + $_modifier_name = $_modifiers[$_i]; + + if($_modifier_name == 'smarty') { + // skip smarty modifier + continue; + } + + preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); + $_modifier_args = $_match[1]; + + if (substr($_modifier_name, 0, 1) == '@') { + $_map_array = false; + $_modifier_name = substr($_modifier_name, 1); + } else { + $_map_array = true; + } + + if (empty($this->_plugins['modifier'][$_modifier_name]) + && !$this->_get_plugin_filepath('modifier', $_modifier_name) + && function_exists($_modifier_name)) { + if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } else { + $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); + } + } + $this->_add_plugin('modifier', $_modifier_name); + + $this->_parse_vars_props($_modifier_args); + + if($_modifier_name == 'default') { + // supress notifications of default modifier vars and args + if(substr($output, 0, 1) == '$') { + $output = '@' . $output; + } + if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { + $_modifier_args[0] = '@' . $_modifier_args[0]; + } + } + if (count($_modifier_args) > 0) + $_modifier_args = ', '.implode(', ', $_modifier_args); + else + $_modifier_args = ''; + + if ($_map_array) { + $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; + + } else { + + $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; + + } + } + } + + + /** + * add plugin + * + * @param string $type + * @param string $name + * @param boolean? $delayed_loading + */ + function _add_plugin($type, $name, $delayed_loading = null) + { + if (!isset($this->_plugin_info[$type])) { + $this->_plugin_info[$type] = array(); + } + if (!isset($this->_plugin_info[$type][$name])) { + $this->_plugin_info[$type][$name] = array($this->_current_file, + $this->_current_line_no, + $delayed_loading); + } + } + + + /** + * Compiles references of type $smarty.foo + * + * @param string $indexes + * @return string + */ + function _compile_smarty_ref(&$indexes) + { + /* Extract the reference name. */ + $_ref = substr($indexes[0], 1); + foreach($indexes as $_index_no=>$_index) { + if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { + $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + } + + switch ($_ref) { + case 'now': + $compiled_ref = 'time()'; + $_max_index = 1; + break; + + case 'foreach': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $_propname = substr($indexes[1], 1); + $_max_index = 1; + switch ($_propname) { + case 'index': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; + break; + + case 'first': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; + break; + + case 'last': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; + break; + + case 'show': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; + break; + + default: + unset($_max_index); + $compiled_ref = "\$this->_foreach[$_var]"; + } + break; + + case 'section': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = "\$this->_sections[$_var]"; + break; + + case 'get': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_GET"; + break; + + case 'post': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_POST"; + break; + + case 'cookies': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_COOKIE"; + break; + + case 'env': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_ENV"; + break; + + case 'server': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_SERVER"; + break; + + case 'session': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_SESSION"; + break; + + /* + * These cases are handled either at run-time or elsewhere in the + * compiler. + */ + case 'request': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + if ($this->request_use_auto_globals) { + $compiled_ref = "\$_REQUEST"; + break; + } else { + $this->_init_smarty_vars = true; + } + return null; + + case 'capture': + return null; + + case 'template': + $compiled_ref = "'" . addslashes($this->_current_file) . "'"; + $_max_index = 1; + break; + + case 'version': + $compiled_ref = "'$this->_version'"; + $_max_index = 1; + break; + + case 'const': + if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { + $this->_syntax_error("(secure mode) constants not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + array_shift($indexes); + if (preg_match('!^\.\w+$!', $indexes[0])) { + $compiled_ref = '@' . substr($indexes[0], 1); + } else { + $_val = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = '@constant(' . $_val . ')'; + } + $_max_index = 1; + break; + + case 'config': + $compiled_ref = "\$this->_config[0]['vars']"; + $_max_index = 3; + break; + + case 'ldelim': + $compiled_ref = "'$this->left_delimiter'"; + break; + + case 'rdelim': + $compiled_ref = "'$this->right_delimiter'"; + break; + + default: + $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if (isset($_max_index) && count($indexes) > $_max_index) { + $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + + array_shift($indexes); + return $compiled_ref; + } + + /** + * compiles call to plugin of type $type with name $name + * returns a string containing the function-name or method call + * without the paramter-list that would have follow to make the + * call valid php-syntax + * + * @param string $type + * @param string $name + * @return string + */ + function _compile_plugin_call($type, $name) { + if (isset($this->_plugins[$type][$name])) { + /* plugin loaded */ + if (is_array($this->_plugins[$type][$name][0])) { + return ((is_object($this->_plugins[$type][$name][0][0])) ? + "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ + : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ + ). $this->_plugins[$type][$name][0][1]; + + } else { + /* function callback */ + return $this->_plugins[$type][$name][0]; + + } + } else { + /* plugin not loaded -> auto-loadable-plugin */ + return 'smarty_'.$type.'_'.$name; + + } + } + + /** + * load pre- and post-filters + */ + function _load_filters() + { + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) { + unset($this->_plugins['prefilter'][$filter_name]); + $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) { + unset($this->_plugins['postfilter'][$filter_name]); + $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + } + + + /** + * Quote subpattern references + * + * @param string $string + * @return string + */ + function _quote_replace($string) + { + return strtr($string, array('\\' => '\\\\', '$' => '\\$')); + } + + /** + * display Smarty syntax error + * + * @param string $error_msg + * @param integer $error_type + * @param string $file + * @param integer $line + */ + function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) + { + $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); + } + + + /** + * check if the compilation changes from cacheable to + * non-cacheable state with the beginning of the current + * plugin. return php-code to reflect the transition. + * @return string + */ + function _push_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || 0<$this->_cacheable_state++) return ''; + if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); + $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' + . $this->_cache_serial . '#' . $this->_nocache_count + . '}\'; endif;'; + return $_ret; + } + + + /** + * check if the compilation changes from non-cacheable to + * cacheable state with the end of the current plugin return + * php-code to reflect the transition. + * @return string + */ + function _pop_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || --$this->_cacheable_state>0) return ''; + return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' + . $this->_cache_serial . '#' . ($this->_nocache_count++) + . '}\'; endif;'; + } + + + /** + * push opening tag-name, file-name and line-number on the tag-stack + * @param string the opening tag's name + */ + function _push_tag($open_tag) + { + array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); + } + + /** + * pop closing tag-name + * raise an error if this stack-top doesn't match with the closing tag + * @param string the closing tag's name + * @return string the opening tag's name + */ + function _pop_tag($close_tag) + { + $message = ''; + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = array_pop($this->_tag_stack); + if ($close_tag == $_open_tag) { + return $_open_tag; + } + if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { + return $this->_pop_tag($close_tag); + } + if ($close_tag == 'section' && $_open_tag == 'sectionelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($_open_tag == 'else' || $_open_tag == 'elseif') { + $_open_tag = 'if'; + } elseif ($_open_tag == 'sectionelse') { + $_open_tag = 'section'; + } elseif ($_open_tag == 'foreachelse') { + $_open_tag = 'foreach'; + } + $message = " expected {/$_open_tag} (opened line $_line_no)."; + } + $this->_syntax_error("mismatched tag {/$close_tag}.$message", + E_USER_ERROR, __FILE__, __LINE__); + } + +} + +/** + * compare to values by their string length + * + * @access private + * @param string $a + * @param string $b + * @return 0|-1|1 + */ +function _smarty_sort_length($a, $b) +{ + if($a == $b) + return 0; + + if(strlen($a) == strlen($b)) + return ($a > $b) ? -1 : 1; + + return (strlen($a) > strlen($b)) ? -1 : 1; +} + + +/* vim: set et: */ + +?> diff --git a/code/web/public_php/admin/smarty/debug.tpl b/code/web/public_php/admin/smarty/debug.tpl index 7f1c9d425..c05ef5d0b 100644 --- a/code/web/public_php/admin/smarty/debug.tpl +++ b/code/web/public_php/admin/smarty/debug.tpl @@ -1,64 +1,157 @@ {* Smarty *} - -{* debug.tpl, last updated version 2.0.1 *} - +{* debug.tpl, last updated version 2.1.0 *} {assign_debug_info} +{capture assign=debug_output} + + + + Smarty Debug Console +{literal} + +{/literal} + + + +

Smarty Debug Console

+ +

included templates & config files (load time in seconds)

+ +
+{section name=templates loop=$_debug_tpls} + {section name=indent loop=$_debug_tpls[templates].depth}   {/section} + + {$_debug_tpls[templates].filename|escape:html} + {if isset($_debug_tpls[templates].exec_time)} + + ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}) + {if %templates.index% eq 0}(total){/if} + + {/if} +
+{sectionelse} +

no templates included

+{/section} +
+ +

assigned template variables

+ + + {section name=vars loop=$_debug_keys} + + + + {sectionelse} + + {/section} +
{ldelim}${$_debug_keys[vars]|escape:'html'}{rdelim}{$_debug_vals[vars]|@debug_print_var}

no template variables assigned

+ +

assigned config file variables (outer template scope)

+ + + {section name=config_vars loop=$_debug_config_keys} + + + + {sectionelse} + + {/section} +
{ldelim}#{$_debug_config_keys[config_vars]|escape:'html'}#{rdelim}{$_debug_config_vals[config_vars]|@debug_print_var}

no config vars assigned

+ + +{/capture} {if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"} - - - - {section name=templates loop=$_debug_tpls} - - {sectionelse} - - {/section} - - {section name=vars loop=$_debug_keys} - - {sectionelse} - - {/section} - - {section name=config_vars loop=$_debug_config_keys} - - {sectionelse} - - {/section} -
Smarty Debug Console
included templates & config files (load time in seconds):
{section name=indent loop=$_debug_tpls[templates].depth}   {/section}{$_debug_tpls[templates].filename|escape:html}{if isset($_debug_tpls[templates].exec_time)} ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}){if %templates.index% eq 0} (total){/if}{/if}
no templates included
assigned template variables:
{ldelim}${$_debug_keys[vars]}{rdelim}{$_debug_vals[vars]|@debug_print_var}
no template variables assigned
assigned config file variables (outer template scope):
{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}{$_debug_config_vals[config_vars]|@debug_print_var}
no config vars assigned
- + {$debug_output} {else} - -{/if} + +{/if} \ No newline at end of file diff --git a/code/web/public_php/admin/smarty/internals/core.create_dir_structure.php b/code/web/public_php/admin/smarty/internals/core.create_dir_structure.php index 999cf5930..3eecc4972 100644 --- a/code/web/public_php/admin/smarty/internals/core.create_dir_structure.php +++ b/code/web/public_php/admin/smarty/internals/core.create_dir_structure.php @@ -22,7 +22,7 @@ function smarty_core_create_dir_structure($params, &$smarty) /* unix-style paths */ $_dir = $params['dir']; $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY); - $_new_dir = ($_dir{0}=='/') ? '/' : getcwd().'/'; + $_new_dir = (substr($_dir, 0, 1)=='/') ? '/' : getcwd().'/'; if($_use_open_basedir = !empty($_open_basedir_ini)) { $_open_basedirs = explode(':', $_open_basedir_ini); } diff --git a/code/web/public_php/admin/smarty/internals/core.display_debug_console.php b/code/web/public_php/admin/smarty/internals/core.display_debug_console.php index a5d72913c..1a80f3909 100644 --- a/code/web/public_php/admin/smarty/internals/core.display_debug_console.php +++ b/code/web/public_php/admin/smarty/internals/core.display_debug_console.php @@ -23,7 +23,7 @@ function smarty_core_display_debug_console($params, &$smarty) // set path to debug template from SMARTY_DIR $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl'; if($smarty->security && is_file($smarty->debug_tpl)) { - $smarty->secure_dir[] = dirname(realpath($smarty->debug_tpl)); + $smarty->secure_dir[] = realpath($smarty->debug_tpl); } $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl'; } diff --git a/code/web/public_php/admin/smarty/internals/core.is_secure.php b/code/web/public_php/admin/smarty/internals/core.is_secure.php index 342f3aff8..d54abd432 100644 --- a/code/web/public_php/admin/smarty/internals/core.is_secure.php +++ b/code/web/public_php/admin/smarty/internals/core.is_secure.php @@ -27,18 +27,21 @@ function smarty_core_is_secure($params, &$smarty) foreach ((array)$params['resource_base_path'] as $curr_dir) { if ( ($_cd = realpath($curr_dir)) !== false && strncmp($_rp, $_cd, strlen($_cd)) == 0 && - $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { return true; } } } if (!empty($smarty->secure_dir)) { foreach ((array)$smarty->secure_dir as $curr_dir) { - if ( ($_cd = realpath($curr_dir)) !== false && - strncmp($_rp, $_cd, strlen($_cd)) == 0 && - $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { - return true; - } + if ( ($_cd = realpath($curr_dir)) !== false) { + if($_cd == $_rp) { + return true; + } elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR) { + return true; + } + } } } } else { diff --git a/code/web/public_php/admin/smarty/internals/core.is_trusted.php b/code/web/public_php/admin/smarty/internals/core.is_trusted.php index f0bd2fb8c..429973158 100644 --- a/code/web/public_php/admin/smarty/internals/core.is_trusted.php +++ b/code/web/public_php/admin/smarty/internals/core.is_trusted.php @@ -25,7 +25,7 @@ function smarty_core_is_trusted($params, &$smarty) if (!empty($curr_dir) && is_readable ($curr_dir)) { $_cd = realpath($curr_dir); if (strncmp($_rp, $_cd, strlen($_cd)) == 0 - && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { + && substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { $_smarty_trusted = true; break; } diff --git a/code/web/public_php/admin/smarty/internals/core.process_cached_inserts.php b/code/web/public_php/admin/smarty/internals/core.process_cached_inserts.php index 29cb007eb..1d78edd93 100644 --- a/code/web/public_php/admin/smarty/internals/core.process_cached_inserts.php +++ b/code/web/public_php/admin/smarty/internals/core.process_cached_inserts.php @@ -52,7 +52,7 @@ function smarty_core_process_cached_inserts($params, &$smarty) $replace = ''; } - $params['results'] = str_replace($cached_inserts[$i], $replace, $params['results']); + $params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i])); if ($smarty->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); diff --git a/code/web/public_php/admin/smarty/internals/core.process_compiled_include.php b/code/web/public_php/admin/smarty/internals/core.process_compiled_include.php index 3e1d4c15a..904d59745 100644 --- a/code/web/public_php/admin/smarty/internals/core.process_compiled_include.php +++ b/code/web/public_php/admin/smarty/internals/core.process_compiled_include.php @@ -20,7 +20,12 @@ function smarty_core_process_compiled_include($params, &$smarty) $smarty->_cache_including = true; $_return = $params['results']; - foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) { + + foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { + $smarty->_include($_include_file_path, true); + } + + foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s', array(&$smarty, '_process_compiled_include_callback'), $_return); diff --git a/code/web/public_php/admin/smarty/internals/core.read_cache_file.php b/code/web/public_php/admin/smarty/internals/core.read_cache_file.php index ecb147089..c60e113a7 100644 --- a/code/web/public_php/admin/smarty/internals/core.read_cache_file.php +++ b/code/web/public_php/admin/smarty/internals/core.read_cache_file.php @@ -90,16 +90,6 @@ function smarty_core_read_cache_file(&$params, &$smarty) } } - foreach ($_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { - if (empty($smarty->_cache_serials[$_include_file_path])) { - $smarty->_include($_include_file_path, true); - } - - if ($smarty->_cache_serials[$_include_file_path] != $_cache_serial) { - /* regenerate */ - return false; - } - } $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info); $smarty->_cache_info = $_cache_info; diff --git a/code/web/public_php/admin/smarty/internals/core.rmdir.php b/code/web/public_php/admin/smarty/internals/core.rmdir.php index 4fdbccc95..2166c44d2 100644 --- a/code/web/public_php/admin/smarty/internals/core.rmdir.php +++ b/code/web/public_php/admin/smarty/internals/core.rmdir.php @@ -32,7 +32,6 @@ function smarty_core_rmdir($params, &$smarty) 'level' => $params['level'] + 1, 'exp_time' => $params['exp_time'] ); - require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); smarty_core_rmdir($_params, $smarty); } else { diff --git a/code/web/public_php/admin/smarty/internals/core.write_cache_file.php b/code/web/public_php/admin/smarty/internals/core.write_cache_file.php index 72f785b74..fa3cdd746 100644 --- a/code/web/public_php/admin/smarty/internals/core.write_cache_file.php +++ b/code/web/public_php/admin/smarty/internals/core.write_cache_file.php @@ -68,7 +68,7 @@ function smarty_core_write_cache_file($params, &$smarty) if (!empty($smarty->cache_handler_func)) { // use cache_handler function call_user_func_array($smarty->cache_handler_func, - array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], $smarty->_cache_info['expires'])); } else { // use local cache file diff --git a/code/web/public_php/admin/smarty/internals/core.write_compiled_include.php b/code/web/public_php/admin/smarty/internals/core.write_compiled_include.php index 5e0b2e0dd..c14adb5f4 100644 --- a/code/web/public_php/admin/smarty/internals/core.write_compiled_include.php +++ b/code/web/public_php/admin/smarty/internals/core.write_compiled_include.php @@ -15,12 +15,12 @@ function smarty_core_write_compiled_include($params, &$smarty) { - $_tag_start = 'if \(\$this->caching && \!\$this->_cache_including\) \{ echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\';\}'; - $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\) \{ echo \'\{/nocache\:(\\2)#(\\3)\}\';\}'; + $_tag_start = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\'; endif;'; + $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{/nocache\:(\\2)#(\\3)\}\'; endif;'; preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', $params['compiled_content'], $_match_source, PREG_SET_ORDER); - + // no nocache-parts found: done if (count($_match_source)==0) return; diff --git a/code/web/public_php/admin/smarty/internals/core.write_file.php b/code/web/public_php/admin/smarty/internals/core.write_file.php index 09e169840..8a3a3b398 100644 --- a/code/web/public_php/admin/smarty/internals/core.write_file.php +++ b/code/web/public_php/admin/smarty/internals/core.write_file.php @@ -23,8 +23,7 @@ function smarty_core_write_file($params, &$smarty) smarty_core_create_dir_structure($_params, $smarty); } - // write to tmp file, then rename it to avoid - // file locking race condition + // write to tmp file, then rename it to avoid file locking race condition $_tmp_file = tempnam($_dirname, 'wrt'); if (!($fd = @fopen($_tmp_file, 'wb'))) { @@ -38,12 +37,13 @@ function smarty_core_write_file($params, &$smarty) fwrite($fd, $params['contents']); fclose($fd); - // Delete the file if it allready exists (this is needed on Win, - // because it cannot overwrite files with rename() - if (file_exists($params['filename'])) { + if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) { + // On platforms and filesystems that cannot overwrite with rename() + // delete the file before renaming it -- because windows always suffers + // this, it is short-circuited to avoid the initial rename() attempt @unlink($params['filename']); + @rename($_tmp_file, $params['filename']); } - @rename($_tmp_file, $params['filename']); @chmod($params['filename'], $smarty->_file_perms); return true; @@ -51,4 +51,4 @@ function smarty_core_write_file($params, &$smarty) /* vim: set expandtab: */ -?> +?> \ No newline at end of file diff --git a/code/web/public_php/admin/smarty/plugins/block.textformat.php b/code/web/public_php/admin/smarty/plugins/block.textformat.php index aaebab2f5..8cd010acb 100644 --- a/code/web/public_php/admin/smarty/plugins/block.textformat.php +++ b/code/web/public_php/admin/smarty/plugins/block.textformat.php @@ -23,6 +23,7 @@ * indent_char: string (" ") * wrap_boundary: boolean (true) * + * @author Monte Ohrt * @param string contents of the block * @param Smarty clever simulation of a method * @return string string $content re-formatted diff --git a/code/web/public_php/admin/smarty/plugins/compiler.assign.php b/code/web/public_php/admin/smarty/plugins/compiler.assign.php index 2e0201779..abef377f8 100644 --- a/code/web/public_php/admin/smarty/plugins/compiler.assign.php +++ b/code/web/public_php/admin/smarty/plugins/compiler.assign.php @@ -13,6 +13,8 @@ * Purpose: assign a value to a template variable * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} * (Smarty online manual) + * @author Monte Ohrt (initial author) + * @author messju mohr (conversion to compiler function) * @param string containing var-attribute and value-attribute * @param Smarty_Compiler */ diff --git a/code/web/public_php/admin/smarty/plugins/function.assign_debug_info.php b/code/web/public_php/admin/smarty/plugins/function.assign_debug_info.php index 8015624b1..654049876 100644 --- a/code/web/public_php/admin/smarty/plugins/function.assign_debug_info.php +++ b/code/web/public_php/admin/smarty/plugins/function.assign_debug_info.php @@ -11,6 +11,7 @@ * Type: function
* Name: assign_debug_info
* Purpose: assign debug info to the template
+ * @author Monte Ohrt * @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} * @param Smarty diff --git a/code/web/public_php/admin/smarty/plugins/function.config_load.php b/code/web/public_php/admin/smarty/plugins/function.config_load.php index db7f8f6b9..db89f638c 100644 --- a/code/web/public_php/admin/smarty/plugins/function.config_load.php +++ b/code/web/public_php/admin/smarty/plugins/function.config_load.php @@ -13,6 +13,8 @@ * Purpose: load config file vars * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} * (Smarty online manual) + * @author Monte Ohrt + * @author messju mohr (added use of resources) * @param array Format: *
  * array('file' => required config file name,
diff --git a/code/web/public_php/admin/smarty/plugins/function.counter.php b/code/web/public_php/admin/smarty/plugins/function.counter.php
index cfe5dd886..1f26db5fb 100644
--- a/code/web/public_php/admin/smarty/plugins/function.counter.php
+++ b/code/web/public_php/admin/smarty/plugins/function.counter.php
@@ -12,6 +12,7 @@
  * Type:     function
* Name: counter
* Purpose: print out a counter value + * @author Monte Ohrt * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} * (Smarty online manual) * @param array parameters diff --git a/code/web/public_php/admin/smarty/plugins/function.cycle.php b/code/web/public_php/admin/smarty/plugins/function.cycle.php index fe78bb87d..80378b7f9 100644 --- a/code/web/public_php/admin/smarty/plugins/function.cycle.php +++ b/code/web/public_php/admin/smarty/plugins/function.cycle.php @@ -63,7 +63,11 @@ function smarty_function_cycle($params, &$smarty) $cycle_vars[$name]['values'] = $params['values']; } - $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ','; + if (isset($params['delimiter'])) { + $cycle_vars[$name]['delimiter'] = $params['delimiter']; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } if(is_array($cycle_vars[$name]['values'])) { $cycle_array = $cycle_vars[$name]['values']; diff --git a/code/web/public_php/admin/smarty/plugins/function.eval.php b/code/web/public_php/admin/smarty/plugins/function.eval.php index 3a4b8b2b8..ff0472de2 100644 --- a/code/web/public_php/admin/smarty/plugins/function.eval.php +++ b/code/web/public_php/admin/smarty/plugins/function.eval.php @@ -14,6 +14,7 @@ * Purpose: evaluate a template variable as a template
* @link http://smarty.php.net/manual/en/language.function.eval.php {eval} * (Smarty online manual) + * @author Monte Ohrt * @param array * @param Smarty */ diff --git a/code/web/public_php/admin/smarty/plugins/function.fetch.php b/code/web/public_php/admin/smarty/plugins/function.fetch.php index f5a6987a9..d72c7b1f9 100644 --- a/code/web/public_php/admin/smarty/plugins/function.fetch.php +++ b/code/web/public_php/admin/smarty/plugins/function.fetch.php @@ -14,6 +14,7 @@ * Purpose: fetch file, web or ftp data and display results * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} * (Smarty online manual) + * @author Monte Ohrt * @param array * @param Smarty * @return string|null if the assign parameter is passed, Smarty assigns the @@ -180,12 +181,12 @@ function smarty_function_fetch($params, &$smarty) $content .= fgets($fp,4096); } fclose($fp); - $csplit = split("\r\n\r\n",$content,2); + $csplit = preg_split("!\r\n\r\n!",$content,2); $content = $csplit[1]; if(!empty($params['assign_headers'])) { - $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); + $smarty->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0])); } } } else { diff --git a/code/web/public_php/admin/smarty/plugins/function.html_image.php b/code/web/public_php/admin/smarty/plugins/function.html_image.php index c62b0fea6..9abae72ef 100644 --- a/code/web/public_php/admin/smarty/plugins/function.html_image.php +++ b/code/web/public_php/admin/smarty/plugins/function.html_image.php @@ -19,9 +19,10 @@ * - width = image width (optional, default actual width) * - basedir = base directory for absolute paths, default * is environment variable DOCUMENT_ROOT + * - path_prefix = prefix for path output (optional, default empty) * - * Examples: {html_image file="images/masthead.gif"} - * Output: + * Examples: {html_image file="/images/masthead.gif"} + * Output: * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} * (Smarty online manual) * @author Monte Ohrt @@ -44,6 +45,7 @@ function smarty_function_html_image($params, &$smarty) $extra = ''; $prefix = ''; $suffix = ''; + $path_prefix = ''; $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; foreach($params as $_key => $_val) { @@ -52,6 +54,7 @@ function smarty_function_html_image($params, &$smarty) case 'height': case 'width': case 'dpi': + case 'path_prefix': case 'basedir': $$_key = $_val; break; @@ -90,15 +93,9 @@ function smarty_function_html_image($params, &$smarty) } else { $_image_path = $file; } - + if(!isset($params['width']) || !isset($params['height'])) { - if ($smarty->security && - ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && - (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && - (!smarty_core_is_secure($_params, $smarty)) ) { - $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); - - } elseif (!$_image_data = @getimagesize($_image_path)) { + if(!$_image_data = @getimagesize($_image_path)) { if(!file_exists($_image_path)) { $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); return; @@ -110,7 +107,13 @@ function smarty_function_html_image($params, &$smarty) return; } } - + if ($smarty->security && + ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && + (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && + (!smarty_core_is_secure($_params, $smarty)) ) { + $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); + } + if(!isset($params['width'])) { $width = $_image_data[0]; } @@ -131,7 +134,7 @@ function smarty_function_html_image($params, &$smarty) $height = round($height * $_resize); } - return $prefix . ''.$alt.'' . $suffix; + return $prefix . ''.$alt.'' . $suffix; } /* vim: set expandtab: */ diff --git a/code/web/public_php/admin/smarty/plugins/function.html_options.php b/code/web/public_php/admin/smarty/plugins/function.html_options.php index 761edf6ab..cebadde47 100644 --- a/code/web/public_php/admin/smarty/plugins/function.html_options.php +++ b/code/web/public_php/admin/smarty/plugins/function.html_options.php @@ -17,11 +17,11 @@ * - options (required if no values supplied) - associative array * - selected (optional) - string default not set * - output (required if not options supplied) - array - * - disabled (optional) - string default not set (added by Yogin) * Purpose: Prints the list of
!is", $source, $match); $_pre_blocks = $match[0]; - $source = preg_replace("!
.*?
!is", + $source = preg_replace("!]*?>.*?!is", '@@@SMARTY:TRIM:PRE@@@', $source); - + // Pull out the textarea blocks - preg_match_all("!]+>.*?!is", $source, $match); + preg_match_all("!]*?>.*?!is", $source, $match); $_textarea_blocks = $match[0]; - $source = preg_replace("!]+>.*?!is", + $source = preg_replace("!]*?>.*?!is", '@@@SMARTY:TRIM:TEXTAREA@@@', $source); // remove all leading spaces, tabs and carriage returns NOT // preceeded by a php close tag. $source = trim(preg_replace('/((?)\n)[\s]+/m', '\1', $source)); - // replace script blocks - smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); + // replace textarea blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); // replace pre blocks smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); - // replace textarea blocks - smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); + // replace script blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); return $source; } diff --git a/code/web/public_php/admin/smarty/plugins/shared.escape_special_chars.php b/code/web/public_php/admin/smarty/plugins/shared.escape_special_chars.php index 515763abe..c07ce31be 100644 --- a/code/web/public_php/admin/smarty/plugins/shared.escape_special_chars.php +++ b/code/web/public_php/admin/smarty/plugins/shared.escape_special_chars.php @@ -12,6 +12,7 @@ * Function: smarty_function_escape_special_chars
* Purpose: used by other smarty functions to escape * special chars except for already escaped ones + * @author Monte Ohrt * @param string * @return string */ diff --git a/code/web/public_php/admin/smarty/plugins/shared.make_timestamp.php b/code/web/public_php/admin/smarty/plugins/shared.make_timestamp.php index acdd77735..b42eb11d8 100644 --- a/code/web/public_php/admin/smarty/plugins/shared.make_timestamp.php +++ b/code/web/public_php/admin/smarty/plugins/shared.make_timestamp.php @@ -10,32 +10,35 @@ * Function: smarty_make_timestamp
* Purpose: used by other smarty functions to make a timestamp * from a string. + * @author Monte Ohrt * @param string * @return string */ function smarty_make_timestamp($string) { if(empty($string)) { - $string = "now"; + // use "now": + $time = time(); + + } elseif (preg_match('/^\d{14}$/', $string)) { + // it is mysql timestamp format of YYYYMMDDHHMMSS? + $time = mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2), + substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4)); + + } elseif (is_numeric($string)) { + // it is a numeric string, we handle it as timestamp + $time = (int)$string; + + } else { + // strtotime should handle it + $time = strtotime($string); + if ($time == -1 || $time === false) { + // strtotime() was not able to parse $string, use "now": + $time = time(); + } } - $time = strtotime($string); - if (is_numeric($time) && $time != -1) - return $time; + return $time; - // is mysql timestamp format of YYYYMMDDHHMMSS? - if (preg_match('/^\d{14}$/', $string)) { - $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2), - substr($string,4,2),substr($string,6,2),substr($string,0,4)); - - return $time; - } - - // couldn't recognize it, try to return a time - $time = (int) $string; - if ($time > 0) - return $time; - else - return time(); } /* vim: set expandtab: */ diff --git a/code/web/public_php/ams/autoload/webusers.php b/code/web/public_php/ams/autoload/webusers.php index b01ddf02d..ebc654f5d 100644 --- a/code/web/public_php/ams/autoload/webusers.php +++ b/code/web/public_php/ams/autoload/webusers.php @@ -80,7 +80,14 @@ class WebUsers extends Users{ $dbw = new DBLayer("web"); $statement = $dbw->select("ams_user", array('value' => $value),"Login=:value OR Email=:value"); $row = $statement->fetch(); - $salt = substr($row['Password'],0,2); + if ($row['Password'][0] == '$') + { + $salt = substr($row['Password'], 0, 19); + } + else + { + $salt = substr($row['Password'], 0, 2); + } $hashed_input_pass = crypt($password, $salt); if($hashed_input_pass == $row['Password']){ return $row; diff --git a/code/web/public_php/ams/css/custom.css b/code/web/public_php/ams/css/custom.css index 65ba21ade..7a36a6799 100644 --- a/code/web/public_php/ams/css/custom.css +++ b/code/web/public_php/ams/css/custom.css @@ -133,3 +133,7 @@ margin-top: 10px; margin-left: -1; margin-right: -1; } + +.col-sm-4 { + width: 33.333%; +} \ No newline at end of file diff --git a/code/web/public_php/ams/func/userRegistration.php b/code/web/public_php/ams/func/userRegistration.php new file mode 100644 index 000000000..632c0681d --- /dev/null +++ b/code/web/public_php/ams/func/userRegistration.php @@ -0,0 +1,42 @@ +update("settings", Array('Value' => $_POST['userRegistration']), "`Setting` = 'userRegistration'"); + + $result['target_id'] = $_GET['id']; + global $SITEBASE; + require_once($SITEBASE . '/inc/settings.php'); + $pageElements = settings(); + $pageElements = array_merge(settings(), $result); + $pageElements['permission'] = unserialize($_SESSION['ticket_user'])->getPermission(); + // pass error and reload template accordingly + helpers :: loadtemplate( 'settings', $pageElements); + throw new SystemExit(); + + } else { + //ERROR: user is not logged in + header("Location: index.php"); + throw new SystemExit(); + } + + } + catch (PDOException $e) { + //go to error page or something, because can't access website db + print_r($e); + throw new SystemExit(); + } + +} \ No newline at end of file diff --git a/code/web/public_php/ams/inc/register.php b/code/web/public_php/ams/inc/register.php index 156ce92bf..1492e5006 100644 --- a/code/web/public_php/ams/inc/register.php +++ b/code/web/public_php/ams/inc/register.php @@ -5,6 +5,7 @@ */ function register(){ global $TOS_URL; + $pageElements['TOS_URL'] = $TOS_URL; return $pageElements; } diff --git a/code/web/public_php/ams/inc/settings.php b/code/web/public_php/ams/inc/settings.php index 751738d93..d04541397 100644 --- a/code/web/public_php/ams/inc/settings.php +++ b/code/web/public_php/ams/inc/settings.php @@ -12,7 +12,7 @@ function settings(){ if(($_GET['id'] != $_SESSION['id']) && (!Ticket_User::isMod(unserialize($_SESSION['ticket_user']))) ){ //ERROR: No access! $_SESSION['error_code'] = "403"; - header("Cache-Control: max-age=1"); + header("Cache-Control: max-age=1"); header("Location: index.php?page=error"); throw new SystemExit(); }else{ @@ -44,6 +44,16 @@ function settings(){ $result['country_array'] = getCountryArray(); global $INGAME_WEBPATH; $result['ingame_webpath'] = $INGAME_WEBPATH; + + + $dbl = new DBLayer("lib"); + $statement = $dbl->executeWithoutParams("SELECT * FROM settings"); + $rows = $statement->fetchAll(); + + foreach ($rows as &$value) { + $result[$value['Setting']] = $value['Value']; + } + return $result; }else{ //ERROR: not logged in! diff --git a/code/web/public_php/ams/sql/db.sql b/code/web/public_php/ams/sql/db.sql index ccc214125..b52ae65ed 100644 --- a/code/web/public_php/ams/sql/db.sql +++ b/code/web/public_php/ams/sql/db.sql @@ -21,4 +21,4 @@ CREATE TABLE ams_querycache ( `SID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `type` VARCHAR( 64 ) NOT NULL , `query` VARCHAR( 512 ) NOT NULL -); \ No newline at end of file +); diff --git a/code/web/public_php/ams/templates/layout.tpl b/code/web/public_php/ams/templates/layout.tpl index c949263d1..33dbf3be0 100644 --- a/code/web/public_php/ams/templates/layout.tpl +++ b/code/web/public_php/ams/templates/layout.tpl @@ -167,7 +167,7 @@
- {if $permission > 1}

AMS 0.10.0 Powered by: Charisma

{/if} + {if $permission > 1}

AMS 0.11.0 Powered by: Charisma

{/if}
{/if}
diff --git a/code/web/public_php/ams/templates/login.tpl b/code/web/public_php/ams/templates/login.tpl index 7acdf3bbe..23834554a 100644 --- a/code/web/public_php/ams/templates/login.tpl +++ b/code/web/public_php/ams/templates/login.tpl @@ -12,6 +12,7 @@
{$login_info}
+
@@ -42,9 +43,13 @@ {$login_error_message}
{/if} + + + + {/block} diff --git a/code/web/public_php/ams/templates/register.tpl b/code/web/public_php/ams/templates/register.tpl index b5ea3980d..24aac42a2 100644 --- a/code/web/public_php/ams/templates/register.tpl +++ b/code/web/public_php/ams/templates/register.tpl @@ -12,6 +12,7 @@
{$welcome_message}
+ {if $userRegistration == '0'|| $userRegistration == '2'} {$title} @@ -111,6 +112,9 @@

+ {else} + Registration Disabled! + {/if} diff --git a/code/web/public_php/ams/templates/settings.tpl b/code/web/public_php/ams/templates/settings.tpl index 4ee9f2c6a..94883c9de 100644 --- a/code/web/public_php/ams/templates/settings.tpl +++ b/code/web/public_php/ams/templates/settings.tpl @@ -323,6 +323,57 @@ + + {if $permission == '3'} +
+
+
+ User Registration +
+
+
+
+ User Registration + +
+
+ +
+ +
+ +
+ +
+
+ + + +
+ +
+ +
+
+
+
+
+
+
+ {/if} + diff --git a/code/web/public_php/login/r2_login.php b/code/web/public_php/login/r2_login.php index ee4b68819..b0a8a2d79 100644 --- a/code/web/public_php/login/r2_login.php +++ b/code/web/public_php/login/r2_login.php @@ -14,6 +14,19 @@ include_once('../ring/join_shard.php'); + function get_salt($password) + { + if ($password[0] == '$') + { + $salt = substr($password, 0, 19); + } + else + { + $salt = substr($password, 0, 2); + } + return $salt; + } + // see errorMsg function errorMsgBlock($errNum=GENERIC_ERROR_NUM) // $mixedArgs { @@ -132,6 +145,7 @@ { $logFile = new CWwwLog(); $logFile->logStr("PHP ERROR/$errno $errmsg ($filename:$linenum)"); + $logFile->logStr("PHP CALLSTACK/" . print_r(debug_backtrace(), TRUE)); // Never die after an error } @@ -331,7 +345,7 @@ else { $row = mysqli_fetch_assoc ($result); - $salt = substr($row["Password"],0,2); + $salt = get_salt($row["Password"]); if (($cp && $row["Password"] == $password) || (!$cp && $row["Password"] == crypt($password, $salt))) { // Store the real login (with correct case) @@ -488,7 +502,7 @@ else { $res_array = mysqli_fetch_assoc($result); - $salt = substr($res_array['Password'], 0, 2); + $salt = get_salt($res_array['Password']); } echo "1:".$salt; diff --git a/code/web/public_php/setup/database.php b/code/web/public_php/setup/database.php index 303df57d5..3e195f2b8 100644 --- a/code/web/public_php/setup/database.php +++ b/code/web/public_php/setup/database.php @@ -1,12 +1,12 @@ serialUInt32(strlen($val)); + $valLen = strlen($val); + $this->serialUInt32($valLen); $this->Buffer .= $val; - $this->Pos += strlen($val); + $this->Pos += $valLen; debug(sprintf ("write string '%s' %d
\n", $val, $this->Pos)); } } @@ -103,7 +104,8 @@ } else { - $this->serialUInt32($val->toInt()); + $intValue = $val->toInt(); + $this->serialUInt32($intValue); debug(sprintf ("write enum '%s' %d
\n", $val->toString(), $this->Pos)); } }