diff --git a/code/CMakeModules/FindLibOVR.cmake b/code/CMakeModules/FindLibOVR.cmake new file mode 100644 index 000000000..1403a4b2c --- /dev/null +++ b/code/CMakeModules/FindLibOVR.cmake @@ -0,0 +1,70 @@ +# - Locate LibOVR library +# This module defines +# LIBOVR_LIBRARIES, the libraries to link against +# LIBOVR_FOUND, if false, do not try to link to LIBOVR +# LIBOVR_INCLUDE_DIR, where to find headers. + +IF(LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIR) + # in cache already + SET(LIBOVR_FIND_QUIETLY TRUE) +ENDIF(LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIR) + +FIND_PATH(LIBOVR_INCLUDE_DIR + OVR.h + PATHS + $ENV{LIBOVR_DIR}/Include + /usr/local/include + /usr/include + /sw/include + /opt/local/include + /opt/csw/include + /opt/include +) + +IF(UNIX) + IF(TARGET_X64) + SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/Linux/Release/x86_64") + ELSE(TARGET_X64) + SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/Linux/Release/i386") + ENDIF(TARGET_X64) +ELSEIF(APPLE) + SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/MacOS/Release") +ELSEIF(WIN32) + IF(TARGET_X64) + SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/x64") + ELSE(TARGET_X64) + SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/Win32") + ENDIF(TARGET_X64) +ENDIF(UNIX) + +FIND_LIBRARY(LIBOVR_LIBRARY + NAMES ovr + PATHS + $ENV{LIBOVR_DIR}/${LIBOVR_LIBRARY_BUILD_PATH} + /usr/local/lib + /usr/lib + /usr/local/X11R6/lib + /usr/X11R6/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + /usr/freeware/lib64 +) + +IF(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR) + IF(NOT LIBOVR_FIND_QUIETLY) + MESSAGE(STATUS "Found LibOVR: ${LIBOVR_LIBRARY}") + ENDIF(NOT LIBOVR_FIND_QUIETLY) + SET(LIBOVR_FOUND "YES") + SET(LIBOVR_DEFINITIONS "-DHAVE_LIBOVR") + IF(UNIX) + SET(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY} X11 Xinerama udev pthread) + ELSE(UNIX) + SET(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY}) + ENDIF(UNIX) +ELSE(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR) + IF(NOT LIBOVR_FIND_QUIETLY) + MESSAGE(STATUS "Warning: Unable to find LibOVR!") + ENDIF(NOT LIBOVR_FIND_QUIETLY) +ENDIF(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR) diff --git a/code/CMakeModules/FindMySQL.cmake b/code/CMakeModules/FindMySQL.cmake index 1da6157fa..eb2102c8d 100644 --- a/code/CMakeModules/FindMySQL.cmake +++ b/code/CMakeModules/FindMySQL.cmake @@ -58,6 +58,8 @@ ELSE(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) SET(MYSQL_LIBRARIES optimized ${MYSQL_LIBRARY_RELEASE}) IF(MYSQL_LIBRARY_DEBUG) SET(MYSQL_LIBRARIES ${MYSQL_LIBRARIES} debug ${MYSQL_LIBRARY_DEBUG}) + ELSE(MYSQL_LIBRARY_DEBUG) + SET(MYSQL_LIBRARIES ${MYSQL_LIBRARIES} debug ${MYSQL_LIBRARY_RELEASE}) ENDIF(MYSQL_LIBRARY_DEBUG) FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index 4308d0b44..f3897cce0 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -324,6 +324,8 @@ MACRO(NL_SETUP_NEL_DEFAULT_OPTIONS) OPTION(WITH_NEL_MAXPLUGIN "Build NeL 3dsMax Plugin" OFF) OPTION(WITH_NEL_SAMPLES "Build NeL Samples" ON ) OPTION(WITH_NEL_TESTS "Build NeL Unit Tests" ON ) + + OPTION(WITH_LIBOVR "With LibOVR support" OFF) ENDMACRO(NL_SETUP_NEL_DEFAULT_OPTIONS) MACRO(NL_SETUP_NELNS_DEFAULT_OPTIONS) diff --git a/code/nel/CMakeLists.txt b/code/nel/CMakeLists.txt index 1929135b4..2a392ddf9 100644 --- a/code/nel/CMakeLists.txt +++ b/code/nel/CMakeLists.txt @@ -41,6 +41,10 @@ IF(WITH_GTK) FIND_PACKAGE(GTK2) ENDIF(WITH_GTK) +IF(WITH_LIBOVR) + FIND_PACKAGE(LibOVR) +ENDIF(WITH_LIBOVR) + IF(WITH_INSTALL_LIBRARIES) IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) diff --git a/code/nel/include/nel/3d/bloom_effect.h b/code/nel/include/nel/3d/bloom_effect.h index 77673741c..c10967254 100644 --- a/code/nel/include/nel/3d/bloom_effect.h +++ b/code/nel/include/nel/3d/bloom_effect.h @@ -138,6 +138,8 @@ private: NLMISC::CSmartPtr _BlurFinalTex; // used as render target in first blur pass, and as displayed texture on second blur pass. NLMISC::CSmartPtr _BlurHorizontalTex; + // original render target + NLMISC::CSmartPtr _OriginalRenderTarget; // materials diff --git a/code/nel/include/nel/3d/driver.h b/code/nel/include/nel/3d/driver.h index d090d77da..655a9e62b 100644 --- a/code/nel/include/nel/3d/driver.h +++ b/code/nel/include/nel/3d/driver.h @@ -30,6 +30,7 @@ #include "nel/3d/vertex_buffer.h" #include "nel/3d/index_buffer.h" #include "nel/3d/vertex_program.h" +#include "nel/3d/pixel_program.h" #include "nel/3d/material.h" #include "nel/misc/mutex.h" #include "nel/3d/primitive_profile.h" @@ -141,7 +142,6 @@ public: */ enum TMatrixCount { MaxModelMatrix= 16 }; - protected: CSynchronized _SyncTexDrvInfos; @@ -152,6 +152,7 @@ protected: TIBDrvInfoPtrList _IBDrvInfos; TPolygonMode _PolygonMode; TVtxPrgDrvInfoPtrList _VtxPrgDrvInfos; + TPixelPrgDrvInfoPtrList _PixelPrgDrvInfos; TShaderDrvInfoPtrList _ShaderDrvInfos; uint _ResetCounter; @@ -172,6 +173,7 @@ public: */ // @{ virtual void disableHardwareVertexProgram()=0; + virtual void disableHardwarePixelProgram()=0; virtual void disableHardwareVertexArrayAGP()=0; virtual void disableHardwareTextureShader()=0; // @} @@ -857,6 +859,8 @@ public: uint32 cubeFace = 0 ) = 0 ; + virtual ITexture *getRenderTarget() const = 0; + /** Trick method : copy the current texture target into another texture without updating the current texture. * * This method copies the current texture into another texture. @@ -1002,13 +1006,19 @@ public: /** * Does the driver supports vertex programs ? */ - virtual bool isVertexProgramSupported () const =0; + virtual bool supportVertexProgram () const =0; /** * Does the driver supports vertex program, but emulated by CPU ? */ virtual bool isVertexProgramEmulated () const =0; + /** + * Does the driver supports pixel programs ? + */ + virtual bool supportPixelProgram() const =0; + virtual bool supportPixelProgram(CPixelProgram::TProfile profile) const =0; + /** @@ -1021,7 +1031,16 @@ public: virtual bool activeVertexProgram (CVertexProgram *program) =0; /** - * Setup constant values. + * Activate / disactivate a pixel program + * + * \param program is a pointer on a pixel program. Can be NULL to disable the current pixel program. + * + * \return true if setup/unsetup successed, false else. + */ + virtual bool activePixelProgram (CPixelProgram *program) =0; + + /** + * Setup vertex program constant (uniform) values. */ virtual void setConstant (uint index, float, float, float, float) =0; virtual void setConstant (uint index, double, double, double, double) =0; @@ -1031,7 +1050,34 @@ public: virtual void setConstant (uint index, uint num, const float *src) =0; /// setup several 4 double csts taken from the given tab virtual void setConstant (uint index, uint num, const double *src) =0; + // TODO: rename to setVertexProgramConstant + + /** + * Setup pixel program constant (uniform) values. + */ + virtual void setPixelProgramConstant (uint index, float, float, float, float) =0; + virtual void setPixelProgramConstant (uint index, double, double, double, double) =0; + virtual void setPixelProgramConstant (uint index, const NLMISC::CVector& value) =0; + virtual void setPixelProgramConstant (uint index, const NLMISC::CVectorD& value) =0; + /// setup several 4 float csts taken from the given tab + virtual void setPixelProgramConstant (uint index, uint num, const float *src) =0; + /// setup several 4 double csts taken from the given tab + virtual void setPixelProgramConstant (uint index, uint num, const double *src) =0; + // TODO: uint32 and sint32 uniform types supported in opengl from gp4fp and gp5fp and sint32 in d3d + /** + * Setup constants with a current matrix. + * + * This call must be done after setFrustum(), setupViewMatrix() or setupModelMatrix() to get correct + * results. + * + * \param index is the base constant index where to store the matrix. This index must be a multiple of 4. + * \param matrix is the matrix id to store in the constants + * \param transform is the transformation to apply to the matrix before store it in the constants. + * + */ + virtual void setPixelProgramConstantMatrix (uint index, TMatrix matrix, TTransform transform) =0; + /** * Setup constants with a current matrix. * @@ -1080,10 +1126,10 @@ public: /// test whether the device supports some form of texture shader. (could be limited to DX6 EMBM for example) virtual bool supportTextureShaders() const = 0; // Is the shader water supported ? If not, the driver caller should implement its own version - virtual bool isWaterShaderSupported() const = 0; + virtual bool supportWaterShader() const = 0; // /// test whether a texture addressing mode is supported - virtual bool isTextureAddrModeSupported(CMaterial::TTexAddressingMode mode) const = 0; + virtual bool supportTextureAddrMode(CMaterial::TTexAddressingMode mode) const = 0; /** setup the 2D matrix for the OffsetTexture, OffsetTextureScale and OffsetTexture addressing mode * It should be stored as the following * [a0 a1] @@ -1258,6 +1304,7 @@ protected: friend class ITextureDrvInfos; friend class IMaterialDrvInfos; friend class IVertexProgramDrvInfos; + friend class IPixelProgramDrvInfos; friend class IShaderDrvInfos; /// remove ptr from the lists in the driver. @@ -1268,6 +1315,7 @@ protected: void removeMatDrvInfoPtr(ItMatDrvInfoPtrList shaderIt); void removeShaderDrvInfoPtr(ItShaderDrvInfoPtrList shaderIt); void removeVtxPrgDrvInfoPtr(ItVtxPrgDrvInfoPtrList vtxPrgDrvInfoIt); + void removePixelPrgDrvInfoPtr(ItPixelPrgDrvInfoPtrList pixelPrgDrvInfoIt); private: bool _StaticMemoryToVRAM; diff --git a/code/nel/include/nel/3d/driver_user.h b/code/nel/include/nel/3d/driver_user.h index bfe4c1755..fff83d6d5 100644 --- a/code/nel/include/nel/3d/driver_user.h +++ b/code/nel/include/nel/3d/driver_user.h @@ -133,6 +133,7 @@ public: // @{ virtual void disableHardwareVertexProgram(); + virtual void disableHardwarePixelProgram(); virtual void disableHardwareVertexArrayAGP(); virtual void disableHardwareTextureShader(); diff --git a/code/nel/include/nel/3d/material.h b/code/nel/include/nel/3d/material.h index a7ca18bff..bf00f9741 100644 --- a/code/nel/include/nel/3d/material.h +++ b/code/nel/include/nel/3d/material.h @@ -171,7 +171,12 @@ public: * - Alpha of texture in stage 0 is blended with alpha of texture in stage 1. Blend done with the alpha color of each * stage and the whole is multiplied by the alpha in color vertex [AT0*ADiffuseCol+AT1*(1-ADiffuseCol)]*AStage * - RGB still unchanged - * + * Water : + * - Water + * PostProcessing : + * - For internal use only when a pixel program is set manually through activePixelProgram. + * - Only textures are set by CMaterial (does not work with ps_3_0 for some reason), the rest must be set manually. + * - May be replaced in the future by some generic shader system. */ enum TShader { Normal=0, Bump, @@ -183,6 +188,7 @@ public: PerPixelLightingNoSpec, Cloud, Water, + PostProcessing, shaderCount}; /// \name Texture Env Modes. diff --git a/code/nel/include/nel/3d/pixel_program.h b/code/nel/include/nel/3d/pixel_program.h new file mode 100644 index 000000000..183ad2d83 --- /dev/null +++ b/code/nel/include/nel/3d/pixel_program.h @@ -0,0 +1,111 @@ +/** \file pixel_program.h + * Pixel program definition + * + * $Id: pixel_program.h,v 1.1.2.3 2007/07/06 15:58:45 legallo Exp $ + */ + +/* Copyright, 2000, 2001 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef NL_PIXEL_PROGRAM_H +#define NL_PIXEL_PROGRAM_H + +#include +#include + +#include + +namespace NL3D { + +// List typedef. +class IDriver; +class IPixelProgramDrvInfos; +typedef std::list TPixelPrgDrvInfoPtrList; +typedef TPixelPrgDrvInfoPtrList::iterator ItPixelPrgDrvInfoPtrList; + +// Class for interaction of pixel program with Driver. +// IPixelProgramDrvInfos represent the real data of the pixel program, stored into the driver. +class IPixelProgramDrvInfos : public NLMISC::CRefCount +{ +private: + IDriver *_Driver; + ItPixelPrgDrvInfoPtrList _DriverIterator; + +public: + IPixelProgramDrvInfos (IDriver *drv, ItPixelPrgDrvInfoPtrList it); + // The virtual dtor is important. + virtual ~IPixelProgramDrvInfos(void); +}; + + +//------------------------------------------------------------------------------- +class CPixelProgram : public NLMISC::CRefCount +{ +public: + + enum TProfile + { + // TODO: + // If it's more useful, change this to a flags bitfield and + // change the d3d (and gl) code to generate the bitfield of + // supported modes instead of doing a >= version check. + + // direct3d - 0xD3D0,major,minor + ps_1_1 = 0xD3D00101, + ps_1_2 = 0xD3D00102, + ps_1_3 = 0xD3D00103, + ps_1_4 = 0xD3D00104, + ps_2_0 = 0xD3D00200, + ps_2_x = 0xD3D00201, // not sure... + ps_3_0 = 0xD3D00300, + + // opengl - 0x0610,bitfield + // fp20 = 0x061B0001, // very limited and outdated, unnecessary + // fp30 = 0x06100002, // NV_fragment_program, now arbfp1, redundant + arbfp1 = 0x06100004, // ARB_fragment_program + fp40 = 0x06100008, // NV_fragment_program2, arbfp1 with "OPTION NV_fragment_program2;\n" + gp4fp = 0x06100010, // NV_gpu_program4 + gp5fp = 0x06100020, // NV_gpu_program5 + }; + + /// Constructor + CPixelProgram (const char* program); + + /// Destructor + virtual ~CPixelProgram (); + + /// Get the program + inline const std::string& getProgram() const { return _Program; }; + + /// The driver informations. For the driver implementation only. + NLMISC::CRefPtr _DrvInfo; + +protected: + + /// The progam + std::string _Program; +}; + + +} // NL3D + + +#endif // NL_PIXEL_PROGRAM_H + +/* End of vertex_program.h */ diff --git a/code/nel/include/nel/3d/scene.h b/code/nel/include/nel/3d/scene.h index 1d54ce7a6..e0648ebd3 100644 --- a/code/nel/include/nel/3d/scene.h +++ b/code/nel/include/nel/3d/scene.h @@ -826,7 +826,8 @@ private: void flushSSSModelRequests(); // common vb for water display CVertexBuffer _WaterVB; - + + bool _RequestParticlesAnimate; }; diff --git a/code/nel/include/nel/3d/stereo_debugger.h b/code/nel/include/nel/3d/stereo_debugger.h new file mode 100644 index 000000000..b07a9630c --- /dev/null +++ b/code/nel/include/nel/3d/stereo_debugger.h @@ -0,0 +1,134 @@ +/** + * \file stereo_debugger.h + * \brief CStereoDebugger + * \date 2013-07-03 20:17GMT + * \author Jan Boon (Kaetemi) + * CStereoDebugger + */ + +/* + * 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 + * . + */ + +#if !FINAL_VERSION +#ifndef NL3D_STEREO_DEBUGGER_H +#define NL3D_STEREO_DEBUGGER_H +#include + +// STL includes + +// NeL includes +#include +#include + +// Project includes +#include +#include +#include +#include + +#define NL_STEREO_MAX_USER_CAMERAS 8 + +namespace NL3D { + +class ITexture; +class CTextureUser; +class CPixelProgram; + +/** + * \brief CStereoDebugger + * \date 2013-07-03 20:17GMT + * \author Jan Boon (Kaetemi) + * CStereoDebugger + */ +class CStereoDebugger : public IStereoDisplay +{ +public: + CStereoDebugger(); + virtual ~CStereoDebugger(); + + + /// Sets driver and generates necessary render targets + virtual void setDriver(NL3D::UDriver *driver); + void releaseTextures(); + void initTextures(); + void setTextures(); + void verifyTextures(); + + /// 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; + + /// 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(); + /// Interface within the 3D scene + virtual bool wantInterface3D(); + /// 2D Interface + virtual bool wantInterface2D(); + + /// 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(); + + + static void listDevices(std::vector &devicesOut); + +private: + UDriver *m_Driver; + + int m_Stage; + int m_SubStage; + + CViewport m_LeftViewport; + CViewport m_RightViewport; + 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; + CPixelProgram *m_PixelProgram; + +}; /* class CStereoDebugger */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_STEREO_DEBUGGER_H */ +#endif /* #if !FINAL_VERSION */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/stereo_display.h b/code/nel/include/nel/3d/stereo_display.h new file mode 100644 index 000000000..e3b5b3716 --- /dev/null +++ b/code/nel/include/nel/3d/stereo_display.h @@ -0,0 +1,141 @@ +/** + * \file stereo_display.h + * \brief IStereoDisplay + * \date 2013-06-27 16:29GMT + * \author Jan Boon (Kaetemi) + * IStereoDisplay + */ + +/* + * 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_STEREO_DISPLAY_H +#define NL3D_STEREO_DISPLAY_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NL3D { + +class UCamera; +class CViewport; +class CFrustum; +class IStereoDisplay; +class UTexture; +class UDriver; + +class IStereoDeviceFactory : public NLMISC::CRefCount +{ +public: + IStereoDeviceFactory() { } + virtual ~IStereoDeviceFactory() { } + virtual IStereoDisplay *createDevice() const = 0; +}; + +struct CStereoDeviceInfo +{ +public: + enum TStereoDeviceClass + { + StereoDisplay, + StereoHMD, + }; + + enum TStereoDeviceLibrary + { + NeL3D, + OVR, + LibVR, + OpenHMD, + }; + + NLMISC::CSmartPtr Factory; + + TStereoDeviceLibrary Library; + TStereoDeviceClass Class; + std::string Manufacturer; + std::string ProductName; + std::string Serial; // A unique device identifier +}; + +/** + * \brief IStereoDisplay + * \date 2013-06-27 16:29GMT + * \author Jan Boon (Kaetemi) + * IStereoDisplay + */ +class IStereoDisplay +{ +public: + IStereoDisplay(); + virtual ~IStereoDisplay(); + + /// Sets driver and generates necessary render targets + virtual void setDriver(NL3D::UDriver *driver) = 0; + + /// Gets the required screen resolution for this device + virtual bool getScreenResolution(uint &width, uint &height) = 0; + /// Set latest camera position etcetera + 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; + + /// Is there a next pass + virtual bool nextPass() = 0; + /// Gets the current viewport + virtual const NL3D::CViewport &getCurrentViewport() const = 0; + /// Gets the current camera frustum + virtual const NL3D::CFrustum &getCurrentFrustum(uint cid) const = 0; + /// Gets the current camera frustum + virtual void getCurrentFrustum(uint cid, NL3D::UCamera *camera) const = 0; + /// Gets the current camera matrix + virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const = 0; + + /// At the start of a new render target + virtual bool wantClear() = 0; + /// The 3D scene + virtual bool wantScene() = 0; + /// Interface within the 3D scene + virtual bool wantInterface3D() = 0; + /// 2D Interface + virtual bool wantInterface2D() = 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); + static void listDevices(std::vector &devicesOut); + static IStereoDisplay *createDevice(const CStereoDeviceInfo &deviceInfo); + static void releaseUnusedLibraries(); + static void releaseAllLibraries(); + +}; /* class IStereoDisplay */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_STEREO_DISPLAY_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/stereo_hmd.h b/code/nel/include/nel/3d/stereo_hmd.h new file mode 100644 index 000000000..95c159cfd --- /dev/null +++ b/code/nel/include/nel/3d/stereo_hmd.h @@ -0,0 +1,73 @@ +/** + * \file stereo_hmd.h + * \brief IStereoHMD + * \date 2013-06-27 16:30GMT + * \author Jan Boon (Kaetemi) + * IStereoHMD + */ + +/* + * 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_STEREO_HMD_H +#define NL3D_STEREO_HMD_H +#include + +// STL includes + +// NeL includes + +// Project includes +#include + +namespace NL3D { + +/** + * \brief IStereoHMD + * \date 2013-06-27 16:30GMT + * \author Jan Boon (Kaetemi) + * IStereoHMD + */ +class IStereoHMD : public IStereoDisplay +{ +public: + IStereoHMD(); + virtual ~IStereoHMD(); + + /// Get the HMD orientation + virtual NLMISC::CQuat getOrientation() const = 0; + + /// Get GUI center (1 = width, 1 = height, 0 = center) + virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const = 0; + + /// Set the head model, eye position relative to orientation point + virtual void setEyePosition(const NLMISC::CVector &v) = 0; + /// Get the head model, eye position relative to orientation point + virtual const NLMISC::CVector &getEyePosition() const = 0; + + /// Set the scale of the game in units per meter + virtual void setScale(float s) = 0; + +}; /* class IStereoHMD */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_STEREO_HMD_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/stereo_ovr.h b/code/nel/include/nel/3d/stereo_ovr.h new file mode 100644 index 000000000..c2dccf930 --- /dev/null +++ b/code/nel/include/nel/3d/stereo_ovr.h @@ -0,0 +1,176 @@ +/** + * \file stereo_ovr.h + * \brief CStereoOVR + * \date 2013-06-25 22:22GMT + * \author Jan Boon (Kaetemi) + * CStereoOVR + */ + +/* + * 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 + * . + * + * 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_H +#define NL3D_STEREO_OVR_H + +#ifdef HAVE_LIBOVR + +#include + +// STL includes + +// NeL includes +#include +#include + +// Project includes +#include +#include +#include +#include + +namespace NL3D { + +class ITexture; +class CTextureUser; +class CStereoOVRDevicePtr; +class CStereoOVRDeviceHandle; +class CPixelProgram; + +#define NL_STEREO_MAX_USER_CAMERAS 8 + +/** + * \brief CStereoOVR + * \date 2013-06-25 22:22GMT + * \author Jan Boon (Kaetemi) + * CStereoOVR + */ +class CStereoOVR : public IStereoHMD +{ +public: + CStereoOVR(const CStereoOVRDeviceHandle *handle); + virtual ~CStereoOVR(); + + /// Sets driver and generates necessary render targets + virtual void setDriver(NL3D::UDriver *driver); + + /// 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; + + /// 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(); + /// Interface within the 3D scene + virtual bool wantInterface3D(); + /// 2D Interface + virtual bool wantInterface2D(); + + /// 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; + + /// 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); + + + 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_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]; + CMatrix m_CameraMatrix[NL_STEREO_MAX_USER_CAMERAS]; + mutable bool m_OrientationCached; + mutable NLMISC::CQuat m_OrientationCache; + UDriver *m_Driver; + NLMISC::CSmartPtr m_BarrelTex; + NL3D::CTextureUser *m_BarrelTexU; + NL3D::UMaterial m_BarrelMat; + NLMISC::CQuadUV m_BarrelQuadLeft; + NLMISC::CQuadUV m_BarrelQuadRight; + CPixelProgram *m_PixelProgram; + NLMISC::CVector m_EyePosition; + float m_Scale; + +}; /* class CStereoOVR */ + +} /* namespace NL3D */ + +#endif /* HAVE_LIBOVR */ + +#endif /* #ifndef NL3D_STEREO_OVR_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/u_driver.h b/code/nel/include/nel/3d/u_driver.h index d66a72e47..1397c9c6e 100644 --- a/code/nel/include/nel/3d/u_driver.h +++ b/code/nel/include/nel/3d/u_driver.h @@ -168,6 +168,7 @@ public: */ // @{ virtual void disableHardwareVertexProgram()=0; + virtual void disableHardwarePixelProgram()=0; virtual void disableHardwareVertexArrayAGP()=0; virtual void disableHardwareTextureShader()=0; // @} diff --git a/code/nel/src/3d/CMakeLists.txt b/code/nel/src/3d/CMakeLists.txt index 6f632e261..b92f58dba 100644 --- a/code/nel/src/3d/CMakeLists.txt +++ b/code/nel/src/3d/CMakeLists.txt @@ -164,7 +164,9 @@ SOURCE_GROUP(Driver FILES vertex_program.cpp ../../include/nel/3d/vertex_program.h vertex_program_parse.cpp - ../../include/nel/3d/vertex_program_parse.h) + ../../include/nel/3d/vertex_program_parse.h + pixel_program.cpp + ../../include/nel/3d/pixel_program.h) SOURCE_GROUP(Font FILES computed_string.cpp @@ -686,12 +688,22 @@ SOURCE_GROUP(Shadows FILES ../../include/nel/3d/shadow_map_manager.h shadow_poly_receiver.cpp ../../include/nel/3d/shadow_poly_receiver.h) +SOURCE_GROUP(Stereo FILES + stereo_display.cpp + ../../include/nel/3d/stereo_display.h + stereo_hmd.cpp + ../../include/nel/3d/stereo_hmd.h + stereo_ovr.cpp + stereo_ovr_fp.cpp + ../../include/nel/3d/stereo_ovr.h + stereo_debugger.cpp + ../../include/nel/3d/stereo_debugger.h) NL_TARGET_LIB(nel3d ${HEADERS} ${SRC}) -INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${FREETYPE_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${FREETYPE_INCLUDE_DIRS} ${LIBOVR_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(nel3d nelmisc ${FREETYPE_LIBRARY}) +TARGET_LINK_LIBRARIES(nel3d nelmisc ${FREETYPE_LIBRARY} ${LIBOVR_LIBRARIES}) SET_TARGET_PROPERTIES(nel3d PROPERTIES LINK_INTERFACE_LIBRARIES "") NL_DEFAULT_PROPS(nel3d "NeL, Library: NeL 3D") NL_ADD_RUNTIME_FLAGS(nel3d) @@ -701,6 +713,8 @@ NL_ADD_LIB_SUFFIX(nel3d) ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) +ADD_DEFINITIONS(${LIBOVR_DEFINITIONS}) + IF(WITH_PCH) ADD_NATIVE_PRECOMPILED_HEADER(nel3d ${CMAKE_CURRENT_SOURCE_DIR}/std3d.h ${CMAKE_CURRENT_SOURCE_DIR}/std3d.cpp) ENDIF(WITH_PCH) diff --git a/code/nel/src/3d/bloom_effect.cpp b/code/nel/src/3d/bloom_effect.cpp index 7cbb48310..3eb24518e 100644 --- a/code/nel/src/3d/bloom_effect.cpp +++ b/code/nel/src/3d/bloom_effect.cpp @@ -285,6 +285,8 @@ void CBloomEffect::initBloom() // clientcfg if(!_Init) init(); + _OriginalRenderTarget = static_cast(_Driver)->getDriver()->getRenderTarget(); + // if window resize, reinitialize textures if(_WndWidth!=_Driver->getWindowWidth() || _WndHeight!=_Driver->getWindowHeight()) { @@ -349,13 +351,15 @@ void CBloomEffect::initBloom() // clientcfg } } - NL3D::CTextureUser *txt = (_InitBloomEffect) ? (new CTextureUser(_InitText)) : (new CTextureUser()); - if(!((CDriverUser *) _Driver)->setRenderTarget(*txt, 0, 0, _WndWidth, _WndHeight)) + if (!_OriginalRenderTarget) { - nlwarning("setRenderTarget return false with initial texture for bloom effect\n"); - return; + 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; + } } - delete txt; } //----------------------------------------------------------------------------------------------------------- @@ -371,13 +375,13 @@ void CBloomEffect::endBloom() // clientcfg if(_Driver->getWindowWidth()==0 || _Driver->getWindowHeight()==0) return; - CTextureUser *txt1 = (_InitBloomEffect) ? (new CTextureUser(_InitText)) : (new CTextureUser()); - CTextureUser *txt2 = new CTextureUser(_BlurFinalTex); - CRect *rect1 = new CRect(0, 0, _WndWidth, _WndHeight); - CRect *rect2 = new CRect(0, 0, _BlurWidth, _BlurHeight); + CTextureUser txt1 = _OriginalRenderTarget ? CTextureUser(_OriginalRenderTarget) : ((_InitBloomEffect) ? (CTextureUser(_InitText)) : (CTextureUser())); + CTextureUser txt2(_BlurFinalTex); + CRect rect1(0, 0, _WndWidth, _WndHeight); + CRect rect2(0, 0, _BlurWidth, _BlurHeight); // stretch rect - ((CDriverUser *) _Driver)->stretchRect(_Scene, *txt1 , *rect1, - *txt2, *rect2); + ((CDriverUser *) _Driver)->stretchRect(_Scene, txt1 , rect1, + txt2, rect2); // horizontal blur pass doBlur(true); @@ -387,10 +391,6 @@ void CBloomEffect::endBloom() // clientcfg // apply blur with a blend operation applyBlur(); - delete txt1; - delete txt2; - delete rect1; - delete rect2; } //----------------------------------------------------------------------------------------------------------- @@ -399,16 +399,30 @@ void CBloomEffect::applyBlur() { NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); - // in opengl, display in init texture - if(_InitBloomEffect) + /*if (_OriginalRenderTarget) { - CTextureUser *txt = new CTextureUser(_InitText); - if(!((CDriverUser *) _Driver)->setRenderTarget(*txt, 0, 0, _WndWidth, _WndHeight)) + 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; } - delete txt; + }*/ + 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 @@ -463,7 +477,9 @@ void CBloomEffect::applyBlur() void CBloomEffect::endInterfacesDisplayBloom() // clientcfg { - if(_InitBloomEffect) + // 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; @@ -475,9 +491,8 @@ void CBloomEffect::endInterfacesDisplayBloom() // clientcfg return; NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); - CTextureUser *txt = new CTextureUser(); - ((CDriverUser *)_Driver)->setRenderTarget(*txt, 0, 0, 0, 0); - delete txt; + CTextureUser txtNull; + ((CDriverUser *)_Driver)->setRenderTarget(txtNull, 0, 0, 0, 0); // initialize texture coordinates float newU = drvInternal->isTextureRectangle(_InitText) ? (float)_WndWidth : 1.f; @@ -497,6 +512,8 @@ void CBloomEffect::endInterfacesDisplayBloom() // clientcfg _Driver->drawQuad(_DisplayQuad, _DisplayInitMat); _Driver->setMatrixMode3D(pCam); } + + _OriginalRenderTarget = NULL; } @@ -523,14 +540,13 @@ void CBloomEffect::doBlur(bool horizontalBlur) } NL3D::IDriver *drvInternal = ((CDriverUser *) _Driver)->getDriver(); - CTextureUser *txt = new CTextureUser(endTexture); + CTextureUser txt(endTexture); // initialize render target - if(!((CDriverUser *) _Driver)->setRenderTarget(*txt, 0, 0, _BlurWidth, _BlurHeight)) + if(!((CDriverUser *) _Driver)->setRenderTarget(txt, 0, 0, _BlurWidth, _BlurHeight)) { nlwarning("setRenderTarget return false with blur texture for bloom effect\n"); return; } - delete txt; // initialize vertex program drvInternal->activeVertexProgram(&TextureOffsetVertexProgram); @@ -579,10 +595,9 @@ void CBloomEffect::doBlur(bool horizontalBlur) // disable render target and vertex program drvInternal->activeVertexProgram(NULL); - txt = new CTextureUser(); - ((CDriverUser *)_Driver)->setRenderTarget(*txt, 0, 0, 0, 0); + CTextureUser cu; + ((CDriverUser *)_Driver)->setRenderTarget(cu, 0, 0, 0, 0); _Driver->setMatrixMode3D(pCam); - delete txt; } }; // NL3D diff --git a/code/nel/src/3d/computed_string.cpp b/code/nel/src/3d/computed_string.cpp index 0c2cd48de..71ea58948 100644 --- a/code/nel/src/3d/computed_string.cpp +++ b/code/nel/src/3d/computed_string.cpp @@ -21,6 +21,7 @@ #include "nel/3d/index_buffer.h" #include "nel/3d/material.h" #include "nel/3d/frustum.h" +#include "nel/3d/viewport.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/debug.h" @@ -85,6 +86,10 @@ void CComputedString::render2D (IDriver& driver, // get window size uint32 wndWidth, wndHeight; driver.getWindowSize(wndWidth, wndHeight); + CViewport vp; + driver.getViewport(vp); + wndWidth = (uint32)((float)wndWidth * vp.getWidth()); + wndHeight = (uint32)((float)wndHeight * vp.getHeight()); // scale to window size. x*= wndWidth; z*= wndHeight; diff --git a/code/nel/src/3d/driver.cpp b/code/nel/src/3d/driver.cpp index fa48649ae..5a08da982 100644 --- a/code/nel/src/3d/driver.cpp +++ b/code/nel/src/3d/driver.cpp @@ -33,7 +33,7 @@ namespace NL3D { // *************************************************************************** -const uint32 IDriver::InterfaceVersion = 0x6b; // added anisotropic filter +const uint32 IDriver::InterfaceVersion = 0x6c; // pixel program interface // *************************************************************************** IDriver::IDriver() : _SyncTexDrvInfos( "IDriver::_SyncTexDrvInfos" ) @@ -258,6 +258,11 @@ void IDriver::removeVtxPrgDrvInfoPtr(ItVtxPrgDrvInfoPtrList vtxPrgDrvInfoIt) { _VtxPrgDrvInfos.erase(vtxPrgDrvInfoIt); } +// *************************************************************************** +void IDriver::removePixelPrgDrvInfoPtr(ItPixelPrgDrvInfoPtrList pixelPrgDrvInfoIt) +{ + _PixelPrgDrvInfos.erase(pixelPrgDrvInfoIt); +} // *************************************************************************** bool IDriver::invalidateShareTexture (ITexture &texture) diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp index 412cb52da..8f8901f5c 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp @@ -193,6 +193,11 @@ CDriverD3D::CDriverD3D() #else // NL_DISABLE_HARDWARE_VERTEX_PROGAM _DisableHardwareVertexProgram = false; #endif // NL_DISABLE_HARDWARE_VERTEX_PROGAM +#ifdef NL_DISABLE_HARDWARE_PIXEL_PROGAM + _DisableHardwarePixelProgram = true; +#else // NL_DISABLE_HARDWARE_PIXEL_PROGAM + _DisableHardwarePixelProgram = false; +#endif // NL_DISABLE_HARDWARE_PIXEL_PROGAM #ifdef NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP _DisableHardwareVertexArrayAGP = true; #else // NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP @@ -1546,13 +1551,15 @@ bool CDriverD3D::setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool r #endif // NL_FORCE_TEXTURE_STAGE_COUNT _VertexProgram = !_DisableHardwareVertexProgram && ((caps.VertexShaderVersion&0xffff) >= 0x0100); - _PixelShader = !_DisableHardwarePixelShader && (caps.PixelShaderVersion&0xffff) >= 0x0101; + _PixelProgramVersion = _DisableHardwareVertexProgram ? 0x0000 : caps.PixelShaderVersion & 0xffff; + nldebug("Pixel Program Version: %i.%i", (uint32)((_PixelProgramVersion & 0xFF00) >> 8), (uint32)(_PixelProgramVersion & 0xFF)); + _PixelProgram = _PixelProgramVersion >= 0x0101; _MaxVerticesByVertexBufferHard = caps.MaxVertexIndex; _MaxLight = caps.MaxActiveLights; if(_MaxLight > 0xFF) _MaxLight = 3; - if (_PixelShader) + if (_PixelProgram) { _MaxNumPerStageConstantLighted = _NbNeLTextureStages; _MaxNumPerStageConstantUnlighted = _NbNeLTextureStages; @@ -2016,6 +2023,8 @@ bool CDriverD3D::swapBuffers() // Reset vertex program setVertexProgram (NULL, NULL); + // Reset pixel program + setPixelShader (NULL); if (_VBHardProfiling) { @@ -2987,7 +2996,7 @@ bool CDriverD3D::stretchRect(ITexture * srcText, NLMISC::CRect &srcRect, ITextur bool CDriverD3D::supportBloomEffect() const { - return isVertexProgramSupported(); + return supportVertexProgram(); } // *************************************************************************** @@ -3330,9 +3339,9 @@ uint COcclusionQueryD3D::getVisibleCount() } // *************************************************************************** -bool CDriverD3D::isWaterShaderSupported() const +bool CDriverD3D::supportWaterShader() const { - H_AUTO_D3D(CDriverD3D_isWaterShaderSupported); + H_AUTO_D3D(CDriverD3D_supportWaterShader); return _PixelShaderVersion >= D3DPS_VERSION(1, 1); } @@ -3618,7 +3627,7 @@ void CDriverD3D::CVertexProgramPtrState::apply(CDriverD3D *driver) void CDriverD3D::CPixelShaderPtrState::apply(CDriverD3D *driver) { H_AUTO_D3D(CDriverD3D_CPixelShaderPtrState); - if (!driver->supportPixelShaders()) return; + if (!driver->supportPixelProgram()) return; driver->_DeviceInterface->SetPixelShader(PixelShader); } diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d.h b/code/nel/src/3d/driver/direct3d/driver_direct3d.h index cff7cb804..085bb7512 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d.h +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d.h @@ -240,6 +240,19 @@ public: CVertexProgamDrvInfosD3D(IDriver *drv, ItVtxPrgDrvInfoPtrList it); ~CVertexProgamDrvInfosD3D(); }; + + +// *************************************************************************** +class CPixelProgramDrvInfosD3D : public IPixelProgramDrvInfos +{ +public: + + // The shader + IDirect3DPixelShader9 *Shader; + + CPixelProgramDrvInfosD3D(IDriver *drv, ItPixelPrgDrvInfoPtrList it); + ~CPixelProgramDrvInfosD3D(); +}; // *************************************************************************** @@ -773,6 +786,7 @@ public: // Driver parameters virtual void disableHardwareVertexProgram(); + virtual void disableHardwarePixelProgram(); virtual void disableHardwareIndexArrayAGP(); virtual void disableHardwareVertexArrayAGP(); virtual void disableHardwareTextureShader(); @@ -841,6 +855,7 @@ public: // todo hulud d3d buffers virtual void getZBufferPart (std::vector &zbuffer, NLMISC::CRect &rect); virtual bool setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width, uint32 height, uint32 mipmapLevel, uint32 cubeFace); + 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 getRenderTargetSize (uint32 &width, uint32 &height); @@ -959,9 +974,9 @@ public: virtual bool supportTextureShaders() const {return false;}; virtual bool supportMADOperator() const; // todo hulud d3d adressing mode - virtual bool isWaterShaderSupported() const; + virtual bool supportWaterShader() const; // todo hulud d3d adressing mode - virtual bool isTextureAddrModeSupported(CMaterial::TTexAddressingMode /* mode */) const {return false;}; + virtual bool supportTextureAddrMode(CMaterial::TTexAddressingMode /* mode */) const {return false;}; // todo hulud d3d adressing mode virtual void setMatrix2DForTextureOffsetAddrMode(const uint /* stage */, const float /* mat */[4]) {} @@ -992,9 +1007,12 @@ public: virtual void endMaterialMultiPass(); // Vertex program - virtual bool isVertexProgramSupported () const; + virtual bool supportVertexProgram () const; + virtual bool supportPixelProgram () const; + virtual bool supportPixelProgram (CPixelProgram::TProfile profile) const; virtual bool isVertexProgramEmulated () const; virtual bool activeVertexProgram (CVertexProgram *program); + virtual bool activePixelProgram (CPixelProgram *program); virtual void setConstant (uint index, float, float, float, float); virtual void setConstant (uint index, double, double, double, double); virtual void setConstant (uint index, const NLMISC::CVector& value); @@ -1006,6 +1024,15 @@ public: virtual void enableVertexProgramDoubleSidedColor(bool doubleSided); virtual bool supportVertexProgramDoubleSidedColor() const; + // Pixel program + virtual void setPixelProgramConstant (uint index, float, float, float, float); + virtual void setPixelProgramConstant (uint index, double, double, double, double); + virtual void setPixelProgramConstant (uint index, const NLMISC::CVector& value); + virtual void setPixelProgramConstant (uint index, const NLMISC::CVectorD& value); + virtual void setPixelProgramConstant (uint index, uint num, const float *src); + virtual void setPixelProgramConstant (uint index, uint num, const double *src); + virtual void setPixelProgramConstantMatrix (uint index, IDriver::TMatrix matrix, IDriver::TTransform transform); + // Occlusion query virtual bool supportOcclusionQuery() const; virtual IOcclusionQuery *createOcclusionQuery(); @@ -1040,8 +1067,6 @@ public: uint32 getMaxVertexIndex() const { return _MaxVertexIndex; } - bool supportPixelShaders() const { return _PixelShader; } - // *** Inline info uint inlGetNumTextStages() const { return _NbNeLTextureStages; } @@ -1892,6 +1917,15 @@ public: return d3dtex; } + // Get the d3dtext mirror of an existing setuped pixel program. + static inline CPixelProgramDrvInfosD3D* getPixelProgramD3D(CPixelProgram& pixelProgram) + { + H_AUTO_D3D(CDriverD3D_getPixelProgramD3D); + CPixelProgramDrvInfosD3D* d3dPixelProgram; + d3dPixelProgram = (CPixelProgramDrvInfosD3D*)(IPixelProgramDrvInfos*)(pixelProgram._DrvInfo); + return d3dPixelProgram; + } + // Get the d3dtext mirror of an existing setuped vertex program. static inline CVertexProgamDrvInfosD3D* getVertexProgramD3D(CVertexProgram& vertexProgram) { @@ -2197,8 +2231,10 @@ private: bool _ForceDXTCCompression:1; bool _TextureCubeSupported; bool _VertexProgram; - bool _PixelShader; + bool _PixelProgram; + uint16 _PixelProgramVersion; bool _DisableHardwareVertexProgram; + bool _DisableHardwarePixelProgram; bool _DisableHardwareVertexArrayAGP; bool _DisableHardwareIndexArrayAGP; bool _DisableHardwarePixelShader; 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 a7d218e79..07ec5187b 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp @@ -567,7 +567,7 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) normalShaderDesc.TexEnvMode[stage] = mat.getTexEnvMode(uint8(stage)); } - if (_PixelShader) + if (_PixelProgram) { #ifdef NL_DEBUG_D3D // Check, should not occured @@ -648,7 +648,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::PostProcessing) { uint stage; for(stage=0 ; stageNeedsConstantForDiffuse && _PixelShader) + if (!pShader->NeedsConstantForDiffuse && _PixelProgram) setPixelShader (pShader->PixelShader); } break; @@ -2019,7 +2019,7 @@ void CDriverD3D::endMaterialMultiPass() bool CDriverD3D::supportCloudRenderSinglePass () const { H_AUTO_D3D(CDriver3D_supportCloudRenderSinglePass); - return _PixelShader; + return _PixelProgram; } // *************************************************************************** diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_pixel_program.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_pixel_program.cpp new file mode 100644 index 000000000..8234fc31d --- /dev/null +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_pixel_program.cpp @@ -0,0 +1,295 @@ +/** \file driver_direct3d_pixel_program.cpp + * Direct 3d driver implementation + * + * $Id: driver_direct3d_pixel_program.cpp,v 1.1.2.4 2007/07/09 15:26:35 legallo Exp $ + * + * \todo manage better the init/release system (if a throw occurs in the init, we must release correctly the driver) + */ + +/* Copyright, 2000 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "stddirect3d.h" + +#include "driver_direct3d.h" + +using namespace std; +using namespace NLMISC; + +namespace NL3D +{ + +// *************************************************************************** + +CPixelProgramDrvInfosD3D::CPixelProgramDrvInfosD3D(IDriver *drv, ItPixelPrgDrvInfoPtrList it) : IPixelProgramDrvInfos (drv, it) +{ + H_AUTO_D3D(CPixelProgramDrvInfosD3D_CPixelProgamDrvInfosD3D) + Shader = NULL; +} + +// *************************************************************************** + +CPixelProgramDrvInfosD3D::~CPixelProgramDrvInfosD3D() +{ + H_AUTO_D3D(CPixelProgramDrvInfosD3D_CPixelProgramDrvInfosD3DDtor) + if (Shader) + Shader->Release(); +} + +// *************************************************************************** + +bool CDriverD3D::supportPixelProgram () const +{ + H_AUTO_D3D(CDriverD3D_supportPixelProgram) + return _PixelProgram; +} + +bool CDriverD3D::supportPixelProgram (CPixelProgram::TProfile profile) const +{ + H_AUTO_D3D(CDriverD3D_supportPixelProgram_profile) + return ((profile & 0xFFFF0000) == 0xD3D00000) + && (_PixelProgramVersion >= (uint16)(profile & 0x0000FFFF)); +} + +// *************************************************************************** + +bool CDriverD3D::activePixelProgram(CPixelProgram *program) +{ + H_AUTO_D3D(CDriverD3D_activePixelProgram ) + if (_DisableHardwarePixelProgram) + return false; + + // Setup or unsetup ? + if (program) + { + // Program setuped ? + if (program->_DrvInfo==NULL) + { + _PixelPrgDrvInfos.push_front (NULL); + ItPixelPrgDrvInfoPtrList itPix = _PixelPrgDrvInfos.begin(); + *itPix = new CPixelProgramDrvInfosD3D(this, itPix); + + // Create a driver info structure + program->_DrvInfo = *itPix; + + const std::string &dest = program->getProgram(); + + LPD3DXBUFFER pShader; + LPD3DXBUFFER pErrorMsgs; + if (D3DXAssembleShader (dest.c_str(), dest.size(), NULL, NULL, 0, &pShader, &pErrorMsgs) == D3D_OK) + { + if (_DeviceInterface->CreatePixelShader((DWORD*)pShader->GetBufferPointer(), &(getPixelProgramD3D(*program)->Shader)) != D3D_OK) + return false; + } + else + { + nlwarning ("Can't assemble pixel program:"); + nlwarning ((const char*)pErrorMsgs->GetBufferPointer()); + return false; + } + } + } + + // Set the pixel program + if (program) + { + CPixelProgramDrvInfosD3D *info = static_cast((IPixelProgramDrvInfos*)program->_DrvInfo); + setPixelShader (info->Shader); + + float z = 0; + float o = 1; + setRenderState (D3DRS_FOGSTART, *((DWORD*) (&o))); + setRenderState (D3DRS_FOGEND, *((DWORD*) (&z))); + } + else + { + setPixelShader (NULL); + + // Set the old fog range + setRenderState (D3DRS_FOGSTART, *((DWORD*) (&_FogStart))); + setRenderState (D3DRS_FOGEND, *((DWORD*) (&_FogEnd))); + } + + return true; +} + +// *************************************************************************** + +void CDriverD3D::setPixelProgramConstant (uint index, float f0, float f1, float f2, float f3) +{ + H_AUTO_D3D(CDriverD3D_setPixelProgramConstant) + if (!_PixelProgram) + { + #ifdef NL_DEBUG + nlwarning("No pixel programs available!!"); + #endif + return; + } + const float tabl[4] = {f0, f1, f2, f3}; + setPixelShaderConstant (index, tabl); +} + +// *************************************************************************** + +void CDriverD3D::setPixelProgramConstant (uint index, double d0, double d1, double d2, double d3) +{ + H_AUTO_D3D(CDriverD3D_setPixelProgramConstant ) + if (!_PixelProgram) + { + #ifdef NL_DEBUG + nlwarning("No pixel programs available!!"); + #endif + return; + } + const float tabl[4] = {(float)d0, (float)d1, (float)d2, (float)d3}; + setPixelShaderConstant (index, tabl); +} + +// *************************************************************************** + +void CDriverD3D::setPixelProgramConstant (uint index, const NLMISC::CVector& value) +{ + H_AUTO_D3D(CDriverD3D_setPixelProgramConstant ) + if (!_PixelProgram) + { + #ifdef NL_DEBUG + nlwarning("No pixel programs available!!"); + #endif + return; + } + const float tabl[4] = {value.x, value.y, value.z, 0}; + setPixelShaderConstant (index, tabl); +} + +// *************************************************************************** + +void CDriverD3D::setPixelProgramConstant (uint index, const NLMISC::CVectorD& value) +{ + H_AUTO_D3D(CDriverD3D_setPixelProgramConstant ) + if (!_PixelProgram) + { + #ifdef NL_DEBUG + nlwarning("No pixel programs available!!"); + #endif + return; + } + const float tabl[4] = {(float)value.x, (float)value.y, (float)value.z, 0}; + setPixelShaderConstant (index, tabl); +} + +// *************************************************************************** + +void CDriverD3D::setPixelProgramConstant (uint index, uint num, const float *src) +{ + H_AUTO_D3D(CDriverD3D_setPixelProgramConstant ) + if (!_PixelProgram) + { + #ifdef NL_DEBUG + nlwarning("No pixel programs available!!"); + #endif + return; + } + uint i; + for (i=0; i_11, matPtr->_21, matPtr->_31, matPtr->_41); + setPixelProgramConstant (index+1, matPtr->_12, matPtr->_22, matPtr->_32, matPtr->_42); + setPixelProgramConstant (index+2, matPtr->_13, matPtr->_23, matPtr->_33, matPtr->_43); + setPixelProgramConstant (index+3, matPtr->_14, matPtr->_24, matPtr->_34, matPtr->_44); +} + +// *************************************************************************** + +void CDriverD3D::disableHardwarePixelProgram() +{ + H_AUTO_D3D(CDriverD3D_disableHardwarePixelProgram) + _DisableHardwarePixelProgram = true; + _PixelProgram = false; +} + +} // NL3D 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 7922b30ea..87f41678b 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp @@ -1187,6 +1187,11 @@ bool CDriverD3D::setRenderTarget (ITexture *tex, uint32 /* x */, uint32 /* y */, return true; } +ITexture *CDriverD3D::getRenderTarget() const +{ + return _RenderTarget.Texture; +} + // *************************************************************************** bool CDriverD3D::copyTargetToTexture (ITexture * /* tex */, uint32 /* offsetx */, uint32 /* offsety */, uint32 /* x */, uint32 /* y */, uint32 /* width */, diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex_program.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex_program.cpp index ce6bda220..a758aa7b3 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex_program.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d_vertex_program.cpp @@ -43,9 +43,9 @@ CVertexProgamDrvInfosD3D::~CVertexProgamDrvInfosD3D() // *************************************************************************** -bool CDriverD3D::isVertexProgramSupported () const +bool CDriverD3D::supportVertexProgram () const { - H_AUTO_D3D(CDriverD3D_isVertexProgramSupported ) + H_AUTO_D3D(CDriverD3D_supportVertexProgram ) return _VertexProgram; } diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.cpp b/code/nel/src/3d/driver/opengl/driver_opengl.cpp index 29e14a1a0..830496681 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl.cpp @@ -263,8 +263,6 @@ CDriverGL::CDriverGL() _CurrentFogColor[2]= 0; _CurrentFogColor[3]= 0; - _RenderTargetFBO = false; - _LightSetupDirty= false; _ModelViewMatrixDirty= false; _RenderSetupDirty= false; @@ -482,6 +480,7 @@ bool CDriverGL::setupDisplay() } _VertexProgramEnabled= false; + _PixelProgramEnabled= false; _LastSetupGLArrayVertexProgram= false; // Init VertexArrayRange according to supported extenstion. @@ -690,7 +689,7 @@ bool CDriverGL::stretchRect(ITexture * /* srcText */, NLMISC::CRect &/* srcRect // *************************************************************************** bool CDriverGL::supportBloomEffect() const { - return (isVertexProgramSupported() && supportFrameBufferObject() && supportPackedDepthStencil() && supportTextureRectangle()); + return (supportVertexProgram() && supportFrameBufferObject() && supportPackedDepthStencil() && supportTextureRectangle()); } // *************************************************************************** @@ -702,7 +701,7 @@ bool CDriverGL::supportNonPowerOfTwoTextures() const // *************************************************************************** bool CDriverGL::isTextureRectangle(ITexture * tex) const { - return (supportTextureRectangle() && tex->isBloomTexture() && tex->mipMapOff() + return (!supportNonPowerOfTwoTextures() && supportTextureRectangle() && tex->isBloomTexture() && tex->mipMapOff() && (!isPowerOf2(tex->getWidth()) || !isPowerOf2(tex->getHeight()))); } @@ -737,6 +736,12 @@ void CDriverGL::disableHardwareVertexProgram() _Extensions.DisableHardwareVertexProgram= true; } +void CDriverGL::disableHardwarePixelProgram() +{ + H_AUTO_OGL(CDriverGL_disableHardwarePixelProgram) + _Extensions.DisableHardwarePixelProgram= true; +} + // *************************************************************************** void CDriverGL::disableHardwareVertexArrayAGP() { @@ -854,6 +859,7 @@ bool CDriverGL::swapBuffers() // Reset texture shaders //resetTextureShaders(); activeVertexProgram(NULL); + activePixelProgram(NULL); #ifndef USE_OPENGLES /* Yoyo: must do this (GeForce bug ??) else weird results if end render with a VBHard. @@ -1531,9 +1537,9 @@ bool CDriverGL::supportTextureShaders() const } // *************************************************************************** -bool CDriverGL::isWaterShaderSupported() const +bool CDriverGL::supportWaterShader() const { - H_AUTO_OGL(CDriverGL_isWaterShaderSupported); + H_AUTO_OGL(CDriverGL_supportWaterShader); if(_Extensions.ARBFragmentProgram && ARBWaterShader[0] != 0) return true; @@ -1543,9 +1549,9 @@ bool CDriverGL::isWaterShaderSupported() const } // *************************************************************************** -bool CDriverGL::isTextureAddrModeSupported(CMaterial::TTexAddressingMode /* mode */) const +bool CDriverGL::supportTextureAddrMode(CMaterial::TTexAddressingMode /* mode */) const { - H_AUTO_OGL(CDriverGL_isTextureAddrModeSupported) + H_AUTO_OGL(CDriverGL_supportTextureAddrMode) if (_Extensions.NVTextureShader) { diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.h b/code/nel/src/3d/driver/opengl/driver_opengl.h index bfe73492d..3f0675276 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl.h @@ -306,6 +306,7 @@ public: virtual bool init (uint windowIcon = 0, emptyProc exitFunc = 0); virtual void disableHardwareVertexProgram(); + virtual void disableHardwarePixelProgram(); virtual void disableHardwareVertexArrayAGP(); virtual void disableHardwareTextureShader(); @@ -563,6 +564,8 @@ public: virtual bool setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width, uint32 height, uint32 mipmapLevel, uint32 cubeFace); + virtual ITexture *getRenderTarget() const; + virtual bool copyTargetToTexture (ITexture *tex, uint32 offsetx, uint32 offsety, uint32 x, uint32 y, uint32 width, uint32 height, uint32 mipmapLevel); @@ -600,9 +603,9 @@ public: // @{ virtual bool supportTextureShaders() const; - virtual bool isWaterShaderSupported() const; + virtual bool supportWaterShader() const; - virtual bool isTextureAddrModeSupported(CMaterial::TTexAddressingMode mode) const; + virtual bool supportTextureAddrMode(CMaterial::TTexAddressingMode mode) const; virtual void setMatrix2DForTextureOffsetAddrMode(const uint stage, const float mat[4]); // @} @@ -692,6 +695,7 @@ private: virtual class IVertexBufferHardGL *createVertexBufferHard(uint size, uint numVertices, CVertexBuffer::TPreferredMemory vbType, CVertexBuffer *vb); friend class CTextureDrvInfosGL; friend class CVertexProgamDrvInfosGL; + friend class CPixelProgamDrvInfosGL; private: // Version of the driver. Not the interface version!! Increment when implementation of the driver change. @@ -887,7 +891,7 @@ private: // viewport before call to setRenderTarget, if BFO extension is supported CViewport _OldViewport; - bool _RenderTargetFBO; + CSmartPtr _RenderTargetFBO; // Num lights return by GL_MAX_LIGHTS @@ -1301,9 +1305,12 @@ private: /// \name Vertex program interface // @{ - bool isVertexProgramSupported () const; + bool supportVertexProgram () const; + bool supportPixelProgram () const; + bool supportPixelProgram (CPixelProgram::TProfile profile) const; bool isVertexProgramEmulated () const; bool activeVertexProgram (CVertexProgram *program); + bool activePixelProgram (CPixelProgram *program); void setConstant (uint index, float, float, float, float); void setConstant (uint index, double, double, double, double); void setConstant (uint indexStart, const NLMISC::CVector& value); @@ -1314,6 +1321,15 @@ private: void setConstantFog (uint index); void enableVertexProgramDoubleSidedColor(bool doubleSided); bool supportVertexProgramDoubleSidedColor() const; + + // Pixel program + virtual void setPixelProgramConstant (uint index, float, float, float, float); + virtual void setPixelProgramConstant (uint index, double, double, double, double); + virtual void setPixelProgramConstant (uint index, const NLMISC::CVector& value); + virtual void setPixelProgramConstant (uint index, const NLMISC::CVectorD& value); + virtual void setPixelProgramConstant (uint index, uint num, const float *src); + virtual void setPixelProgramConstant (uint index, uint num, const double *src); + virtual void setPixelProgramConstantMatrix (uint index, IDriver::TMatrix matrix, IDriver::TTransform transform); virtual bool supportMADOperator() const ; @@ -1328,6 +1344,12 @@ private: //@} + /// \name Pixel program implementation + // @{ + bool activeARBPixelProgram (CPixelProgram *program); + bool setupARBPixelProgram (const CPixelProgram *program, GLuint id/*, bool &specularWritten*/); + //@} + /// \fallback for material shaders // @{ @@ -1340,15 +1362,27 @@ private: // Don't use glIsEnabled, too slow. return _VertexProgramEnabled; } + + bool isPixelProgramEnabled () const + { + // Don't use glIsEnabled, too slow. + return _PixelProgramEnabled; + } // Track state of activeVertexProgram() bool _VertexProgramEnabled; + // Track state of activePixelProgram() + bool _PixelProgramEnabled; + // Say if last setupGlArrays() was a VertexProgram setup. bool _LastSetupGLArrayVertexProgram; // The last vertex program that was setupped NLMISC::CRefPtr _LastSetuppedVP; + // The last pixel program that was setupped + NLMISC::CRefPtr _LastSetuppedPP; + bool _ForceDXTCCompression; /// Divisor for textureResize (power). uint _ForceTextureResizePower; @@ -1518,6 +1552,17 @@ public: CVertexProgamDrvInfosGL (CDriverGL *drv, ItVtxPrgDrvInfoPtrList it); }; +// *************************************************************************** +class CPixelProgamDrvInfosGL : public IPixelProgramDrvInfos +{ +public: + // The GL Id. + GLuint ID; + + // The gl id is auto created here. + CPixelProgamDrvInfosGL (CDriverGL *drv, ItPixelPrgDrvInfoPtrList it); +}; + #ifdef NL_STATIC } // NLDRIVERGL/ES #endif diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp index d38ff8f51..3b771e1c1 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp @@ -1225,6 +1225,15 @@ static bool setupARBFragmentProgram(const char *glext) return true; } +// ********************************* +static bool setupNVFragmentProgram2(const char *glext) +{ + H_AUTO_OGL(setupNVFragmentProgram2); + CHECK_EXT("GL_NV_fragment_program2"); + + return true; +} + // *************************************************************************** static bool setupARBVertexBufferObject(const char *glext) { @@ -1560,6 +1569,19 @@ void registerGlExtensions(CGlExtensions &ext) ext.EXTVertexShader = false; ext.ARBVertexProgram = false; } + + // Check pixel program + // Disable feature ??? + if (!ext.DisableHardwarePixelProgram) + { + ext.ARBFragmentProgram = setupARBFragmentProgram(glext); + ext.NVFragmentProgram2 = setupNVFragmentProgram2(glext); + } + else + { + ext.ARBFragmentProgram = false; + ext.NVFragmentProgram2 = false; + } ext.OESDrawTexture = setupOESDrawTexture(glext); ext.OESMapBuffer = setupOESMapBuffer(glext); @@ -1571,14 +1593,12 @@ void registerGlExtensions(CGlExtensions &ext) ext.NVTextureShader = setupNVTextureShader(glext); ext.ATIEnvMapBumpMap = setupATIEnvMapBumpMap(glext); ext.ATIFragmentShader = setupATIFragmentShader(glext); - ext.ARBFragmentProgram = setupARBFragmentProgram(glext); } else { ext.ATIEnvMapBumpMap = false; ext.NVTextureShader = false; ext.ATIFragmentShader = false; - ext.ARBFragmentProgram = false; } // For now, the only way to know if emulation, is to test some extension which exist only on GeForce3. diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_extension.h b/code/nel/src/3d/driver/opengl/driver_opengl_extension.h index 9d28a15ab..fe7738fd8 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_extension.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl_extension.h @@ -103,6 +103,9 @@ struct CGlExtensions bool ARBTextureNonPowerOfTwo; bool ARBMultisample; + // NV Pixel Programs + bool NVFragmentProgram2; + bool OESDrawTexture; bool OESMapBuffer; @@ -111,6 +114,7 @@ public: /// \name Disable Hardware feature. False by default. setuped by IDriver // @{ bool DisableHardwareVertexProgram; + bool DisableHardwarePixelProgram; bool DisableHardwareVertexArrayAGP; bool DisableHardwareTextureShader; // @} @@ -174,6 +178,7 @@ public: /// \name Disable Hardware feature. False by default. setuped by IDriver DisableHardwareVertexProgram= false; + DisableHardwarePixelProgram= false; DisableHardwareVertexArrayAGP= false; DisableHardwareTextureShader= false; } @@ -206,6 +211,7 @@ public: result += NVTextureShader ? "NVTextureShader " : ""; result += ATIFragmentShader ? "ATIFragmentShader " : ""; result += ARBFragmentProgram ? "ARBFragmentProgram " : ""; + result += NVFragmentProgram2 ? "NVFragmentProgram2 " : ""; result += ARBVertexProgram ? "ARBVertexProgram " : ""; result += NVVertexProgram ? "NVVertexProgram " : ""; result += EXTVertexShader ? "EXTVertexShader " : ""; diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_pixel_program.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_pixel_program.cpp new file mode 100644 index 000000000..2bcfc185d --- /dev/null +++ b/code/nel/src/3d/driver/opengl/driver_opengl_pixel_program.cpp @@ -0,0 +1,336 @@ +/** \file driver_opengl_pixel_program.cpp + * OpenGL driver implementation for pixel program manipulation. + * + * $Id: driver_opengl_pixel_program.cpp,v 1.1.2.4 2007/07/09 15:29:00 legallo Exp $ + * + * \todo manage better the init/release system (if a throw occurs in the init, we must release correctly the driver) + */ + +/* Copyright, 2000 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "stdopengl.h" + +#include "driver_opengl.h" +#include "nel/3d/index_buffer.h" +#include "nel/3d/pixel_program.h" +#include + +// tmp +#include "nel/misc/file.h" + +using namespace std; +using namespace NLMISC; + +namespace NL3D +{ + +#ifdef NL_STATIC +#ifdef USE_OPENGLES +namespace NLDRIVERGLES { +#else +namespace NLDRIVERGL { +#endif +#endif + +// *************************************************************************** +CPixelProgamDrvInfosGL::CPixelProgamDrvInfosGL (CDriverGL *drv, ItPixelPrgDrvInfoPtrList it) : IPixelProgramDrvInfos (drv, it) +{ + H_AUTO_OGL(CPixelProgamDrvInfosGL_CPixelProgamDrvInfosGL) + // Extension must exist + nlassert(drv->_Extensions.ARBFragmentProgram); + + if (drv->_Extensions.ARBFragmentProgram) // ARB implementation + { + nglGenProgramsARB(1, &ID); + } +} + +// *************************************************************************** +bool CDriverGL::supportPixelProgram() const +{ + H_AUTO_OGL(CPixelProgamDrvInfosGL_supportPixelProgram) + return _Extensions.ARBFragmentProgram; +} +bool CDriverGL::supportPixelProgram(CPixelProgram::TProfile profile) const +{ + H_AUTO_OGL(CPixelProgamDrvInfosGL_supportPixelProgram_profile) + switch (profile) + { + case CPixelProgram::arbfp1: + return _Extensions.ARBFragmentProgram; + case CPixelProgram::fp40: + return _Extensions.NVFragmentProgram2; + } + return false; +} + +// *************************************************************************** +bool CDriverGL::activePixelProgram(CPixelProgram *program) +{ + H_AUTO_OGL(CDriverGL_activePixelProgram) + + if (_Extensions.ARBFragmentProgram) + { + return activeARBPixelProgram(program); + } + + return false; +} + +// *************************************************************************** +bool CDriverGL::activeARBPixelProgram(CPixelProgram *program) +{ + H_AUTO_OGL(CDriverGL_activeARBPixelProgram) + + // Setup or unsetup ? + if (program) + { + // Driver info + CPixelProgamDrvInfosGL *drvInfo; + + // Program setuped ? + if (program->_DrvInfo==NULL) + { + // Insert into driver list. (so it is deleted when driver is deleted). + ItPixelPrgDrvInfoPtrList it= _PixelPrgDrvInfos.insert(_PixelPrgDrvInfos.end(), (NL3D::IPixelProgramDrvInfos*)NULL); + + // Create a driver info + *it = drvInfo = new CPixelProgamDrvInfosGL (this, it); + // Set the pointer + program->_DrvInfo=drvInfo; + + if(!setupARBPixelProgram(program, drvInfo->ID)) + { + delete drvInfo; + program->_DrvInfo = NULL; + _PixelPrgDrvInfos.erase(it); + return false; + } + } + else + { + // Cast the driver info pointer + drvInfo=safe_cast((IPixelProgramDrvInfos*)program->_DrvInfo); + } + glEnable( GL_FRAGMENT_PROGRAM_ARB ); + _PixelProgramEnabled = true; + nglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, drvInfo->ID ); + + glDisable( GL_COLOR_SUM_ARB ); // no specular written + + _LastSetuppedPP = program; + } + else + { + glDisable( GL_FRAGMENT_PROGRAM_ARB ); + glDisable( GL_COLOR_SUM_ARB ); + _PixelProgramEnabled = false; + } + + return true; +} + +// *************************************************************************** +bool CDriverGL::setupARBPixelProgram (const CPixelProgram *program, GLuint id/*, bool &specularWritten*/) +{ + H_AUTO_OGL(CDriverGL_setupARBPixelProgram) + + const std::string &code = program->getProgram(); + + nglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, id); + glGetError(); + nglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, code.size(), code.c_str() ); + GLenum err = glGetError(); + if (err != GL_NO_ERROR) + { + if (err == GL_INVALID_OPERATION) + { + GLint position; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position); + nlassert(position != -1); // there was an error.. + nlassert(position < (GLint) code.size()); + uint line = 0; + const char *lineStart = program->getProgram().c_str(); + for(uint k = 0; k < (uint) position; ++k) + { + if (code[k] == '\n') + { + lineStart = code.c_str() + k; + ++line; + } + } + nlwarning("ARB fragment program parse error at line %d.", (int) line); + // search end of line + const char *lineEnd = code.c_str() + code.size(); + for(uint k = position; k < code.size(); ++k) + { + if (code[k] == '\n') + { + lineEnd = code.c_str() + k; + break; + } + } + nlwarning(std::string(lineStart, lineEnd).c_str()); + // display the gl error msg + const GLubyte *errorMsg = glGetString(GL_PROGRAM_ERROR_STRING_ARB); + nlassert((const char *) errorMsg); + nlwarning((const char *) errorMsg); + } + nlassert(0); + return false; + } + return true; +} + +// *************************************************************************** + +void CDriverGL::setPixelProgramConstant (uint index, float f0, float f1, float f2, float f3) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstant) + + if (_Extensions.ARBFragmentProgram) + nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, index, f0, f1, f2, f3); +} + + +// *************************************************************************** + +void CDriverGL::setPixelProgramConstant (uint index, double d0, double d1, double d2, double d3) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstant) + + if (_Extensions.ARBFragmentProgram) + nglProgramEnvParameter4dARB(GL_FRAGMENT_PROGRAM_ARB, index, d0, d1, d2, d3); +} + + +// *************************************************************************** + +void CDriverGL::setPixelProgramConstant (uint index, const NLMISC::CVector& value) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstant) + + if (_Extensions.ARBFragmentProgram) + nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, index, value.x, value.y, value.z, 0); +} + + +// *************************************************************************** + +void CDriverGL::setPixelProgramConstant (uint index, const NLMISC::CVectorD& value) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstant) + + if (_Extensions.ARBFragmentProgram) + nglProgramEnvParameter4dARB(GL_FRAGMENT_PROGRAM_ARB, index, value.x, value.y, value.z, 0); +} + + +// *************************************************************************** +void CDriverGL::setPixelProgramConstant (uint index, uint num, const float *src) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstant) + + if (_Extensions.ARBFragmentProgram) + { + for(uint k = 0; k < num; ++k) + { + nglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, index + k, src + 4 * k); + } + } +} + +// *************************************************************************** +void CDriverGL::setPixelProgramConstant (uint index, uint num, const double *src) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstant) + + if (_Extensions.ARBFragmentProgram) + { + for(uint k = 0; k < num; ++k) + { + nglProgramEnvParameter4dvARB(GL_FRAGMENT_PROGRAM_ARB, index + k, src + 4 * k); + } + } +} + +// *************************************************************************** + +void CDriverGL::setPixelProgramConstantMatrix (uint index, IDriver::TMatrix matrix, IDriver::TTransform transform) +{ + H_AUTO_OGL(CDriverGL_setPixelProgramConstantMatrix) + + if (_Extensions.ARBFragmentProgram) + { + + // First, ensure that the render setup is correctly setuped. + refreshRenderSetup(); + CMatrix mat; + switch (matrix) + { + case IDriver::ModelView: + mat = _ModelViewMatrix; + break; + case IDriver::Projection: + { + refreshProjMatrixFromGL(); + mat = _GLProjMat; + } + break; + case IDriver::ModelViewProjection: + refreshProjMatrixFromGL(); + mat = _GLProjMat * _ModelViewMatrix; + break; + default: + break; + } + + switch(transform) + { + case IDriver::Identity: break; + case IDriver::Inverse: + mat.invert(); + break; + case IDriver::Transpose: + mat.transpose(); + break; + case IDriver::InverseTranspose: + mat.invert(); + mat.transpose(); + break; + default: + break; + } + mat.transpose(); + float matDatas[16]; + mat.get(matDatas); + + nglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, index, matDatas); + nglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, index + 1, matDatas + 4); + nglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, index + 2, matDatas + 8); + nglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, index + 3, matDatas + 12); + } +} + +#ifdef NL_STATIC +} // NLDRIVERGL/ES +#endif + +} // NL3D 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 77954a8e3..7ded32b27 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp @@ -2314,7 +2314,7 @@ bool CDriverGL::setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width newVP.init(0, 0, ((float)width/(float)w), ((float)height/(float)h)); setupViewport(newVP); - _RenderTargetFBO = true; + _RenderTargetFBO = tex; return activeFrameBufferObject(tex); } @@ -2334,7 +2334,7 @@ bool CDriverGL::setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width setupViewport(_OldViewport); _OldViewport = _CurrViewport; - _RenderTargetFBO = false; + _RenderTargetFBO = NULL; return false; } @@ -2347,12 +2347,17 @@ bool CDriverGL::setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width // Update the scissor setupScissor (_CurrScissor); - _RenderTargetFBO = false; + _RenderTargetFBO = NULL; _OldViewport = _CurrViewport; return true; } +ITexture *CDriverGL::getRenderTarget() const +{ + return _RenderTargetFBO ? _RenderTargetFBO : _TextureTarget; +} + // *************************************************************************** bool CDriverGL::copyTargetToTexture (ITexture *tex, diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_vertex_program.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_vertex_program.cpp index 5392bcbdd..1ddb42a7d 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_vertex_program.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_vertex_program.cpp @@ -70,9 +70,9 @@ CVertexProgamDrvInfosGL::CVertexProgamDrvInfosGL (CDriverGL *drv, ItVtxPrgDrvInf // *************************************************************************** -bool CDriverGL::isVertexProgramSupported () const +bool CDriverGL::supportVertexProgram () const { - H_AUTO_OGL(CVertexProgamDrvInfosGL_isVertexProgramSupported) + H_AUTO_OGL(CVertexProgamDrvInfosGL_supportVertexProgram) return _Extensions.NVVertexProgram || _Extensions.EXTVertexShader || _Extensions.ARBVertexProgram; } diff --git a/code/nel/src/3d/driver_user.cpp b/code/nel/src/3d/driver_user.cpp index b45ebbd37..83c7343ec 100644 --- a/code/nel/src/3d/driver_user.cpp +++ b/code/nel/src/3d/driver_user.cpp @@ -213,6 +213,12 @@ void CDriverUser::disableHardwareVertexProgram() _Driver->disableHardwareVertexProgram(); } +void CDriverUser::disableHardwarePixelProgram() +{ + NL3D_HAUTO_UI_DRIVER; + + _Driver->disableHardwarePixelProgram(); +} void CDriverUser::disableHardwareVertexArrayAGP() { NL3D_HAUTO_UI_DRIVER; diff --git a/code/nel/src/3d/flare_model.cpp b/code/nel/src/3d/flare_model.cpp index 47d9fdb43..ba5cc8098 100644 --- a/code/nel/src/3d/flare_model.cpp +++ b/code/nel/src/3d/flare_model.cpp @@ -363,6 +363,7 @@ void CFlareModel::traverseRender() } // setup driver drv->activeVertexProgram(NULL); + drv->activePixelProgram(NULL); drv->setupModelMatrix(fs->getLookAtMode() ? CMatrix::Identity : getWorldMatrix()); // we don't change the fustrum to draw 2d shapes : it is costly, and we need to restore it after the drawing has been done // we setup Z to be (near + far) / 2, and setup x and y to get the screen coordinates we want @@ -565,6 +566,7 @@ void CFlareModel::updateOcclusionQueryBegin(IDriver *drv) { nlassert(drv); drv->activeVertexProgram(NULL); + drv->activePixelProgram(NULL); drv->setupModelMatrix(CMatrix::Identity); initStatics(); drv->setColorMask(false, false, false, false); // don't write any pixel during the test @@ -661,6 +663,7 @@ void CFlareModel::occlusionTest(CMesh &mesh, IDriver &drv) } drv.setColorMask(false, false, false, false); // don't write any pixel during the test drv.activeVertexProgram(NULL); + drv.activePixelProgram(NULL); setupOcclusionMeshMatrix(drv, *_Scene); drv.activeVertexBuffer(const_cast(mesh.getVertexBuffer())); // query drawn count diff --git a/code/nel/src/3d/landscape.cpp b/code/nel/src/3d/landscape.cpp index 31f1bb051..e842ae369 100644 --- a/code/nel/src/3d/landscape.cpp +++ b/code/nel/src/3d/landscape.cpp @@ -574,7 +574,7 @@ void CLandscape::setDriver(IDriver *drv) // Does the driver support VertexShader??? // only if VP supported by GPU. - _VertexShaderOk= (_Driver->isVertexProgramSupported() && !_Driver->isVertexProgramEmulated()); + _VertexShaderOk= (_Driver->supportVertexProgram() && !_Driver->isVertexProgramEmulated()); // Does the driver has sufficient requirements for Vegetable??? diff --git a/code/nel/src/3d/landscapevb_allocator.cpp b/code/nel/src/3d/landscapevb_allocator.cpp index 00cf78f1f..f57d6ef8d 100644 --- a/code/nel/src/3d/landscapevb_allocator.cpp +++ b/code/nel/src/3d/landscapevb_allocator.cpp @@ -82,7 +82,7 @@ void CLandscapeVBAllocator::updateDriver(IDriver *driver) deleteVertexProgram(); // Then rebuild VB format, and VertexProgram, if needed. // Do it only if VP supported by GPU. - setupVBFormatAndVertexProgram(_Driver->isVertexProgramSupported() && !_Driver->isVertexProgramEmulated()); + setupVBFormatAndVertexProgram(_Driver->supportVertexProgram() && !_Driver->isVertexProgramEmulated()); // must reallocate the VertexBuffer. if( _NumVerticesAllocated>0 ) diff --git a/code/nel/src/3d/meshvp_per_pixel_light.cpp b/code/nel/src/3d/meshvp_per_pixel_light.cpp index ab84492c4..dd06e951c 100644 --- a/code/nel/src/3d/meshvp_per_pixel_light.cpp +++ b/code/nel/src/3d/meshvp_per_pixel_light.cpp @@ -428,7 +428,7 @@ bool CMeshVPPerPixelLight::begin(IDriver *drv, { // test if supported by driver if (! - (drv->isVertexProgramSupported() + (drv->supportVertexProgram() && !drv->isVertexProgramEmulated() && drv->supportPerPixelLighting(SpecularLighting) ) diff --git a/code/nel/src/3d/meshvp_wind_tree.cpp b/code/nel/src/3d/meshvp_wind_tree.cpp index bf04c6096..579557012 100644 --- a/code/nel/src/3d/meshvp_wind_tree.cpp +++ b/code/nel/src/3d/meshvp_wind_tree.cpp @@ -287,7 +287,7 @@ inline void CMeshVPWindTree::setupPerInstanceConstants(IDriver *driver, CScene // *************************************************************************** bool CMeshVPWindTree::begin(IDriver *driver, CScene *scene, CMeshBaseInstance *mbi, const NLMISC::CMatrix &invertedModelMat, const NLMISC::CVector & /*viewerPos*/) { - if (!(driver->isVertexProgramSupported() && !driver->isVertexProgramEmulated())) return false; + if (!(driver->supportVertexProgram() && !driver->isVertexProgramEmulated())) return false; // precompute mesh @@ -367,7 +367,7 @@ bool CMeshVPWindTree::supportMeshBlockRendering() const // *************************************************************************** bool CMeshVPWindTree::isMBRVpOk(IDriver *driver) const { - return driver->isVertexProgramSupported() && !driver->isVertexProgramEmulated(); + return driver->supportVertexProgram() && !driver->isVertexProgramEmulated(); } // *************************************************************************** diff --git a/code/nel/src/3d/pixel_program.cpp b/code/nel/src/3d/pixel_program.cpp new file mode 100644 index 000000000..320bfa541 --- /dev/null +++ b/code/nel/src/3d/pixel_program.cpp @@ -0,0 +1,63 @@ +/** \file pixel_program.cpp + * Pixel program definition + * + * $Id: pixel_program.cpp,v 1.1.2.1 2007/04/27 17:35:07 legallo Exp $ + */ + +/* Copyright, 2000, 2001 Nevrax Ltd. + * + * This file is part of NEVRAX NEL. + * NEVRAX NEL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + * NEVRAX NEL is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with NEVRAX NEL; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "std3d.h" + +#include + +#include + +namespace NL3D +{ + +// *************************************************************************** +IPixelProgramDrvInfos::IPixelProgramDrvInfos (IDriver *drv, ItPixelPrgDrvInfoPtrList it) +{ + _Driver= drv; + _DriverIterator= it; +} + + +// *************************************************************************** +IPixelProgramDrvInfos::~IPixelProgramDrvInfos () +{ + _Driver->removePixelPrgDrvInfoPtr (_DriverIterator); +} + + +// *************************************************************************** +CPixelProgram::CPixelProgram(const char* program) : _Program(program) +{ + +} + + +// *************************************************************************** +CPixelProgram::~CPixelProgram() +{ + +} + +} // NL3D diff --git a/code/nel/src/3d/ps_particle_basic.cpp b/code/nel/src/3d/ps_particle_basic.cpp index 1cb57d2bc..c2d6b6357 100644 --- a/code/nel/src/3d/ps_particle_basic.cpp +++ b/code/nel/src/3d/ps_particle_basic.cpp @@ -786,7 +786,7 @@ void CPSMultiTexturedParticle::setupMaterial(ITexture *primary, IDriver *driver, /// if bump is used, the matrix must be setupped each time (not a material field) if (!_ForceBasicCaps && isMultiTextureEnabled() && _MainOp == EnvBumpMap) { - if (driver->isTextureAddrModeSupported(CMaterial::OffsetTexture)) + if (driver->supportTextureAddrMode(CMaterial::OffsetTexture)) { CTextureBump *tb = dynamic_cast((ITexture *) _Texture2); if (tb != NULL) @@ -858,7 +858,7 @@ void CPSMultiTexturedParticle::setupMaterial(ITexture *primary, IDriver *driver, } else { - if (!_ForceBasicCaps && (driver->isTextureAddrModeSupported(CMaterial::OffsetTexture) || driver->supportEMBM())) // envbumpmap supported ? + if (!_ForceBasicCaps && (driver->supportTextureAddrMode(CMaterial::OffsetTexture) || driver->supportEMBM())) // envbumpmap supported ? { CTextureBump *tb = dynamic_cast((ITexture *) _Texture2); if (tb != NULL) @@ -917,7 +917,7 @@ void CPSMultiTexturedParticle::setupMultiTexEnv(TOperator op, ITexture *tex1, IT mat.enableTexAddrMode(false); break; case EnvBumpMap: - if (drv.isTextureAddrModeSupported(CMaterial::OffsetTexture)) + if (drv.supportTextureAddrMode(CMaterial::OffsetTexture)) { mat.setTexture(0, tex2); mat.setTexture(1, tex1); @@ -1113,7 +1113,7 @@ void CPSMultiTexturedParticle::enumTexs(std::vector NL_PS_FUNC(CPSMultiTexturedParticle_enumTexs) if (_MainOp == EnvBumpMap && !_ForceBasicCaps) { - if (drv.isTextureAddrModeSupported(CMaterial::OffsetTexture) || drv.supportEMBM()) + if (drv.supportTextureAddrMode(CMaterial::OffsetTexture) || drv.supportEMBM()) { if (_Texture2) dest.push_back(_Texture2); } @@ -1132,7 +1132,7 @@ bool CPSMultiTexturedParticle::isAlternateTextureUsed(IDriver &driver) const NL_PS_FUNC(CPSMultiTexturedParticle_isAlternateTextureUsed) if (!isTouched() && areBasicCapsForcedLocal() == areBasicCapsForced()) return (_MultiTexState & AlternateTextureUsed) != 0; if (_MainOp != EnvBumpMap) return false; - return _ForceBasicCaps || (!driver.isTextureAddrModeSupported(CMaterial::OffsetTexture) && !driver.supportEMBM()); + return _ForceBasicCaps || (!driver.supportTextureAddrMode(CMaterial::OffsetTexture) && !driver.supportEMBM()); } } // NL3D diff --git a/code/nel/src/3d/scene.cpp b/code/nel/src/3d/scene.cpp index df5297e2f..76761bc71 100644 --- a/code/nel/src/3d/scene.cpp +++ b/code/nel/src/3d/scene.cpp @@ -191,6 +191,8 @@ CScene::CScene(bool bSmallScene) : LightTrav(bSmallScene) _WaterEnvMap = NULL; _GlobalSystemTime= 0.0; + + _RequestParticlesAnimate = false; } // *************************************************************************** void CScene::release() @@ -377,6 +379,12 @@ void CScene::endPartRender() // Reset profiling _NextRenderProfile= false; + IDriver *drv = getDriver(); + drv->activeVertexProgram(NULL); + drv->activePixelProgram(NULL); + + // Ensure nothing animates on subsequent renders + _EllapsedTime = 0.f; /* uint64 total = PSStatsRegisterPSModelObserver + @@ -614,7 +622,11 @@ void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass) // loadBalance LoadBalancingTrav.traverse(); // - _ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems + if (_RequestParticlesAnimate) + { + _ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems + _RequestParticlesAnimate = false; + } // Light LightTrav.traverse(); } @@ -860,6 +872,9 @@ void CScene::animate( TGlobalAnimationTime atTime ) // Rendered part are invalidate _RenderedPart = UScene::RenderNothing; + + // Particles are animated later due to dependencies + _RequestParticlesAnimate = true; } @@ -1561,6 +1576,7 @@ void CScene::renderOcclusionTestMeshs() nlassert(RenderTrav.getDriver()); RenderTrav.getDriver()->setupViewport(RenderTrav.getViewport()); RenderTrav.getDriver()->activeVertexProgram(NULL); + RenderTrav.getDriver()->activePixelProgram(NULL); IDriver::TPolygonMode oldPolygonMode = RenderTrav.getDriver()->getPolygonMode(); CMaterial m; m.initUnlit(); diff --git a/code/nel/src/3d/shadow_map_manager.cpp b/code/nel/src/3d/shadow_map_manager.cpp index 79f4ade20..383a28184 100644 --- a/code/nel/src/3d/shadow_map_manager.cpp +++ b/code/nel/src/3d/shadow_map_manager.cpp @@ -244,11 +244,12 @@ void CShadowMapManager::addShadowReceiver(CTransform *model) void CShadowMapManager::renderGenerate(CScene *scene) { H_AUTO( NL3D_ShadowManager_Generate ); - + // Each frame, do a small garbage collector for unused free textures. garbageShadowTextures(scene); IDriver *driverForShadowGeneration= scene->getRenderTrav().getAuxDriver(); + CSmartPtr previousRenderTarget = driverForShadowGeneration->getRenderTarget(); // Init // ******** @@ -488,7 +489,7 @@ void CShadowMapManager::renderGenerate(CScene *scene) } // Set default render target - driverForShadowGeneration->setRenderTarget (NULL); + driverForShadowGeneration->setRenderTarget (previousRenderTarget); // Allow Writing on all. driverForShadowGeneration->setColorMask(true, true, true, true); diff --git a/code/nel/src/3d/stereo_debugger.cpp b/code/nel/src/3d/stereo_debugger.cpp new file mode 100644 index 000000000..9255fa812 --- /dev/null +++ b/code/nel/src/3d/stereo_debugger.cpp @@ -0,0 +1,409 @@ +/** + * \file stereo_debugger.cpp + * \brief CStereoDebugger + * \date 2013-07-03 20:17GMT + * \author Jan Boon (Kaetemi) + * CStereoDebugger + */ + +/* + * 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 + * . + */ + +#if !FINAL_VERSION +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +namespace { + +const char *a_arbfp1 = + "!!ARBfp1.0\n" + "PARAM c[1] = { { 1, 0, 0.5 } };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "TEMP R2;\n" + "TEX R0, fragment.texcoord[0], texture[0], 2D;\n" + "TEX R1, fragment.texcoord[0], texture[1], 2D;\n" + "ADD R2, R0, -R1;\n" + "ADD R1, R0, R1;\n" + "MUL R1, R1, c[0].z;\n" + "ABS R2, R2;\n" + "CMP R2, -R2, c[0].x, c[0].y;\n" + "ADD_SAT R2.x, R2, R2.y;\n" + "ADD_SAT R2.x, R2, R2.z;\n" + "ADD_SAT R2.x, R2, R2.w;\n" + "ABS R2.x, R2;\n" + "CMP R2.x, -R2, c[0].y, c[0];\n" + "ABS R0.x, R2;\n" + "CMP R2.x, -R0, c[0].y, c[0];\n" + "MOV R0.xzw, R1;\n" + "MAD R0.y, R1, c[0].z, c[0].z;\n" + "CMP R0, -R2.x, R1, R0;\n" + "MAD R1.x, R0, c[0].z, c[0].z;\n" + "CMP result.color.x, -R2, R1, R0;\n" + "MOV result.color.yzw, R0;\n" + "END\n"; + +class CStereoDebuggerFactory : public IStereoDeviceFactory +{ +public: + IStereoDisplay *createDevice() const + { + return new CStereoDebugger(); + } +}; + +} /* anonymous namespace */ + +CStereoDebugger::CStereoDebugger() : m_Driver(NULL), m_Stage(0), m_SubStage(0), m_LeftTexU(NULL), m_RightTexU(NULL), m_PixelProgram(NULL) +{ + +} + +CStereoDebugger::~CStereoDebugger() +{ + releaseTextures(); + + if (!m_Mat.empty()) + { + m_Driver->deleteMaterial(m_Mat); + } + + delete m_PixelProgram; + m_PixelProgram = NULL; + + m_Driver = NULL; +} + +/// Sets driver and generates necessary render targets +void CStereoDebugger::setDriver(NL3D::UDriver *driver) +{ + nlassert(!m_PixelProgram); + + NL3D::IDriver *drvInternal = (static_cast(driver))->getDriver(); + /*if (drvInternal->supportPixelProgram(CPixelProgram::fp40) && drvInternal->supportBloomEffect() && drvInternal->supportNonPowerOfTwoTextures()) + { + nldebug("VR: fp40"); + m_PixelProgram = new CPixelProgram(a_fp40); + } + else*/ if (drvInternal->supportPixelProgram(CPixelProgram::arbfp1) && drvInternal->supportBloomEffect() && drvInternal->supportNonPowerOfTwoTextures()) + { + nldebug("VR: arbfp1"); + m_PixelProgram = new CPixelProgram(a_arbfp1); + } + /*else if (drvInternal->supportPixelProgram(CPixelProgram::ps_2_0)) + { + nldebug("VR: ps_2_0"); + m_PixelProgram = new CPixelProgram(a_ps_2_0); + }*/ + + if (m_PixelProgram) + { + m_Driver = driver; + + initTextures(); + + 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::PostProcessing); + mat->setBlendFunc(CMaterial::one, CMaterial::zero); + mat->setZWrite(false); + 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); + m_QuadUV.V3 = CVector(0.f, 1.f, 0.5f); + + 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); + } +} + +void CStereoDebugger::releaseTextures() +{ + if (!m_Mat.empty()) + { + m_Mat.getObjectPtr()->setTexture(0, NULL); + m_Mat.getObjectPtr()->setTexture(1, NULL); + m_Driver->deleteMaterial(m_Mat); + } + + delete m_LeftTexU; + m_LeftTexU = NULL; + m_LeftTex = NULL; // CSmartPtr + + delete m_RightTexU; + m_RightTexU = NULL; + m_RightTex = NULL; // CSmartPtr +} + +void CStereoDebugger::initTextures() +{ + uint32 width, height; + m_Driver->getWindowSize(width, height); + NL3D::IDriver *drvInternal = (static_cast(m_Driver))->getDriver(); + + m_LeftTex = new CTextureBloom(); + m_LeftTex->setRenderTarget(true); + m_LeftTex->setReleasable(false); + m_LeftTex->resize(width, height); + m_LeftTex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); + m_LeftTex->setWrapS(ITexture::Clamp); + m_LeftTex->setWrapT(ITexture::Clamp); + drvInternal->setupTexture(*m_LeftTex); + m_LeftTexU = new CTextureUser(m_LeftTex); + nlassert(!drvInternal->isTextureRectangle(m_LeftTex)); // not allowed + + m_RightTex = new CTextureBloom(); + m_RightTex->setRenderTarget(true); + m_RightTex->setReleasable(false); + m_RightTex->resize(width, height); + m_RightTex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); + m_RightTex->setWrapS(ITexture::Clamp); + m_RightTex->setWrapT(ITexture::Clamp); + 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) + { + uint32 width, height; + m_Driver->getWindowSize(width, height); + if (m_LeftTex->getWidth() != width + || m_RightTex->getWidth() != width + || m_LeftTex->getHeight() != height + || m_RightTex->getHeight() != height) + { + nldebug("Rebuild textures"); + releaseTextures(); + initTextures(); + setTextures(); + } + } +} + +/// Gets the required screen resolution for this device +bool CStereoDebugger::getScreenResolution(uint &width, uint &height) +{ + return false; +} + +/// Set latest camera position etcetera +void CStereoDebugger::updateCamera(uint cid, const NL3D::UCamera *camera) +{ + m_Frustum[cid] = camera->getFrustum(); +} + +/// Get the frustum to use for clipping +void CStereoDebugger::getClippingFrustum(uint cid, NL3D::UCamera *camera) const +{ + // do nothing +} + +/// Is there a next pass +bool CStereoDebugger::nextPass() +{ + if (m_Driver->getPolygonMode() == UDriver::Filled) + { + switch (m_Stage) + { + case 0: + ++m_Stage; + m_SubStage = 0; + return true; + case 1: + ++m_Stage; + m_SubStage = 0; + return true; + case 2: + ++m_Stage; + m_SubStage = 0; + return true; + case 3: + m_Stage = 0; + m_SubStage = 0; + 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; + } + } +} + +/// Gets the current viewport +const NL3D::CViewport &CStereoDebugger::getCurrentViewport() const +{ + if (m_Stage % 2) return m_LeftViewport; + else return m_RightViewport; +} + +/// Gets the current camera frustum +const NL3D::CFrustum &CStereoDebugger::getCurrentFrustum(uint cid) const +{ + return m_Frustum[cid]; +} + +/// Gets the current camera frustum +void CStereoDebugger::getCurrentFrustum(uint cid, NL3D::UCamera *camera) const +{ + // do nothing +} + +/// Gets the current camera matrix +void CStereoDebugger::getCurrentMatrix(uint cid, NL3D::UCamera *camera) const +{ + // do nothing +} + +/// At the start of a new render target +bool CStereoDebugger::wantClear() +{ + m_SubStage = 1; + return m_Stage != 3; +} + +/// The 3D scene +bool CStereoDebugger::wantScene() +{ + m_SubStage = 2; + return m_Stage != 3; +} + +/// Interface within the 3D scene +bool CStereoDebugger::wantInterface3D() +{ + m_SubStage = 3; + return m_Stage == 3; +} + +/// 2D Interface +bool CStereoDebugger::wantInterface2D() +{ + m_SubStage = 4; + 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_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; + } + return false; +} + +/// Returns true if a render target was fully drawn, always false if not using render targets +bool CStereoDebugger::endRenderTarget() +{ + if (m_Stage != 3 && m_Driver && (m_Driver->getPolygonMode() == UDriver::Filled)) + { + CTextureUser cu; + (static_cast(m_Driver))->setRenderTarget(cu); + bool fogEnabled = m_Driver->fogEnabled(); + m_Driver->enableFog(false); + + m_Driver->setMatrixMode2D11(); + CViewport vp = CViewport(); + m_Driver->setViewport(vp); + 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); + drvInternal->activePixelProgram(m_PixelProgram); + + m_Driver->drawQuad(m_QuadUV, m_Mat); + + drvInternal->activePixelProgram(NULL); + m_Driver->enableFog(fogEnabled); + + return true; + } + return false; +} + +void CStereoDebugger::listDevices(std::vector &devicesOut) +{ + CStereoDeviceInfo devInfo; + devInfo.Factory = new CStereoDebuggerFactory(); + devInfo.Library = CStereoDeviceInfo::NeL3D; + devInfo.Class = CStereoDeviceInfo::StereoDisplay; + devInfo.Manufacturer = "NeL"; + devInfo.ProductName = "Stereo Debugger"; + devInfo.Serial = "NL-3D-DEBUG"; + devicesOut.push_back(devInfo); +} + +} /* namespace NL3D */ + +#endif /* #if !FINAL_VERSION */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_display.cpp b/code/nel/src/3d/stereo_display.cpp new file mode 100644 index 000000000..0f6d0cbfb --- /dev/null +++ b/code/nel/src/3d/stereo_display.cpp @@ -0,0 +1,108 @@ +/** + * \file stereo_display.cpp + * \brief IStereoDisplay + * \date 2013-06-27 16:29GMT + * \author Jan Boon (Kaetemi) + * IStereoDisplay + */ + +/* + * 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 + * . + */ + +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes +#include +#include + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +IStereoDisplay::IStereoDisplay() +{ + +} + +IStereoDisplay::~IStereoDisplay() +{ + +} + +const char *IStereoDisplay::getLibraryName(CStereoDeviceInfo::TStereoDeviceLibrary library) +{ + static const char *nel3dName = "NeL 3D"; + static const char *ovrName = "Oculus SDK"; + static const char *libvrName = "LibVR"; + static const char *openhmdName = "OpenHMD"; + switch (library) + { + case CStereoDeviceInfo::NeL3D: + return nel3dName; + case CStereoDeviceInfo::OVR: + return ovrName; + case CStereoDeviceInfo::LibVR: + return libvrName; + case CStereoDeviceInfo::OpenHMD: + return openhmdName; + } + nlerror("Invalid device library specified"); + return ""; +} + +void IStereoDisplay::listDevices(std::vector &devicesOut) +{ +#ifdef HAVE_LIBOVR + CStereoOVR::listDevices(devicesOut); +#endif +#if !FINAL_VERSION + CStereoDebugger::listDevices(devicesOut); +#endif +} + +IStereoDisplay *IStereoDisplay::createDevice(const CStereoDeviceInfo &deviceInfo) +{ + return deviceInfo.Factory->createDevice(); +} + +void IStereoDisplay::releaseUnusedLibraries() +{ +#ifdef HAVE_LIBOVR + if (!CStereoOVR::isLibraryInUse()) + CStereoOVR::releaseLibrary(); +#endif +} + +void IStereoDisplay::releaseAllLibraries() +{ +#ifdef HAVE_LIBOVR + CStereoOVR::releaseLibrary(); +#endif +} + +} /* namespace NL3D */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_hmd.cpp b/code/nel/src/3d/stereo_hmd.cpp new file mode 100644 index 000000000..d28017482 --- /dev/null +++ b/code/nel/src/3d/stereo_hmd.cpp @@ -0,0 +1,55 @@ +/** + * \file stereo_hmd.cpp + * \brief IStereoHMD + * \date 2013-06-27 16:30GMT + * \author Jan Boon (Kaetemi) + * IStereoHMD + */ + +/* + * 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 + * . + */ + +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +IStereoHMD::IStereoHMD() +{ + +} + +IStereoHMD::~IStereoHMD() +{ + +} + +} /* namespace NL3D */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_ovr.cpp b/code/nel/src/3d/stereo_ovr.cpp new file mode 100644 index 000000000..a57a0ffcb --- /dev/null +++ b/code/nel/src/3d/stereo_ovr.cpp @@ -0,0 +1,743 @@ +/** + * \file stereo_ovr.cpp + * \brief CStereoOVR + * \date 2013-06-25 22:22GMT + * \author Jan Boon (Kaetemi) + * CStereoOVR + */ + +/* + * 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 + * . + * + * 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 +#include + +// STL includes +#include + +// External includes +#include + +// NeL includes +// #include +#include +#include +#include +#include +#include +#include +#include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +extern const char *g_StereoOVR_fp40; +extern const char *g_StereoOVR_arbfp1; +extern const char *g_StereoOVR_ps_2_0; + +namespace { + +class CStereoOVRLog : public OVR::Log +{ +public: + CStereoOVRLog(unsigned logMask = OVR::LogMask_All) : OVR::Log(logMask) + { + + } + + virtual void LogMessageVarg(OVR::LogMessageType messageType, const char* fmt, va_list argList) + { + if (NLMISC::INelContext::isContextInitialised()) + { + char buffer[MaxLogBufferMessageSize]; + FormatLog(buffer, MaxLogBufferMessageSize, messageType, fmt, argList); + if (IsDebugMessage(messageType)) + NLMISC::INelContext::getInstance().getDebugLog()->displayNL("OVR: %s", buffer); + else + NLMISC::INelContext::getInstance().getInfoLog()->displayNL("OVR: %s", buffer); + } + } +}; + +CStereoOVRLog *s_StereoOVRLog = NULL; +OVR::Ptr s_DeviceManager; + +class CStereoOVRSystem +{ +public: + ~CStereoOVRSystem() + { + Release(); + } + + void Init() + { + if (!s_StereoOVRLog) + { + nldebug("Initialize OVR"); + s_StereoOVRLog = new CStereoOVRLog(); + } + if (!OVR::System::IsInitialized()) + OVR::System::Init(s_StereoOVRLog); + if (!s_DeviceManager) + s_DeviceManager = OVR::DeviceManager::Create(); + } + + void Release() + { + if (s_DeviceManager) + { + nldebug("Release OVR"); + s_DeviceManager->Release(); + } + s_DeviceManager.Clear(); + if (OVR::System::IsInitialized()) + OVR::System::Destroy(); + if (s_StereoOVRLog) + nldebug("Release OVR Ok"); + delete s_StereoOVRLog; + s_StereoOVRLog = NULL; + } +}; + +CStereoOVRSystem s_StereoOVRSystem; + +sint s_DeviceCounter = 0; + +} + +class CStereoOVRDeviceHandle : public IStereoDeviceFactory +{ +public: + // fixme: virtual destructor??? + OVR::DeviceEnumerator DeviceHandle; + IStereoDisplay *createDevice() const + { + CStereoOVR *stereo = new CStereoOVR(this); + if (stereo->isDeviceCreated()) + return stereo; + delete stereo; + return NULL; + } +}; + +class CStereoOVRDevicePtr +{ +public: + OVR::Ptr HMDDevice; + OVR::Ptr SensorDevice; + OVR::SensorFusion SensorFusion; + 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) +{ + ++s_DeviceCounter; + m_DevicePtr = new CStereoOVRDevicePtr(); + + OVR::DeviceEnumerator dh = handle->DeviceHandle; + m_DevicePtr->HMDDevice = dh.CreateDevice(); + + if (m_DevicePtr->HMDDevice) + { + m_DevicePtr->HMDDevice->GetDeviceInfo(&m_DevicePtr->HMDInfo); + nldebug("OVR: HScreenSize: %f, VScreenSize: %f", m_DevicePtr->HMDInfo.HScreenSize, m_DevicePtr->HMDInfo.VScreenSize); + 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: HResolution: %i, VResolution: %i", m_DevicePtr->HMDInfo.HResolution, m_DevicePtr->HMDInfo.VResolution); + 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]); + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 160 NL3D::CStereoOVR::CStereoOVR : OVR: HScreenSize: 0.149760, VScreenSize: 0.093600 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 161 NL3D::CStereoOVR::CStereoOVR : OVR: VScreenCenter: 0.046800 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 162 NL3D::CStereoOVR::CStereoOVR : OVR: EyeToScreenDistance: 0.041000 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 163 NL3D::CStereoOVR::CStereoOVR : OVR: LensSeparationDistance: 0.063500 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 164 NL3D::CStereoOVR::CStereoOVR : OVR: InterpupillaryDistance: 0.064000 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 165 NL3D::CStereoOVR::CStereoOVR : OVR: HResolution: 1280, VResolution: 800 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 166 NL3D::CStereoOVR::CStereoOVR : OVR: DistortionK[0]: 1.000000, DistortionK[1]: 0.220000 + //2013/06/26 05:31:51 DBG 17a0 snowballs_client.exe stereo_ovr.cpp 167 NL3D::CStereoOVR::CStereoOVR : OVR: DistortionK[2]: 0.240000, DistortionK[3]: 0.000000 + m_DevicePtr->SensorDevice = m_DevicePtr->HMDDevice->GetSensor(); + m_DevicePtr->SensorFusion.AttachToSensor(m_DevicePtr->SensorDevice); + m_DevicePtr->SensorFusion.SetGravityEnabled(true); + m_DevicePtr->SensorFusion.SetPredictionEnabled(true); + m_DevicePtr->SensorFusion.SetYawCorrectionEnabled(true); + m_LeftViewport.init(0.f, 0.f, 0.5f, 1.0f); + m_RightViewport.init(0.5f, 0.f, 0.5f, 1.0f); + } +} + +CStereoOVR::~CStereoOVR() +{ + if (!m_BarrelMat.empty()) + { + 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; + + m_Driver = NULL; + + if (m_DevicePtr->SensorDevice) + m_DevicePtr->SensorDevice->Release(); + m_DevicePtr->SensorDevice.Clear(); + if (m_DevicePtr->HMDDevice) + m_DevicePtr->HMDDevice->Release(); + m_DevicePtr->HMDDevice.Clear(); + + delete m_DevicePtr; + m_DevicePtr = NULL; + --s_DeviceCounter; +} + +void CStereoOVR::setDriver(NL3D::UDriver *driver) +{ + nlassert(!m_PixelProgram); + + NL3D::IDriver *drvInternal = (static_cast(driver))->getDriver(); + if (drvInternal->supportPixelProgram(CPixelProgram::fp40) && drvInternal->supportBloomEffect() && drvInternal->supportNonPowerOfTwoTextures()) + { + nldebug("VR: fp40"); + m_PixelProgram = new CPixelProgram(g_StereoOVR_fp40); + } + else if (drvInternal->supportPixelProgram(CPixelProgram::arbfp1) && drvInternal->supportBloomEffect() && drvInternal->supportNonPowerOfTwoTextures()) + { + nldebug("VR: arbfp1"); + m_PixelProgram = new CPixelProgram(g_StereoOVR_arbfp1); + } + else if (drvInternal->supportPixelProgram(CPixelProgram::ps_2_0)) + { + nldebug("VR: ps_2_0"); + m_PixelProgram = new CPixelProgram(g_StereoOVR_ps_2_0); + } + + if (m_PixelProgram) + { + m_Driver = driver; + + 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); + m_BarrelTex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff); + m_BarrelTex->setWrapS(ITexture::Clamp); + m_BarrelTex->setWrapT(ITexture::Clamp); + drvInternal->setupTexture(*m_BarrelTex); + m_BarrelTexU = new CTextureUser(m_BarrelTex); + + m_BarrelMat = m_Driver->createMaterial(); + m_BarrelMat.initUnlit(); + m_BarrelMat.setColor(CRGBA::White); + m_BarrelMat.setBlend (false); + m_BarrelMat.setAlphaTest (false); + NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr(); + barrelMat->setShader(NL3D::CMaterial::PostProcessing); + barrelMat->setBlendFunc(CMaterial::one, CMaterial::zero); + barrelMat->setZWrite(false); + barrelMat->setZFunc(CMaterial::always); + barrelMat->setDoubleSided(true); + 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); + m_BarrelQuadLeft.V2 = CVector(0.5f, 1.f, 0.5f); + m_BarrelQuadLeft.V3 = CVector(0.f, 1.f, 0.5f); + + m_BarrelQuadRight.V0 = CVector(0.5f, 0.f, 0.5f); + m_BarrelQuadRight.V1 = CVector(1.f, 0.f, 0.5f); + 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 + + m_BarrelQuadLeft.Uv0 = CUV(0.f, 0.f); + m_BarrelQuadLeft.Uv1 = CUV(0.5f, 0.f); + m_BarrelQuadLeft.Uv2 = CUV(0.5f, 1.f); + m_BarrelQuadLeft.Uv3 = CUV(0.f, 1.f); + + m_BarrelQuadRight.Uv0 = CUV(0.5f, 0.f); + m_BarrelQuadRight.Uv1 = CUV(1.f, 0.f); + m_BarrelQuadRight.Uv2 = CUV(1.f, 1.f); + m_BarrelQuadRight.Uv3 = CUV(0.5f, 1.f); + } + else + { + nlwarning("VR: No pixel program support"); + } +} + +bool CStereoOVR::getScreenResolution(uint &width, uint &height) +{ + width = m_DevicePtr->HMDInfo.HResolution; + height = m_DevicePtr->HMDInfo.VResolution; + return true; +} + +void CStereoOVR::initCamera(uint cid, const NL3D::UCamera *camera) +{ + 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); + m_RightFrustum[cid] = m_LeftFrustum[cid]; + + float viewCenter = m_DevicePtr->HMDInfo.HScreenSize * 0.25f; + float eyeProjectionShift = viewCenter - m_DevicePtr->HMDInfo.LensSeparationDistance * 0.5f; // docs say LensSeparationDistance, why not InterpupillaryDistance? related to how the lenses work? + float projectionCenterOffset = (eyeProjectionShift / (m_DevicePtr->HMDInfo.HScreenSize * 0.5f)) * (m_LeftFrustum[cid].Right - m_LeftFrustum[cid].Left); // used logic for this one, but it ends up being the same as the one i made up + nldebug("OVR: projectionCenterOffset = %f", projectionCenterOffset); + + m_LeftFrustum[cid].Left -= projectionCenterOffset; + m_LeftFrustum[cid].Right -= projectionCenterOffset; + m_RightFrustum[cid].Left += projectionCenterOffset; + m_RightFrustum[cid].Right += projectionCenterOffset; + + // TODO: Clipping frustum should also take into account the IPD + m_ClippingFrustum[cid] = m_LeftFrustum[cid]; + m_ClippingFrustum[cid].Left = min(m_LeftFrustum[cid].Left, m_RightFrustum[cid].Left); + m_ClippingFrustum[cid].Right = max(m_LeftFrustum[cid].Right, m_RightFrustum[cid].Right); +} + +/// Get the frustum to use for clipping +void CStereoOVR::getClippingFrustum(uint cid, NL3D::UCamera *camera) const +{ + camera->setFrustum(m_ClippingFrustum[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() +{ + // 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); + + if (m_Driver->getPolygonMode() == UDriver::Filled) + { + switch (m_Stage) + { + case 0: + ++m_Stage; + m_SubStage = 0; + // stage 1: + // (initBloom) + // clear buffer + // draw scene left + return true; + case 1: + ++m_Stage; + m_SubStage = 0; + // stage 2: + // draw scene right + return true; + case 2: + ++m_Stage; + m_SubStage = 0; + // stage 3: + // (endBloom) + // draw interface 3d left + return true; + case 3: + ++m_Stage; + m_SubStage = 0; + // stage 4: + // draw interface 3d right + return true; + case 4: + ++m_Stage; + m_SubStage = 0; + // stage 5: + // (endInterfacesDisplayBloom) + // draw interface 2d left + return true; + case 5: + ++m_Stage; + m_SubStage = 0; + // stage 6: + // 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_LeftViewport; + else return m_RightViewport; +} + +const NL3D::CFrustum &CStereoOVR::getCurrentFrustum(uint cid) const +{ + 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]); + 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)); + 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) + { + camera->setPos(mat.getPos()); + camera->setRotQuat(mat.getRot()); + } + else + { + // camera->setTransformMode(NL3D::UTransformable::DirectMatrix); + camera->setMatrix(mat); + } +} + +bool CStereoOVR::wantClear() +{ + switch (m_Stage) + { + case 1: + m_SubStage = 1; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantScene() +{ + switch (m_Stage) + { + case 1: + case 2: + m_SubStage = 2; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantInterface3D() +{ + switch (m_Stage) + { + case 3: + case 4: + m_SubStage = 3; + return true; + } + return m_Driver->getPolygonMode() != UDriver::Filled; +} + +bool CStereoOVR::wantInterface2D() +{ + switch (m_Stage) + { + case 5: + case 6: + 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)) + { + static_cast(m_Driver)->setRenderTarget(*m_BarrelTexU, 0, 0, 0, 0); + return true; + } + return false; +} + +/// Returns true if a render target was fully drawn +bool CStereoOVR::endRenderTarget() +{ + // after rendering of course + // nlassert(m_SubStage > 1); + 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); + 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_BarrelTex); + 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->setPixelProgramConstant(0, lensCenterX, lensCenterY, 0.f, 0.f); + drvInternal->setPixelProgramConstant(1, screenCenterX, screenCenterY, 0.f, 0.f); + drvInternal->setPixelProgramConstant(2, scaleX, scaleY, 0.f, 0.f); + drvInternal->setPixelProgramConstant(3, scaleInX, scaleInY, 0.f, 0.f); + drvInternal->setPixelProgramConstant(4, 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->setPixelProgramConstant(0, lensCenterX, lensCenterY, 0.f, 0.f); + drvInternal->setPixelProgramConstant(1, screenCenterX, screenCenterY, 0.f, 0.f); + + m_Driver->drawQuad(m_BarrelQuadRight, m_BarrelMat); + + drvInternal->activePixelProgram(NULL); + m_Driver->enableFog(fogEnabled); + + return true; + } + return false; +} + +NLMISC::CQuat CStereoOVR::getOrientation() const +{ + if (m_OrientationCached) + return m_OrientationCache; + + OVR::Quatf quatovr = m_DevicePtr->SensorFusion.GetPredictedOrientation(); + 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.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; +} + +/// Get GUI shift +void CStereoOVR::getInterface2DShift(uint cid, float &x, float &y, float distance) const +{ +#if 0 + + // todo: take into account m_EyePosition + + NLMISC::CVector vector = CVector(0.f, -distance, 0.f); + NLMISC::CQuat rot = getOrientation(); + rot.invert(); + NLMISC::CMatrix mat; + mat.rotate(rot); + //if (m_Stage % 2) mat.translate(CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * -0.5f, 0.f, 0.f)); + //else mat.translate(CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * 0.5f, 0.f, 0.f)); + mat.translate(vector); + CVector proj = CStereoOVR::getCurrentFrustum(cid).project(mat.getPos()); + + NLMISC::CVector ipd; + if (m_Stage % 2) ipd = CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * -0.5f, 0.f, 0.f); + else ipd = CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * 0.5f, 0.f, 0.f); + CVector projipd = CStereoOVR::getCurrentFrustum(cid).project(vector + ipd); + CVector projvec = CStereoOVR::getCurrentFrustum(cid).project(vector); + + x = (proj.x + projipd.x - projvec.x - 0.5f); + y = (proj.y + projipd.y - projvec.y - 0.5f); + +#elif 1 + + // Alternative method + // todo: take into account m_EyePosition + + NLMISC::CVector vec = CVector(0.f, -distance, 0.f); + NLMISC::CVector ipd; + if (m_Stage % 2) ipd = CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f); + else ipd = CVector((m_DevicePtr->HMDInfo.InterpupillaryDistance * m_Scale) * 0.5f, 0.f, 0.f); + + + NLMISC::CQuat rot = getOrientation(); + NLMISC::CQuat modrot = NLMISC::CQuat(CVector(0.f, 1.f, 0.f), NLMISC::Pi); + rot = rot * modrot; + float p = NLMISC::Pi + atan2f(2.0f * ((rot.x * rot.y) + (rot.z * rot.w)), 1.0f - 2.0f * ((rot.y * rot.y) + (rot.w * rot.w))); + if (p > NLMISC::Pi) p -= NLMISC::Pi * 2.0f; + float t = -atan2f(2.0f * ((rot.x * rot.w) + (rot.y * rot.z)), 1.0f - 2.0f * ((rot.z * rot.z) + (rot.w * rot.w)));// // asinf(2.0f * ((rot.x * rot.z) - (rot.w * rot.y))); + + CVector rotshift = CVector(p, 0.f, t) * -distance; + + CVector proj = CStereoOVR::getCurrentFrustum(cid).project(vec + ipd + rotshift); + + x = (proj.x - 0.5f); + y = (proj.y - 0.5f); + +#endif +} + +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) +{ + s_StereoOVRSystem.Init(); + OVR::DeviceEnumerator devices = s_DeviceManager->EnumerateDevices(); + uint id = 1; + do + { + CStereoDeviceInfo deviceInfoOut; + OVR::DeviceInfo deviceInfo; + if (devices.IsAvailable()) + { + devices.GetDeviceInfo(&deviceInfo); + CStereoOVRDeviceHandle *handle = new CStereoOVRDeviceHandle(); + deviceInfoOut.Factory = static_cast(handle); + handle->DeviceHandle = devices; + deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD; // 1; // OVR::HMDDevice + deviceInfoOut.Library = CStereoDeviceInfo::OVR; // "Oculus SDK"; + deviceInfoOut.Manufacturer = deviceInfo.Manufacturer; + deviceInfoOut.ProductName = deviceInfo.ProductName; + stringstream ser; + ser << id; + deviceInfoOut.Serial = ser.str(); // can't get the real serial from the sdk... + devicesOut.push_back(deviceInfoOut); + ++id; + } + + } while (devices.Next()); +} + +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->HMDDevice != NULL; +} + +} /* namespace NL3D */ + +#endif /* HAVE_LIBOVR */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_ovr_fp.cpp b/code/nel/src/3d/stereo_ovr_fp.cpp new file mode 100644 index 000000000..b81ee8421 --- /dev/null +++ b/code/nel/src/3d/stereo_ovr_fp.cpp @@ -0,0 +1,202 @@ +/************************************************************************************ + +Filename : stereo_ovf_fp.cpp +Content : Barrel fragment program compiled to a blob of assembly +Created : July 01, 2013 +Modified by : Jan Boon (Kaetemi) + +Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +namespace NL3D { +const char *g_StereoOVR_fp40 = + "!!ARBfp1.0\n" + "OPTION NV_fragment_program2;\n" + //# cgc version 3.1.0013, build date Apr 18 2012 + //# command line args: -profile fp40 + //# source file: pp_oculus_vr.cg + //#vendor NVIDIA Corporation + //#version 3.1.0.13 + //#profile fp40 + //#program pp_oculus_vr + //#semantic pp_oculus_vr.cLensCenter + //#semantic pp_oculus_vr.cScreenCenter + //#semantic pp_oculus_vr.cScale + //#semantic pp_oculus_vr.cScaleIn + //#semantic pp_oculus_vr.cHmdWarpParam + //#semantic pp_oculus_vr.cTex0 : TEX0 + //#var float2 texCoord : $vin.TEXCOORD0 : TEX0 : 0 : 1 + //#var float2 cLensCenter : : c[0] : 1 : 1 + //#var float2 cScreenCenter : : c[1] : 2 : 1 + //#var float2 cScale : : c[2] : 3 : 1 + //#var float2 cScaleIn : : c[3] : 4 : 1 + //#var float4 cHmdWarpParam : : c[4] : 5 : 1 + //#var sampler2D cTex0 : TEX0 : texunit 0 : 6 : 1 + //#var float4 oCol : $vout.COLOR : COL : 7 : 1 + //#const c[5] = 0.25 0.5 0 + "PARAM c[6] = { program.env[0..4],\n" // program.local->program.env! + " { 0.25, 0.5, 0 } };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "SHORT TEMP H0;\n" + "TEMP RC;\n" + "TEMP HC;\n" + "OUTPUT oCol = result.color;\n" + "ADDR R0.xy, fragment.texcoord[0], -c[0];\n" + "MULR R0.xy, R0, c[3];\n" + "MULR R0.z, R0.y, R0.y;\n" + "MADR R1.x, R0, R0, R0.z;\n" + "MULR R0.zw, R1.x, c[4].xywz;\n" + "MADR R1.y, R1.x, c[4], c[4].x;\n" + "MADR R0.w, R0, R1.x, R1.y;\n" + "MULR R0.z, R0, R1.x;\n" + "MADR R0.z, R0, R1.x, R0.w;\n" + "MULR R1.xy, R0, R0.z;\n" + "MOVR R0.xy, c[5];\n" + "ADDR R1.zw, R0.xyxy, c[1].xyxy;\n" + "MOVR R0.zw, c[0].xyxy;\n" + "MADR R0.zw, R1.xyxy, c[2].xyxy, R0;\n" + "MINR R1.xy, R0.zwzw, R1.zwzw;\n" + "ADDR R0.xy, -R0, c[1];\n" + "MAXR R0.xy, R0, R1;\n" + "SEQR H0.xy, R0, R0.zwzw;\n" + "MULXC HC.x, H0, H0.y;\n" + "IF EQ.x;\n" + "MOVR oCol, c[5].z;\n" + "ELSE;\n" + "TEX oCol, R0.zwzw, texture[0], 2D;\n" + "ENDIF;\n" + "END\n"; + //# 24 instructions, 2 R-regs, 1 H-regs +const char *g_StereoOVR_arbfp1 = + "!!ARBfp1.0\n" + //# cgc version 3.1.0013, build date Apr 18 2012 + //# command line args: -profile arbfp1 + //# source file: pp_oculus_vr.cg + //#vendor NVIDIA Corporation + //#version 3.1.0.13 + //#profile arbfp1 + //#program pp_oculus_vr + //#semantic pp_oculus_vr.cLensCenter + //#semantic pp_oculus_vr.cScreenCenter + //#semantic pp_oculus_vr.cScale + //#semantic pp_oculus_vr.cScaleIn + //#semantic pp_oculus_vr.cHmdWarpParam + //#semantic pp_oculus_vr.cTex0 : TEX0 + //#var float2 texCoord : $vin.TEXCOORD0 : TEX0 : 0 : 1 + //#var float2 cLensCenter : : c[0] : 1 : 1 + //#var float2 cScreenCenter : : c[1] : 2 : 1 + //#var float2 cScale : : c[2] : 3 : 1 + //#var float2 cScaleIn : : c[3] : 4 : 1 + //#var float4 cHmdWarpParam : : c[4] : 5 : 1 + //#var sampler2D cTex0 : TEX0 : texunit 0 : 6 : 1 + //#var float4 oCol : $vout.COLOR : COL : 7 : 1 + //#const c[5] = 0.25 0.5 0 1 + "PARAM c[6] = { program.env[0..4],\n" + " { 0.25, 0.5, 0, 1 } };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "ADD R0.xy, fragment.texcoord[0], -c[0];\n" + "MUL R0.xy, R0, c[3];\n" + "MUL R0.z, R0.y, R0.y;\n" + "MAD R0.z, R0.x, R0.x, R0;\n" + "MUL R0.w, R0.z, c[4];\n" + "MUL R0.w, R0, R0.z;\n" + "MAD R1.y, R0.z, c[4], c[4].x;\n" + "MUL R1.x, R0.z, c[4].z;\n" + "MAD R1.x, R0.z, R1, R1.y;\n" + "MAD R0.z, R0.w, R0, R1.x;\n" + "MUL R0.xy, R0, R0.z;\n" + "MOV R0.zw, c[5].xyxy;\n" + "ADD R1.xy, R0.zwzw, c[1];\n" + "MUL R0.xy, R0, c[2];\n" + "ADD R0.xy, R0, c[0];\n" + "MIN R1.xy, R1, R0;\n" + "ADD R0.zw, -R0, c[1].xyxy;\n" + "MAX R0.zw, R0, R1.xyxy;\n" + "ADD R0.zw, R0, -R0.xyxy;\n" + "ABS R0.zw, R0;\n" + "CMP R0.zw, -R0, c[5].z, c[5].w;\n" + "MUL R0.z, R0, R0.w;\n" + "ABS R0.z, R0;\n" + "CMP R0.z, -R0, c[5], c[5].w;\n" + "ABS R1.x, R0.z;\n" + "TEX R0, R0, texture[0], 2D;\n" + "CMP R1.x, -R1, c[5].z, c[5].w;\n" + "CMP result.color, -R1.x, R0, c[5].z;\n" + "END\n"; + //# 28 instructions, 2 R-regs +const char *g_StereoOVR_ps_2_0 = + "ps_2_0\n" + // cgc version 3.1.0013, build date Apr 18 2012 + // command line args: -profile ps_2_0 + // source file: pp_oculus_vr.cg + //vendor NVIDIA Corporation + //version 3.1.0.13 + //profile ps_2_0 + //program pp_oculus_vr + //semantic pp_oculus_vr.cLensCenter + //semantic pp_oculus_vr.cScreenCenter + //semantic pp_oculus_vr.cScale + //semantic pp_oculus_vr.cScaleIn + //semantic pp_oculus_vr.cHmdWarpParam + //semantic pp_oculus_vr.cTex0 : TEX0 + //var float2 texCoord : $vin.TEXCOORD0 : TEX0 : 0 : 1 + //var float2 cLensCenter : : c[0] : 1 : 1 + //var float2 cScreenCenter : : c[1] : 2 : 1 + //var float2 cScale : : c[2] : 3 : 1 + //var float2 cScaleIn : : c[3] : 4 : 1 + //var float4 cHmdWarpParam : : c[4] : 5 : 1 + //var sampler2D cTex0 : TEX0 : texunit 0 : 6 : 1 + //var float4 oCol : $vout.COLOR : COL : 7 : 1 + //const c[5] = -0.25 -0.5 0.25 0.5 + //const c[6] = 1 0 + "dcl_2d s0\n" + "def c5, -0.25000000, -0.50000000, 0.25000000, 0.50000000\n" + "def c6, 1.00000000, 0.00000000, 0, 0\n" + "dcl t0.xy\n" + "add r0.xy, t0, -c0\n" + "mul r4.xy, r0, c3\n" + "mul r0.x, r4.y, r4.y\n" + "mad r0.x, r4, r4, r0\n" + "mul r1.x, r0, c4.w\n" + "mul r1.x, r1, r0\n" + "mad r3.x, r0, c4.y, c4\n" + "mul r2.x, r0, c4.z\n" + "mad r2.x, r0, r2, r3\n" + "mad r0.x, r1, r0, r2\n" + "mul r0.xy, r4, r0.x\n" + "mul r0.xy, r0, c2\n" + "add r3.xy, r0, c0\n" + "mov r1.x, c5.z\n" + "mov r1.y, c5.w\n" + "mov r2.xy, c1\n" + "add r2.xy, r1, r2\n" + "mov r1.xy, c1\n" + "min r2.xy, r2, r3\n" + "add r1.xy, c5, r1\n" + "max r1.xy, r1, r2\n" + "add r1.xy, r1, -r3\n" + "abs r1.xy, r1\n" + "cmp r1.xy, -r1, c6.x, c6.y\n" + "mul_pp r1.x, r1, r1.y\n" + "abs_pp r1.x, r1\n" + "cmp_pp r1.x, -r1, c6, c6.y\n" + "abs_pp r1.x, r1\n" + "texld r0, r3, s0\n" + "cmp r0, -r1.x, r0, c6.y\n" + "mov oC0, r0\n"; +} \ No newline at end of file diff --git a/code/nel/src/3d/vegetablevb_allocator.cpp b/code/nel/src/3d/vegetablevb_allocator.cpp index 9c801b179..efbd1f5a3 100644 --- a/code/nel/src/3d/vegetablevb_allocator.cpp +++ b/code/nel/src/3d/vegetablevb_allocator.cpp @@ -98,7 +98,7 @@ void CVegetableVBAllocator::updateDriver(IDriver *driver) _VBHardOk= false; // Driver must support VP. - nlassert(_Driver->isVertexProgramSupported()); + nlassert(_Driver->supportVertexProgram()); // must reallocate the VertexBuffer. if( _NumVerticesAllocated>0 ) diff --git a/code/nel/src/3d/water_model.cpp b/code/nel/src/3d/water_model.cpp index ddf3d35b2..e72d7bab9 100644 --- a/code/nel/src/3d/water_model.cpp +++ b/code/nel/src/3d/water_model.cpp @@ -61,7 +61,7 @@ void CWaterModel::setupVertexBuffer(CVertexBuffer &vb, uint numWantedVertices, I vb.setNumVertices(0); vb.setName("Water"); vb.setPreferredMemory(CVertexBuffer::AGPPreferred, false); - if (drv->isWaterShaderSupported()) + if (drv->supportWaterShader()) { vb.setVertexFormat(CVertexBuffer::PositionFlag); } @@ -377,7 +377,7 @@ void CWaterModel::traverseRender() #ifndef FORCE_SIMPLE_WATER_RENDER - if (!drv->isWaterShaderSupported()) + if (!drv->supportWaterShader()) #endif { doSimpleRender(drv); @@ -1363,7 +1363,7 @@ uint CWaterModel::getNumWantedVertices() uint CWaterModel::fillVB(void *datas, uint startTri, IDriver &drv) { H_AUTO( NL3D_Water_Render ); - if (drv.isWaterShaderSupported()) + if (drv.supportWaterShader()) { return fillVBHard(datas, startTri); } @@ -1657,7 +1657,7 @@ void CWaterModel::traverseRender() drv->setupModelMatrix(modelMat); bool isAbove = obsPos.z > getWorldMatrix().getPos().z; CVertexBuffer &vb = renderTrav.Scene->getWaterVB(); - if (drv->isWaterShaderSupported()) + if (drv->supportWaterShader()) { setupMaterialNVertexShader(drv, shape, obsPos, isAbove, zHeight); nlassert(vb.getNumVertices() > 0); diff --git a/code/nel/src/3d/water_shape.cpp b/code/nel/src/3d/water_shape.cpp index 0196294c3..227b85254 100644 --- a/code/nel/src/3d/water_shape.cpp +++ b/code/nel/src/3d/water_shape.cpp @@ -372,7 +372,7 @@ void CWaterShape::flushTextures (IDriver &driver, uint selectedTexture) /* if ( - (driver.supportTextureShaders() && driver.isTextureAddrModeSupported(CMaterial::OffsetTexture)) + (driver.supportTextureShaders() && driver.supportTextureAddrMode(CMaterial::OffsetTexture)) || driver.supportEMBM() ) { diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/login_main.xml b/code/ryzom/client/data/gamedev/interfaces_v3/login_main.xml index 9d3ff0052..648cbbb6a 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/login_main.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/login_main.xml @@ -1,837 +1,837 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -