1 /* 2 * OpenClonk, http://www.openclonk.org 3 * 4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ 5 * Copyright (c) 2010-2016, The OpenClonk Team and contributors 6 * 7 * Distributed under the terms of the ISC license; see accompanying file 8 * "COPYING" for details. 9 * 10 * "Clonk" is a registered trademark of Matthes Bender, used with permission. 11 * See accompanying file "TRADEMARK" for details. 12 * 13 * To redistribute this file separately, substitute the full license texts 14 * for the above references. 15 */ 16 17 /* OpenGL implementation of NewGfx */ 18 19 #include "C4ForbidLibraryCompilation.h" 20 #if !defined(INC_StdGL) && !defined(USE_CONSOLE) 21 #define INC_StdGL 22 23 #ifdef _WIN32 24 #include "platform/C4windowswrapper.h" 25 #endif 26 27 #include <GL/glew.h> 28 29 #ifdef USE_COCOA 30 #import "platform/ObjectiveCAssociated.h" 31 #endif 32 #include "graphics/C4Draw.h" 33 #include "graphics/C4Shader.h" 34 35 class C4Window; 36 37 class C4DrawGLError: public std::exception 38 { 39 public: C4DrawGLError(const StdStrBuf & buf)40 C4DrawGLError(const StdStrBuf& buf): Buf(buf) {} 41 ~C4DrawGLError() throw() override = default; 42 what()43 const char* what() const throw() override { return Buf.getData(); } 44 45 private: 46 StdCopyStrBuf Buf; 47 }; 48 49 // Uniform data we give the sprite shader (constants from its viewpoint) 50 enum C4SS_Uniforms 51 { 52 C4SSU_ProjectionMatrix, // 4x4 53 C4SSU_ModelViewMatrix, // 4x4 54 C4SSU_NormalMatrix, // 3x3, transpose-inverse of modelview matrix 55 56 C4SSU_ClrMod, // always 57 C4SSU_Gamma, // always 58 59 C4SSU_BaseTex, // C4SSC_BASE 60 C4SSU_OverlayTex, // C4SSC_OVERLAY 61 C4SSU_OverlayClr, // C4SSC_OVERLAY 62 63 C4SSU_LightTex, // C4SSC_LIGHT 64 C4SSU_LightTransform, // C4SSC_LIGHT 65 C4SSU_NormalTex, // C4SSC_LIGHT | C4SSC_NORMAL 66 67 C4SSU_AmbientTex, // C4SSC_LIGHT 68 C4SSU_AmbientTransform, // C4SSC_LIGHT 69 C4SSU_AmbientBrightness, // C4SSC_LIGHT 70 71 C4SSU_MaterialAmbient, // for meshes 72 C4SSU_MaterialDiffuse, // for meshes 73 C4SSU_MaterialSpecular, // for meshes 74 C4SSU_MaterialEmission, // for meshes 75 C4SSU_MaterialShininess, // for meshes 76 77 C4SSU_Bones, // for meshes 78 C4SSU_CullMode, // for meshes 79 80 C4SSU_FrameCounter, // for custom shaders 81 82 C4SSU_Count 83 }; 84 85 // Attribute data for sprites and meshes 86 enum C4SS_Attributes 87 { 88 C4SSA_Position, // 2d for sprites, 3d for meshes 89 C4SSA_Normal, // meshes only 90 C4SSA_TexCoord, // 2d 91 C4SSA_Color, // sprites only, 4d 92 93 C4SSA_BoneIndices0, 94 C4SSA_BoneIndices1, 95 96 C4SSA_BoneWeights0, 97 C4SSA_BoneWeights1, 98 99 C4SSA_Count 100 }; 101 102 // one OpenGL context 103 class CStdGLCtx 104 #ifdef USE_COCOA 105 : public ObjectiveCAssociated 106 #endif 107 { 108 public: 109 CStdGLCtx(); // ctor ~CStdGLCtx()110 virtual ~CStdGLCtx() { Clear(); } // dtor 111 112 virtual void Clear(bool multisample_change = false); // clear objects 113 114 #ifdef USE_WGL 115 std::vector<int> EnumerateMultiSamples() const; 116 #endif 117 virtual bool Init(C4Window * pWindow, C4AbstractApp *pApp); 118 119 virtual bool Select(bool verbose = false); // select this context 120 virtual void Deselect(); // select this context 121 122 virtual bool PageFlip(); // present scene 123 124 protected: 125 void SelectCommon(); 126 // this handles are declared as pointers to structs 127 C4Window * pWindow{nullptr}; // window to draw in 128 #ifdef USE_WGL 129 HDC hDC{nullptr}; // device context handle 130 #elif defined(USE_SDL_MAINLOOP) 131 void * ctx; 132 #endif 133 134 // Global list of all OpenGL contexts in use 135 static std::list<CStdGLCtx*> contexts; 136 std::list<CStdGLCtx*>::iterator this_context; 137 138 // VAOs available on this context 139 std::vector<GLuint> hVAOs; 140 // VAOs to be deleted the next time this context is being made current. 141 std::vector<unsigned int> VAOsToBeDeleted; 142 143 friend class CStdGL; 144 friend class C4Surface; 145 }; 146 147 #ifdef WITH_QT_EDITOR 148 // OpenGL context with Qt as backend. Implemented as subclass to allow co-existance with a different backend for fullscreen. 149 class CStdGLCtxQt : public CStdGLCtx 150 { 151 public: 152 CStdGLCtxQt(); ~CStdGLCtxQt()153 ~CStdGLCtxQt() override { Clear(); } 154 155 void Clear(bool multisample_change = false) override; // clear objects 156 bool Init(C4Window * pWindow, C4AbstractApp *pApp) override; 157 bool Select(bool verbose = false) override; // select this context 158 void Deselect() override; // select this context 159 bool PageFlip() override; // present scene 160 161 private: 162 class QOpenGLContext *context = nullptr; 163 class QOffscreenSurface *surface = nullptr; 164 }; 165 #endif 166 167 // OpenGL encapsulation 168 class CStdGL : public C4Draw 169 { 170 public: 171 CStdGL(); 172 ~CStdGL() override; 173 protected: 174 175 int iPixelFormat; // used pixel format 176 177 GLenum sfcFmt; // texture surface format 178 CStdGLCtx * pMainCtx{nullptr}; // main GL context 179 CStdGLCtx *pCurrCtx; // current context (owned if fullscreen) 180 // texture for smooth lines 181 GLuint lines_tex; 182 183 // The orthographic projection matrix 184 StdProjectionMatrix ProjectionMatrix; 185 186 // programs for drawing points, lines, quads 187 188 // Sprite shaders -- there is a variety of shaders to avoid 189 // conditionals in the GLSL code. 190 C4Shader SpriteShader; 191 C4Shader SpriteShaderMod2; 192 C4Shader SpriteShaderBase; 193 C4Shader SpriteShaderBaseMod2; 194 C4Shader SpriteShaderBaseOverlay; 195 C4Shader SpriteShaderBaseOverlayMod2; 196 197 C4Shader SpriteShaderLight; 198 C4Shader SpriteShaderLightMod2; 199 C4Shader SpriteShaderLightBase; 200 C4Shader SpriteShaderLightBaseMod2; 201 C4Shader SpriteShaderLightBaseOverlay; 202 C4Shader SpriteShaderLightBaseOverlayMod2; 203 C4Shader SpriteShaderLightBaseNormal; 204 C4Shader SpriteShaderLightBaseNormalMod2; 205 C4Shader SpriteShaderLightBaseNormalOverlay; 206 C4Shader SpriteShaderLightBaseNormalOverlayMod2; 207 208 // Generic VBOs for rendering arbitrary points, lines and 209 // triangles, used by PerformMultiBlt. Use more than one VBO, so that 210 // two PerformMultiBlt calls in quick succession can use two different 211 // buffers. Otherwise, the second call would need to wait until the 212 // rendering pipeline has actually drained the buffer. Each buffer 213 // starts with a fixed size. If more than this many vertices need to 214 // be rendered (can happen e.g. for PXS), then the buffer is resized. 215 static const unsigned int N_GENERIC_VBOS = 16; 216 static const unsigned int GENERIC_VBO_SIZE = 3 * 64; // vertices 217 GLuint GenericVBOs[N_GENERIC_VBOS]; 218 unsigned int GenericVBOSizes[N_GENERIC_VBOS]; 219 unsigned int CurrentVBO{0}; 220 // We need twice as much VAOs, since the sprite rendering routines work 221 // both with and without textures (in which case we either need texture 222 // coordinates or not). 223 unsigned int GenericVAOs[N_GENERIC_VBOS * 2]; 224 225 // VAO IDs currently in use. 226 std::set<unsigned int> VAOIDs; 227 std::set<unsigned int>::iterator NextVAOID; 228 229 public: 230 // Create a new (unique) VAO ID. A VAO ID is a number that identifies 231 // a certain VAO across all OpenGL contexts. This indirection is needed 232 // because, unlike most other GL state, VAOs are not shared between 233 // OpenGL contexts. 234 unsigned int GenVAOID(); 235 236 // Free the given VAO ID, i.e. it can be re-used for new VAOs. This causes 237 // the VAO associated with this ID to be deleted in all OpenGL contexts. 238 void FreeVAOID(unsigned int vaoid); 239 240 // Return a VAO with the given vao ID in the "vao" output variable. 241 // If the function returns false, the VAO was newly created, otherwise 242 // an existing VAO is returned. 243 bool GetVAO(unsigned int vaoid, GLuint& vao); 244 245 // General 246 void Clear() override; 247 void Default() override ; 248 bool OnResolutionChanged(unsigned int iXRes, unsigned int iYRes) override; // reinit clipper for new resolution 249 // Clipper 250 bool UpdateClipper() override; // set current clipper to render target GetProjectionMatrix()251 const StdProjectionMatrix& GetProjectionMatrix() const { return ProjectionMatrix; } 252 bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat) override; 253 // Surface 254 bool PrepareRendering(C4Surface * sfcToSurface) override; // check if/make rendering possible to given surface 255 bool PrepareSpriteShader(C4Shader& shader, const char* name, int ssc, C4GroupSet* pGroups, const char* const* additionalDefines, const char* const* additionalSlices) override; 256 bool EnsureMainContextSelected() override; 257 258 CStdGLCtx *CreateContext(C4Window * pWindow, C4AbstractApp *pApp) override; 259 // Blit 260 void SetupMultiBlt(C4ShaderCall& call, const C4BltTransform* pTransform, GLuint baseTex, GLuint overlayTex, GLuint normalTex, DWORD dwOverlayModClr, StdProjectionMatrix* out_modelview); 261 void PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, DWORD dwPlayerColor, C4BltTransform* pTransform) override; 262 void FillBG(DWORD dwClr=0) override; 263 // Drawing 264 void PerformMultiPix(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, C4ShaderCall* shader_call) override; 265 void PerformMultiLines(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, float width, C4ShaderCall* shader_call) override; 266 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) override; 267 void PerformMultiBlt(C4Surface* sfcTarget, DrawOperation op, const C4BltVertex* vertices, unsigned int n_vertices, bool has_tex, C4ShaderCall* shader_call); 268 // device objects 269 bool RestoreDeviceObjects() override; // restore device dependent objects 270 bool InvalidateDeviceObjects() override; // free device dependent objects DeviceReady()271 bool DeviceReady() override { return !!pMainCtx; } 272 bool InitShaders(C4GroupSet* pGroups); // load shaders from given group 273 C4Shader* GetSpriteShader(int ssc); 274 C4Shader* GetSpriteShader(bool haveBase, bool haveOverlay, bool haveNormal); 275 276 struct 277 { 278 bool LowMaxVertexUniformCount; 279 bool ForceSoftwareTransform; 280 } Workarounds; 281 void ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char * label); 282 283 protected: 284 bool CheckGLError(const char *szAtOp); 285 const char* GLErrorString(GLenum code); 286 bool Error(const char *szMsg) override; 287 288 friend class C4Surface; 289 friend class C4TexRef; 290 friend class C4Pattern; 291 friend class CStdGLCtx; 292 friend class C4StartupOptionsDlg; 293 friend class C4FullScreen; 294 friend class C4Window; 295 friend class C4ShaderCall; 296 friend class C4FoWRegion; 297 #ifdef WITH_QT_EDITOR 298 friend class CStdGLCtxQt; 299 #endif 300 }; 301 302 // Global access pointer 303 extern CStdGL *pGL; 304 305 #endif // INC_StdGL 306