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