// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DRIVER_OPENGL_H #define NL_DRIVER_OPENGL_H #include "nel/misc/types_nl.h" //#define NL_PROFILE_DRIVER_OGL #ifdef NL_PROFILE_DRIVER_OGL # define H_AUTO_OGL(label) H_AUTO(label) #else # define H_AUTO_OGL(label) #endif #ifdef NL_OS_WINDOWS # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include # include #elif defined(NL_OS_MAC) && defined(NL_MAC_NATIVE) # define GL_GLEXT_LEGACY # include #elif defined (NL_OS_UNIX) # define GLX_GLXEXT_PROTOTYPES # include # include # ifdef XF86VIDMODE # include # endif //XF86VIDMODE #endif // NL_OS_UNIX #include "driver_opengl_extension.h" #include "nel/3d/driver.h" #include "nel/3d/material.h" #include "nel/3d/shader.h" #include "nel/3d/vertex_buffer.h" #include "nel/misc/matrix.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/rgba.h" #include "nel/misc/event_emitter.h" #include "nel/misc/bit_set.h" #include "nel/misc/hierarchical_timer.h" #include "nel/3d/ptr_set.h" #include "nel/misc/heap_memory.h" #include "nel/misc/event_emitter_multi.h" #include "driver_opengl_states.h" #include "nel/3d/texture_cube.h" #include "nel/3d/vertex_program_parse.h" #include "nel/3d/viewport.h" #include "nel/3d/scissor.h" #include "nel/3d/light.h" #include "nel/misc/time_nl.h" #include "nel/3d/occlusion_query.h" #ifdef NL_OS_WINDOWS #include "nel/misc/win_event_emitter.h" #elif defined(NL_OS_MAC) && defined(NL_MAC_NATIVE) #include "mac/cocoa_event_emitter.h" #elif defined (NL_OS_UNIX) #include "unix_event_emitter.h" #endif // NL_OS_UNIX // For optimisation consideration, allow 256 lightmaps at max. #define NL3D_DRV_MAX_LIGHTMAP 256 void displayGLError(GLenum error); /* #define CHECK_GL_ERROR { \ GLenum error = glGetError(); \ if (error != GL_NO_ERROR)\ {\ displayGLError(error);\ nlassert(0);\ }\ } */ #define UNSUPPORTED_INDEX_OFFSET_MSG "Unsupported by driver, check IDriver::supportIndexOffset." namespace NL3D { using NLMISC::CMatrix; using NLMISC::CVector; class CDriverGL; class IVertexArrayRange; class IVertexBufferHardGL; class COcclusionQueryGL; typedef std::list TOcclusionQueryList; // *************************************************************************** class COcclusionQueryGL : public IOcclusionQuery { public: GLuint ID; // id of gl object NLMISC::CRefPtr Driver; // owner driver TOcclusionQueryList::iterator Iterator; // iterator in owner driver list of queries TOcclusionType OcclusionType; // current type of occlusion uint VisibleCount; // number of samples that passed the test // From IOcclusionQuery virtual void begin(); virtual void end(); virtual TOcclusionType getOcclusionType(); virtual uint getVisibleCount(); }; // *************************************************************************** class CTextureDrvInfosGL : public ITextureDrvInfos { public: /* ANY DATA ADDED HERE MUST BE SWAPPED IN swapTextureHandle() !! */ // The GL Id. GLuint ID; // Is the internal format of the texture is a compressed one? bool Compressed; // Is the internal format of the texture has mipmaps? bool MipMap; // This is the computed size of what memory this texture take. uint32 TextureMemory; // This is the owner driver. CDriverGL *_Driver; // enum to use for this texture (GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV..) GLenum TextureMode; // FBO Id GLuint FBOId; // depth stencil FBO id GLuint DepthFBOId; GLuint StencilFBOId; bool InitFBO; bool AttachDepthStencil; bool UsePackedDepthStencil; // The current wrap modes assigned to the texture. ITexture::TWrapMode WrapS; ITexture::TWrapMode WrapT; ITexture::TMagFilter MagFilter; ITexture::TMinFilter MinFilter; // The gl id is auto created here. CTextureDrvInfosGL(IDriver *drv, ItTexDrvInfoPtrMap it, CDriverGL *drvGl, bool isRectangleTexture); // The gl id is auto deleted here. ~CTextureDrvInfosGL(); // For Debug info. return the memory cost of this texture virtual uint getTextureMemoryUsed() const {return TextureMemory;} bool initFrameBufferObject(ITexture * tex); bool activeFrameBufferObject(ITexture * tex); }; // *************************************************************************** class CVBDrvInfosGL : public IVBDrvInfos { public: CVBDrvInfosGL(CDriverGL *drv, ItVBDrvInfoPtrList it, CVertexBuffer *vb); // Verex buffer hard ? IVertexBufferHardGL *_VBHard; class CDriverGL *_DriverGL; uint8 *_SystemMemory; // From IVBDrvInfos virtual ~CVBDrvInfosGL(); virtual uint8 *lock (uint first, uint last, bool readOnly); virtual void unlock (uint first, uint last); }; // *************************************************************************** class CShaderGL : public IMaterialDrvInfos { public: GLenum SrcBlend; GLenum DstBlend; GLenum ZComp; GLfloat Emissive[4]; GLfloat Ambient[4]; GLfloat Diffuse[4]; GLfloat Specular[4]; // For fast comp. uint32 PackedEmissive; uint32 PackedAmbient; uint32 PackedDiffuse; uint32 PackedSpecular; // The supported Shader type. CMaterial::TShader SupportedShader; CShaderGL(IDriver *drv, ItMatDrvInfoPtrList it) : IMaterialDrvInfos(drv, it) {} }; // *************************************************************************** /// Info for the last VertexBuffer setuped (iether normal or hard). class CVertexBufferInfo { public: uint16 VertexFormat; uint16 VertexSize; uint32 NumVertices; CVertexBuffer::TType Type[CVertexBuffer::NumValue]; uint8 UVRouting[CVertexBuffer::MaxStage]; // NB: ptrs are invalid if VertexFormat does not support the compoennt. must test VertexFormat, not the ptr. void *ValuePtr[CVertexBuffer::NumValue]; enum TVBMode { TVBModeNone = 0, SysMem, HwNVIDIA, HwARB, HwATI }; // standard VBs, or Hard VBs using different extensions // Kind of vb TVBMode VBMode; // the handle of ATI or ARB vertex object uint VertexObjectId; CVertexBufferInfo() { VBMode = TVBModeNone; } void setupVertexBuffer(CVertexBuffer &vb); void setupVertexBufferHard(IVertexBufferHardGL &vb); }; // *************************************************************************** /// Info for the last IndexBuffer setuped (iether normal or hard). class CIndexBufferInfo { public: const void *_Values; CIndexBuffer::TFormat _Format; CIndexBufferInfo (); void setupIndexBuffer(CIndexBuffer &vb); }; // *************************************************************************** class CDriverGL : public IDriver { public: // Some constants enum { MaxLight=8 }; CDriverGL(); virtual ~CDriverGL(); virtual bool isLost() const { return false; } // there's no notion of 'lost device" in OpenGL virtual bool init (uint windowIcon = 0, emptyProc exitFunc = 0); virtual void disableHardwareVertexProgram(); virtual void disableHardwareVertexArrayAGP(); virtual void disableHardwareTextureShader(); virtual bool setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable) throw(EBadDisplay); virtual bool setMode(const GfxMode& mode); virtual bool getModes(std::vector &modes); virtual bool getCurrentScreenMode(GfxMode &mode); virtual void beginDialogMode(); virtual void endDialogMode(); /// Set the title of the NeL window virtual void setWindowTitle(const ucstring &title); /// Set the position of the NeL window virtual void setWindowPos(uint32 x, uint32 y); /// Show or hide the NeL window virtual void showWindow(bool show); virtual nlWindow getDisplay() { #ifdef NL_OS_WINDOWS return _hWnd; #elif defined(NL_OS_MAC) && defined(NL_MAC_NATIVE) return NULL; #elif defined(NL_OS_UNIX) return win; #endif // NL_OS_WINDOWS } virtual uint32 getAvailableVertexAGPMemory (); virtual uint32 getAvailableVertexVRAMMemory (); virtual emptyProc getWindowProc(); virtual bool activate(); virtual uint getNbTextureStages() const; virtual bool isTextureExist(const ITexture&tex); virtual NLMISC::IEventEmitter *getEventEmitter() { return&_EventEmitter; }; virtual bool clear2D(CRGBA rgba); virtual bool clearZBuffer(float zval=1); virtual bool clearStencilBuffer(float stencilval=0); virtual void setColorMask (bool bRed, bool bGreen, bool bBlue, bool bAlpha); virtual void setDepthRange(float znear, float zfar); virtual void getDepthRange(float &znear, float &zfar) const; virtual bool setupTexture (ITexture& tex); virtual bool setupTextureEx (ITexture& tex, bool bUpload, bool &bAllUploaded, bool bMustRecreateSharedTexture= false); virtual bool uploadTexture (ITexture& tex, NLMISC::CRect& rect, uint8 nNumMipMap); virtual bool uploadTextureCube (ITexture& tex, NLMISC::CRect& rect, uint8 nNumMipMap, uint8 nNumFace); virtual void forceDXTCCompression(bool dxtcComp); virtual void forceTextureResize(uint divisor); virtual void forceNativeFragmentPrograms(bool nativeOnly); /// Setup texture env functions. Used by setupMaterial void setTextureEnvFunction(uint stage, CMaterial& mat); /// setup the texture matrix for a given number of stages (starting from 0) void setupUserTextureMatrix(uint numStages, CMaterial& mat); /// disable all texture matrix void disableUserTextureMatrix(); /// For objects with caustics, setup the first texture (which actually is the one from the material) /*static inline void setupCausticsFirstTex(const CMaterial &mat); /// For objects with caustics, setup the caustic texture itself static inline void setupCausticsSecondTex(uint stage);*/ virtual bool setupMaterial(CMaterial& mat); virtual void startSpecularBatch(); virtual void endSpecularBatch(); virtual void setFrustum(float left, float right, float bottom, float top, float znear, float zfar, bool perspective = true); virtual void setFrustumMatrix(CMatrix &frust); virtual CMatrix getFrustumMatrix(); virtual float getClipSpaceZMin() const { return -1.f; } virtual void setupViewMatrix(const CMatrix& mtx); virtual void setupViewMatrixEx(const CMatrix& mtx, const CVector &cameraPos); virtual void setupModelMatrix(const CMatrix& mtx); virtual CMatrix getViewMatrix() const; virtual bool activeShader(CShader *shd); virtual void forceNormalize(bool normalize) { _ForceNormalize= normalize; // if ForceNormalize, must enable GLNormalize now. if(normalize) enableGlNormalize(true); } virtual bool isForceNormalize() const { return _ForceNormalize; } virtual void getNumPerStageConstant(uint &lightedMaterial, uint &unlightedMaterial) const; virtual bool supportVertexBufferHard() const; virtual bool supportVolatileVertexBuffer() const; virtual bool supportCloudRenderSinglePass() const; virtual bool supportIndexOffset() const { return false; /* feature only supported in D3D for now */ } virtual bool slowUnlockVertexBufferHard() const; virtual uint getMaxVerticesByVertexBufferHard() const; virtual bool initVertexBufferHard(uint agpMem, uint vramMem); virtual bool activeVertexBuffer(CVertexBuffer& VB); virtual bool activeIndexBuffer(CIndexBuffer& IB); virtual void mapTextureStageToUV(uint stage, uint uv); virtual bool renderLines(CMaterial& mat, uint32 firstIndex, uint32 nlines); virtual bool renderTriangles(CMaterial& Mat, uint32 firstIndex, uint32 ntris); virtual bool renderSimpleTriangles(uint32 firstTri, uint32 ntris); virtual bool renderRawPoints(CMaterial& Mat, uint32 startIndex, uint32 numPoints); virtual bool renderRawLines(CMaterial& Mat, uint32 startIndex, uint32 numLines); virtual bool renderRawTriangles(CMaterial& Mat, uint32 startIndex, uint32 numTris); virtual bool renderRawQuads(CMaterial& Mat, uint32 startIndex, uint32 numQuads); // virtual bool renderLinesWithIndexOffset(CMaterial& /* mat */, uint32 /* firstIndex */, uint32 /* nlines */, uint /* indexOffset */) { nlassertex(0, (UNSUPPORTED_INDEX_OFFSET_MSG)); return false; } virtual bool renderTrianglesWithIndexOffset(CMaterial& /* mat */, uint32 /* firstIndex */, uint32 /* ntris */, uint /* indexOffset */) { nlassertex(0, (UNSUPPORTED_INDEX_OFFSET_MSG)); return false; } virtual bool renderSimpleTrianglesWithIndexOffset(uint32 /* firstIndex */, uint32 /* ntris */, uint /* indexOffset */) { nlassertex(0, (UNSUPPORTED_INDEX_OFFSET_MSG)); return false; } virtual bool swapBuffers(); virtual void setSwapVBLInterval(uint interval); virtual uint getSwapVBLInterval(); virtual void profileRenderedPrimitives(CPrimitiveProfile &pIn, CPrimitiveProfile &pOut); virtual uint32 profileAllocatedTextureMemory(); virtual uint32 profileSetupedMaterials() const; virtual uint32 profileSetupedModelMatrix() const; void enableUsedTextureMemorySum (bool enable); uint32 getUsedTextureMemory() const; virtual void startProfileVBHardLock(); virtual void endProfileVBHardLock(std::vector &result); virtual void profileVBHardAllocation(std::vector &result); virtual void startProfileIBLock(); virtual void endProfileIBLock(std::vector &result); virtual void profileIBAllocation(std::vector &result); virtual bool release(); virtual TMessageBoxId systemMessageBox (const char* message, const char* title, TMessageBoxType type=okType, TMessageBoxIcon icon=noIcon); virtual void setupScissor (const class CScissor& scissor); virtual void setupViewport (const class CViewport& viewport); virtual void getViewport(CViewport &viewport); virtual uint32 getImplementationVersion () const { return ReleaseVersion; } virtual const char* getDriverInformation () { return "Opengl 1.2 NeL Driver"; } virtual const char* getVideocardInformation (); virtual bool isActive (); virtual uint8 getBitPerPixel (); virtual void showCursor (bool b); // between 0.0 and 1.0 virtual void setMousePos(float x, float y); virtual void setCapture (bool b); virtual NLMISC::IMouseDevice *enableLowLevelMouse(bool enable, bool exclusive); virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable); virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager(); virtual uint getDoubleClickDelay(bool hardwareMouse); virtual void getWindowSize (uint32 &width, uint32 &height); virtual void getWindowPos (uint32 &x, uint32 &y); virtual void getBuffer (CBitmap &bitmap); virtual void getZBuffer (std::vector &zbuffer); virtual void getBufferPart (CBitmap &bitmap, NLMISC::CRect &rect); // copy the first texture in a second one of different dimensions virtual bool stretchRect(ITexture * srcText, NLMISC::CRect &srcRect, ITexture * destText, NLMISC::CRect &destRect); // return true if driver support Bloom effect. virtual bool supportBloomEffect() const; // return true if driver support non-power of two textures virtual bool supportNonPowerOfTwoTextures() const; virtual bool activeFrameBufferObject(ITexture * tex); 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 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); virtual bool fillBuffer (CBitmap &bitmap); virtual void setPolygonMode (TPolygonMode mode); virtual uint getMaxLight () const; virtual void setLight (uint8 num, const CLight& light); virtual void enableLight (uint8 num, bool enable=true); virtual void setPerPixelLightingLight(CRGBA diffuse, CRGBA specular, float shininess); virtual void setLightMapDynamicLight (bool enable, const CLight& light); virtual void setAmbientColor (CRGBA color); /// \name Fog support. // @{ virtual bool fogEnabled(); virtual void enableFog(bool enable); /// setup fog parameters. fog must enabled to see result. start and end are in [0,1] range. virtual void setupFog(float start, float end, CRGBA color); virtual float getFogStart() const; virtual float getFogEnd() const; virtual CRGBA getFogColor() const; // @} /// \name texture addressing modes // @{ virtual bool supportTextureShaders() const; virtual bool isWaterShaderSupported() const; virtual bool isTextureAddrModeSupported(CMaterial::TTexAddressingMode mode) const; virtual void setMatrix2DForTextureOffsetAddrMode(const uint stage, const float mat[4]); // @} /// \name EMBM support // @{ virtual bool supportEMBM() const; virtual bool isEMBMSupportedAtStage(uint stage) const; virtual void setEMBMMatrix(const uint stage, const float mat[4]); // @} virtual bool supportPerPixelLighting(bool specular) const; /// \name Misc // @{ virtual bool supportBlendConstantColor() const; virtual void setBlendConstantColor(NLMISC::CRGBA col); virtual NLMISC::CRGBA getBlendConstantColor() const; virtual bool setMonitorColorProperties (const CMonitorColorProperties &properties); virtual void finish(); virtual void flush(); virtual void enablePolygonSmoothing(bool smooth); virtual bool isPolygonSmoothingEnabled() const; // @} virtual void swapTextureHandle(ITexture &tex0, ITexture &tex1); virtual uint getTextureHandle(const ITexture&tex); /// \name Material multipass. /** NB: setupMaterial() must be called before thoses methods. * NB: This is intended to be use with the rendering of simple primitives. * NB: Other render calls performs the needed setup automatically */ // @{ /// init multipass for _CurrentMaterial. return number of pass required to render this material. virtual sint beginMaterialMultiPass() { return beginMultiPass(); } /// active the ith pass of this material. virtual void setupMaterialPass(uint pass) { setupPass(pass); } /// end multipass for this material. virtual void endMaterialMultiPass() { endMultiPass(); } // @} /// Adaptor information virtual uint getNumAdapter() const; virtual bool getAdapter(uint adapter, CAdapter &desc) const; virtual bool setAdapter(uint adapter); virtual CVertexBuffer::TVertexColorType getVertexColorFormat() const; // Bench virtual void startBench (bool wantStandardDeviation = false, bool quick = false, bool reset = true); virtual void endBench (); virtual void displayBench (class NLMISC::CLog *log); virtual bool supportOcclusionQuery() const; virtual IOcclusionQuery *createOcclusionQuery(); virtual void deleteOcclusionQuery(IOcclusionQuery *oq); // Test whether this device supports the frame buffer object mecanism virtual bool supportTextureRectangle() const; virtual bool supportFrameBufferObject() const; virtual bool supportPackedDepthStencil() const; virtual uint64 getSwapBufferCounter() const { return _SwapBufferCounter; } virtual void setCullMode(TCullMode cullMode); virtual TCullMode getCullMode() const; virtual void enableStencilTest(bool enable); virtual bool isStencilTestEnabled() const; virtual void stencilFunc(TStencilFunc stencilFunc, int ref, uint mask); virtual void stencilOp(TStencilOp fail, TStencilOp zfail, TStencilOp zpass); virtual void stencilMask(uint mask); private: virtual class IVertexBufferHardGL *createVertexBufferHard(uint size, uint numVertices, CVertexBuffer::TPreferredMemory vbType, CVertexBuffer *vb); friend class CTextureDrvInfosGL; friend class CVertexProgamDrvInfosGL; private: // Version of the driver. Not the interface version!! Increment when implementation of the driver change. static const uint32 ReleaseVersion; bool _FullScreen; bool _OffScreen; uint _Interval; sint32 _WindowWidth, _WindowHeight, _WindowX, _WindowY; #ifdef NL_OS_WINDOWS friend static bool GlWndProc(CDriverGL *driver, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); HWND _hWnd; HDC _hDC; PIXELFORMATDESCRIPTOR _pfd; HGLRC _hRC; static uint _Registered; DEVMODE _OldScreenMode; NLMISC::CEventEmitterMulti _EventEmitter; // this can contains a win emitter and eventually a direct input emitter bool _DestroyWindow; // Off-screen rendering in Dib section HPBUFFERARB _PBuffer; #elif defined(NL_OS_MAC) && defined(NL_MAC_NATIVE) NLMISC::CCocoaEventEmitter _EventEmitter; #elif defined (NL_OS_UNIX) Display *dpy; GLXContext ctx; Window win; Cursor cursor; NLMISC::CUnixEventEmitter _EventEmitter; #ifdef XF86VIDMODE int _OldDotClock; // old dotclock XF86VidModeModeLine _OldScreenMode; // old modeline int _OldX, _OldY; //Viewport settings #endif //XF86VIDMODE #endif // NL_OS_UNIX bool _Initialized; /// \name Driver Caps. // @{ // OpenGL extensions Extensions. CGlExtensions _Extensions; // @} // Depth of the driver in Bit Per Pixel uint8 _Depth; // The forceNormalize() state. bool _ForceNormalize; // To know if light setup has been changed from last render() ( any call to setupViewMatrix() or setLight() ). bool _LightSetupDirty; // To know if the modelview matrix setup has been changed from last render() (any call to setupViewMatrix() / setupModelMatrix() ). bool _ModelViewMatrixDirty; // To know if the projection matrix has been changed bool _ProjMatDirty; // Mirror the gl projection matrix when _ProjMatDirty = false NLMISC::CMatrix _GLProjMat; // Ored of _LightSetupDirty and _ModelViewMatrixDirty bool _RenderSetupDirty; // Backup znear and zfar float _OODeltaZ; // Current View matrix, in NEL basis. This is the parameter passed in setupViewMatrix*(). CMatrix _UserViewMtx; // Current (OpenGL basis) View matrix. // NB: if setuped with setupViewMatrixEx(), _ViewMtx.Pos()==(0,0,0) CMatrix _ViewMtx; // Matrix used for specular CMatrix _SpecularTexMtx; // Precision ZBuffer: The Current cameraPosition, to remove from each model Position. CVector _PZBCameraPos; // Current computed (OpenGL basis) ModelView matrix. // NB: This matrix have already substracted the _PZBCameraPos // Hence this matrix represent the Exact eye-space basis (only _ViewMtx is a bit tricky). CMatrix _ModelViewMatrix; // Fog. bool _FogEnabled; float _FogEnd, _FogStart; GLfloat _CurrentFogColor[4]; // current viewport and scissor CViewport _CurrViewport; CScissor _CurrScissor; // viewport before call to setRenderTarget, if BFO extension is supported CViewport _OldViewport; bool _RenderTargetFBO; // Num lights return by GL_MAX_LIGHTS uint _MaxDriverLight; // real mirror of GL state uint _LightMode[MaxLight]; // Light mode. CVector _WorldLightPos[MaxLight]; // World position of the lights. CVector _WorldLightDirection[MaxLight]; // World direction of the lights. bool _LightDirty[MaxLight]; // Light that need a View position setup in refreshRenderSetup(). // For Lightmap Dynamic Lighting CLight _LightMapDynamicLight; bool _LightMapDynamicLightEnabled; bool _LightMapDynamicLightDirty; // this is the backup of standard lighting (cause GL states may be modified by Lightmap Dynamic Lighting) CLight _UserLight0; bool _UserLightEnable[MaxLight]; //\name description of the per pixel light // @{ void checkForPerPixelLightingSupport(); bool _SupportPerPixelShader; bool _SupportPerPixelShaderNoSpec; float _PPLExponent; NLMISC::CRGBA _PPLightDiffuseColor; NLMISC::CRGBA _PPLightSpecularColor; // @} /// \name Prec settings, for optimisation. // @{ // Special Texture environnements. enum CTexEnvSpecial { TexEnvSpecialDisabled= 0, TexEnvSpecialLightMap, TexEnvSpecialSpecularStage1, TexEnvSpecialSpecularStage1NoText, TexEnvSpecialPPLStage0, TexEnvSpecialPPLStage2, TexEnvSpecialCloudStage0, TexEnvSpecialCloudStage1, }; // NB: CRefPtr are not used for mem/spped optimisation. setupMaterial() and setupTexture() reset those states. CMaterial* _CurrentMaterial; CMaterial::TShader _CurrentMaterialSupportedShader; /* NB : this pointers handles the caching of glBindTexture() and setTextureMode() calls. */ ITexture* _CurrentTexture[IDRV_MAT_MAXTEXTURES]; CTextureDrvInfosGL* _CurrentTextureInfoGL[IDRV_MAT_MAXTEXTURES]; CMaterial::CTexEnv _CurrentTexEnv[IDRV_MAT_MAXTEXTURES]; // Special Texture Environnement. CTexEnvSpecial _CurrentTexEnvSpecial[IDRV_MAT_MAXTEXTURES]; // Texture addressing mode GLenum _CurrentTexAddrMode[IDRV_MAT_MAXTEXTURES]; // Reset texture shaders to their initial state if they are used void resetTextureShaders(); /** set texture shaders from stage 0 to stage IDRV_MAT_MAXTEXTURES - 1 * textures are needed to setup the right kind of shader (cubic or 2d texture) */ void setTextureShaders(const uint8 *addressingModes, const NLMISC::CSmartPtr *textures); // activation of texture shaders bool _NVTextureShaderEnabled; // Which stages support EMBM bool _StageSupportEMBM[IDRV_MAT_MAXTEXTURES]; // Prec settings for material. CDriverGLStates _DriverGLStates; // Optim: To not test change in Materials states if just texture has changed. Very useful for landscape. uint32 _MaterialAllTextureTouchedFlag; // @} bool _CurrentGlNormalize; private: void switchBackToOldMode(); // Get the proj matrix setupped in GL void refreshProjMatrixFromGL(); bool setupVertexBuffer(CVertexBuffer& VB); // Activate Texture Environnement. Do it with caching. bool activateTexture(uint stage, ITexture *tex); // NB: this test _CurrentTexEnv[] and _CurrentTexEnvSpecial[]. void activateTexEnvMode(uint stage, const CMaterial::CTexEnv &env); void activateTexEnvColor(uint stage, const CMaterial::CTexEnv &env); // Force Activate Texture Environnement. no caching here. TexEnvSpecial is disabled. void forceActivateTexEnvMode(uint stage, const CMaterial::CTexEnv &env); void activateTexEnvColor(uint stage, NLMISC::CRGBA col); void forceActivateTexEnvColor(uint stage, NLMISC::CRGBA col) { static const float OO255= 1.0f/255; _CurrentTexEnv[stage].ConstantColor= col; // Setup the gl cte color. _DriverGLStates.activeTextureARB(stage); GLfloat glcol[4]; glcol[0]= col.R*OO255; glcol[1]= col.G*OO255; glcol[2]= col.B*OO255; glcol[3]= col.A*OO255; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, glcol); } void forceActivateTexEnvColor(uint stage, const CMaterial::CTexEnv &env) { H_AUTO_OGL(CDriverGL_forceActivateTexEnvColor) forceActivateTexEnvColor(stage, env.ConstantColor); } /// nv texture shaders. Should be used only if this caps is present! void enableNVTextureShader(bool enabled); // check nv texture shader consistency void verifyNVTextureShaderConfig(); // Called by doRefreshRenderSetup(). set _LightSetupDirty to false void cleanLightSetup (); // According to extensions, retrieve GL tex format of the texture. GLint getGlTextureFormat(ITexture& tex, bool &compressed); // Clip the wanted rectangle with window. return true if rect is not NULL. bool clipRect(NLMISC::CRect &rect); // Copy the frame buffer to a texture void copyFrameBufferToTexture(ITexture *tex, uint32 level, uint32 offsetx, uint32 offsety, uint32 x, uint32 y, uint32 width, uint32 height, uint cubeFace = 0 ); // is this texture a rectangle texture ? virtual bool isTextureRectangle(ITexture * tex) const; /// \name Material multipass. /** NB: setupMaterial() must be called before thoses methods. */ // @{ /// init multipass for _CurrentMaterial. return number of pass required to render this material. sint beginMultiPass(); /// active the ith pass of this material. void setupPass(uint pass); /// end multipass for this material. void endMultiPass(); // @} /// LastVB for UV setup. CVertexBufferInfo _LastVB; CIndexBufferInfo _LastIB; /// setup a texture stage with an UV from VB. void setupUVPtr(uint stage, CVertexBufferInfo &VB, uint uvId); /// \name Lightmap. // @{ void computeLightMapInfos(const CMaterial &mat); sint beginLightMapMultiPass(); void setupLightMapPass(uint pass); void endLightMapMultiPass(); /// Temp Variables computed in beginLightMapMultiPass(). Reused in setupLightMapPass(). uint _NLightMaps; uint _NLightMapPerPass; uint _NLightMapPass; bool _LightMapNoMulAddFallBack; // This array is the LUT from lmapId in [0, _NLightMaps[, to original lightmap id in material. std::vector _LightMapLUT; // last stage env. CMaterial::CTexEnv _LightMapLastStageEnv; // Caching bool _LastVertexSetupIsLightMap; sint8 _LightMapUVMap[IDRV_MAT_MAXTEXTURES]; // restore std vertex Setup. void resetLightMapVertexSetup(); // @} /// \name Specular. // @{ sint beginSpecularMultiPass(); void setupSpecularPass(uint pass); void endSpecularMultiPass(); void setupSpecularBegin(); void setupSpecularEnd(); bool _SpecularBatchOn; // @} /// \name Water // @{ sint beginWaterMultiPass(); void setupWaterPass(uint pass); void endWaterMultiPass(); // @} /// \name Per pixel lighting // @{ // per pixel lighting with specular sint beginPPLMultiPass(); void setupPPLPass(uint pass); void endPPLMultiPass(); // per pixel lighting, no specular sint beginPPLNoSpecMultiPass(); void setupPPLNoSpecPass(uint pass); void endPPLNoSpecMultiPass(); typedef NLMISC::CSmartPtr TSPTextureCube; typedef std::vector TTexCubeVect; TTexCubeVect _SpecularTextureCubes; // the cube maps used to compute the specular lighting. /// get (and if necessary, build) a cube map used for specular lighting. The range for exponent is limited, and only the best fit is used CTextureCube *getSpecularCubeMap(uint exp); // get (and if necessary, build) the cube map used for diffuse lighting CTextureCube *getDiffuseCubeMap() { return getSpecularCubeMap(1); } // @} /// \name Caustics // @{ /*sint beginCausticsMultiPass(const CMaterial &mat); void setupCausticsPass(const CMaterial &mat, uint pass); void endCausticsMultiPass(const CMaterial &mat);*/ // @} /// \name Cloud Shader sint beginCloudMultiPass (); void setupCloudPass (uint pass); void endCloudMultiPass (); // @} /// setup GL arrays, with a vb info. void setupGlArrays(CVertexBufferInfo &vb); /// Tools fct used by setupGLArrays void setupGlArraysStd(CVertexBufferInfo &vb); void setupGlArraysForNVVertexProgram(CVertexBufferInfo &vb); void setupGlArraysForARBVertexProgram(CVertexBufferInfo &vb); void setupGlArraysForEXTVertexShader(CVertexBufferInfo &vb); void toggleGlArraysForNVVertexProgram(); void toggleGlArraysForARBVertexProgram(); void toggleGlArraysForEXTVertexShader(); /// Test/activate normalisation of normal. void enableGlNormalize(bool normalize) { if(_CurrentGlNormalize!=normalize) { _CurrentGlNormalize= normalize; if(normalize) glEnable(GL_NORMALIZE); else glDisable(GL_NORMALIZE); } } // refresh matrixes and lights. void refreshRenderSetup() { // check if something to change. if(_RenderSetupDirty) { doRefreshRenderSetup(); } } void doRefreshRenderSetup(); void setLightInternal(uint8 num, const CLight& light); void enableLightInternal(uint8 num, bool enable); void setupLightMapDynamicLighting(bool enable); /// \name VertexBufferHard // @{ CPtrSet _VertexBufferHardSet; friend class CVertexArrayRangeNVidia; friend class CVertexBufferHardGLNVidia; friend class CVertexArrayRangeATI; friend class CVertexArrayRangeARB; friend class CVertexBufferHardARB; friend class CVertexBufferHardGLATI; friend class CVertexArrayRangeMapObjectATI; friend class CVertexBufferHardGLMapObjectATI; friend class CVBDrvInfosGL; // The VertexArrayRange activated. IVertexArrayRange *_CurrentVertexArrayRange; // The VertexBufferHardGL activated. IVertexBufferHardGL *_CurrentVertexBufferHard; // current setup passed to nglVertexArrayRangeNV() void *_NVCurrentVARPtr; uint32 _NVCurrentVARSize; // Info got from ATI or NVidia extension. bool _SupportVBHard; bool _SlowUnlockVBHard; uint32 _MaxVerticesByVBHard; // The AGP VertexArrayRange. IVertexArrayRange *_AGPVertexArrayRange; // The VRAM VertexArrayRange. IVertexArrayRange *_VRAMVertexArrayRange; void resetVertexArrayRange(); void fenceOnCurVBHardIfNeeded(IVertexBufferHardGL *newVBHard); // @} /// \name Profiling // @{ CPrimitiveProfile _PrimitiveProfileIn; CPrimitiveProfile _PrimitiveProfileOut; uint32 _AllocatedTextureMemory; uint32 _NbSetupMaterialCall; uint32 _NbSetupModelMatrixCall; bool _SumTextureMemoryUsed; std::set _TextureUsed; uint computeMipMapMemoryUsage(uint w, uint h, GLint glfmt) const; // VBHard Lock Profiling struct CVBHardProfile { NLMISC::CRefPtr VBHard; NLMISC::TTicks AccumTime; // true if the VBHard was not always the same for the same chronogical place. bool Change; CVBHardProfile() { AccumTime= 0; Change= false; } }; // The Profiles in chronogical order. bool _VBHardProfiling; std::vector _VBHardProfiles; uint _CurVBHardLockCount; uint _NumVBHardProfileFrame; void appendVBHardLockProfile(NLMISC::TTicks time, CVertexBuffer *vb); // @} /// \name Vertex program interface // @{ bool isVertexProgramSupported () const; bool isVertexProgramEmulated () const; bool activeVertexProgram (CVertexProgram *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); void setConstant (uint indexStart, const NLMISC::CVectorD& value); void setConstant (uint index, uint num, const float *src); void setConstant (uint index, uint num, const double *src); void setConstantMatrix (uint index, IDriver::TMatrix matrix, IDriver::TTransform transform); void setConstantFog (uint index); void enableVertexProgramDoubleSidedColor(bool doubleSided); bool supportVertexProgramDoubleSidedColor() const; virtual bool supportMADOperator() const ; // @} /// \name Vertex program implementation // @{ bool activeNVVertexProgram (CVertexProgram *program); bool activeARBVertexProgram (CVertexProgram *program); bool activeEXTVertexShader (CVertexProgram *program); //@} /// \fallback for material shaders // @{ /// test whether the given shader is supported, and gives back a supported shader CMaterial::TShader getSupportedShader(CMaterial::TShader shader); // @} bool isVertexProgramEnabled () const { // Don't use glIsEnabled, too slow. return _VertexProgramEnabled; } // Track state of activeVertexProgram() bool _VertexProgramEnabled; // Say if last setupGlArrays() was a VertexProgram setup. bool _LastSetupGLArrayVertexProgram; // The last vertex program that was setupped NLMISC::CRefPtr _LastSetuppedVP; bool _ForceDXTCCompression; /// Divisor for textureResize (power). uint _ForceTextureResizePower; // enforcement of native fragment program check bool _ForceNativeFragmentPrograms; // user texture matrix NLMISC::CMatrix _UserTexMat[IDRV_MAT_MAXTEXTURES]; uint _UserTexMatEnabled; // bitm ask for user texture coords //NLMISC::CMatrix _UserTexMat[IDRV_MAT_MAXTEXTURES]; // Static const static const uint NumCoordinatesType[CVertexBuffer::NumType]; static const uint GLType[CVertexBuffer::NumType]; static const uint GLVertexAttribIndex[CVertexBuffer::NumValue]; static const bool GLTypeIsIntegral[CVertexBuffer::NumType]; static const uint GLMatrix[IDriver::NumMatrix]; static const uint GLTransform[IDriver::NumTransform]; /// \name Caustics shaders // @{ NLMISC::CSmartPtr _CausticCubeMap; // a cube map used for the rendering of caustics static void initCausticCubeMap(); // @} /// Same as getNbTextureStages(), but faster because inline, and not virtual!! uint inlGetNumTextStages() const { return _Extensions.NbTextureStages; } NLMISC::CRGBA _CurrentBlendConstantColor; /// \name EXTVertexShader specifics. // @{ // Variants offset used for : // Secondary color // Fog Coords // Skin Weight // Palette Skin // This mean that they must have 4 components public: enum EEVSVariants { EVSSecondaryColorVariant = 0, EVSFogCoordsVariant = 1, EVSSkinWeightVariant = 2, EVSPaletteSkinVariant = 3, EVSNumVariants }; private: // Handle for standard gl arrays GLuint _EVSPositionHandle; GLuint _EVSNormalHandle; GLuint _EVSColorHandle; GLuint _EVSTexHandle[8]; // Handle of the first constant c[0]. In vertex program we have 96 constant c[0] .. c[95] GLuint _EVSConstantHandle; // number of constant static const uint _EVSNumConstant; // bool setupEXTVertexShader(const CVPParser::TProgram &program, GLuint id, uint variants[EVSNumVariants], uint16 &usedInputRegisters); bool setupARBVertexProgram (const CVPParser::TProgram &parsedProgram, GLuint id, bool &specularWritten); // // @} // init EMBM settings (set each stage to modify the next) void initEMBM(); // Monitor color parameters backup #ifdef WIN32 bool _NeedToRestaureGammaRamp; uint16 _GammaRampBackuped[3*256]; #endif /// \fragment shaders // @{ GLuint ATIWaterShaderHandleNoDiffuseMap; // water support on R200 GLuint ATIWaterShaderHandle; // water support on R200 GLuint ATICloudShaderHandle; // cloud support for R200 and more GLuint ARBWaterShader[4]; // water support on R300, NV30 & the like void initFragmentShaders(); void deleteFragmentShaders(); void deleteARBFragmentPrograms(); void setupWaterPassR200(const CMaterial &mat); void setupWaterPassARB(const CMaterial &mat); void setupWaterPassNV20(const CMaterial &mat); // @} bool _PolygonSmooth; // driver version for ATI hardware (0 if unknown) uint _ATIDriverVersion; bool _ATIFogRangeFixed; void retrieveATIDriverVersion(); /// \Render to texture // @{ CSmartPtr _TextureTarget; uint32 _TextureTargetLevel; uint32 _TextureTargetX; uint32 _TextureTargetY; uint32 _TextureTargetWidth; uint32 _TextureTargetHeight; bool _TextureTargetUpload; uint _TextureTargetCubeFace; // @} // misc public: static GLenum NLCubeFaceToGLCubeFace[6]; static CMaterial::CTexEnv _TexEnvReplace; // occlusion query TOcclusionQueryList _OcclusionQueryList; COcclusionQueryGL *_CurrentOcclusionQuery; protected: // is the window active , bool _WndActive; uint64 _SwapBufferCounter; public: void incrementResetCounter() { ++_ResetCounter; } bool isWndActive() const { return _WndActive; } const IVertexBufferHardGL *getCurrentVertexBufferHard() const { return _CurrentVertexBufferHard; } // For debug : dump list of mapped buffers #ifdef NL_DEBUG void dumpMappedBuffers(); #endif emptyProc ExitFunc; // tmp for debug void checkTextureOn() const; private: /** Bind a texture at stage 0 for the good texture mode(2d or cube) * Parameters / part of the texture are ready to be changed in the gl after that * _CurrentTexture & _CurrentTextureInfoGL are not modified ! */ inline void bindTextureWithMode(ITexture &tex); /** Force to set clamp & wrap mode for the given texture * Setup is done for texture currently bind to the gl, so calling bindTextureWithMode is necessary */ inline void setupTextureBasicParameters(ITexture &tex); }; // *************************************************************************** class CVertexProgamDrvInfosGL : public IVertexProgramDrvInfos { public: // The GL Id. GLuint ID; // ARB_vertex_program specific -> must know if specular part is written bool SpecularWritten; /** EXTVertexShader specific * handle of allocated variants */ GLuint Variants[CDriverGL::EVSNumVariants]; /** EXTVertexShader specific * Used input registers. * This allow to activate only the gl arrays that are needed by a given shader. */ uint16 UsedVertexComponents; // The gl id is auto created here. CVertexProgamDrvInfosGL (CDriverGL *drv, ItVtxPrgDrvInfoPtrList it); }; #ifdef NL_OS_MAC // Specific mac functions extern bool getMacModes(std::vector &modes); #endif } // NL3D #endif // NL_DRIVER_OPENGL_H