1 // rendergl.cpp: core opengl rendering stuff
2 
3 #include "engine.h"
4 
5 bool hasVAO = false, hasTR = false, hasTSW = false, hasPBO = false, hasFBO = false, hasAFBO = false, hasDS = false, hasTF = false, hasCBF = false, hasS3TC = false, hasFXT1 = false, hasLATC = false, hasRGTC = false, hasAF = false, hasFBB = false, hasFBMS = false, hasTMS = false, hasMSS = false, hasFBMSBS = false, hasUBO = false, hasMBR = false, hasDB2 = false, hasDBB = false, hasTG = false, hasTQ = false, hasPF = false, hasTRG = false, hasTI = false, hasHFV = false, hasHFP = false, hasDBT = false, hasDC = false, hasDBGO = false, hasEGPU4 = false, hasGPU4 = false, hasGPU5 = false, hasBFE = false, hasEAL = false, hasCR = false, hasOQ2 = false, hasES3 = false, hasCB = false, hasCI = false;
6 bool mesa = false, intel = false, amd = false, nvidia = false;
7 int hasstencil = 0;
8 
9 VAR(IDF_READONLY, glversion, 1, 0, 0);
10 VAR(IDF_READONLY, glslversion, 1, 0, 0);
11 VAR(IDF_READONLY, glcompat, 1, 0, 0);
12 
13 // GL_EXT_timer_query
14 PFNGLGETQUERYOBJECTI64VEXTPROC glGetQueryObjecti64v_  = NULL;
15 PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v_ = NULL;
16 
17 // GL_EXT_framebuffer_object
18 PFNGLBINDRENDERBUFFERPROC           glBindRenderbuffer_           = NULL;
19 PFNGLDELETERENDERBUFFERSPROC        glDeleteRenderbuffers_        = NULL;
20 PFNGLGENFRAMEBUFFERSPROC            glGenRenderbuffers_           = NULL;
21 PFNGLRENDERBUFFERSTORAGEPROC        glRenderbufferStorage_        = NULL;
22 PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv_ = NULL;
23 PFNGLCHECKFRAMEBUFFERSTATUSPROC     glCheckFramebufferStatus_     = NULL;
24 PFNGLBINDFRAMEBUFFERPROC            glBindFramebuffer_            = NULL;
25 PFNGLDELETEFRAMEBUFFERSPROC         glDeleteFramebuffers_         = NULL;
26 PFNGLGENFRAMEBUFFERSPROC            glGenFramebuffers_            = NULL;
27 PFNGLFRAMEBUFFERTEXTURE1DPROC       glFramebufferTexture1D_       = NULL;
28 PFNGLFRAMEBUFFERTEXTURE2DPROC       glFramebufferTexture2D_       = NULL;
29 PFNGLFRAMEBUFFERTEXTURE3DPROC       glFramebufferTexture3D_       = NULL;
30 PFNGLFRAMEBUFFERRENDERBUFFERPROC    glFramebufferRenderbuffer_    = NULL;
31 PFNGLGENERATEMIPMAPPROC             glGenerateMipmap_             = NULL;
32 
33 // GL_EXT_framebuffer_blit
34 PFNGLBLITFRAMEBUFFERPROC         glBlitFramebuffer_         = NULL;
35 
36 // GL_EXT_framebuffer_multisample
37 PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample_ = NULL;
38 
39 // GL_ARB_texture_multisample
40 PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample_ = NULL;
41 PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample_ = NULL;
42 PFNGLGETMULTISAMPLEFVPROC      glGetMultisamplefv_      = NULL;
43 PFNGLSAMPLEMASKIPROC           glSampleMaski_           = NULL;
44 
45 // GL_ARB_sample_shading
46 PFNGLMINSAMPLESHADINGPROC glMinSampleShading_ = NULL;
47 
48 // GL_ARB_draw_buffers_blend
49 PFNGLBLENDEQUATIONIPROC         glBlendEquationi_         = NULL;
50 PFNGLBLENDEQUATIONSEPARATEIPROC glBlendEquationSeparatei_ = NULL;
51 PFNGLBLENDFUNCIPROC             glBlendFunci_             = NULL;
52 PFNGLBLENDFUNCSEPARATEIPROC     glBlendFuncSeparatei_     = NULL;
53 
54 // OpenGL 1.3
55 #ifdef WIN32
56 PFNGLACTIVETEXTUREPROC    glActiveTexture_    = NULL;
57 
58 PFNGLBLENDEQUATIONEXTPROC glBlendEquation_ = NULL;
59 PFNGLBLENDCOLOREXTPROC    glBlendColor_    = NULL;
60 
61 PFNGLTEXIMAGE3DPROC        glTexImage3D_        = NULL;
62 PFNGLTEXSUBIMAGE3DPROC     glTexSubImage3D_     = NULL;
63 PFNGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D_ = NULL;
64 
65 PFNGLCOMPRESSEDTEXIMAGE3DPROC    glCompressedTexImage3D_    = NULL;
66 PFNGLCOMPRESSEDTEXIMAGE2DPROC    glCompressedTexImage2D_    = NULL;
67 PFNGLCOMPRESSEDTEXIMAGE1DPROC    glCompressedTexImage1D_    = NULL;
68 PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D_ = NULL;
69 PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D_ = NULL;
70 PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D_ = NULL;
71 PFNGLGETCOMPRESSEDTEXIMAGEPROC   glGetCompressedTexImage_   = NULL;
72 
73 PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements_ = NULL;
74 #endif
75 
76 // OpenGL 2.0
77 #ifndef __APPLE__
78 PFNGLMULTIDRAWARRAYSPROC   glMultiDrawArrays_   = NULL;
79 PFNGLMULTIDRAWELEMENTSPROC glMultiDrawElements_ = NULL;
80 
81 PFNGLBLENDFUNCSEPARATEPROC     glBlendFuncSeparate_     = NULL;
82 PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate_ = NULL;
83 PFNGLSTENCILOPSEPARATEPROC     glStencilOpSeparate_     = NULL;
84 PFNGLSTENCILFUNCSEPARATEPROC   glStencilFuncSeparate_   = NULL;
85 PFNGLSTENCILMASKSEPARATEPROC   glStencilMaskSeparate_   = NULL;
86 
87 PFNGLGENBUFFERSPROC       glGenBuffers_       = NULL;
88 PFNGLBINDBUFFERPROC       glBindBuffer_       = NULL;
89 PFNGLMAPBUFFERPROC        glMapBuffer_        = NULL;
90 PFNGLUNMAPBUFFERPROC      glUnmapBuffer_      = NULL;
91 PFNGLBUFFERDATAPROC       glBufferData_       = NULL;
92 PFNGLBUFFERSUBDATAPROC    glBufferSubData_    = NULL;
93 PFNGLDELETEBUFFERSPROC    glDeleteBuffers_    = NULL;
94 PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData_ = NULL;
95 
96 PFNGLGENQUERIESPROC        glGenQueries_        = NULL;
97 PFNGLDELETEQUERIESPROC     glDeleteQueries_     = NULL;
98 PFNGLBEGINQUERYPROC        glBeginQuery_        = NULL;
99 PFNGLENDQUERYPROC          glEndQuery_          = NULL;
100 PFNGLGETQUERYIVPROC        glGetQueryiv_        = NULL;
101 PFNGLGETQUERYOBJECTIVPROC  glGetQueryObjectiv_  = NULL;
102 PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv_ = NULL;
103 
104 PFNGLCREATEPROGRAMPROC            glCreateProgram_            = NULL;
105 PFNGLDELETEPROGRAMPROC            glDeleteProgram_            = NULL;
106 PFNGLUSEPROGRAMPROC               glUseProgram_               = NULL;
107 PFNGLCREATESHADERPROC             glCreateShader_             = NULL;
108 PFNGLDELETESHADERPROC             glDeleteShader_             = NULL;
109 PFNGLSHADERSOURCEPROC             glShaderSource_             = NULL;
110 PFNGLCOMPILESHADERPROC            glCompileShader_            = NULL;
111 PFNGLGETSHADERIVPROC              glGetShaderiv_              = NULL;
112 PFNGLGETPROGRAMIVPROC             glGetProgramiv_             = NULL;
113 PFNGLATTACHSHADERPROC             glAttachShader_             = NULL;
114 PFNGLGETPROGRAMINFOLOGPROC        glGetProgramInfoLog_        = NULL;
115 PFNGLGETSHADERINFOLOGPROC         glGetShaderInfoLog_         = NULL;
116 PFNGLLINKPROGRAMPROC              glLinkProgram_              = NULL;
117 PFNGLGETUNIFORMLOCATIONPROC       glGetUniformLocation_       = NULL;
118 PFNGLUNIFORM1FPROC                glUniform1f_                = NULL;
119 PFNGLUNIFORM2FPROC                glUniform2f_                = NULL;
120 PFNGLUNIFORM3FPROC                glUniform3f_                = NULL;
121 PFNGLUNIFORM4FPROC                glUniform4f_                = NULL;
122 PFNGLUNIFORM1FVPROC               glUniform1fv_               = NULL;
123 PFNGLUNIFORM2FVPROC               glUniform2fv_               = NULL;
124 PFNGLUNIFORM3FVPROC               glUniform3fv_               = NULL;
125 PFNGLUNIFORM4FVPROC               glUniform4fv_               = NULL;
126 PFNGLUNIFORM1IPROC                glUniform1i_                = NULL;
127 PFNGLUNIFORM2IPROC                glUniform2i_                = NULL;
128 PFNGLUNIFORM3IPROC                glUniform3i_                = NULL;
129 PFNGLUNIFORM4IPROC                glUniform4i_                = NULL;
130 PFNGLUNIFORM1IVPROC               glUniform1iv_               = NULL;
131 PFNGLUNIFORM2IVPROC               glUniform2iv_               = NULL;
132 PFNGLUNIFORM3IVPROC               glUniform3iv_               = NULL;
133 PFNGLUNIFORM4IVPROC               glUniform4iv_               = NULL;
134 PFNGLUNIFORMMATRIX2FVPROC         glUniformMatrix2fv_         = NULL;
135 PFNGLUNIFORMMATRIX3FVPROC         glUniformMatrix3fv_         = NULL;
136 PFNGLUNIFORMMATRIX4FVPROC         glUniformMatrix4fv_         = NULL;
137 PFNGLBINDATTRIBLOCATIONPROC       glBindAttribLocation_       = NULL;
138 PFNGLGETACTIVEUNIFORMPROC         glGetActiveUniform_         = NULL;
139 PFNGLENABLEVERTEXATTRIBARRAYPROC  glEnableVertexAttribArray_  = NULL;
140 PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray_ = NULL;
141 
142 PFNGLVERTEXATTRIB1FPROC           glVertexAttrib1f_           = NULL;
143 PFNGLVERTEXATTRIB1FVPROC          glVertexAttrib1fv_          = NULL;
144 PFNGLVERTEXATTRIB1SPROC           glVertexAttrib1s_           = NULL;
145 PFNGLVERTEXATTRIB1SVPROC          glVertexAttrib1sv_          = NULL;
146 PFNGLVERTEXATTRIB2FPROC           glVertexAttrib2f_           = NULL;
147 PFNGLVERTEXATTRIB2FVPROC          glVertexAttrib2fv_          = NULL;
148 PFNGLVERTEXATTRIB2SPROC           glVertexAttrib2s_           = NULL;
149 PFNGLVERTEXATTRIB2SVPROC          glVertexAttrib2sv_          = NULL;
150 PFNGLVERTEXATTRIB3FPROC           glVertexAttrib3f_           = NULL;
151 PFNGLVERTEXATTRIB3FVPROC          glVertexAttrib3fv_          = NULL;
152 PFNGLVERTEXATTRIB3SPROC           glVertexAttrib3s_           = NULL;
153 PFNGLVERTEXATTRIB3SVPROC          glVertexAttrib3sv_          = NULL;
154 PFNGLVERTEXATTRIB4FPROC           glVertexAttrib4f_           = NULL;
155 PFNGLVERTEXATTRIB4FVPROC          glVertexAttrib4fv_          = NULL;
156 PFNGLVERTEXATTRIB4SPROC           glVertexAttrib4s_           = NULL;
157 PFNGLVERTEXATTRIB4SVPROC          glVertexAttrib4sv_          = NULL;
158 PFNGLVERTEXATTRIB4BVPROC          glVertexAttrib4bv_          = NULL;
159 PFNGLVERTEXATTRIB4IVPROC          glVertexAttrib4iv_          = NULL;
160 PFNGLVERTEXATTRIB4UBVPROC         glVertexAttrib4ubv_         = NULL;
161 PFNGLVERTEXATTRIB4UIVPROC         glVertexAttrib4uiv_         = NULL;
162 PFNGLVERTEXATTRIB4USVPROC         glVertexAttrib4usv_         = NULL;
163 PFNGLVERTEXATTRIB4NBVPROC         glVertexAttrib4Nbv_         = NULL;
164 PFNGLVERTEXATTRIB4NIVPROC         glVertexAttrib4Niv_         = NULL;
165 PFNGLVERTEXATTRIB4NUBPROC         glVertexAttrib4Nub_         = NULL;
166 PFNGLVERTEXATTRIB4NUBVPROC        glVertexAttrib4Nubv_        = NULL;
167 PFNGLVERTEXATTRIB4NUIVPROC        glVertexAttrib4Nuiv_        = NULL;
168 PFNGLVERTEXATTRIB4NUSVPROC        glVertexAttrib4Nusv_        = NULL;
169 PFNGLVERTEXATTRIBPOINTERPROC      glVertexAttribPointer_      = NULL;
170 
171 PFNGLDRAWBUFFERSPROC glDrawBuffers_ = NULL;
172 #endif
173 
174 // OpenGL 3.0
175 PFNGLGETSTRINGIPROC           glGetStringi_           = NULL;
176 PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation_ = NULL;
177 PFNGLUNIFORM1UIPROC           glUniform1ui_           = NULL;
178 PFNGLUNIFORM2UIPROC           glUniform2ui_           = NULL;
179 PFNGLUNIFORM3UIPROC           glUniform3ui_           = NULL;
180 PFNGLUNIFORM4UIPROC           glUniform4ui_           = NULL;
181 PFNGLUNIFORM1UIVPROC          glUniform1uiv_          = NULL;
182 PFNGLUNIFORM2UIVPROC          glUniform2uiv_          = NULL;
183 PFNGLUNIFORM3UIVPROC          glUniform3uiv_          = NULL;
184 PFNGLUNIFORM4UIVPROC          glUniform4uiv_          = NULL;
185 PFNGLCLEARBUFFERIVPROC        glClearBufferiv_        = NULL;
186 PFNGLCLEARBUFFERUIVPROC       glClearBufferuiv_       = NULL;
187 PFNGLCLEARBUFFERFVPROC        glClearBufferfv_        = NULL;
188 PFNGLCLEARBUFFERFIPROC        glClearBufferfi_        = NULL;
189 
190 // GL_EXT_draw_buffers2
191 PFNGLCOLORMASKIPROC glColorMaski_ = NULL;
192 PFNGLENABLEIPROC    glEnablei_    = NULL;
193 PFNGLDISABLEIPROC   glDisablei_   = NULL;
194 
195 // GL_NV_conditional_render
196 PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender_ = NULL;
197 PFNGLENDCONDITIONALRENDERPROC   glEndConditionalRender_   = NULL;
198 
199 // GL_EXT_texture_integer
200 PFNGLTEXPARAMETERIIVPROC     glTexParameterIiv_     = NULL;
201 PFNGLTEXPARAMETERIUIVPROC    glTexParameterIuiv_    = NULL;
202 PFNGLGETTEXPARAMETERIIVPROC  glGetTexParameterIiv_  = NULL;
203 PFNGLGETTEXPARAMETERIUIVPROC glGetTexParameterIuiv_ = NULL;
204 PFNGLCLEARCOLORIIEXTPROC     glClearColorIi_        = NULL;
205 PFNGLCLEARCOLORIUIEXTPROC    glClearColorIui_       = NULL;
206 
207 // GL_ARB_uniform_buffer_object
208 PFNGLGETUNIFORMINDICESPROC       glGetUniformIndices_       = NULL;
209 PFNGLGETACTIVEUNIFORMSIVPROC     glGetActiveUniformsiv_     = NULL;
210 PFNGLGETUNIFORMBLOCKINDEXPROC    glGetUniformBlockIndex_    = NULL;
211 PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv_ = NULL;
212 PFNGLUNIFORMBLOCKBINDINGPROC     glUniformBlockBinding_     = NULL;
213 PFNGLBINDBUFFERBASEPROC          glBindBufferBase_          = NULL;
214 PFNGLBINDBUFFERRANGEPROC         glBindBufferRange_         = NULL;
215 
216 // GL_ARB_copy_buffer
217 PFNGLCOPYBUFFERSUBDATAPROC glCopyBufferSubData_ = NULL;
218 
219 // GL_EXT_depth_bounds_test
220 PFNGLDEPTHBOUNDSEXTPROC glDepthBounds_ = NULL;
221 
222 // GL_ARB_color_buffer_float
223 PFNGLCLAMPCOLORPROC glClampColor_ = NULL;
224 
225 // GL_ARB_debug_output
226 PFNGLDEBUGMESSAGECONTROLPROC  glDebugMessageControl_  = NULL;
227 PFNGLDEBUGMESSAGEINSERTPROC   glDebugMessageInsert_   = NULL;
228 PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback_ = NULL;
229 PFNGLGETDEBUGMESSAGELOGPROC   glGetDebugMessageLog_   = NULL;
230 
231 // GL_ARB_map_buffer_range
232 PFNGLMAPBUFFERRANGEPROC         glMapBufferRange_         = NULL;
233 PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange_ = NULL;
234 
235 // GL_ARB_vertex_array_object
236 PFNGLBINDVERTEXARRAYPROC    glBindVertexArray_    = NULL;
237 PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays_ = NULL;
238 PFNGLGENVERTEXARRAYSPROC    glGenVertexArrays_    = NULL;
239 PFNGLISVERTEXARRAYPROC      glIsVertexArray_      = NULL;
240 
241 // GL_ARB_blend_func_extended
242 PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glBindFragDataLocationIndexed_ = NULL;
243 
244 // GL_ARB_copy_image
245 PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData_ = NULL;
246 
getprocaddress(const char * name)247 void *getprocaddress(const char *name)
248 {
249     return SDL_GL_GetProcAddress(name);
250 }
251 
252 VAR(0, glerr, 0, 0, 1);
253 
glerror(const char * file,int line,GLenum error)254 void glerror(const char *file, int line, GLenum error)
255 {
256     const char *desc = "unknown";
257     switch(error)
258     {
259     case GL_NO_ERROR: desc = "no error"; break;
260     case GL_INVALID_ENUM: desc = "invalid enum"; break;
261     case GL_INVALID_VALUE: desc = "invalid value"; break;
262     case GL_INVALID_OPERATION: desc = "invalid operation"; break;
263     case GL_STACK_OVERFLOW: desc = "stack overflow"; break;
264     case GL_STACK_UNDERFLOW: desc = "stack underflow"; break;
265     case GL_OUT_OF_MEMORY: desc = "out of memory"; break;
266     }
267     printf("GL error: %s:%d: %s (%x)\n", file, line, desc, error);
268 }
269 
270 VAR(0, amd_pf_bug, 0, 0, 1);
271 VAR(0, amd_eal_bug, 0, 0, 1);
272 VAR(0, mesa_texrectoffset_bug, 0, 0, 1);
273 VAR(0, intel_texalpha_bug, 0, 0, 1);
274 VAR(0, intel_mapbufferrange_bug, 0, 0, 1);
275 VAR(0, mesa_swap_bug, 0, 0, 1);
276 VAR(0, useubo, 1, 0, 0);
277 VAR(0, usetexgather, 1, 0, 0);
278 VAR(0, usetexcompress, 1, 0, 0);
279 VAR(0, maxdrawbufs, 1, 0, 0);
280 VAR(0, maxdualdrawbufs, 1, 0, 0);
281 
checkseries(const char * s,const char * name,int low,int high)282 static bool checkseries(const char *s, const char *name, int low, int high)
283 {
284     if(name) s = strstr(s, name);
285     if(!s) return false;
286     while(*s && !isdigit(*s)) ++s;
287     if(!*s) return false;
288     int n = 0;
289     while(isdigit(*s)) n = n*10 + (*s++ - '0');
290     return n >= low && n <= high;
291 }
292 
checkmesaversion(const char * s,int major,int minor,int patch)293 static bool checkmesaversion(const char *s, int major, int minor, int patch)
294 {
295     const char *v = strstr(s, "Mesa");
296     if(!v) return false;
297     int vmajor = 0, vminor = 0, vpatch = 0;
298     if(sscanf(v, "Mesa %d.%d.%d", &vmajor, &vminor, &vpatch) < 1) return false;
299     if(vmajor > major) return true; else if(vmajor < major) return false;
300     if(vminor > minor) return true; else if(vminor < minor) return false;
301     return vpatch >= patch;
302 }
303 
304 VAR(0, dbgexts, 0, 0, 1);
305 
306 hashset<const char *> glexts;
307 
parseglexts()308 void parseglexts()
309 {
310     if(glversion >= 300)
311     {
312         GLint numexts = 0;
313         glGetIntegerv(GL_NUM_EXTENSIONS, &numexts);
314         loopi(numexts)
315         {
316             const char *ext = (const char *)glGetStringi_(GL_EXTENSIONS, i);
317             glexts.add(newstring(ext));
318         }
319     }
320     else
321     {
322         const char *exts = (const char *)glGetString(GL_EXTENSIONS);
323         for(;;)
324         {
325             while(*exts == ' ') exts++;
326             if(!*exts) break;
327             const char *ext = exts;
328             while(*exts && *exts != ' ') exts++;
329             if(exts > ext) glexts.add(newstring(ext, size_t(exts-ext)));
330         }
331     }
332 }
333 
hasext(const char * ext)334 bool hasext(const char *ext)
335 {
336     return glexts.access(ext)!=NULL;
337 }
338 
checkdepthtexstencilrb()339 bool checkdepthtexstencilrb()
340 {
341     int w = 256, h = 256;
342     GLuint fbo = 0;
343     glGenFramebuffers_(1, &fbo);
344     glBindFramebuffer_(GL_FRAMEBUFFER, fbo);
345 
346     GLuint depthtex = 0;
347     glGenTextures(1, &depthtex);
348     createtexture(depthtex, w, h, NULL, 3, 0, GL_DEPTH_COMPONENT24, GL_TEXTURE_RECTANGLE);
349     glBindTexture(GL_TEXTURE_RECTANGLE, 0);
350     glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, depthtex, 0);
351 
352     GLuint stencilrb = 0;
353     glGenRenderbuffers_(1, &stencilrb);
354     glBindRenderbuffer_(GL_RENDERBUFFER, stencilrb);
355     glRenderbufferStorage_(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h);
356     glBindRenderbuffer_(GL_RENDERBUFFER, 0);
357     glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilrb);
358 
359     bool supported = glCheckFramebufferStatus_(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
360 
361     glBindFramebuffer_(GL_FRAMEBUFFER, 0);
362     glDeleteFramebuffers_(1, &fbo);
363     glDeleteTextures(1, &depthtex);
364     glDeleteRenderbuffers_(1, &stencilrb);
365 
366     return supported;
367 }
368 
369 SVAR(IDF_READONLY, gfxvendor, "");
370 SVAR(IDF_READONLY, gfxrenderer, "");
371 SVAR(IDF_READONLY, gfxversion, "");
372 
gl_checkextensions()373 void gl_checkextensions()
374 {
375     setsvar("gfxvendor", (const char *)glGetString(GL_VENDOR));
376     setsvar("gfxrenderer", (const char *)glGetString(GL_RENDERER));
377     setsvar("gfxversion", (const char *)glGetString(GL_VERSION));
378 
379     conoutf("Renderer: %s (%s)", gfxrenderer, gfxvendor);
380     conoutf("Driver: %s", gfxversion);
381 
382 #ifdef __APPLE__
383     // extern int mac_osversion();
384     // int osversion = mac_osversion();  /* 0x0A0600 = 10.6, assumed minimum */
385 #endif
386 
387     if(strstr(gfxrenderer, "Mesa") || strstr(gfxversion, "Mesa"))
388     {
389         mesa = true;
390         if(strstr(gfxrenderer, "Intel")) intel = true;
391     }
392     else if(strstr(gfxvendor, "NVIDIA"))
393         nvidia = true;
394     else if(strstr(gfxvendor, "ATI") || strstr(gfxvendor, "Advanced Micro Devices"))
395         amd = true;
396     else if(strstr(gfxvendor, "Intel"))
397         intel = true;
398 
399     uint glmajorversion, glminorversion;
400     if(sscanf(gfxversion, " %u.%u", &glmajorversion, &glminorversion) != 2) glversion = 100;
401     else glversion = glmajorversion*100 + glminorversion*10;
402 
403     if(glversion < 200) fatal("OpenGL 2.0 or greater is required!");
404 
405 #ifdef WIN32
406     glActiveTexture_ =            (PFNGLACTIVETEXTUREPROC)            getprocaddress("glActiveTexture");
407 
408     glBlendEquation_ =            (PFNGLBLENDEQUATIONPROC)            getprocaddress("glBlendEquation");
409     glBlendColor_ =               (PFNGLBLENDCOLORPROC)               getprocaddress("glBlendColor");
410 
411     glTexImage3D_ =               (PFNGLTEXIMAGE3DPROC)               getprocaddress("glTexImage3D");
412     glTexSubImage3D_ =            (PFNGLTEXSUBIMAGE3DPROC)            getprocaddress("glTexSubImage3D");
413     glCopyTexSubImage3D_ =        (PFNGLCOPYTEXSUBIMAGE3DPROC)        getprocaddress("glCopyTexSubImage3D");
414 
415     glCompressedTexImage3D_ =     (PFNGLCOMPRESSEDTEXIMAGE3DPROC)     getprocaddress("glCompressedTexImage3D");
416     glCompressedTexImage2D_ =     (PFNGLCOMPRESSEDTEXIMAGE2DPROC)     getprocaddress("glCompressedTexImage2D");
417     glCompressedTexImage1D_ =     (PFNGLCOMPRESSEDTEXIMAGE1DPROC)     getprocaddress("glCompressedTexImage1D");
418     glCompressedTexSubImage3D_ =  (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)  getprocaddress("glCompressedTexSubImage3D");
419     glCompressedTexSubImage2D_ =  (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)  getprocaddress("glCompressedTexSubImage2D");
420     glCompressedTexSubImage1D_ =  (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)  getprocaddress("glCompressedTexSubImage1D");
421     glGetCompressedTexImage_ =    (PFNGLGETCOMPRESSEDTEXIMAGEPROC)    getprocaddress("glGetCompressedTexImage");
422 
423     glDrawRangeElements_ =        (PFNGLDRAWRANGEELEMENTSPROC)        getprocaddress("glDrawRangeElements");
424 #endif
425 
426 #ifndef __APPLE__
427     glMultiDrawArrays_ =          (PFNGLMULTIDRAWARRAYSPROC)          getprocaddress("glMultiDrawArrays");
428     glMultiDrawElements_ =        (PFNGLMULTIDRAWELEMENTSPROC)        getprocaddress("glMultiDrawElements");
429 
430     glBlendFuncSeparate_ =        (PFNGLBLENDFUNCSEPARATEPROC)        getprocaddress("glBlendFuncSeparate");
431     glBlendEquationSeparate_ =    (PFNGLBLENDEQUATIONSEPARATEPROC)    getprocaddress("glBlendEquationSeparate");
432     glStencilOpSeparate_ =        (PFNGLSTENCILOPSEPARATEPROC)        getprocaddress("glStencilOpSeparate");
433     glStencilFuncSeparate_ =      (PFNGLSTENCILFUNCSEPARATEPROC)      getprocaddress("glStencilFuncSeparate");
434     glStencilMaskSeparate_ =      (PFNGLSTENCILMASKSEPARATEPROC)      getprocaddress("glStencilMaskSeparate");
435 
436     glGenBuffers_ =               (PFNGLGENBUFFERSPROC)               getprocaddress("glGenBuffers");
437     glBindBuffer_ =               (PFNGLBINDBUFFERPROC)               getprocaddress("glBindBuffer");
438     glMapBuffer_ =                (PFNGLMAPBUFFERPROC)                getprocaddress("glMapBuffer");
439     glUnmapBuffer_ =              (PFNGLUNMAPBUFFERPROC)              getprocaddress("glUnmapBuffer");
440     glBufferData_ =               (PFNGLBUFFERDATAPROC)               getprocaddress("glBufferData");
441     glBufferSubData_ =            (PFNGLBUFFERSUBDATAPROC)            getprocaddress("glBufferSubData");
442     glDeleteBuffers_ =            (PFNGLDELETEBUFFERSPROC)            getprocaddress("glDeleteBuffers");
443     glGetBufferSubData_ =         (PFNGLGETBUFFERSUBDATAPROC)         getprocaddress("glGetBufferSubData");
444 
445     glGetQueryiv_ =               (PFNGLGETQUERYIVPROC)               getprocaddress("glGetQueryiv");
446     glGenQueries_ =               (PFNGLGENQUERIESPROC)               getprocaddress("glGenQueries");
447     glDeleteQueries_ =            (PFNGLDELETEQUERIESPROC)            getprocaddress("glDeleteQueries");
448     glBeginQuery_ =               (PFNGLBEGINQUERYPROC)               getprocaddress("glBeginQuery");
449     glEndQuery_ =                 (PFNGLENDQUERYPROC)                 getprocaddress("glEndQuery");
450     glGetQueryObjectiv_ =         (PFNGLGETQUERYOBJECTIVPROC)         getprocaddress("glGetQueryObjectiv");
451     glGetQueryObjectuiv_ =        (PFNGLGETQUERYOBJECTUIVPROC)        getprocaddress("glGetQueryObjectuiv");
452 
453     glCreateProgram_ =            (PFNGLCREATEPROGRAMPROC)            getprocaddress("glCreateProgram");
454     glDeleteProgram_ =            (PFNGLDELETEPROGRAMPROC)            getprocaddress("glDeleteProgram");
455     glUseProgram_ =               (PFNGLUSEPROGRAMPROC)               getprocaddress("glUseProgram");
456     glCreateShader_ =             (PFNGLCREATESHADERPROC)             getprocaddress("glCreateShader");
457     glDeleteShader_ =             (PFNGLDELETESHADERPROC)             getprocaddress("glDeleteShader");
458     glShaderSource_ =             (PFNGLSHADERSOURCEPROC)             getprocaddress("glShaderSource");
459     glCompileShader_ =            (PFNGLCOMPILESHADERPROC)            getprocaddress("glCompileShader");
460     glGetShaderiv_ =              (PFNGLGETSHADERIVPROC)              getprocaddress("glGetShaderiv");
461     glGetProgramiv_ =             (PFNGLGETPROGRAMIVPROC)             getprocaddress("glGetProgramiv");
462     glAttachShader_ =             (PFNGLATTACHSHADERPROC)             getprocaddress("glAttachShader");
463     glGetProgramInfoLog_ =        (PFNGLGETPROGRAMINFOLOGPROC)        getprocaddress("glGetProgramInfoLog");
464     glGetShaderInfoLog_ =         (PFNGLGETSHADERINFOLOGPROC)         getprocaddress("glGetShaderInfoLog");
465     glLinkProgram_ =              (PFNGLLINKPROGRAMPROC)              getprocaddress("glLinkProgram");
466     glGetUniformLocation_ =       (PFNGLGETUNIFORMLOCATIONPROC)       getprocaddress("glGetUniformLocation");
467     glUniform1f_ =                (PFNGLUNIFORM1FPROC)                getprocaddress("glUniform1f");
468     glUniform2f_ =                (PFNGLUNIFORM2FPROC)                getprocaddress("glUniform2f");
469     glUniform3f_ =                (PFNGLUNIFORM3FPROC)                getprocaddress("glUniform3f");
470     glUniform4f_ =                (PFNGLUNIFORM4FPROC)                getprocaddress("glUniform4f");
471     glUniform1fv_ =               (PFNGLUNIFORM1FVPROC)               getprocaddress("glUniform1fv");
472     glUniform2fv_ =               (PFNGLUNIFORM2FVPROC)               getprocaddress("glUniform2fv");
473     glUniform3fv_ =               (PFNGLUNIFORM3FVPROC)               getprocaddress("glUniform3fv");
474     glUniform4fv_ =               (PFNGLUNIFORM4FVPROC)               getprocaddress("glUniform4fv");
475     glUniform1i_ =                (PFNGLUNIFORM1IPROC)                getprocaddress("glUniform1i");
476     glUniform2i_ =                (PFNGLUNIFORM2IPROC)                getprocaddress("glUniform2i");
477     glUniform3i_ =                (PFNGLUNIFORM3IPROC)                getprocaddress("glUniform3i");
478     glUniform4i_ =                (PFNGLUNIFORM4IPROC)                getprocaddress("glUniform4i");
479     glUniform1iv_ =               (PFNGLUNIFORM1IVPROC)               getprocaddress("glUniform1iv");
480     glUniform2iv_ =               (PFNGLUNIFORM2IVPROC)               getprocaddress("glUniform2iv");
481     glUniform3iv_ =               (PFNGLUNIFORM3IVPROC)               getprocaddress("glUniform3iv");
482     glUniform4iv_ =               (PFNGLUNIFORM4IVPROC)               getprocaddress("glUniform4iv");
483     glUniformMatrix2fv_ =         (PFNGLUNIFORMMATRIX2FVPROC)         getprocaddress("glUniformMatrix2fv");
484     glUniformMatrix3fv_ =         (PFNGLUNIFORMMATRIX3FVPROC)         getprocaddress("glUniformMatrix3fv");
485     glUniformMatrix4fv_ =         (PFNGLUNIFORMMATRIX4FVPROC)         getprocaddress("glUniformMatrix4fv");
486     glBindAttribLocation_ =       (PFNGLBINDATTRIBLOCATIONPROC)       getprocaddress("glBindAttribLocation");
487     glGetActiveUniform_ =         (PFNGLGETACTIVEUNIFORMPROC)         getprocaddress("glGetActiveUniform");
488     glEnableVertexAttribArray_ =  (PFNGLENABLEVERTEXATTRIBARRAYPROC)  getprocaddress("glEnableVertexAttribArray");
489     glDisableVertexAttribArray_ = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) getprocaddress("glDisableVertexAttribArray");
490 
491     glVertexAttrib1f_ =           (PFNGLVERTEXATTRIB1FPROC)           getprocaddress("glVertexAttrib1f");
492     glVertexAttrib1fv_ =          (PFNGLVERTEXATTRIB1FVPROC)          getprocaddress("glVertexAttrib1fv");
493     glVertexAttrib1s_ =           (PFNGLVERTEXATTRIB1SPROC)           getprocaddress("glVertexAttrib1s");
494     glVertexAttrib1sv_ =          (PFNGLVERTEXATTRIB1SVPROC)          getprocaddress("glVertexAttrib1sv");
495     glVertexAttrib2f_ =           (PFNGLVERTEXATTRIB2FPROC)           getprocaddress("glVertexAttrib2f");
496     glVertexAttrib2fv_ =          (PFNGLVERTEXATTRIB2FVPROC)          getprocaddress("glVertexAttrib2fv");
497     glVertexAttrib2s_ =           (PFNGLVERTEXATTRIB2SPROC)           getprocaddress("glVertexAttrib2s");
498     glVertexAttrib2sv_ =          (PFNGLVERTEXATTRIB2SVPROC)          getprocaddress("glVertexAttrib2sv");
499     glVertexAttrib3f_ =           (PFNGLVERTEXATTRIB3FPROC)           getprocaddress("glVertexAttrib3f");
500     glVertexAttrib3fv_ =          (PFNGLVERTEXATTRIB3FVPROC)          getprocaddress("glVertexAttrib3fv");
501     glVertexAttrib3s_ =           (PFNGLVERTEXATTRIB3SPROC)           getprocaddress("glVertexAttrib3s");
502     glVertexAttrib3sv_ =          (PFNGLVERTEXATTRIB3SVPROC)          getprocaddress("glVertexAttrib3sv");
503     glVertexAttrib4f_ =           (PFNGLVERTEXATTRIB4FPROC)           getprocaddress("glVertexAttrib4f");
504     glVertexAttrib4fv_ =          (PFNGLVERTEXATTRIB4FVPROC)          getprocaddress("glVertexAttrib4fv");
505     glVertexAttrib4s_ =           (PFNGLVERTEXATTRIB4SPROC)           getprocaddress("glVertexAttrib4s");
506     glVertexAttrib4sv_ =          (PFNGLVERTEXATTRIB4SVPROC)          getprocaddress("glVertexAttrib4sv");
507     glVertexAttrib4bv_ =          (PFNGLVERTEXATTRIB4BVPROC)          getprocaddress("glVertexAttrib4bv");
508     glVertexAttrib4iv_ =          (PFNGLVERTEXATTRIB4IVPROC)          getprocaddress("glVertexAttrib4iv");
509     glVertexAttrib4ubv_ =         (PFNGLVERTEXATTRIB4UBVPROC)         getprocaddress("glVertexAttrib4ubv");
510     glVertexAttrib4uiv_ =         (PFNGLVERTEXATTRIB4UIVPROC)         getprocaddress("glVertexAttrib4uiv");
511     glVertexAttrib4usv_ =         (PFNGLVERTEXATTRIB4USVPROC)         getprocaddress("glVertexAttrib4usv");
512     glVertexAttrib4Nbv_ =         (PFNGLVERTEXATTRIB4NBVPROC)         getprocaddress("glVertexAttrib4Nbv");
513     glVertexAttrib4Niv_ =         (PFNGLVERTEXATTRIB4NIVPROC)         getprocaddress("glVertexAttrib4Niv");
514     glVertexAttrib4Nub_ =         (PFNGLVERTEXATTRIB4NUBPROC)         getprocaddress("glVertexAttrib4Nub");
515     glVertexAttrib4Nubv_ =        (PFNGLVERTEXATTRIB4NUBVPROC)        getprocaddress("glVertexAttrib4Nubv");
516     glVertexAttrib4Nuiv_ =        (PFNGLVERTEXATTRIB4NUIVPROC)        getprocaddress("glVertexAttrib4Nuiv");
517     glVertexAttrib4Nusv_ =        (PFNGLVERTEXATTRIB4NUSVPROC)        getprocaddress("glVertexAttrib4Nusv");
518     glVertexAttribPointer_ =      (PFNGLVERTEXATTRIBPOINTERPROC)      getprocaddress("glVertexAttribPointer");
519 
520     glDrawBuffers_ =              (PFNGLDRAWBUFFERSPROC)              getprocaddress("glDrawBuffers");
521 #endif
522 
523     if(glversion >= 300)
524     {
525         glGetStringi_ =            (PFNGLGETSTRINGIPROC)          getprocaddress("glGetStringi");
526     }
527 
528     const char *glslstr = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
529     conoutf("GLSL: %s", glslstr ? glslstr : "unknown");
530 
531     uint glslmajorversion, glslminorversion;
532     if(glslstr && sscanf(glslstr, " %u.%u", &glslmajorversion, &glslminorversion) == 2) glslversion = glslmajorversion*100 + glslminorversion;
533 
534     if(glslversion < 120) fatal("GLSL 1.20 or greater is required!");
535 
536     parseglexts();
537 
538     GLint texsize = 0, texunits = 0, vtexunits = 0, cubetexsize = 0, drawbufs = 0;
539     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texsize);
540     hwtexsize = texsize;
541     if(hwtexsize < 2048)
542         fatal("Large texture support is required!");
543     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &texunits);
544     hwtexunits = texunits;
545     if(hwtexunits < 16)
546         fatal("Hardware does not support at least 16 texture units.");
547     glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &vtexunits);
548     hwvtexunits = vtexunits;
549     //if(hwvtexunits < 4)
550     //    fatal("Hardware does not support at least 4 vertex texture units.");
551     glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &cubetexsize);
552     hwcubetexsize = cubetexsize;
553     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &drawbufs);
554     maxdrawbufs = drawbufs;
555     if(maxdrawbufs < 4) fatal("Hardware does not support at least 4 draw buffers.");
556 
557     if(glversion >= 210 || hasext("GL_ARB_pixel_buffer_object") || hasext("GL_EXT_pixel_buffer_object"))
558     {
559         hasPBO = true;
560         if(glversion < 210 && dbgexts) conoutf("\frUsing GL_ARB_pixel_buffer_object extension.");
561     }
562     else fatal("Pixel buffer object support is required!");
563 
564     if(glversion >= 300 || hasext("GL_ARB_vertex_array_object"))
565     {
566         glBindVertexArray_ =    (PFNGLBINDVERTEXARRAYPROC)   getprocaddress("glBindVertexArray");
567         glDeleteVertexArrays_ = (PFNGLDELETEVERTEXARRAYSPROC)getprocaddress("glDeleteVertexArrays");
568         glGenVertexArrays_ =    (PFNGLGENVERTEXARRAYSPROC)   getprocaddress("glGenVertexArrays");
569         glIsVertexArray_ =      (PFNGLISVERTEXARRAYPROC)     getprocaddress("glIsVertexArray");
570         hasVAO = true;
571         if(glversion < 300 && dbgexts) conoutf("\frUsing GL_ARB_vertex_array_object extension.");
572     }
573     else if(hasext("GL_APPLE_vertex_array_object"))
574     {
575         glBindVertexArray_ =    (PFNGLBINDVERTEXARRAYPROC)   getprocaddress("glBindVertexArrayAPPLE");
576         glDeleteVertexArrays_ = (PFNGLDELETEVERTEXARRAYSPROC)getprocaddress("glDeleteVertexArraysAPPLE");
577         glGenVertexArrays_ =    (PFNGLGENVERTEXARRAYSPROC)   getprocaddress("glGenVertexArraysAPPLE");
578         glIsVertexArray_ =      (PFNGLISVERTEXARRAYPROC)     getprocaddress("glIsVertexArrayAPPLE");
579         hasVAO = true;
580         if(dbgexts) conoutf("\frUsing GL_APPLE_vertex_array_object extension.");
581     }
582 
583     if(glversion >= 300)
584     {
585         hasTF = hasTRG = hasRGTC = hasPF = hasHFV = hasHFP = true;
586 
587         glBindFragDataLocation_ = (PFNGLBINDFRAGDATALOCATIONPROC)getprocaddress("glBindFragDataLocation");
588         glUniform1ui_ =           (PFNGLUNIFORM1UIPROC)          getprocaddress("glUniform1ui");
589         glUniform2ui_ =           (PFNGLUNIFORM2UIPROC)          getprocaddress("glUniform2ui");
590         glUniform3ui_ =           (PFNGLUNIFORM3UIPROC)          getprocaddress("glUniform3ui");
591         glUniform4ui_ =           (PFNGLUNIFORM4UIPROC)          getprocaddress("glUniform4ui");
592         glUniform1uiv_ =          (PFNGLUNIFORM1UIVPROC)         getprocaddress("glUniform1uiv");
593         glUniform2uiv_ =          (PFNGLUNIFORM2UIVPROC)         getprocaddress("glUniform2uiv");
594         glUniform3uiv_ =          (PFNGLUNIFORM3UIVPROC)         getprocaddress("glUniform3uiv");
595         glUniform4uiv_ =          (PFNGLUNIFORM4UIVPROC)         getprocaddress("glUniform4uiv");
596         glClearBufferiv_ =        (PFNGLCLEARBUFFERIVPROC)       getprocaddress("glClearBufferiv");
597         glClearBufferuiv_ =       (PFNGLCLEARBUFFERUIVPROC)      getprocaddress("glClearBufferuiv");
598         glClearBufferfv_ =        (PFNGLCLEARBUFFERFVPROC)       getprocaddress("glClearBufferfv");
599         glClearBufferfi_ =        (PFNGLCLEARBUFFERFIPROC)       getprocaddress("glClearBufferfi");
600         hasGPU4 = true;
601 
602         if(hasext("GL_EXT_gpu_shader4"))
603         {
604             hasEGPU4 = true;
605             if(dbgexts) conoutf("\frUsing GL_EXT_gpu_shader4 extension.");
606         }
607 
608         glClampColor_ = (PFNGLCLAMPCOLORPROC)getprocaddress("glClampColor");
609         hasCBF = true;
610 
611         glColorMaski_ = (PFNGLCOLORMASKIPROC)getprocaddress("glColorMaski");
612         glEnablei_ =    (PFNGLENABLEIPROC)   getprocaddress("glEnablei");
613         glDisablei_ =   (PFNGLENABLEIPROC)   getprocaddress("glDisablei");
614         hasDB2 = true;
615 
616         glBeginConditionalRender_ = (PFNGLBEGINCONDITIONALRENDERPROC)getprocaddress("glBeginConditionalRender");
617         glEndConditionalRender_ =   (PFNGLENDCONDITIONALRENDERPROC)  getprocaddress("glEndConditionalRender");
618         hasCR = true;
619 
620         glTexParameterIiv_ =     (PFNGLTEXPARAMETERIIVPROC)    getprocaddress("glTexParameterIiv");
621         glTexParameterIuiv_ =    (PFNGLTEXPARAMETERIUIVPROC)   getprocaddress("glTexParameterIuiv");
622         glGetTexParameterIiv_ =  (PFNGLGETTEXPARAMETERIIVPROC) getprocaddress("glGetTexParameterIiv");
623         glGetTexParameterIuiv_ = (PFNGLGETTEXPARAMETERIUIVPROC)getprocaddress("glGetTexParameterIuiv");
624         hasTI = true;
625     }
626     else
627     {
628         if(hasext("GL_ARB_texture_float"))
629         {
630             hasTF = true;
631             if(dbgexts) conoutf("\frUsing GL_ARB_texture_float extension.");
632         }
633         if(hasext("GL_ARB_texture_rg"))
634         {
635             hasTRG = true;
636             if(dbgexts) conoutf("\frUsing GL_ARB_texture_rg extension.");
637         }
638         if(hasext("GL_ARB_texture_compression_rgtc") || hasext("GL_EXT_texture_compression_rgtc"))
639         {
640             hasRGTC = true;
641             if(dbgexts) conoutf("\frUsing GL_ARB_texture_compression_rgtc extension.");
642         }
643         if(hasext("GL_EXT_packed_float"))
644         {
645             hasPF = true;
646             if(dbgexts) conoutf("\frUsing GL_EXT_packed_float extension.");
647         }
648         if(hasext("GL_EXT_gpu_shader4"))
649         {
650             glBindFragDataLocation_ = (PFNGLBINDFRAGDATALOCATIONPROC)getprocaddress("glBindFragDataLocationEXT");
651             glUniform1ui_ =           (PFNGLUNIFORM1UIPROC)          getprocaddress("glUniform1uiEXT");
652             glUniform2ui_ =           (PFNGLUNIFORM2UIPROC)          getprocaddress("glUniform2uiEXT");
653             glUniform3ui_ =           (PFNGLUNIFORM3UIPROC)          getprocaddress("glUniform3uiEXT");
654             glUniform4ui_ =           (PFNGLUNIFORM4UIPROC)          getprocaddress("glUniform4uiEXT");
655             glUniform1uiv_ =          (PFNGLUNIFORM1UIVPROC)         getprocaddress("glUniform1uivEXT");
656             glUniform2uiv_ =          (PFNGLUNIFORM2UIVPROC)         getprocaddress("glUniform2uivEXT");
657             glUniform3uiv_ =          (PFNGLUNIFORM3UIVPROC)         getprocaddress("glUniform3uivEXT");
658             glUniform4uiv_ =          (PFNGLUNIFORM4UIVPROC)         getprocaddress("glUniform4uivEXT");
659             hasEGPU4 = hasGPU4 = true;
660             if(dbgexts) conoutf("\frUsing GL_EXT_gpu_shader4 extension.");
661         }
662         if(hasext("GL_ARB_color_buffer_float"))
663         {
664             glClampColor_ = (PFNGLCLAMPCOLORPROC)getprocaddress("glClampColorARB");
665             hasCBF = true;
666             if(dbgexts) conoutf("\frUsing GL_ARB_color_buffer_float extension.");
667         }
668         if(hasext("GL_EXT_draw_buffers2"))
669         {
670             glColorMaski_ = (PFNGLCOLORMASKIPROC)getprocaddress("glColorMaskIndexedEXT");
671             glEnablei_ =    (PFNGLENABLEIPROC)   getprocaddress("glEnableIndexedEXT");
672             glDisablei_ =   (PFNGLENABLEIPROC)   getprocaddress("glDisableIndexedEXT");
673             hasDB2 = true;
674             if(dbgexts) conoutf("\frUsing GL_EXT_draw_buffers2 extension.");
675         }
676         if(hasext("GL_NV_conditional_render"))
677         {
678             glBeginConditionalRender_ = (PFNGLBEGINCONDITIONALRENDERPROC)getprocaddress("glBeginConditionalRenderNV");
679             glEndConditionalRender_ =   (PFNGLENDCONDITIONALRENDERPROC)  getprocaddress("glEndConditionalRenderNV");
680             hasCR = true;
681             if(dbgexts) conoutf("\frUsing GL_NV_conditional_render extension.");
682         }
683         if(hasext("GL_EXT_texture_integer"))
684         {
685             glTexParameterIiv_ =     (PFNGLTEXPARAMETERIIVPROC)    getprocaddress("glTexParameterIivEXT");
686             glTexParameterIuiv_ =    (PFNGLTEXPARAMETERIUIVPROC)   getprocaddress("glTexParameterIuivEXT");
687             glGetTexParameterIiv_ =  (PFNGLGETTEXPARAMETERIIVPROC) getprocaddress("glGetTexParameterIivEXT");
688             glGetTexParameterIuiv_ = (PFNGLGETTEXPARAMETERIUIVPROC)getprocaddress("glGetTexParameterIuivEXT");
689             glClearColorIi_ =        (PFNGLCLEARCOLORIIEXTPROC)    getprocaddress("glClearColorIiEXT");
690             glClearColorIui_ =       (PFNGLCLEARCOLORIUIEXTPROC)   getprocaddress("glClearColorIuiEXT");
691             hasTI = true;
692             if(dbgexts) conoutf("\frUsing GL_EXT_texture_integer extension.");
693         }
694         if(hasext("GL_NV_half_float"))
695         {
696             hasHFV = hasHFP = true;
697             if(dbgexts) conoutf("\frUsing GL_NV_half_float extension.");
698         }
699         else
700         {
701             if(hasext("GL_ARB_half_float_vertex"))
702             {
703                 hasHFV = true;
704                 if(dbgexts) conoutf("\frUsing GL_ARB_half_float_vertex extension.");
705             }
706             if(hasext("GL_ARB_half_float_pixel"))
707             {
708                 hasHFP = true;
709                 if(dbgexts) conoutf("\frUsing GL_ARB_half_float_pixel extension.");
710             }
711         }
712     }
713 
714     if(!hasHFV) fatal("Half-precision floating-point support is required!");
715 
716     if(glversion >= 300 || hasext("GL_ARB_framebuffer_object"))
717     {
718         glBindRenderbuffer_               = (PFNGLBINDRENDERBUFFERPROC)              getprocaddress("glBindRenderbuffer");
719         glDeleteRenderbuffers_            = (PFNGLDELETERENDERBUFFERSPROC)           getprocaddress("glDeleteRenderbuffers");
720         glGenRenderbuffers_               = (PFNGLGENFRAMEBUFFERSPROC)               getprocaddress("glGenRenderbuffers");
721         glRenderbufferStorage_            = (PFNGLRENDERBUFFERSTORAGEPROC)           getprocaddress("glRenderbufferStorage");
722         glGetRenderbufferParameteriv_     = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)    getprocaddress("glGetRenderbufferParameteriv");
723         glCheckFramebufferStatus_         = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)        getprocaddress("glCheckFramebufferStatus");
724         glBindFramebuffer_                = (PFNGLBINDFRAMEBUFFERPROC)               getprocaddress("glBindFramebuffer");
725         glDeleteFramebuffers_             = (PFNGLDELETEFRAMEBUFFERSPROC)            getprocaddress("glDeleteFramebuffers");
726         glGenFramebuffers_                = (PFNGLGENFRAMEBUFFERSPROC)               getprocaddress("glGenFramebuffers");
727         glFramebufferTexture1D_           = (PFNGLFRAMEBUFFERTEXTURE1DPROC)          getprocaddress("glFramebufferTexture1D");
728         glFramebufferTexture2D_           = (PFNGLFRAMEBUFFERTEXTURE2DPROC)          getprocaddress("glFramebufferTexture2D");
729         glFramebufferTexture3D_           = (PFNGLFRAMEBUFFERTEXTURE3DPROC)          getprocaddress("glFramebufferTexture3D");
730         glFramebufferRenderbuffer_        = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)       getprocaddress("glFramebufferRenderbuffer");
731         glGenerateMipmap_                 = (PFNGLGENERATEMIPMAPPROC)                getprocaddress("glGenerateMipmap");
732         glBlitFramebuffer_                = (PFNGLBLITFRAMEBUFFERPROC)               getprocaddress("glBlitFramebuffer");
733         glRenderbufferStorageMultisample_ = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)getprocaddress("glRenderbufferStorageMultisample");
734 
735         hasAFBO = hasFBO = hasFBB = hasFBMS = hasDS = true;
736         if(glversion < 300 && dbgexts) conoutf("\frUsing GL_ARB_framebuffer_object extension.");
737     }
738     else if(hasext("GL_EXT_framebuffer_object"))
739     {
740         glBindRenderbuffer_           = (PFNGLBINDRENDERBUFFERPROC)          getprocaddress("glBindRenderbufferEXT");
741         glDeleteRenderbuffers_        = (PFNGLDELETERENDERBUFFERSPROC)       getprocaddress("glDeleteRenderbuffersEXT");
742         glGenRenderbuffers_           = (PFNGLGENFRAMEBUFFERSPROC)           getprocaddress("glGenRenderbuffersEXT");
743         glRenderbufferStorage_        = (PFNGLRENDERBUFFERSTORAGEPROC)       getprocaddress("glRenderbufferStorageEXT");
744         glGetRenderbufferParameteriv_ = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)getprocaddress("glGetRenderbufferParameterivEXT");
745         glCheckFramebufferStatus_     = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)    getprocaddress("glCheckFramebufferStatusEXT");
746         glBindFramebuffer_            = (PFNGLBINDFRAMEBUFFERPROC)           getprocaddress("glBindFramebufferEXT");
747         glDeleteFramebuffers_         = (PFNGLDELETEFRAMEBUFFERSPROC)        getprocaddress("glDeleteFramebuffersEXT");
748         glGenFramebuffers_            = (PFNGLGENFRAMEBUFFERSPROC)           getprocaddress("glGenFramebuffersEXT");
749         glFramebufferTexture1D_       = (PFNGLFRAMEBUFFERTEXTURE1DPROC)      getprocaddress("glFramebufferTexture1DEXT");
750         glFramebufferTexture2D_       = (PFNGLFRAMEBUFFERTEXTURE2DPROC)      getprocaddress("glFramebufferTexture2DEXT");
751         glFramebufferTexture3D_       = (PFNGLFRAMEBUFFERTEXTURE3DPROC)      getprocaddress("glFramebufferTexture3DEXT");
752         glFramebufferRenderbuffer_    = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)   getprocaddress("glFramebufferRenderbufferEXT");
753         glGenerateMipmap_             = (PFNGLGENERATEMIPMAPPROC)            getprocaddress("glGenerateMipmapEXT");
754         hasFBO = true;
755         if(dbgexts) conoutf("\frUsing GL_EXT_framebuffer_object extension.");
756 
757         if(hasext("GL_EXT_framebuffer_blit"))
758         {
759             glBlitFramebuffer_     = (PFNGLBLITFRAMEBUFFERPROC)        getprocaddress("glBlitFramebufferEXT");
760             hasFBB = true;
761             if(dbgexts) conoutf("\frUsing GL_EXT_framebuffer_blit extension.");
762         }
763         if(hasext("GL_EXT_framebuffer_multisample"))
764         {
765             glRenderbufferStorageMultisample_ = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)getprocaddress("glRenderbufferStorageMultisampleEXT");
766             hasFBMS = true;
767             if(dbgexts) conoutf("\frUsing GL_EXT_framebuffer_multisample extension.");
768         }
769 
770         if(hasext("GL_EXT_packed_depth_stencil") || hasext("GL_NV_packed_depth_stencil"))
771         {
772             hasDS = true;
773             if(dbgexts) conoutf("\frUsing GL_EXT_packed_depth_stencil extension.");
774         }
775     }
776     else fatal("Framebuffer object support is required!");
777 
778     if(glversion >= 300 || hasext("GL_ARB_map_buffer_range"))
779     {
780         glMapBufferRange_         = (PFNGLMAPBUFFERRANGEPROC)        getprocaddress("glMapBufferRange");
781         glFlushMappedBufferRange_ = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)getprocaddress("glFlushMappedBufferRange");
782         hasMBR = true;
783         if(glversion < 300 && dbgexts) conoutf("\frUsing GL_ARB_map_buffer_range.");
784     }
785 
786     if(glversion >= 310 || hasext("GL_ARB_uniform_buffer_object"))
787     {
788         glGetUniformIndices_       = (PFNGLGETUNIFORMINDICESPROC)      getprocaddress("glGetUniformIndices");
789         glGetActiveUniformsiv_     = (PFNGLGETACTIVEUNIFORMSIVPROC)    getprocaddress("glGetActiveUniformsiv");
790         glGetUniformBlockIndex_    = (PFNGLGETUNIFORMBLOCKINDEXPROC)   getprocaddress("glGetUniformBlockIndex");
791         glGetActiveUniformBlockiv_ = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)getprocaddress("glGetActiveUniformBlockiv");
792         glUniformBlockBinding_     = (PFNGLUNIFORMBLOCKBINDINGPROC)    getprocaddress("glUniformBlockBinding");
793         glBindBufferBase_          = (PFNGLBINDBUFFERBASEPROC)         getprocaddress("glBindBufferBase");
794         glBindBufferRange_         = (PFNGLBINDBUFFERRANGEPROC)        getprocaddress("glBindBufferRange");
795 
796         useubo = 1;
797         hasUBO = true;
798         if(glversion < 310 && dbgexts) conoutf("\frUsing GL_ARB_uniform_buffer_object extension.");
799     }
800 
801     if(glversion >= 310 || hasext("GL_ARB_texture_rectangle"))
802     {
803         hasTR = true;
804         if(glversion < 310 && dbgexts) conoutf("\frUsing GL_ARB_texture_rectangle extension.");
805     }
806     else fatal("Texture rectangle support is required!");
807 
808     if(glversion >= 310 || hasext("GL_ARB_copy_buffer"))
809     {
810         glCopyBufferSubData_ = (PFNGLCOPYBUFFERSUBDATAPROC)getprocaddress("glCopyBufferSubData");
811         hasCB = true;
812         if(glversion < 310 && dbgexts) conoutf("\frUsing GL_ARB_copy_buffer extension.");
813     }
814 
815     if(glversion >= 320 || hasext("GL_ARB_texture_multisample"))
816     {
817         glTexImage2DMultisample_ = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)getprocaddress("glTexImage2DMultisample");
818         glTexImage3DMultisample_ = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)getprocaddress("glTexImage3DMultisample");
819         glGetMultisamplefv_      = (PFNGLGETMULTISAMPLEFVPROC)     getprocaddress("glGetMultisamplefv");
820         glSampleMaski_           = (PFNGLSAMPLEMASKIPROC)          getprocaddress("glSampleMaski");
821         hasTMS = true;
822         if(glversion < 320 && dbgexts) conoutf("\frUsing GL_ARB_texture_multisample extension.");
823     }
824     if(hasext("GL_EXT_framebuffer_multisample_blit_scaled"))
825     {
826         hasFBMSBS = true;
827         if(dbgexts) conoutf("\frUsing GL_EXT_framebuffer_multisample_blit_scaled extension.");
828     }
829 
830     if(hasext("GL_EXT_timer_query"))
831     {
832         glGetQueryObjecti64v_ =  (PFNGLGETQUERYOBJECTI64VEXTPROC)  getprocaddress("glGetQueryObjecti64vEXT");
833         glGetQueryObjectui64v_ = (PFNGLGETQUERYOBJECTUI64VEXTPROC) getprocaddress("glGetQueryObjectui64vEXT");
834         hasTQ = true;
835         if(dbgexts) conoutf("\frUsing GL_EXT_timer_query extension.");
836     }
837     else if(glversion >= 330 || hasext("GL_ARB_timer_query"))
838     {
839         glGetQueryObjecti64v_ =  (PFNGLGETQUERYOBJECTI64VEXTPROC)  getprocaddress("glGetQueryObjecti64v");
840         glGetQueryObjectui64v_ = (PFNGLGETQUERYOBJECTUI64VEXTPROC) getprocaddress("glGetQueryObjectui64v");
841         hasTQ = true;
842         if(glversion < 330 && dbgexts) conoutf("\frUsing GL_ARB_timer_query extension.");
843     }
844 
845     if(hasext("GL_EXT_texture_compression_s3tc"))
846     {
847         hasS3TC = true;
848 #ifdef __APPLE__
849         usetexcompress = 1;
850 #else
851         if(!mesa) usetexcompress = 2;
852 #endif
853         if(dbgexts) conoutf("\frUsing GL_EXT_texture_compression_s3tc extension.");
854     }
855     else if(hasext("GL_EXT_texture_compression_dxt1") && hasext("GL_ANGLE_texture_compression_dxt3") && hasext("GL_ANGLE_texture_compression_dxt5"))
856     {
857         hasS3TC = true;
858         if(dbgexts) conoutf("\frUsing GL_EXT_texture_compression_dxt1 extension.");
859     }
860     if(hasext("GL_3DFX_texture_compression_FXT1"))
861     {
862         hasFXT1 = true;
863         if(mesa) usetexcompress = max(usetexcompress, 1);
864         if(dbgexts) conoutf("\frUsing GL_3DFX_texture_compression_FXT1.");
865     }
866     if(hasext("GL_EXT_texture_compression_latc"))
867     {
868         hasLATC = true;
869         if(dbgexts) conoutf("\frUsing GL_EXT_texture_compression_latc extension.");
870     }
871 
872     if(hasext("GL_EXT_texture_filter_anisotropic"))
873     {
874        GLint val = 0;
875        glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val);
876        hwmaxaniso = val;
877        hasAF = true;
878        if(dbgexts) conoutf("\frUsing GL_EXT_texture_filter_anisotropic extension.");
879     }
880 
881     if(hasext("GL_EXT_depth_bounds_test"))
882     {
883         glDepthBounds_ = (PFNGLDEPTHBOUNDSEXTPROC) getprocaddress("glDepthBoundsEXT");
884         hasDBT = true;
885         if(dbgexts) conoutf("\frUsing GL_EXT_depth_bounds_test extension.");
886     }
887 
888     if(glversion >= 320 || hasext("GL_ARB_depth_clamp"))
889     {
890         hasDC = true;
891         if(glversion < 320 && dbgexts) conoutf("\frUsing GL_ARB_depth_clamp extension.");
892     }
893     else if(hasext("GL_NV_depth_clamp"))
894     {
895         hasDC = true;
896         if(dbgexts) conoutf("\frUsing GL_NV_depth_clamp extension.");
897     }
898 
899     if(glversion >= 330)
900     {
901         hasTSW = hasEAL = hasOQ2 = true;
902     }
903     else
904     {
905         if(hasext("GL_ARB_texture_swizzle") || hasext("GL_EXT_texture_swizzle"))
906         {
907             hasTSW = true;
908             if(dbgexts) conoutf("\frUsing GL_ARB_texture_swizzle extension.");
909         }
910         if(hasext("GL_ARB_explicit_attrib_location"))
911         {
912             hasEAL = true;
913             if(dbgexts) conoutf("\frUsing GL_ARB_explicit_attrib_location extension.");
914         }
915         if(hasext("GL_ARB_occlusion_query2"))
916         {
917             hasOQ2 = true;
918             if(dbgexts) conoutf("\frUsing GL_ARB_occlusion_query2 extension.");
919         }
920     }
921 
922     if(glversion >= 330 || hasext("GL_ARB_blend_func_extended"))
923     {
924         glBindFragDataLocationIndexed_ = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)getprocaddress("glBindFragDataLocationIndexed");
925 
926         if(hasGPU4)
927         {
928             GLint dualbufs = 0;
929             glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &dualbufs);
930             maxdualdrawbufs = dualbufs;
931         }
932 
933         hasBFE = true;
934         if(glversion < 330 && dbgexts) conoutf("\frUsing GL_ARB_blend_func_extended extension.");
935     }
936 
937     if(glversion >= 400)
938     {
939         hasTG = hasGPU5 = true;
940 
941         glMinSampleShading_ = (PFNGLMINSAMPLESHADINGPROC)getprocaddress("glMinSampleShading");
942         hasMSS = true;
943 
944         glBlendEquationi_ =         (PFNGLBLENDEQUATIONIPROC)        getprocaddress("glBlendEquationi");
945         glBlendEquationSeparatei_ = (PFNGLBLENDEQUATIONSEPARATEIPROC)getprocaddress("glBlendEquationSeparatei");
946         glBlendFunci_ =             (PFNGLBLENDFUNCIPROC)            getprocaddress("glBlendFunci");
947         glBlendFuncSeparatei_ =     (PFNGLBLENDFUNCSEPARATEIPROC)    getprocaddress("glBlendFuncSeparatei");
948         hasDBB = true;
949     }
950     else
951     {
952         if(hasext("GL_ARB_texture_gather"))
953         {
954             hasTG = true;
955             if(dbgexts) conoutf("\frUsing GL_ARB_texture_gather extension.");
956         }
957         if(hasext("GL_ARB_gpu_shader5"))
958         {
959             hasGPU5 = true;
960             if(dbgexts) conoutf("\frUsing GL_ARB_gpu_shader5 extension.");
961         }
962         if(hasext("GL_ARB_sample_shading"))
963         {
964             glMinSampleShading_ = (PFNGLMINSAMPLESHADINGPROC)getprocaddress("glMinSampleShadingARB");
965             hasMSS = true;
966             if(dbgexts) conoutf("\frUsing GL_ARB_sample_shading extension.");
967         }
968         if(hasext("GL_ARB_draw_buffers_blend"))
969         {
970             glBlendEquationi_ =         (PFNGLBLENDEQUATIONIPROC)        getprocaddress("glBlendEquationiARB");
971             glBlendEquationSeparatei_ = (PFNGLBLENDEQUATIONSEPARATEIPROC)getprocaddress("glBlendEquationSeparateiARB");
972             glBlendFunci_ =             (PFNGLBLENDFUNCIPROC)            getprocaddress("glBlendFunciARB");
973             glBlendFuncSeparatei_ =     (PFNGLBLENDFUNCSEPARATEIPROC)    getprocaddress("glBlendFuncSeparateiARB");
974             hasDBB = true;
975             if(dbgexts) conoutf("\frUsing GL_ARB_draw_buffers_blend extension.");
976         }
977     }
978     if(hasTG) usetexgather = hasGPU5 && !intel && !nvidia ? 2 : 1;
979 
980     if(glversion >= 430 || hasext("GL_ARB_ES3_compatibility"))
981     {
982         hasES3 = true;
983         if(glversion < 430 && dbgexts) conoutf("\frUsing GL_ARB_ES3_compatibility extension.");
984     }
985 
986     if(glversion >= 430)
987     {
988         glDebugMessageControl_ =  (PFNGLDEBUGMESSAGECONTROLPROC) getprocaddress("glDebugMessageControl");
989         glDebugMessageInsert_ =   (PFNGLDEBUGMESSAGEINSERTPROC)  getprocaddress("glDebugMessageInsert");
990         glDebugMessageCallback_ = (PFNGLDEBUGMESSAGECALLBACKPROC)getprocaddress("glDebugMessageCallback");
991         glGetDebugMessageLog_ =   (PFNGLGETDEBUGMESSAGELOGPROC)  getprocaddress("glGetDebugMessageLog");
992         hasDBGO = true;
993     }
994     else
995     {
996         if(hasext("GL_ARB_debug_output"))
997         {
998             glDebugMessageControl_ =  (PFNGLDEBUGMESSAGECONTROLPROC) getprocaddress("glDebugMessageControlARB");
999             glDebugMessageInsert_ =   (PFNGLDEBUGMESSAGEINSERTPROC)  getprocaddress("glDebugMessageInsertARB");
1000             glDebugMessageCallback_ = (PFNGLDEBUGMESSAGECALLBACKPROC)getprocaddress("glDebugMessageCallbackARB");
1001             glGetDebugMessageLog_ =   (PFNGLGETDEBUGMESSAGELOGPROC)  getprocaddress("glGetDebugMessageLogARB");
1002             hasDBGO = true;
1003             if(dbgexts) conoutf("\frUsing GL_ARB_debug_output extension.");
1004         }
1005     }
1006 
1007     if(glversion >= 430 || hasext("GL_ARB_copy_image"))
1008     {
1009         glCopyImageSubData_ = (PFNGLCOPYIMAGESUBDATAPROC)getprocaddress("glCopyImageSubData");
1010 
1011         hasCI = true;
1012         if(glversion < 430 && dbgexts) conoutf("\frUsing GL_ARB_copy_image extension.");
1013     }
1014     else if(hasext("GL_NV_copy_image"))
1015     {
1016         glCopyImageSubData_ = (PFNGLCOPYIMAGESUBDATAPROC)getprocaddress("glCopyImageSubDataNV");
1017 
1018         hasCI = true;
1019         if(dbgexts) conoutf("\frUsing GL_NV_copy_image extension.");
1020     }
1021 
1022     extern int gdepthstencil, gstencil, glineardepth, msaadepthstencil, msaalineardepth, batchsunlight, smgather, rhrect, tqaaresolvegather;
1023     if(amd || nvidia) msaalineardepth = glineardepth = 1; // reading back from depth-stencil still buggy on newer cards, and requires stencil for MSAA
1024     if(amd)
1025     {
1026         msaadepthstencil = gdepthstencil = 1; // some older AMD GPUs do not support reading from depth-stencil textures, so only use depth-stencil renderbuffer for now
1027         if(checkseries(gfxrenderer, "Radeon HD", 4000, 5199)) amd_pf_bug = 1;
1028         if(glversion < 400)
1029         {
1030             amd_eal_bug = 1; // explicit_attrib_location broken when used with blend_func_extended on legacy Catalyst
1031             rhrect = 1; // bad cpu stalls on Catalyst 13.x when trying to use 3D textures previously bound to FBOs
1032         }
1033     }
1034     else if(nvidia)
1035     {
1036     }
1037     else if(intel)
1038     {
1039         smgather = 1; // native shadow filter is slow
1040         if(mesa)
1041         {
1042             batchsunlight = 0; // causes massive slowdown in linux driver
1043             if(!checkmesaversion(gfxversion, 10, 0, 3))
1044                 mesa_texrectoffset_bug = 1; // mesa i965 driver has buggy textureOffset with texture rectangles
1045             msaalineardepth = 1; // MSAA depth texture access is buggy and resolves are slow
1046         }
1047         else
1048         {
1049             // causes massive slowdown in windows driver if reading depth-stencil texture
1050             if(checkdepthtexstencilrb())
1051             {
1052                 gdepthstencil = 1;
1053                 gstencil = 1;
1054             }
1055             // sampling alpha by itself from a texture generates garbage on Intel drivers on Windows
1056             intel_texalpha_bug = 1;
1057             // MapBufferRange is buggy on older Intel drivers on Windows
1058             if(glversion <= 310) intel_mapbufferrange_bug = 1;
1059         }
1060     }
1061     if(mesa) mesa_swap_bug = 1;
1062     if(hasGPU5 && hasTG) tqaaresolvegather = 1;
1063 }
1064 
1065 ICOMMAND(0, glext, "s", (char *ext), intret(hasext(ext) ? 1 : 0));
1066 
1067 struct timer
1068 {
1069     enum { MAXQUERY = 4 };
1070 
1071     const char *name;
1072     bool gpu;
1073     GLuint query[MAXQUERY];
1074     int waiting;
1075     uint starttime;
1076     float result, print;
1077 };
1078 static vector<timer> timers;
1079 static vector<int> timerorder;
1080 static int timercycle = 0;
1081 
1082 extern int usetimers;
1083 
findtimer(const char * name,bool gpu)1084 timer *findtimer(const char *name, bool gpu)
1085 {
1086     loopv(timers) if(!strcmp(timers[i].name, name) && timers[i].gpu == gpu)
1087     {
1088         timerorder.removeobj(i);
1089         timerorder.add(i);
1090         return &timers[i];
1091     }
1092     timerorder.add(timers.length());
1093     timer &t = timers.add();
1094     t.name = name;
1095     t.gpu = gpu;
1096     memset(t.query, 0, sizeof(t.query));
1097     if(gpu) glGenQueries_(timer::MAXQUERY, t.query);
1098     t.waiting = 0;
1099     t.starttime = 0;
1100     t.result = -1;
1101     t.print = -1;
1102     return &t;
1103 }
1104 
begintimer(const char * name,bool gpu)1105 timer *begintimer(const char *name, bool gpu)
1106 {
1107     if(!usetimers || inbetweenframes || (gpu && (!hasTQ || deferquery))) return NULL;
1108     timer *t = findtimer(name, gpu);
1109     if(t->gpu)
1110     {
1111         deferquery++;
1112         glBeginQuery_(GL_TIME_ELAPSED_EXT, t->query[timercycle]);
1113         t->waiting |= 1<<timercycle;
1114     }
1115     else t->starttime = getclockmillis();
1116     return t;
1117 }
1118 
endtimer(timer * t)1119 void endtimer(timer *t)
1120 {
1121     if(!t) return;
1122     if(t->gpu)
1123     {
1124         glEndQuery_(GL_TIME_ELAPSED_EXT);
1125         deferquery--;
1126     }
1127     else t->result = max(float(getclockmillis() - t->starttime), 0.0f);
1128 }
1129 
synctimers()1130 void synctimers()
1131 {
1132     timercycle = (timercycle + 1) % timer::MAXQUERY;
1133 
1134     loopv(timers)
1135     {
1136         timer &t = timers[i];
1137         if(t.waiting&(1<<timercycle))
1138         {
1139             GLint available = 0;
1140             while(!available)
1141                 glGetQueryObjectiv_(t.query[timercycle], GL_QUERY_RESULT_AVAILABLE, &available);
1142             GLuint64EXT result = 0;
1143             glGetQueryObjectui64v_(t.query[timercycle], GL_QUERY_RESULT, &result);
1144             t.result = max(float(result) * 1e-6f, 0.0f);
1145             t.waiting &= ~(1<<timercycle);
1146         }
1147         else t.result = -1;
1148     }
1149 }
1150 
cleanuptimers()1151 void cleanuptimers()
1152 {
1153     loopv(timers)
1154     {
1155         timer &t = timers[i];
1156         if(t.gpu) glDeleteQueries_(timer::MAXQUERY, t.query);
1157     }
1158     timers.shrink(0);
1159     timerorder.shrink(0);
1160 }
1161 
1162 VARFN(IDF_PERSIST, timer, usetimers, 0, 0, 1, cleanuptimers());
1163 VAR(IDF_PERSIST, frametimer, 0, 0, 1);
1164 int framemillis = 0, lastprint = 0, printmillis = 0; // frame time (ie does not take into account the swap)
1165 
updatetimers()1166 int updatetimers()
1167 {
1168     if(!frametimer && !usetimers) return 0;
1169     if(frametimer && totalmillis-lastprint >= 200) printmillis = framemillis;
1170     if(usetimers) loopv(timerorder)
1171     {
1172         timer &t = timers[timerorder[i]];
1173         if(t.print < 0 ? t.result >= 0 : totalmillis-lastprint >= 200) t.print = t.result;
1174     }
1175     if(totalmillis - lastprint >= 200) lastprint = totalmillis;
1176     return usetimers ? 2 : 1;
1177 }
1178 ICOMMAND(0, updatetimers, "", (), intret(updatetimers()));
1179 
gettimers(int timenum,int prop,int idx)1180 void gettimers(int timenum, int prop, int idx)
1181 {
1182     if(timenum < 0)
1183     {
1184         switch(prop)
1185         {
1186             case -1: intret(usetimers ? timerorder.length() : 0); break;
1187             case 0: intret(lastprint); break;
1188             case 1: intret(printmillis); break;
1189             default: intret(-1); break;
1190         }
1191     }
1192     else if(!usetimers) intret(-1);
1193     else if(timerorder.inrange(timenum))
1194     {
1195         timer &t = timers[timerorder[timenum]];
1196         switch(prop)
1197         {
1198             case -2: intret(t.print < 0 || (t.gpu && !(t.waiting&(1<<timercycle))) ? 1 : 0); break; // skip
1199             case -1: intret(7); break;
1200             case 0: result(t.name); break;
1201             case 1: intret(t.gpu ? 1 : 0); break;
1202             case 2:
1203             {
1204                 if(idx < 0) intret(timer::MAXQUERY);
1205                 else if(idx < timer::MAXQUERY) intret(t.query[idx]);
1206                 break;
1207             }
1208             case 3: intret(t.waiting); break;
1209             case 4: intret(t.starttime); break;
1210             case 5: floatret(t.result); break;
1211             case 6: floatret(t.print); break;
1212             default: intret(-1); break;
1213         }
1214     }
1215 }
1216 ICOMMAND(0, gettimer, "bbb", (int *timenum, int *prop, int *idx), gettimers(*timenum, *prop, *idx));
1217 
gl_resize()1218 void gl_resize()
1219 {
1220     gl_setupframe();
1221     glViewport(0, 0, hudw, hudh);
1222 }
1223 
gl_init()1224 void gl_init()
1225 {
1226     GLERROR;
1227 
1228     glClearColor(0, 0, 0, 0);
1229     glClearDepth(1);
1230     glClearStencil(0);
1231     glDepthFunc(GL_LESS);
1232     glDisable(GL_DEPTH_TEST);
1233     glDisable(GL_STENCIL_TEST);
1234     glStencilFunc(GL_ALWAYS, 0, ~0);
1235     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1236 
1237     glEnable(GL_LINE_SMOOTH);
1238     //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
1239 
1240     glFrontFace(GL_CW);
1241     glCullFace(GL_BACK);
1242     glDisable(GL_CULL_FACE);
1243 
1244     gle::setup();
1245 
1246     setupshaders();
1247     setuptexcompress();
1248 
1249     GLERROR;
1250 
1251     gl_resize();
1252 }
1253 
1254 VAR(0, wireframe, 0, 0, 1);
1255 
1256 ICOMMAND(0, getcamyaw, "", (), floatret(camera1->yaw));
1257 ICOMMAND(0, getcampitch, "", (), floatret(camera1->pitch));
1258 ICOMMAND(0, getcamroll, "", (), floatret(camera1->roll));
1259 ICOMMAND(0, getcampos, "", (),
1260 {
1261     defformatstring(pos, "%s %s %s", floatstr(camera1->o.x), floatstr(camera1->o.y), floatstr(camera1->o.z));
1262     result(pos);
1263 });
1264 
1265 physent camera, *camera1 = &camera;
1266 vec worldpos, camdir, camright, camup;
1267 
findorientation(vec & o,float yaw,float pitch,vec & pos)1268 bool findorientation(vec &o, float yaw, float pitch, vec &pos)
1269 {
1270     vec dir(yaw*RAD, pitch*RAD);
1271     if(raycubepos(o, dir, pos, 0, RAY_CLIPMAT|RAY_SKIPFIRST) == -1)
1272     {
1273         pos = dir.mul(2*worldsize).add(o);
1274         return true;
1275     }
1276     return false;
1277 }
1278 
safefindorientation(vec & o,float yaw,float pitch,vec & pos)1279 void safefindorientation(vec &o, float yaw, float pitch, vec &pos)
1280 {
1281     if(!findorientation(o, yaw, pitch, pos)) pos = vec(yaw*RAD, pitch*RAD).mul(2*worldsize).add(o);
1282 }
1283 
setcammatrix()1284 void setcammatrix()
1285 {
1286     // move from RH to Z-up LH quake style worldspace
1287     cammatrix = viewmatrix;
1288     cammatrix.rotate_around_y(camera1->roll*RAD);
1289     cammatrix.rotate_around_x(camera1->pitch*-RAD);
1290     cammatrix.rotate_around_z(camera1->yaw*-RAD);
1291     cammatrix.translate(vec(camera1->o).neg());
1292 
1293     cammatrix.transposedtransformnormal(vec(viewmatrix.b), camdir);
1294     cammatrix.transposedtransformnormal(vec(viewmatrix.a).neg(), camright);
1295     cammatrix.transposedtransformnormal(vec(viewmatrix.c), camup);
1296     #if 0
1297     if(!drawtex)
1298     {
1299         if(raycubepos(camera1->o, camdir, worldpos, 0, RAY_CLIPMAT|RAY_SKIPFIRST) == -1)
1300             worldpos = vec(camdir).mul(2*worldsize).add(camera1->o); // if nothing is hit, just far away in the view direction
1301     }
1302     #endif
1303 }
1304 
setcamprojmatrix(bool init=true,bool flush=false)1305 void setcamprojmatrix(bool init = true, bool flush = false)
1306 {
1307     if(init)
1308     {
1309         setcammatrix();
1310     }
1311 
1312     jitteraa();
1313 
1314     camprojmatrix.muld(projmatrix, cammatrix);
1315 
1316     if(init)
1317     {
1318         invcammatrix.invert(cammatrix);
1319         invprojmatrix.invert(projmatrix);
1320         invcamprojmatrix.invert(camprojmatrix);
1321     }
1322 
1323     GLOBALPARAM(camprojmatrix, camprojmatrix);
1324     GLOBALPARAM(lineardepthscale, projmatrix.lineardepthscale()); //(invprojmatrix.c.z, invprojmatrix.d.z));
1325 
1326     if(flush && Shader::lastshader) Shader::lastshader->flushparams();
1327 }
1328 
1329 matrix4 hudmatrix, hudmatrixstack[64];
1330 int hudmatrixpos = 0;
1331 
resethudmatrix()1332 void resethudmatrix()
1333 {
1334     hudmatrixpos = 0;
1335     GLOBALPARAM(hudmatrix, hudmatrix);
1336 }
1337 
pushhudmatrix()1338 void pushhudmatrix()
1339 {
1340     if(hudmatrixpos >= 0 && hudmatrixpos < int(sizeof(hudmatrixstack)/sizeof(hudmatrixstack[0]))) hudmatrixstack[hudmatrixpos] = hudmatrix;
1341     ++hudmatrixpos;
1342 }
1343 
flushhudmatrix(bool flushparams)1344 void flushhudmatrix(bool flushparams)
1345 {
1346     GLOBALPARAM(hudmatrix, hudmatrix);
1347     if(flushparams && Shader::lastshader) Shader::lastshader->flushparams();
1348 }
1349 
pophudmatrix(bool flush,bool flushparams)1350 void pophudmatrix(bool flush, bool flushparams)
1351 {
1352     --hudmatrixpos;
1353     if(hudmatrixpos >= 0 && hudmatrixpos < int(sizeof(hudmatrixstack)/sizeof(hudmatrixstack[0])))
1354     {
1355         hudmatrix = hudmatrixstack[hudmatrixpos];
1356         if(flush) flushhudmatrix(flushparams);
1357     }
1358 }
1359 
pushhudscale(float sx,float sy)1360 void pushhudscale(float sx, float sy)
1361 {
1362     if(!sy) sy = sx;
1363     pushhudmatrix();
1364     hudmatrix.scale(sx, sy, 1);
1365     flushhudmatrix();
1366 }
1367 
pushhudtranslate(float tx,float ty,float sx,float sy)1368 void pushhudtranslate(float tx, float ty, float sx, float sy)
1369 {
1370     if(!sy) sy = sx;
1371     pushhudmatrix();
1372     hudmatrix.translate(tx, ty, 0);
1373     if(sy) hudmatrix.scale(sx, sy, 1);
1374     flushhudmatrix();
1375 }
1376 
1377 int vieww = -1, viewh = -1, farplane;
1378 float curfov = 100, fovy = 100, aspect = 1, cursorx = 0.5f, cursory = 0.5f;
1379 vec cursordir(0, 0, 0);
1380 FVARN(IDF_PERSIST, aspect, forceaspect, 0, 0, 1e3f);
1381 
vecfromcursor(float x,float y,float z,vec & dir)1382 void vecfromcursor(float x, float y, float z, vec &dir)
1383 {
1384     vec dir1 = invcamprojmatrix.perspectivetransform(vec(x*2-1, 1-2*y, z*2-1)),
1385         dir2 = invcamprojmatrix.perspectivetransform(vec(x*2-1, 1-2*y, -1));
1386     (dir = dir1).sub(dir2).normalize();
1387 }
1388 
vectocursor(const vec & v,float & x,float & y,float & z,float clampxy)1389 bool vectocursor(const vec &v, float &x, float &y, float &z, float clampxy)
1390 {
1391     vec4 clippos;
1392     camprojmatrix.transform(v, clippos);
1393     if(clippos.z <= -clippos.w)
1394     {
1395         x = y = z = 0;
1396         return false;
1397     }
1398 
1399     vec screenpos = vec(clippos).div(clippos.w);
1400     x = screenpos.x*0.5f + 0.5f;
1401     y = 0.5f - screenpos.y*0.5f;
1402     z = screenpos.z*0.5f + 0.5f;
1403 
1404     bool inside = true;
1405     if(clampxy >= 0)
1406     {
1407         if(x <= 0-clampxy) { y += (0-clampxy-x)*(0.5-y)/(0.5-x); x = 0-clampxy; inside = false; }
1408         else if(x >= 1+clampxy) { y += (1+clampxy-x)*(0.5-y)/(0.5-x); x = 1+clampxy; inside = false; }
1409         if(y <= 0-clampxy) { x += (0-clampxy-y)*(0.5-x)/(0.5-y); y = 0-clampxy; inside = false; }
1410         else if(y >= 1+clampxy) { x += (1+clampxy-y)*(0.5-x)/(0.5-y); y = 1+clampxy; inside = false; }
1411     }
1412     if(z <= 0) { z = 0; inside = false; }
1413     else if(z >= 1) { z = 1; inside = false; }
1414     return inside;
1415 }
1416 
calcfrustumboundsphere(float nearplane,float farplane,const vec & pos,const vec & view,vec & center)1417 float calcfrustumboundsphere(float nearplane, float farplane, const vec &pos, const vec &view, vec &center)
1418 {
1419     if(drawtex == DRAWTEX_MINIMAP)
1420     {
1421         center = minimapcenter;
1422         return minimapradius.magnitude();
1423     }
1424 
1425     float width = tan(curfov/2.0f*RAD), height = width / aspect,
1426           cdist = ((nearplane + farplane)/2)*(1 + width*width + height*height);
1427     if(cdist <= farplane)
1428     {
1429         center = vec(view).mul(cdist).add(pos);
1430         return vec(width*nearplane, height*nearplane, cdist-nearplane).magnitude();
1431     }
1432     else
1433     {
1434         center = vec(view).mul(farplane).add(pos);
1435         return vec(width*farplane, height*farplane, 0).magnitude();
1436     }
1437 }
1438 
1439 extern const matrix4 viewmatrix(vec(-1, 0, 0), vec(0, 0, 1), vec(0, -1, 0));
1440 extern const matrix4 invviewmatrix(vec(-1, 0, 0), vec(0, 0, -1), vec(0, 1, 0));
1441 matrix4 cammatrix, projmatrix, camprojmatrix, invcammatrix, invcamprojmatrix, invprojmatrix;
1442 
1443 FVAR(0, nearplane, 0.01f, 0.54f, 2.0f);
1444 
setavatarscale(float fov,float zscale)1445 void setavatarscale(float fov, float zscale)
1446 {
1447     projmatrix.perspective(fov, aspect, nearplane, farplane);
1448     projmatrix.scalez(zscale);
1449     setcamprojmatrix(false);
1450 }
1451 
renderavatar()1452 void renderavatar()
1453 {
1454     matrix4 oldprojmatrix = nojittermatrix;
1455 
1456     enableavatarmask();
1457     game::renderavatar();
1458     disableavatarmask();
1459 
1460     projmatrix = oldprojmatrix;
1461     setcamprojmatrix(false);
1462 }
1463 
1464 FVAR(0, polygonoffsetfactor, -1e4f, -3.0f, 1e4f);
1465 FVAR(0, polygonoffsetunits, -1e4f, -3.0f, 1e4f);
1466 FVAR(0, depthoffset, -1e4f, 0.01f, 1e4f);
1467 
1468 matrix4 nooffsetmatrix;
1469 
enablepolygonoffset(GLenum type)1470 void enablepolygonoffset(GLenum type)
1471 {
1472     if(!depthoffset)
1473     {
1474         glPolygonOffset(polygonoffsetfactor, polygonoffsetunits);
1475         glEnable(type);
1476         return;
1477     }
1478 
1479     projmatrix = nojittermatrix;
1480     nooffsetmatrix = projmatrix;
1481     projmatrix.d.z += depthoffset * projmatrix.c.z;
1482     setcamprojmatrix(false, true);
1483 }
1484 
disablepolygonoffset(GLenum type)1485 void disablepolygonoffset(GLenum type)
1486 {
1487     if(!depthoffset)
1488     {
1489         glDisable(type);
1490         return;
1491     }
1492 
1493     projmatrix = nooffsetmatrix;
1494     setcamprojmatrix(false, true);
1495 }
1496 
calcspherescissor(const vec & center,float size,float & sx1,float & sy1,float & sx2,float & sy2,float & sz1,float & sz2)1497 bool calcspherescissor(const vec &center, float size, float &sx1, float &sy1, float &sx2, float &sy2, float &sz1, float &sz2)
1498 {
1499     vec e;
1500     cammatrix.transform(center, e);
1501     if(e.z > 2*size) { sx1 = sy1 = sz1 = 1; sx2 = sy2 = sz2 = -1; return false; }
1502     if(drawtex == DRAWTEX_MINIMAP)
1503     {
1504         vec dir(size, size, size);
1505         if(projmatrix.a.x < 0) dir.x = -dir.x;
1506         if(projmatrix.b.y < 0) dir.y = -dir.y;
1507         if(projmatrix.c.z < 0) dir.z = -dir.z;
1508         sx1 = max(projmatrix.a.x*(e.x - dir.x) + projmatrix.d.x, -1.0f);
1509         sx2 = min(projmatrix.a.x*(e.x + dir.x) + projmatrix.d.x, 1.0f);
1510         sy1 = max(projmatrix.b.y*(e.y - dir.y) + projmatrix.d.y, -1.0f);
1511         sy2 = min(projmatrix.b.y*(e.y + dir.y) + projmatrix.d.y, 1.0f);
1512         sz1 = max(projmatrix.c.z*(e.z - dir.z) + projmatrix.d.z, -1.0f);
1513         sz2 = min(projmatrix.c.z*(e.z + dir.z) + projmatrix.d.z, 1.0f);
1514         return sx1 < sx2 && sy1 < sy2 && sz1 < sz2;
1515     }
1516     float zzrr = e.z*e.z - size*size,
1517           dx = e.x*e.x + zzrr, dy = e.y*e.y + zzrr,
1518           focaldist = 1.0f/tan(fovy*0.5f*RAD);
1519     sx1 = sy1 = -1;
1520     sx2 = sy2 = 1;
1521     #define CHECKPLANE(c, dir, focaldist, low, high) \
1522     do { \
1523         float nzc = (cz*cz + 1) / (cz dir drt) - cz, \
1524               pz = (d##c)/(nzc*e.c - e.z); \
1525         if(pz > 0) \
1526         { \
1527             float c = (focaldist)*nzc, \
1528                   pc = pz*nzc; \
1529             if(pc < e.c) low = c; \
1530             else if(pc > e.c) high = c; \
1531         } \
1532     } while(0)
1533     if(dx > 0)
1534     {
1535         float cz = e.x/e.z, drt = sqrtf(dx)/size;
1536         CHECKPLANE(x, -, focaldist/aspect, sx1, sx2);
1537         CHECKPLANE(x, +, focaldist/aspect, sx1, sx2);
1538     }
1539     if(dy > 0)
1540     {
1541         float cz = e.y/e.z, drt = sqrtf(dy)/size;
1542         CHECKPLANE(y, -, focaldist, sy1, sy2);
1543         CHECKPLANE(y, +, focaldist, sy1, sy2);
1544     }
1545     float z1 = min(e.z + size, -1e-3f - nearplane), z2 = min(e.z - size, -1e-3f - nearplane);
1546     sz1 = (z1*projmatrix.c.z + projmatrix.d.z) / (z1*projmatrix.c.w + projmatrix.d.w);
1547     sz2 = (z2*projmatrix.c.z + projmatrix.d.z) / (z2*projmatrix.c.w + projmatrix.d.w);
1548     return sx1 < sx2 && sy1 < sy2 && sz1 < sz2;
1549 }
1550 
calcbbscissor(const ivec & bbmin,const ivec & bbmax,float & sx1,float & sy1,float & sx2,float & sy2)1551 bool calcbbscissor(const ivec &bbmin, const ivec &bbmax, float &sx1, float &sy1, float &sx2, float &sy2)
1552 {
1553 #define ADDXYSCISSOR(p) do { \
1554         if(p.z >= -p.w) \
1555         { \
1556             float x = p.x / p.w, y = p.y / p.w; \
1557             sx1 = min(sx1, x); \
1558             sy1 = min(sy1, y); \
1559             sx2 = max(sx2, x); \
1560             sy2 = max(sy2, y); \
1561         } \
1562     } while(0)
1563     vec4 v[8];
1564     sx1 = sy1 = 1;
1565     sx2 = sy2 = -1;
1566     camprojmatrix.transform(vec(bbmin.x, bbmin.y, bbmin.z), v[0]);
1567     ADDXYSCISSOR(v[0]);
1568     camprojmatrix.transform(vec(bbmax.x, bbmin.y, bbmin.z), v[1]);
1569     ADDXYSCISSOR(v[1]);
1570     camprojmatrix.transform(vec(bbmin.x, bbmax.y, bbmin.z), v[2]);
1571     ADDXYSCISSOR(v[2]);
1572     camprojmatrix.transform(vec(bbmax.x, bbmax.y, bbmin.z), v[3]);
1573     ADDXYSCISSOR(v[3]);
1574     camprojmatrix.transform(vec(bbmin.x, bbmin.y, bbmax.z), v[4]);
1575     ADDXYSCISSOR(v[4]);
1576     camprojmatrix.transform(vec(bbmax.x, bbmin.y, bbmax.z), v[5]);
1577     ADDXYSCISSOR(v[5]);
1578     camprojmatrix.transform(vec(bbmin.x, bbmax.y, bbmax.z), v[6]);
1579     ADDXYSCISSOR(v[6]);
1580     camprojmatrix.transform(vec(bbmax.x, bbmax.y, bbmax.z), v[7]);
1581     ADDXYSCISSOR(v[7]);
1582     if(sx1 > sx2 || sy1 > sy2) return false;
1583     loopi(8)
1584     {
1585         const vec4 &p = v[i];
1586         if(p.z >= -p.w) continue;
1587         loopj(3)
1588         {
1589             const vec4 &o = v[i^(1<<j)];
1590             if(o.z <= -o.w) continue;
1591 #define INTERPXYSCISSOR(p, o) do { \
1592             float t = (p.z + p.w)/(p.z + p.w - o.z - o.w), \
1593                   w = p.w + t*(o.w - p.w), \
1594                   x = (p.x + t*(o.x - p.x))/w, \
1595                   y = (p.y + t*(o.y - p.y))/w; \
1596             sx1 = min(sx1, x); \
1597             sy1 = min(sy1, y); \
1598             sx2 = max(sx2, x); \
1599             sy2 = max(sy2, y); \
1600         } while(0)
1601             INTERPXYSCISSOR(p, o);
1602         }
1603     }
1604     sx1 = max(sx1, -1.0f);
1605     sy1 = max(sy1, -1.0f);
1606     sx2 = min(sx2, 1.0f);
1607     sy2 = min(sy2, 1.0f);
1608     return true;
1609 }
1610 
calcspotscissor(const vec & origin,float radius,const vec & dir,int spot,const vec & spotx,const vec & spoty,float & sx1,float & sy1,float & sx2,float & sy2,float & sz1,float & sz2)1611 bool calcspotscissor(const vec &origin, float radius, const vec &dir, int spot, const vec &spotx, const vec &spoty, float &sx1, float &sy1, float &sx2, float &sy2, float &sz1, float &sz2)
1612 {
1613     float spotscale = radius * tan360(spot);
1614     vec up = vec(spotx).mul(spotscale), right = vec(spoty).mul(spotscale), center = vec(dir).mul(radius).add(origin);
1615 #define ADDXYZSCISSOR(p) do { \
1616         if(p.z >= -p.w) \
1617         { \
1618             float x = p.x / p.w, y = p.y / p.w, z = p.z / p.w; \
1619             sx1 = min(sx1, x); \
1620             sy1 = min(sy1, y); \
1621             sz1 = min(sz1, z); \
1622             sx2 = max(sx2, x); \
1623             sy2 = max(sy2, y); \
1624             sz2 = max(sz2, z); \
1625         } \
1626     } while(0)
1627     vec4 v[5];
1628     sx1 = sy1 = sz1 = 1;
1629     sx2 = sy2 = sz2 = -1;
1630     camprojmatrix.transform(vec(center).sub(right).sub(up), v[0]);
1631     ADDXYZSCISSOR(v[0]);
1632     camprojmatrix.transform(vec(center).add(right).sub(up), v[1]);
1633     ADDXYZSCISSOR(v[1]);
1634     camprojmatrix.transform(vec(center).sub(right).add(up), v[2]);
1635     ADDXYZSCISSOR(v[2]);
1636     camprojmatrix.transform(vec(center).add(right).add(up), v[3]);
1637     ADDXYZSCISSOR(v[3]);
1638     camprojmatrix.transform(origin, v[4]);
1639     ADDXYZSCISSOR(v[4]);
1640     if(sx1 > sx2 || sy1 > sy2 || sz1 > sz2) return false;
1641     loopi(4)
1642     {
1643         const vec4 &p = v[i];
1644         if(p.z >= -p.w) continue;
1645         loopj(2)
1646         {
1647             const vec4 &o = v[i^(1<<j)];
1648             if(o.z <= -o.w) continue;
1649 #define INTERPXYZSCISSOR(p, o) do { \
1650             float t = (p.z + p.w)/(p.z + p.w - o.z - o.w), \
1651                   w = p.w + t*(o.w - p.w), \
1652                   x = (p.x + t*(o.x - p.x))/w, \
1653                   y = (p.y + t*(o.y - p.y))/w; \
1654             sx1 = min(sx1, x); \
1655             sy1 = min(sy1, y); \
1656             sz1 = min(sz1, -1.0f); \
1657             sx2 = max(sx2, x); \
1658             sy2 = max(sy2, y); \
1659         } while(0)
1660             INTERPXYZSCISSOR(p, o);
1661         }
1662         if(v[4].z > -v[4].w) INTERPXYZSCISSOR(p, v[4]);
1663     }
1664     if(v[4].z < -v[4].w) loopj(4)
1665     {
1666         const vec4 &o = v[j];
1667         if(o.z <= -o.w) continue;
1668         INTERPXYZSCISSOR(v[4], o);
1669     }
1670     sx1 = max(sx1, -1.0f);
1671     sy1 = max(sy1, -1.0f);
1672     sz1 = max(sz1, -1.0f);
1673     sx2 = min(sx2, 1.0f);
1674     sy2 = min(sy2, 1.0f);
1675     sz2 = min(sz2, 1.0f);
1676     return true;
1677 }
1678 
1679 static GLuint screenquadvbo = 0;
1680 
setupscreenquad()1681 static void setupscreenquad()
1682 {
1683     if(!screenquadvbo)
1684     {
1685         glGenBuffers_(1, &screenquadvbo);
1686         gle::bindvbo(screenquadvbo);
1687         vec2 verts[4] = { vec2(1, -1), vec2(-1, -1), vec2(1, 1), vec2(-1, 1) };
1688         glBufferData_(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
1689         gle::clearvbo();
1690     }
1691 }
1692 
cleanupscreenquad()1693 static void cleanupscreenquad()
1694 {
1695     if(screenquadvbo) { glDeleteBuffers_(1, &screenquadvbo); screenquadvbo = 0; }
1696 }
1697 
screenquad()1698 void screenquad()
1699 {
1700     setupscreenquad();
1701     gle::bindvbo(screenquadvbo);
1702     gle::enablevertex();
1703     gle::vertexpointer(sizeof(vec2), (const vec2 *)0, GL_FLOAT, 2);
1704     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1705     gle::disablevertex();
1706     gle::clearvbo();
1707 }
1708 
1709 static LocalShaderParam screentexcoord[2] = { LocalShaderParam("screentexcoord0"), LocalShaderParam("screentexcoord1") };
1710 
setscreentexcoord(int i,float w,float h,float x=0,float y=0)1711 static inline void setscreentexcoord(int i, float w, float h, float x = 0, float y = 0)
1712 {
1713     screentexcoord[i].setf(w*0.5f, h*0.5f, x + w*0.5f, y + fabs(h)*0.5f);
1714 }
1715 
screenquad(float sw,float sh)1716 void screenquad(float sw, float sh)
1717 {
1718     setscreentexcoord(0, sw, sh);
1719     screenquad();
1720 }
1721 
screenquadflipped(float sw,float sh)1722 void screenquadflipped(float sw, float sh)
1723 {
1724     setscreentexcoord(0, sw, -sh);
1725     screenquad();
1726 }
1727 
screenquad(float sw,float sh,float sw2,float sh2)1728 void screenquad(float sw, float sh, float sw2, float sh2)
1729 {
1730     setscreentexcoord(0, sw, sh);
1731     setscreentexcoord(1, sw2, sh2);
1732     screenquad();
1733 }
1734 
screenquadoffset(float x,float y,float w,float h)1735 void screenquadoffset(float x, float y, float w, float h)
1736 {
1737     setscreentexcoord(0, w, h, x, y);
1738     screenquad();
1739 }
1740 
screenquadoffset(float x,float y,float w,float h,float x2,float y2,float w2,float h2)1741 void screenquadoffset(float x, float y, float w, float h, float x2, float y2, float w2, float h2)
1742 {
1743     setscreentexcoord(0, w, h, x, y);
1744     setscreentexcoord(1, w2, h2, x2, y2);
1745     screenquad();
1746 }
1747 
1748 #define HUDQUAD(x1, y1, x2, y2, sx1, sy1, sx2, sy2) { \
1749     gle::defvertex(2); \
1750     gle::deftexcoord0(); \
1751     gle::begin(GL_TRIANGLE_STRIP); \
1752     gle::attribf(x2, y1); gle::attribf(sx2, sy1); \
1753     gle::attribf(x1, y1); gle::attribf(sx1, sy1); \
1754     gle::attribf(x2, y2); gle::attribf(sx2, sy2); \
1755     gle::attribf(x1, y2); gle::attribf(sx1, sy2); \
1756     gle::end(); \
1757 }
1758 
hudquad(float x,float y,float w,float h,float tx,float ty,float tw,float th)1759 void hudquad(float x, float y, float w, float h, float tx, float ty, float tw, float th)
1760 {
1761     HUDQUAD(x, y, x+w, y+h, tx, ty, tx+tw, ty+th);
1762 }
1763 
debugquad(float x,float y,float w,float h,float tx,float ty,float tw,float th)1764 void debugquad(float x, float y, float w, float h, float tx, float ty, float tw, float th)
1765 {
1766     HUDQUAD(x, y, x+w, y+h, tx, ty+th, tx+tw, ty);
1767 }
1768 
1769 VAR(0, fogoverlay, 0, 1, 1);
1770 
findsurface(int fogmat,const vec & v,int & abovemat)1771 static float findsurface(int fogmat, const vec &v, int &abovemat)
1772 {
1773     fogmat &= MATF_VOLUME;
1774     ivec o(v), co;
1775     int csize;
1776     do
1777     {
1778         cube &c = lookupcube(o, 0, co, csize);
1779         int mat = c.material&MATF_VOLUME;
1780         if(mat != fogmat)
1781         {
1782             abovemat = isliquid(mat) ? c.material : MAT_AIR;
1783             return o.z;
1784         }
1785         o.z = co.z + csize;
1786     }
1787     while(o.z < worldsize);
1788     abovemat = MAT_AIR;
1789     return worldsize;
1790 }
1791 
getcamfogmat(int & fogmat,int & abovemat,float & fogbelow)1792 static void getcamfogmat(int &fogmat, int &abovemat, float &fogbelow)
1793 {
1794     float fogmargin = 1 + WATER_AMPLITUDE + nearplane;
1795     abovemat = MAT_AIR;
1796     fogmat = lookupmaterial(vec(camera1->o.x, camera1->o.y, camera1->o.z - fogmargin))&(MATF_VOLUME|MATF_INDEX), abovemat = MAT_AIR;
1797     fogbelow = 0;
1798     if(isliquid(fogmat&MATF_VOLUME))
1799     {
1800         float z = findsurface(fogmat, vec(camera1->o.x, camera1->o.y, camera1->o.z - fogmargin), abovemat) - WATER_OFFSET;
1801         if(camera1->o.z < z + fogmargin)
1802         {
1803             fogbelow = z - camera1->o.z;
1804         }
1805         else fogmat = abovemat;
1806     }
1807     else fogmat = MAT_AIR;
1808 }
1809 
getmatfog(int fogmat,float & start,float & end)1810 static void getmatfog(int fogmat, float &start, float &end)
1811 {
1812     start = 0;
1813 
1814     switch(fogmat&MATF_VOLUME)
1815     {
1816         case MAT_WATER:
1817             end = getwaterfog(fogmat);
1818             break;
1819 
1820         case MAT_LAVA:
1821             end = getlavafog(fogmat);
1822             break;
1823 
1824         default:
1825             start = (getfog()+64)/8;
1826             end = getfog();
1827             break;
1828     }
1829 }
1830 
blendfog(int fogmat,float below,float blend,float logblend,float & start,float & end,vec & fogc)1831 static void blendfog(int fogmat, float below, float blend, float logblend, float &start, float &end, vec &fogc)
1832 {
1833     float matstart = 0, matend = 0;
1834 
1835     getmatfog(fogmat, start, end);
1836 
1837     switch(fogmat&MATF_VOLUME)
1838     {
1839         case MAT_WATER:
1840         {
1841             const bvec &wcol = getwatercolour(fogmat), &wdeepcol = getwaterdeepcolour(fogmat);
1842             float wdeep = getwaterdeep(fogmat);
1843             float deepfade = clamp(below/max(wdeep, matend), 0.0f, 1.0f);
1844             vec color;
1845             color.lerp(wcol.tocolor(), wdeepcol.tocolor(), deepfade);
1846             fogc.add(vec(color).mul(blend));
1847             end += logblend*min((float)getfog(), max(matend*2, 16.0f));
1848             break;
1849         }
1850 
1851         case MAT_LAVA:
1852         {
1853             const bvec &lcol = getlavacolour(fogmat);
1854             fogc.add(lcol.tocolor().mul(blend));
1855             end += logblend*min((float)getfog(), max(matend*2, 16.0f));
1856             break;
1857         }
1858 
1859         default:
1860             fogc.add(getfogcolour().tocolor().mul(blend));
1861             start += logblend*matstart;
1862             end += logblend*matend;
1863             break;
1864     }
1865 }
1866 
1867 vec curfogcolor(0, 0, 0);
1868 
setfogcolor(const vec & v)1869 void setfogcolor(const vec &v)
1870 {
1871     GLOBALPARAM(fogcolor, v);
1872 }
1873 
zerofogcolor()1874 void zerofogcolor()
1875 {
1876     setfogcolor(vec(0, 0, 0));
1877 }
1878 
resetfogcolor()1879 void resetfogcolor()
1880 {
1881     setfogcolor(curfogcolor);
1882 }
1883 
1884 FVAR(0, fogintensity, 0, 0.15f, 1);
1885 
calcfogdensity(float dist)1886 float calcfogdensity(float dist)
1887 {
1888     return log(fogintensity)/(M_LN2*dist);
1889 }
1890 
1891 FVAR(0, fogcullintensity, 0, 1e-3f, 1);
1892 
calcfogcull()1893 float calcfogcull()
1894 {
1895     int fogmat, abovemat;
1896     float below, start, end, startabove, endabove;
1897 
1898     getcamfogmat(fogmat, abovemat, below);
1899     getmatfog(fogmat, start, end);
1900     getmatfog(abovemat, startabove, endabove);
1901 
1902     float fogdepth = end > endabove ? (end - start) : (endabove - startabove);
1903 
1904     return log(fogcullintensity) / (M_LN2*calcfogdensity(fogdepth));
1905 }
1906 
setfog(int fogmat,float below=0,float blend=1,int abovemat=MAT_AIR)1907 static void setfog(int fogmat, float below = 0, float blend = 1, int abovemat = MAT_AIR)
1908 {
1909     float start = 0, end = 0;
1910     float logscale = 256, logblend = log(1 + (logscale - 1)*blend) / log(logscale);
1911 
1912     curfogcolor = vec(0, 0, 0);
1913     blendfog(fogmat, below, blend, logblend, start, end, curfogcolor);
1914     if(blend < 1) blendfog(abovemat, 0, 1-blend, 1-logblend, start, end, curfogcolor);
1915     curfogcolor.mul(ldrscale);
1916 
1917     GLOBALPARAM(fogcolor, curfogcolor);
1918 
1919     float fogdensity = calcfogdensity(end-start);
1920     GLOBALPARAMF(fogdensity, fogdensity, 1/exp(M_LN2*start*fogdensity));
1921 }
1922 
blendfogoverlay(int fogmat,float below,float blend,vec & overlay)1923 static void blendfogoverlay(int fogmat, float below, float blend, vec &overlay)
1924 {
1925     float maxc;
1926     switch(fogmat&MATF_VOLUME)
1927     {
1928         case MAT_WATER:
1929         {
1930             const bvec &wcol = getwatercolour(fogmat), &wdeepcol = getwaterdeepcolour(fogmat);
1931             int wfog = getwaterfog(fogmat), wdeep = getwaterdeep(fogmat);
1932             float deepfade = clamp(below/max(wdeep, wfog), 0.0f, 1.0f);
1933             vec color = vec(wcol.r, wcol.g, wcol.b).lerp(vec(wdeepcol.r, wdeepcol.g, wdeepcol.b), deepfade);
1934             overlay.add(color.div(min(32.0f + max(color.r, max(color.g, color.b))*7.0f/8.0f, 255.0f)).max(0.4f).mul(blend));
1935             break;
1936         }
1937 
1938         case MAT_LAVA:
1939         {
1940             const bvec &lcol = getlavacolour(fogmat);
1941             maxc = max(lcol.r, max(lcol.g, lcol.b));
1942             overlay.add(vec(lcol.r, lcol.g, lcol.b).div(min(32.0f + maxc*7.0f/8.0f, 255.0f)).max(0.4f).mul(blend));
1943             break;
1944         }
1945 
1946         default:
1947             overlay.add(blend);
1948             break;
1949     }
1950 }
1951 
drawfogoverlay(int fogmat,float fogbelow,float fogblend,int abovemat)1952 void drawfogoverlay(int fogmat, float fogbelow, float fogblend, int abovemat)
1953 {
1954     SETSHADER(fogoverlay);
1955 
1956     glEnable(GL_BLEND);
1957     glBlendFunc(GL_ZERO, GL_SRC_COLOR);
1958     vec overlay(0, 0, 0);
1959     blendfogoverlay(fogmat, fogbelow, fogblend, overlay);
1960     blendfogoverlay(abovemat, 0, 1-fogblend, overlay);
1961 
1962     gle::color(overlay);
1963     screenquad();
1964 
1965     glDisable(GL_BLEND);
1966 }
1967 
1968 int drawtex = 0;
1969 
1970 GLuint minimaptex = 0;
1971 vec minimapcenter(0, 0, 0), minimapradius(0, 0, 0), minimapscale(0, 0, 0);
1972 
clearminimap()1973 void clearminimap()
1974 {
1975     if(minimaptex) { glDeleteTextures(1, &minimaptex); minimaptex = 0; }
1976 }
1977 
1978 VAR(IDF_WORLD, minimapheight, 0, 0, 2<<16);
1979 CVAR0(IDF_WORLD, minimapcolour, 0);
1980 VAR(IDF_WORLD, minimapclip, 0, 0, 1);
1981 VARF(IDF_PERSIST, minimapsize, 7, 8, 10, { if(minimaptex) drawminimap(); });
1982 CVARF(IDF_PERSIST, nominimapcolour, 0x101010, { if(minimaptex) drawminimap(); });
1983 
bindminimap()1984 void bindminimap()
1985 {
1986     glBindTexture(GL_TEXTURE_2D, minimaptex);
1987 }
1988 
clipminimap(ivec & bbmin,ivec & bbmax,cube * c=worldroot,const ivec & co=ivec (0,0,0),int size=worldsize>>1)1989 void clipminimap(ivec &bbmin, ivec &bbmax, cube *c = worldroot, const ivec &co = ivec(0, 0, 0), int size = worldsize>>1)
1990 {
1991     loopi(8)
1992     {
1993         ivec o(i, co, size);
1994         if(c[i].children) clipminimap(bbmin, bbmax, c[i].children, o, size>>1);
1995         else if(!isentirelysolid(c[i]) && (c[i].material&MATF_CLIP)!=MAT_CLIP)
1996         {
1997             loopk(3) bbmin[k] = min(bbmin[k], o[k]);
1998             loopk(3) bbmax[k] = max(bbmax[k], o[k] + size);
1999         }
2000     }
2001 }
2002 
drawminimap()2003 void drawminimap()
2004 {
2005     if(!hud::needminimap()) { clearminimap(); return; }
2006 
2007     GLERROR;
2008     progress(0, "Generating mini-map...");
2009 
2010     drawtex = DRAWTEX_MINIMAP;
2011 
2012     GLERROR;
2013     gl_setupframe(true);
2014 
2015     int size = 1<<minimapsize, sizelimit = min(hwtexsize, min(gw, gh));
2016     while(size > sizelimit) size /= 2;
2017     if(!minimaptex) glGenTextures(1, &minimaptex);
2018 
2019     ivec bbmin(worldsize, worldsize, worldsize), bbmax(0, 0, 0);
2020     loopv(valist)
2021     {
2022         vtxarray *va = valist[i];
2023         loopk(3)
2024         {
2025             if(va->geommin[k]>va->geommax[k]) continue;
2026             bbmin[k] = min(bbmin[k], va->geommin[k]);
2027             bbmax[k] = max(bbmax[k], va->geommax[k]);
2028         }
2029     }
2030     if(minimapclip)
2031     {
2032         ivec clipmin(worldsize, worldsize, worldsize), clipmax(0, 0, 0);
2033         clipminimap(clipmin, clipmax);
2034         loopk(2) bbmin[k] = max(bbmin[k], clipmin[k]);
2035         loopk(2) bbmax[k] = min(bbmax[k], clipmax[k]);
2036     }
2037 
2038     minimapradius = vec(bbmax).sub(vec(bbmin)).mul(0.5f);
2039     minimapcenter = vec(bbmin).add(minimapradius);
2040     minimapradius.x = minimapradius.y = max(minimapradius.x, minimapradius.y);
2041     minimapscale = vec((0.5f - 1.0f/size)/minimapradius.x, (0.5f - 1.0f/size)/minimapradius.y, 1.0f);
2042 
2043     physent *oldcamera = camera1;
2044     static physent cmcamera;
2045     cmcamera = *camera1;
2046     cmcamera.reset();
2047     cmcamera.type = ENT_CAMERA;
2048     cmcamera.o = vec(minimapcenter.x, minimapcenter.y, minimapheight > 0 ? minimapheight : minimapcenter.z + minimapradius.z + 1);
2049     cmcamera.yaw = 0;
2050     cmcamera.pitch = -90;
2051     cmcamera.roll = 0;
2052     camera1 = &cmcamera;
2053     setviewcell(vec(-1, -1, -1));
2054 
2055     float oldldrscale = ldrscale, oldldrscaleb = ldrscaleb;
2056     int oldfarplane = farplane, oldvieww = vieww, oldviewh = viewh;
2057     farplane = worldsize*2;
2058     vieww = viewh = size;
2059 
2060     float zscale = max(float(minimapheight), minimapcenter.z + minimapradius.z + 1) + 1;
2061 
2062     projmatrix.ortho(-minimapradius.x, minimapradius.x, -minimapradius.y, minimapradius.y, 0, 2*zscale);
2063     setcamprojmatrix();
2064 
2065     glEnable(GL_CULL_FACE);
2066     glEnable(GL_DEPTH_TEST);
2067 
2068     xtravertsva = xtraverts = glde = gbatches = vtris = vverts = 0;
2069     flipqueries();
2070 
2071     ldrscale = 1;
2072     ldrscaleb = ldrscale/255;
2073 
2074     visiblecubes(false);
2075 
2076     rendergbuffer();
2077 
2078     rendershadowatlas();
2079 
2080     shademinimap(minimapcolour.tocolor().mul(ldrscale));
2081 
2082     if(minimapheight > 0 && minimapheight < minimapcenter.z + minimapradius.z)
2083     {
2084         camera1->o.z = minimapcenter.z + minimapradius.z + 1;
2085         projmatrix.ortho(-minimapradius.x, minimapradius.x, -minimapradius.y, minimapradius.y, -zscale, zscale);
2086         setcamprojmatrix();
2087         rendergbuffer(false);
2088         shademinimap();
2089     }
2090 
2091     glDisable(GL_DEPTH_TEST);
2092     glDisable(GL_CULL_FACE);
2093 
2094     farplane = oldfarplane;
2095     vieww = oldvieww;
2096     viewh = oldviewh;
2097     ldrscale = oldldrscale;
2098     ldrscaleb = oldldrscaleb;
2099 
2100     camera1 = oldcamera;
2101     drawtex = 0;
2102 
2103     createtexture(minimaptex, size, size, NULL, 3, 1, GL_RGB5, GL_TEXTURE_2D);
2104     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
2105     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
2106     GLfloat border[4] = { minimapcolour.x/255.0f, minimapcolour.y/255.0f, minimapcolour.z/255.0f, 1.0f };
2107     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
2108     glBindTexture(GL_TEXTURE_2D, 0);
2109 
2110     GLuint fbo = 0;
2111     glGenFramebuffers_(1, &fbo);
2112     glBindFramebuffer_(GL_FRAMEBUFFER, fbo);
2113     glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, minimaptex, 0);
2114     copyhdr(size, size, fbo);
2115     glBindFramebuffer_(GL_FRAMEBUFFER, 0);
2116     glDeleteFramebuffers_(1, &fbo);
2117 
2118     glViewport(0, 0, hudw, hudh);
2119 }
2120 
drawcubemap(int size,const vec & o,float yaw,float pitch,bool onlysky)2121 void drawcubemap(int size, const vec &o, float yaw, float pitch, bool onlysky)
2122 {
2123     drawtex = DRAWTEX_ENVMAP;
2124 
2125     physent *oldcamera = camera1;
2126     static physent cmcamera;
2127     cmcamera = *camera1;
2128     cmcamera.reset();
2129     cmcamera.type = ENT_CAMERA;
2130     cmcamera.o = o;
2131     cmcamera.yaw = yaw;
2132     cmcamera.pitch = pitch;
2133     cmcamera.roll = 0;
2134     camera1 = &cmcamera;
2135     setviewcell(camera1->o);
2136 
2137     int fogmat, abovemat;
2138     float fogbelow;
2139     getcamfogmat(fogmat, abovemat, fogbelow);
2140     setfog(abovemat);
2141 
2142     float oldaspect = aspect, oldfovy = fovy, oldfov = curfov, oldldrscale = ldrscale, oldldrscaleb = ldrscaleb;
2143     int oldfarplane = farplane, oldvieww = vieww, oldviewh = viewh;
2144     curfov = fovy = 90;
2145     aspect = 1;
2146     farplane = worldsize*2;
2147     vieww = viewh = size;
2148     projmatrix.perspective(fovy, aspect, nearplane, farplane);
2149     setcamprojmatrix();
2150 
2151     glEnable(GL_CULL_FACE);
2152     glEnable(GL_DEPTH_TEST);
2153 
2154     xtravertsva = xtraverts = glde = gbatches = vtris = vverts = 0;
2155     flipqueries();
2156 
2157     ldrscale = 1;
2158     ldrscaleb = ldrscale/255;
2159 
2160     visiblecubes();
2161 
2162     if(onlysky)
2163     {
2164         preparegbuffer();
2165         GLERROR;
2166 
2167         shadesky();
2168         GLERROR;
2169     }
2170     else
2171     {
2172         rendergbuffer();
2173         GLERROR;
2174 
2175         renderradiancehints();
2176         GLERROR;
2177 
2178         rendershadowatlas();
2179         GLERROR;
2180 
2181         shadegbuffer();
2182         GLERROR;
2183 
2184         if(fogmat)
2185         {
2186             setfog(fogmat, fogbelow, 1, abovemat);
2187 
2188             renderwaterfog(fogmat, fogbelow);
2189 
2190             setfog(fogmat, fogbelow, clamp(fogbelow, 0.0f, 1.0f), abovemat);
2191         }
2192 
2193         rendertransparent();
2194         GLERROR;
2195     }
2196 
2197     glDisable(GL_DEPTH_TEST);
2198     glDisable(GL_CULL_FACE);
2199 
2200     aspect = oldaspect;
2201     fovy = oldfovy;
2202     curfov = oldfov;
2203     farplane = oldfarplane;
2204     vieww = oldvieww;
2205     viewh = oldviewh;
2206     ldrscale = oldldrscale;
2207     ldrscaleb = oldldrscaleb;
2208 
2209     camera1 = oldcamera;
2210     drawtex = 0;
2211 }
2212 
2213 VAR(0, modelpreviewfov, 10, 20, 100);
2214 VAR(0, modelpreviewpitch, -90, -15, 90);
2215 
2216 namespace modelpreview
2217 {
2218     physent *oldcamera;
2219     physent mpcam;
2220 
2221     float oldaspect, oldfovy, oldfov, oldldrscale, oldldrscaleb;
2222     int oldfarplane, oldvieww, oldviewh;
2223 
2224     int x, y, w, h;
2225     bool background, scissor;
2226 
start(int x,int y,int w,int h,bool background,bool scissor)2227     void start(int x, int y, int w, int h, bool background, bool scissor)
2228     {
2229         modelpreview::x = x;
2230         modelpreview::y = y;
2231         modelpreview::w = w;
2232         modelpreview::h = h;
2233         modelpreview::background = background;
2234         modelpreview::scissor = scissor;
2235 
2236         setupgbuffer();
2237 
2238         useshaderbyname("modelpreview");
2239 
2240         drawtex = DRAWTEX_MODELPREVIEW;
2241 
2242         oldcamera = camera1;
2243         mpcam = *camera1;
2244         mpcam.reset();
2245         mpcam.type = ENT_CAMERA;
2246         mpcam.o = vec(0, 0, 0);
2247         mpcam.yaw = 0;
2248         mpcam.pitch = modelpreviewpitch;
2249         mpcam.roll = 0;
2250         camera1 = &mpcam;
2251 
2252         oldaspect = aspect;
2253         oldfovy = fovy;
2254         oldfov = curfov;
2255         oldldrscale = ldrscale;
2256         oldldrscaleb = ldrscaleb;
2257         oldfarplane = farplane;
2258         oldvieww = vieww;
2259         oldviewh = viewh;
2260 
2261         aspect = w/float(h);
2262         fovy = modelpreviewfov;
2263         curfov = 2*atan2(tan(fovy/2*RAD), 1/aspect)/RAD;
2264         farplane = 1024;
2265         vieww = min(gw, w);
2266         viewh = min(gh, h);
2267         ldrscale = 1;
2268         ldrscaleb = ldrscale/255;
2269 
2270         projmatrix.perspective(fovy, aspect, nearplane, farplane);
2271         setcamprojmatrix();
2272 
2273         glEnable(GL_CULL_FACE);
2274         glEnable(GL_DEPTH_TEST);
2275 
2276         preparegbuffer();
2277     }
2278 
end()2279     void end()
2280     {
2281         rendermodelbatches();
2282 
2283         glDisable(GL_DEPTH_TEST);
2284         glDisable(GL_CULL_FACE);
2285 
2286         shademodelpreview(x, y, w, h, background, scissor);
2287 
2288         aspect = oldaspect;
2289         fovy = oldfovy;
2290         curfov = oldfov;
2291         farplane = oldfarplane;
2292         vieww = oldvieww;
2293         viewh = oldviewh;
2294         ldrscale = oldldrscale;
2295         ldrscaleb = oldldrscaleb;
2296 
2297         camera1 = oldcamera;
2298         drawtex = 0;
2299     }
2300 }
2301 
calcmodelpreviewpos(const vec & radius,float & yaw)2302 vec calcmodelpreviewpos(const vec &radius, float &yaw)
2303 {
2304     yaw = fmod(lastmillis/10000.0f*360.0f, 360.0f);
2305     float dist = max(radius.magnitude2()/aspect, radius.magnitude())/sinf(fovy/2*RAD);
2306     return vec(0, dist, 0).rotate_around_x(camera1->pitch*RAD);
2307 }
2308 
2309 VAR(0, showboundingboxes, 0, 0, 2);
2310 int xtraverts, xtravertsva;
2311 
gl_drawview()2312 void gl_drawview()
2313 {
2314     GLuint scalefbo = shouldscale();
2315     if(scalefbo) { vieww = gw; viewh = gh; }
2316 
2317     int fogmat, abovemat;
2318     float fogbelow;
2319     getcamfogmat(fogmat, abovemat, fogbelow);
2320     setfog(abovemat);
2321     //setfog(fogmat, fogbelow, 1, abovemat);
2322 
2323     farplane = worldsize*2;
2324 
2325     projmatrix.perspective(fovy, aspect, nearplane, farplane);
2326     setcamprojmatrix();
2327     game::project();
2328 
2329     glEnable(GL_CULL_FACE);
2330     glEnable(GL_DEPTH_TEST);
2331 
2332     ldrscale = 0.5f;
2333     ldrscaleb = ldrscale/255;
2334 
2335     visiblecubes();
2336 
2337     if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2338 
2339     rendergbuffer();
2340 
2341     if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2342     else if(limitsky() && editmode) renderexplicitsky(true);
2343 
2344     renderao();
2345     GLERROR;
2346 
2347     // render avatar after AO to avoid weird contact shadows
2348     if(drawtex != DRAWTEX_MAPSHOT)
2349     {
2350         renderavatar();
2351         GLERROR;
2352     }
2353 
2354     // render grass after AO to avoid disturbing shimmering patterns
2355     generategrass();
2356     rendergrass();
2357     GLERROR;
2358 
2359     glFlush();
2360 
2361     renderradiancehints();
2362     GLERROR;
2363 
2364     rendershadowatlas();
2365     GLERROR;
2366 
2367     shadegbuffer();
2368     GLERROR;
2369 
2370     if(fogmat)
2371     {
2372         setfog(fogmat, fogbelow, 1, abovemat);
2373 
2374         renderwaterfog(fogmat, fogbelow);
2375 
2376         setfog(fogmat, fogbelow, clamp(fogbelow, 0.0f, 1.0f), abovemat);
2377     }
2378 
2379     rendertransparent();
2380     GLERROR;
2381 
2382     if(drawtex != DRAWTEX_MAPSHOT) game::renderpost();
2383     if(fogmat) setfog(fogmat, fogbelow, 1, abovemat);
2384 
2385     rendervolumetric();
2386     GLERROR;
2387 
2388     if(drawtex != DRAWTEX_MAPSHOT && editmode)
2389     {
2390         if(!wireframe && outline) renderoutline();
2391         GLERROR;
2392         rendereditmaterials();
2393         GLERROR;
2394         renderparticles();
2395         GLERROR;
2396 
2397         glDepthMask(GL_FALSE);
2398         renderblendbrush();
2399         rendereditcursor();
2400         glDepthMask(GL_TRUE);
2401     }
2402     if(showboundingboxes)
2403     {
2404         glDepthMask(GL_FALSE);
2405         renderboundboxes();
2406         glDepthMask(GL_TRUE);
2407     }
2408 
2409     glDisable(GL_CULL_FACE);
2410     glDisable(GL_DEPTH_TEST);
2411 
2412     if(fogoverlay && fogmat != MAT_AIR) drawfogoverlay(fogmat, fogbelow, clamp(fogbelow, 0.0f, 1.0f), abovemat);
2413 
2414     doaa(setuppostfx(vieww, viewh, scalefbo), processhdr);
2415     renderpostfx(scalefbo);
2416     if(scalefbo) doscale();
2417 }
2418 
resethudshader()2419 void resethudshader()
2420 {
2421     hudshader->set();
2422     gle::colorf(1, 1, 1);
2423 }
2424 
2425 VAR(0, forcenoview, 0, 0, 1);
hasnoview()2426 bool hasnoview()
2427 {
2428     return forcenoview || progressing || client::waiting() > 0;
2429 }
2430 ICOMMAND(0, getnoview, "", (), intret(hasnoview() ? 1 : 0));
2431 
usetexturing(bool on)2432 void usetexturing(bool on)
2433 {
2434     if(on) resethudshader();
2435     else hudnotextureshader->set();
2436 }
2437 
2438 #define MINRESW 640
2439 #define MINRESH 480
gettextres(int & w,int & h)2440 void gettextres(int &w, int &h)
2441 {
2442     if(w < MINRESW || h < MINRESH)
2443     {
2444         if(MINRESW > w*MINRESH/h)
2445         {
2446             h = h*MINRESW/w;
2447             w = MINRESW;
2448         }
2449         else
2450         {
2451             w = w*MINRESH/h;
2452             h = MINRESH;
2453         }
2454     }
2455 }
2456 
2457 int renderw = 0, renderh = 0, hudw = 0, hudh = 0;
2458 
gl_setupframe(bool force)2459 void gl_setupframe(bool force)
2460 {
2461     hudw = renderw;
2462     hudh = renderh;
2463     if(!force) return;
2464     setuplights();
2465 }
2466 
gl_drawhud(bool noview=false)2467 void gl_drawhud(bool noview = false)
2468 {
2469     hudmatrix.ortho(0, hudw, hudh, 0, -1, 1);
2470     resethudmatrix();
2471     resethudshader();
2472 
2473     debuglights();
2474 
2475     hud::render(noview);
2476 }
2477 
gl_drawnoview()2478 void gl_drawnoview()
2479 {
2480     gl_setupframe();
2481     vieww = hudw;
2482     viewh = hudh;
2483     hud::update(vieww, viewh);
2484     gl_drawhud(true);
2485 }
2486 
gl_drawframe()2487 void gl_drawframe()
2488 {
2489     bool noview = hasnoview();
2490     synctimers();
2491     xtravertsva = xtraverts = glde = gbatches = vtris = vverts = 0;
2492     flipqueries();
2493 
2494     gl_setupframe(!noview);
2495     vieww = hudw;
2496     viewh = hudh;
2497     hud::update(hudw, hudh);
2498 
2499     if(!noview) gl_drawview();
2500     gl_drawhud(noview);
2501 
2502     if(frametimer)
2503     {
2504         glFinish();
2505         framemillis = getclockmillis() - totalmillis;
2506     }
2507 }
2508 
cleanupgl()2509 void cleanupgl()
2510 {
2511     clearminimap();
2512     cleanuptimers();
2513     cleanupscreenquad();
2514     gle::cleanup();
2515 }
2516 
drawslice(float start,float length,float x,float y,float size)2517 void drawslice(float start, float length, float x, float y, float size)
2518 {
2519     float end = start + length,
2520           sx = cosf((start + 0.25f)*2*M_PI), sy = -sinf((start + 0.25f)*2*M_PI),
2521           ex = cosf((end + 0.25f)*2*M_PI), ey = -sinf((end + 0.25f)*2*M_PI);
2522 
2523     #define SLICEVERT(ox, oy) do { \
2524         gle::attribf(x + (ox)*size, y + (oy)*size); \
2525         gle::attribf(0.5f + (ox)*0.5f, 0.5f + (oy)*0.5f); \
2526     } while(0)
2527 
2528     gle::defvertex(2);
2529     gle::deftexcoord0();
2530     gle::begin(GL_TRIANGLE_FAN);
2531     SLICEVERT(0, 0);
2532 
2533     if(start < 0.125f || start >= 0.875f) SLICEVERT(sx/sy, -1);
2534     else if(start < 0.375f) SLICEVERT(1, -sy/sx);
2535     else if(start < 0.625f) SLICEVERT(-sx/sy, 1);
2536     else SLICEVERT(-1, sy/sx);
2537 
2538     if(start <= 0.125f && end >= 0.125f) SLICEVERT(1, -1);
2539     if(start <= 0.375f && end >= 0.375f) SLICEVERT(1, 1);
2540     if(start <= 0.625f && end >= 0.625f) SLICEVERT(-1, 1);
2541     if(start <= 0.875f && end >= 0.875f) SLICEVERT(-1, -1);
2542 
2543     if(end < 0.125f || end >= 0.875f) SLICEVERT(ex/ey, -1);
2544     else if(end < 0.375f) SLICEVERT(1, -ey/ex);
2545     else if(end < 0.625f) SLICEVERT(-ex/ey, 1);
2546     else SLICEVERT(-1, ey/ex);
2547     gle::end();
2548 }
2549 
drawfadedslice(float start,float length,float x,float y,float size,float alpha,float r,float g,float b,float minsize)2550 void drawfadedslice(float start, float length, float x, float y, float size, float alpha, float r, float g, float b, float minsize)
2551 {
2552     float end = start + length,
2553           sx = cosf((start + 0.25f)*2*M_PI), sy = -sinf((start + 0.25f)*2*M_PI),
2554           ex = cosf((end + 0.25f)*2*M_PI), ey = -sinf((end + 0.25f)*2*M_PI);
2555 
2556     #define SLICESPOKE(ox, oy) do { \
2557         SLICEVERT((ox)*minsize, (oy)*minsize); \
2558         gle::attrib(color); \
2559         SLICEVERT(ox, oy); \
2560         gle::attrib(color); \
2561     } while(0)
2562 
2563     gle::defvertex(2);
2564     gle::deftexcoord0();
2565     gle::defcolor(4);
2566     gle::begin(GL_TRIANGLE_STRIP);
2567     vec4 color(r, g, b, alpha);
2568     if(start < 0.125f || start >= 0.875f) SLICESPOKE(sx/sy, -1);
2569     else if(start < 0.375f) SLICESPOKE(1, -sy/sx);
2570     else if(start < 0.625f) SLICESPOKE(-sx/sy, 1);
2571     else SLICESPOKE(-1, sy/sx);
2572 
2573     if(start <= 0.125f && end >= 0.125f) { color.a = alpha - alpha*(0.125f - start)/(end - start); SLICESPOKE(1, -1); }
2574     if(start <= 0.375f && end >= 0.375f) { color.a = alpha - alpha*(0.375f - start)/(end - start); SLICESPOKE(1, 1); }
2575     if(start <= 0.625f && end >= 0.625f) { color.a = alpha - alpha*(0.625f - start)/(end - start); SLICESPOKE(-1, 1); }
2576     if(start <= 0.875f && end >= 0.875f) { color.a = alpha - alpha*(0.875f - start)/(end - start); SLICESPOKE(-1, -1); }
2577 
2578     color.a = 0;
2579     if(end < 0.125f || end >= 0.875f) SLICESPOKE(ex/ey, -1);
2580     else if(end < 0.375f) SLICESPOKE(1, -ey/ex);
2581     else if(end < 0.625f) SLICESPOKE(-ex/ey, 1);
2582     else SLICESPOKE(-1, ey/ex);
2583     gle::end();
2584 }
2585