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 ¢er)
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 ¢er, 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