/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2010-2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ /* OpenGL implementation of NewGfx */ #if !defined(INC_StdGL) && !defined(USE_CONSOLE) #define INC_StdGL #ifdef _WIN32 #include "platform/C4windowswrapper.h" #endif #include #ifdef USE_COCOA #import "ObjectiveCAssociated.h" #endif #include "graphics/C4Draw.h" #include "graphics/C4Shader.h" class C4Window; class C4DrawGLError: public std::exception { public: C4DrawGLError(const StdStrBuf& buf): Buf(buf) {} virtual ~C4DrawGLError() throw() {} virtual const char* what() const throw() { return Buf.getData(); } private: StdCopyStrBuf Buf; }; // Uniform data we give the sprite shader (constants from its viewpoint) enum C4SS_Uniforms { C4SSU_ProjectionMatrix, // 4x4 C4SSU_ModelViewMatrix, // 4x4 C4SSU_NormalMatrix, // 3x3, transpose-inverse of modelview matrix C4SSU_ClrMod, // always C4SSU_Gamma, // always C4SSU_BaseTex, // C4SSC_BASE C4SSU_OverlayTex, // C4SSC_OVERLAY C4SSU_OverlayClr, // C4SSC_OVERLAY C4SSU_LightTex, // C4SSC_LIGHT C4SSU_LightTransform, // C4SSC_LIGHT C4SSU_NormalTex, // C4SSC_LIGHT | C4SSC_NORMAL C4SSU_AmbientTex, // C4SSC_LIGHT C4SSU_AmbientTransform, // C4SSC_LIGHT C4SSU_AmbientBrightness, // C4SSC_LIGHT C4SSU_MaterialAmbient, // for meshes C4SSU_MaterialDiffuse, // for meshes C4SSU_MaterialSpecular, // for meshes C4SSU_MaterialEmission, // for meshes C4SSU_MaterialShininess, // for meshes C4SSU_Bones, // for meshes C4SSU_CullMode, // for meshes C4SSU_FrameCounter, // for custom shaders C4SSU_Count }; // Attribute data for sprites and meshes enum C4SS_Attributes { C4SSA_Position, // 2d for sprites, 3d for meshes C4SSA_Normal, // meshes only C4SSA_TexCoord, // 2d C4SSA_Color, // sprites only, 4d C4SSA_BoneIndices0, C4SSA_BoneIndices1, C4SSA_BoneWeights0, C4SSA_BoneWeights1, C4SSA_Count }; // one OpenGL context class CStdGLCtx #ifdef USE_COCOA : public ObjectiveCAssociated #endif { public: CStdGLCtx(); // ctor ~CStdGLCtx() { Clear(); } // dtor void Clear(bool multisample_change = false); // clear objects #ifdef USE_WGL std::vector EnumerateMultiSamples() const; #endif bool Init(C4Window * pWindow, C4AbstractApp *pApp); bool Select(bool verbose = false); // select this context void Deselect(); // select this context bool PageFlip(); // present scene protected: void SelectCommon(); // this handles are declared as pointers to structs C4Window * pWindow; // window to draw in #ifdef USE_WGL HDC hDC; // device context handle #elif defined(USE_GTK) /*GLXContext*/void * ctx; #elif defined(USE_SDL_MAINLOOP) void * ctx; #endif // Global list of all OpenGL contexts in use static std::list contexts; std::list::iterator this_context; // VAOs available on this context std::vector hVAOs; // VAOs to be deleted the next time this context is being made current. std::vector VAOsToBeDeleted; friend class CStdGL; friend class C4Surface; }; // OpenGL encapsulation class CStdGL : public C4Draw { public: CStdGL(); ~CStdGL(); protected: int iPixelFormat; // used pixel format GLenum sfcFmt; // texture surface format CStdGLCtx * pMainCtx; // main GL context CStdGLCtx *pCurrCtx; // current context (owned if fullscreen) // texture for smooth lines GLuint lines_tex; // The orthographic projection matrix StdProjectionMatrix ProjectionMatrix; // programs for drawing points, lines, quads // Sprite shaders -- there is a variety of shaders to avoid // conditionals in the GLSL code. C4Shader SpriteShader; C4Shader SpriteShaderMod2; C4Shader SpriteShaderBase; C4Shader SpriteShaderBaseMod2; C4Shader SpriteShaderBaseOverlay; C4Shader SpriteShaderBaseOverlayMod2; C4Shader SpriteShaderLight; C4Shader SpriteShaderLightMod2; C4Shader SpriteShaderLightBase; C4Shader SpriteShaderLightBaseMod2; C4Shader SpriteShaderLightBaseOverlay; C4Shader SpriteShaderLightBaseOverlayMod2; C4Shader SpriteShaderLightBaseNormal; C4Shader SpriteShaderLightBaseNormalMod2; C4Shader SpriteShaderLightBaseNormalOverlay; C4Shader SpriteShaderLightBaseNormalOverlayMod2; // Generic VBOs for rendering arbitrary points, lines and // triangles, used by PerformMultiBlt. Use more than one VBO, so that // two PerformMultiBlt calls in quick succession can use two different // buffers. Otherwise, the second call would need to wait until the // rendering pipeline has actually drained the buffer. Each buffer // starts with a fixed size. If more than this many vertices need to // be rendered (can happen e.g. for PXS), then the buffer is resized. static const unsigned int N_GENERIC_VBOS = 16; static const unsigned int GENERIC_VBO_SIZE = 3 * 64; // vertices GLuint GenericVBOs[N_GENERIC_VBOS]; unsigned int GenericVBOSizes[N_GENERIC_VBOS]; unsigned int CurrentVBO; // We need twice as much VAOs, since the sprite rendering routines work // both with and without textures (in which case we either need texture // coordinates or not). unsigned int GenericVAOs[N_GENERIC_VBOS * 2]; // VAO IDs currently in use. std::set VAOIDs; std::set::iterator NextVAOID; public: // Create a new (unique) VAO ID. A VAO ID is a number that identifies // a certain VAO across all OpenGL contexts. This indirection is needed // because, unlike most other GL state, VAOs are not shared between // OpenGL contexts. unsigned int GenVAOID(); // Free the given VAO ID, i.e. it can be re-used for new VAOs. This causes // the VAO associated with this ID to be deleted in all OpenGL contexts. void FreeVAOID(unsigned int vaoid); // Return a VAO with the given vao ID in the "vao" output variable. // If the function returns false, the VAO was newly created, otherwise // an existing VAO is returned. bool GetVAO(unsigned int vaoid, GLuint& vao); // General void Clear(); void Default(); virtual bool OnResolutionChanged(unsigned int iXRes, unsigned int iYRes); // reinit clipper for new resolution // Clipper bool UpdateClipper(); // set current clipper to render target const StdProjectionMatrix& GetProjectionMatrix() const { return ProjectionMatrix; } virtual bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat); // Surface virtual bool PrepareRendering(C4Surface * sfcToSurface); // check if/make rendering possible to given surface virtual bool PrepareSpriteShader(C4Shader& shader, const char* name, int ssc, C4GroupSet* pGroups, const char* const* additionalDefines, const char* const* additionalSlices); virtual CStdGLCtx *CreateContext(C4Window * pWindow, C4AbstractApp *pApp); // Blit void SetupMultiBlt(C4ShaderCall& call, const C4BltTransform* pTransform, GLuint baseTex, GLuint overlayTex, GLuint normalTex, DWORD dwOverlayModClr, StdProjectionMatrix* out_modelview); virtual void PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, DWORD dwPlayerColor, C4BltTransform* pTransform); void FillBG(DWORD dwClr=0); // Drawing virtual void PerformMultiPix(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, C4ShaderCall* shader_call); virtual void PerformMultiLines(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, float width, C4ShaderCall* shader_call); virtual void PerformMultiTris(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, const C4BltTransform* pTransform, C4TexRef* pTex, C4TexRef* pOverlay, C4TexRef* pNormal, DWORD dwOverlayClrMod, C4ShaderCall* shader_call); void PerformMultiBlt(C4Surface* sfcTarget, DrawOperation op, const C4BltVertex* vertices, unsigned int n_vertices, bool has_tex, C4ShaderCall* shader_call); // device objects bool RestoreDeviceObjects(); // restore device dependent objects bool InvalidateDeviceObjects(); // free device dependent objects bool DeviceReady() { return !!pMainCtx; } bool InitShaders(C4GroupSet* pGroups); // load shaders from given group C4Shader* GetSpriteShader(int ssc); C4Shader* GetSpriteShader(bool haveBase, bool haveOverlay, bool haveNormal); struct { bool LowMaxVertexUniformCount; } Workarounds; void ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char * label); protected: bool CheckGLError(const char *szAtOp); const char* GLErrorString(GLenum code); virtual bool Error(const char *szMsg); friend class C4Surface; friend class C4TexRef; friend class C4Pattern; friend class CStdGLCtx; friend class C4StartupOptionsDlg; friend class C4FullScreen; friend class C4Window; friend class C4ShaderCall; friend class C4FoWRegion; }; // Global access pointer extern CStdGL *pGL; #endif // INC_StdGL