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