1 // rendergl.cpp: core opengl rendering stuff
2
3 #include "engine.h"
4
5 bool hasVBO = false, hasDRE = false, hasOQ = false, hasTR = false, hasFBO = false, hasDS = false, hasTF = false, hasBE = false, hasBC = false, hasCM = false, hasNP2 = false, hasTC = false, hasTE = false, hasMT = false, hasD3 = false, hasAF = false, hasVP2 = false, hasVP3 = false, hasPP = false, hasMDA = false, hasTE3 = false, hasTE4 = false, hasVP = false, hasFP = false, hasGLSL = false, hasGM = false, hasNVFB = false, hasSGIDT = false, hasSGISH = false, hasDT = false, hasSH = false, hasNVPCF = false, hasRN = false, hasPBO = false, hasFBB = false;
6 int hasstencil = 0;
7
8 VAR(renderpath, 1, 0, 0);
9
10 // GL_ARB_vertex_buffer_object, GL_ARB_pixel_buffer_object
11 PFNGLGENBUFFERSARBPROC glGenBuffers_ = NULL;
12 PFNGLBINDBUFFERARBPROC glBindBuffer_ = NULL;
13 PFNGLMAPBUFFERARBPROC glMapBuffer_ = NULL;
14 PFNGLUNMAPBUFFERARBPROC glUnmapBuffer_ = NULL;
15 PFNGLBUFFERDATAARBPROC glBufferData_ = NULL;
16 PFNGLBUFFERSUBDATAARBPROC glBufferSubData_ = NULL;
17 PFNGLDELETEBUFFERSARBPROC glDeleteBuffers_ = NULL;
18 PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubData_ = NULL;
19
20 // GL_ARB_multitexture
21 PFNGLACTIVETEXTUREARBPROC glActiveTexture_ = NULL;
22 PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture_ = NULL;
23 PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2f_ = NULL;
24 PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3f_ = NULL;
25 PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4f_ = NULL;
26
27 // GL_ARB_vertex_program, GL_ARB_fragment_program
28 PFNGLGENPROGRAMSARBPROC glGenPrograms_ = NULL;
29 PFNGLDELETEPROGRAMSARBPROC glDeletePrograms_ = NULL;
30 PFNGLBINDPROGRAMARBPROC glBindProgram_ = NULL;
31 PFNGLPROGRAMSTRINGARBPROC glProgramString_ = NULL;
32 PFNGLGETPROGRAMIVARBPROC glGetProgramiv_ = NULL;
33 PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4f_ = NULL;
34 PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fv_ = NULL;
35 PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArray_ = NULL;
36 PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArray_ = NULL;
37 PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointer_ = NULL;
38
39 // GL_EXT_gpu_program_parameters
40 PFNGLPROGRAMENVPARAMETERS4FVEXTPROC glProgramEnvParameters4fv_ = NULL;
41 PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC glProgramLocalParameters4fv_ = NULL;
42
43 // GL_ARB_occlusion_query
44 PFNGLGENQUERIESARBPROC glGenQueries_ = NULL;
45 PFNGLDELETEQUERIESARBPROC glDeleteQueries_ = NULL;
46 PFNGLBEGINQUERYARBPROC glBeginQuery_ = NULL;
47 PFNGLENDQUERYARBPROC glEndQuery_ = NULL;
48 PFNGLGETQUERYIVARBPROC glGetQueryiv_ = NULL;
49 PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectiv_ = NULL;
50 PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuiv_ = NULL;
51
52 // GL_EXT_framebuffer_object
53 PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbuffer_ = NULL;
54 PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffers_ = NULL;
55 PFNGLGENFRAMEBUFFERSEXTPROC glGenRenderbuffers_ = NULL;
56 PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorage_ = NULL;
57 PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus_ = NULL;
58 PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebuffer_ = NULL;
59 PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffers_ = NULL;
60 PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffers_ = NULL;
61 PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2D_ = NULL;
62 PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbuffer_ = NULL;
63 PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmap_ = NULL;
64
65 // GL_EXT_framebuffer_blit
66 PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebuffer_ = NULL;
67
68 // GL_ARB_shading_language_100, GL_ARB_shader_objects, GL_ARB_fragment_shader, GL_ARB_vertex_shader
69 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObject_ = NULL;
70 PFNGLDELETEOBJECTARBPROC glDeleteObject_ = NULL;
71 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObject_ = NULL;
72 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObject_ = NULL;
73 PFNGLSHADERSOURCEARBPROC glShaderSource_ = NULL;
74 PFNGLCOMPILESHADERARBPROC glCompileShader_ = NULL;
75 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameteriv_ = NULL;
76 PFNGLATTACHOBJECTARBPROC glAttachObject_ = NULL;
77 PFNGLGETINFOLOGARBPROC glGetInfoLog_ = NULL;
78 PFNGLLINKPROGRAMARBPROC glLinkProgram_ = NULL;
79 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocation_ = NULL;
80 PFNGLUNIFORM4FVARBPROC glUniform4fv_ = NULL;
81 PFNGLUNIFORM1IARBPROC glUniform1i_ = NULL;
82
83 // GL_EXT_draw_range_elements
84 PFNGLDRAWRANGEELEMENTSEXTPROC glDrawRangeElements_ = NULL;
85
86 // GL_EXT_blend_minmax
87 PFNGLBLENDEQUATIONEXTPROC glBlendEquation_ = NULL;
88
89 // GL_EXT_blend_color
90 PFNGLBLENDCOLOREXTPROC glBlendColor_ = NULL;
91
92 // GL_EXT_multi_draw_arrays
93 PFNGLMULTIDRAWARRAYSEXTPROC glMultiDrawArrays_ = NULL;
94 PFNGLMULTIDRAWELEMENTSEXTPROC glMultiDrawElements_ = NULL;
95
96 // GL_ARB_texture_compression
97 PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glCompressedTexImage3D_ = NULL;
98 PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2D_ = NULL;
99 PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glCompressedTexImage1D_ = NULL;
100 PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glCompressedTexSubImage3D_ = NULL;
101 PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glCompressedTexSubImage2D_ = NULL;
102 PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glCompressedTexSubImage1D_ = NULL;
103 PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImage_ = NULL;
104
getprocaddress(const char * name)105 void *getprocaddress(const char *name)
106 {
107 return SDL_GL_GetProcAddress(name);
108 }
109
110 VARP(ati_skybox_bug, 0, 0, 1);
111 VAR(ati_texgen_bug, 0, 0, 1);
112 VAR(ati_oq_bug, 0, 0, 1);
113 VAR(ati_minmax_bug, 0, 0, 1);
114 VAR(ati_dph_bug, 0, 0, 1);
115 VAR(nvidia_texgen_bug, 0, 0, 1);
116 VAR(nvidia_scissor_bug, 0, 0, 1);
117 VAR(apple_glsldepth_bug, 0, 0, 1);
118 VAR(apple_ff_bug, 0, 0, 1);
119 VAR(apple_vp_bug, 0, 0, 1);
120 VAR(sdl_backingstore_bug, -1, 0, 1);
121 VAR(intel_quadric_bug, 0, 0, 1);
122 VAR(mesa_program_bug, 0, 0, 1);
123 VAR(avoidshaders, 1, 0, 0);
124 VAR(minimizetcusage, 1, 0, 0);
125 VAR(emulatefog, 1, 0, 0);
126 VAR(usevp2, 1, 0, 0);
127 VAR(usevp3, 1, 0, 0);
128 VAR(usetexrect, 1, 0, 0);
129 VAR(rtscissor, 0, 1, 1);
130 VAR(blurtile, 0, 1, 1);
131 VAR(rtsharefb, 0, 1, 1);
132
checkseries(const char * s,int low,int high)133 static bool checkseries(const char *s, int low, int high)
134 {
135 while(*s && !isdigit(*s)) ++s;
136 if(!*s) return false;
137 int n = 0;
138 while(isdigit(*s)) n = n*10 + (*s++ - '0');
139 return n >= low && n < high;
140 }
141
142 VAR(dbgexts, 0, 0, 1);
143
gl_checkextensions()144 void gl_checkextensions()
145 {
146 const char *vendor = (const char *)glGetString(GL_VENDOR);
147 const char *exts = (const char *)glGetString(GL_EXTENSIONS);
148 const char *renderer = (const char *)glGetString(GL_RENDERER);
149 const char *version = (const char *)glGetString(GL_VERSION);
150 conoutf("renderer: %s (%s)", renderer, vendor);
151 conoutf("driver: %s", version);
152
153 #ifdef __APPLE__
154 extern int mac_osversion();
155 int osversion = mac_osversion(); /* 0x1050 = 10.5 (Leopard) */
156 sdl_backingstore_bug = -1;
157 #endif
158
159 //extern int shaderprecision;
160 // default to low precision shaders on certain cards, can be overridden with -f3
161 // char *weakcards[] = { "GeForce FX", "Quadro FX", "6200", "9500", "9550", "9600", "9700", "9800", "X300", "X600", "FireGL", "Intel", "Chrome", NULL }
162 // if(shaderprecision==2) for(char **wc = weakcards; *wc; wc++) if(strstr(renderer, *wc)) shaderprecision = 1;
163
164 if(strstr(exts, "GL_EXT_texture_env_combine") || strstr(exts, "GL_ARB_texture_env_combine"))
165 {
166 hasTE = true;
167 if(strstr(exts, "GL_ATI_texture_env_combine3")) hasTE3 = true;
168 if(strstr(exts, "GL_NV_texture_env_combine4")) hasTE4 = true;
169 if(strstr(exts, "GL_EXT_texture_env_dot3") || strstr(exts, "GL_ARB_texture_env_dot3")) hasD3 = true;
170 if(dbgexts) conoutf("\frUsing GL_ARB_texture_env_combine extension.");
171 }
172 else conoutf("\frWARNING: No texture_env_combine extension! (your video card is WAY too old)");
173
174 if(strstr(exts, "GL_ARB_multitexture"))
175 {
176 glActiveTexture_ = (PFNGLACTIVETEXTUREARBPROC) getprocaddress("glActiveTextureARB");
177 glClientActiveTexture_ = (PFNGLCLIENTACTIVETEXTUREARBPROC)getprocaddress("glClientActiveTextureARB");
178 glMultiTexCoord2f_ = (PFNGLMULTITEXCOORD2FARBPROC) getprocaddress("glMultiTexCoord2fARB");
179 glMultiTexCoord3f_ = (PFNGLMULTITEXCOORD3FARBPROC) getprocaddress("glMultiTexCoord3fARB");
180 glMultiTexCoord4f_ = (PFNGLMULTITEXCOORD4FARBPROC) getprocaddress("glMultiTexCoord4fARB");
181 hasMT = true;
182 if(dbgexts) conoutf("\frUsing GL_ARB_multitexture extension.");
183 }
184 else conoutf("\frWARNING: No multitexture extension");
185
186 if(strstr(exts, "GL_ARB_vertex_buffer_object"))
187 {
188 hasVBO = true;
189 if(dbgexts) conoutf("\frUsing GL_ARB_vertex_buffer_object extension.");
190 }
191 else conoutf("\frWARNING: No vertex_buffer_object extension! (geometry heavy maps will be SLOW)");
192
193 if(strstr(exts, "GL_ARB_pixel_buffer_object"))
194 {
195 hasPBO = true;
196 if(dbgexts) conoutf("\frUsing GL_ARB_pixel_buffer_object extension.");
197 }
198
199 if(hasVBO || hasPBO)
200 {
201 glGenBuffers_ = (PFNGLGENBUFFERSARBPROC) getprocaddress("glGenBuffersARB");
202 glBindBuffer_ = (PFNGLBINDBUFFERARBPROC) getprocaddress("glBindBufferARB");
203 glMapBuffer_ = (PFNGLMAPBUFFERARBPROC) getprocaddress("glMapBufferARB");
204 glUnmapBuffer_ = (PFNGLUNMAPBUFFERARBPROC) getprocaddress("glUnmapBufferARB");
205 glBufferData_ = (PFNGLBUFFERDATAARBPROC) getprocaddress("glBufferDataARB");
206 glBufferSubData_ = (PFNGLBUFFERSUBDATAARBPROC) getprocaddress("glBufferSubDataARB");
207 glDeleteBuffers_ = (PFNGLDELETEBUFFERSARBPROC) getprocaddress("glDeleteBuffersARB");
208 glGetBufferSubData_ = (PFNGLGETBUFFERSUBDATAARBPROC)getprocaddress("glGetBufferSubDataARB");
209 }
210
211 if(strstr(exts, "GL_EXT_draw_range_elements"))
212 {
213 glDrawRangeElements_ = (PFNGLDRAWRANGEELEMENTSEXTPROC)getprocaddress("glDrawRangeElementsEXT");
214 hasDRE = true;
215 if(dbgexts) conoutf("\frUsing GL_EXT_draw_range_elements extension.");
216 }
217
218 if(strstr(exts, "GL_EXT_multi_draw_arrays"))
219 {
220 glMultiDrawArrays_ = (PFNGLMULTIDRAWARRAYSEXTPROC) getprocaddress("glMultiDrawArraysEXT");
221 glMultiDrawElements_ = (PFNGLMULTIDRAWELEMENTSEXTPROC)getprocaddress("glMultiDrawElementsEXT");
222 hasMDA = true;
223 if(dbgexts) conoutf("\frUsing GL_EXT_multi_draw_arrays extension.");
224 }
225
226 #ifdef __APPLE__
227 // floating point FBOs not fully supported until 10.5
228 if(osversion>=0x1050)
229 #endif
230 if(strstr(exts, "GL_ARB_texture_float") || strstr(exts, "GL_ATI_texture_float"))
231 {
232 hasTF = true;
233 if(dbgexts) conoutf("\frUsing GL_ARB_texture_float extension");
234 shadowmap = 1;
235 extern int smoothshadowmappeel;
236 smoothshadowmappeel = 1;
237 }
238
239 if(strstr(exts, "GL_NV_float_buffer"))
240 {
241 hasNVFB = true;
242 if(dbgexts) conoutf("\frUsing GL_NV_float_buffer extension.");
243 }
244
245 if(strstr(exts, "GL_EXT_framebuffer_object"))
246 {
247 glBindRenderbuffer_ = (PFNGLBINDRENDERBUFFEREXTPROC) getprocaddress("glBindRenderbufferEXT");
248 glDeleteRenderbuffers_ = (PFNGLDELETERENDERBUFFERSEXTPROC) getprocaddress("glDeleteRenderbuffersEXT");
249 glGenRenderbuffers_ = (PFNGLGENFRAMEBUFFERSEXTPROC) getprocaddress("glGenRenderbuffersEXT");
250 glRenderbufferStorage_ = (PFNGLRENDERBUFFERSTORAGEEXTPROC) getprocaddress("glRenderbufferStorageEXT");
251 glCheckFramebufferStatus_ = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) getprocaddress("glCheckFramebufferStatusEXT");
252 glBindFramebuffer_ = (PFNGLBINDFRAMEBUFFEREXTPROC) getprocaddress("glBindFramebufferEXT");
253 glDeleteFramebuffers_ = (PFNGLDELETEFRAMEBUFFERSEXTPROC) getprocaddress("glDeleteFramebuffersEXT");
254 glGenFramebuffers_ = (PFNGLGENFRAMEBUFFERSEXTPROC) getprocaddress("glGenFramebuffersEXT");
255 glFramebufferTexture2D_ = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) getprocaddress("glFramebufferTexture2DEXT");
256 glFramebufferRenderbuffer_ = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)getprocaddress("glFramebufferRenderbufferEXT");
257 glGenerateMipmap_ = (PFNGLGENERATEMIPMAPEXTPROC) getprocaddress("glGenerateMipmapEXT");
258 hasFBO = true;
259 if(dbgexts) conoutf("\frUsing GL_EXT_framebuffer_object extension.");
260
261 if(strstr(exts, "GL_EXT_framebuffer_blit"))
262 {
263 glBlitFramebuffer_ = (PFNGLBLITFRAMEBUFFEREXTPROC) getprocaddress("glBlitFramebufferEXT");
264 hasFBB = true;
265 if(dbgexts) conoutf("\frUsing GL_EXT_framebuffer_blit extension.");
266 }
267 }
268 else conoutf("\frWARNING: No framebuffer object support. (reflective water may be slow)");
269
270 if(strstr(exts, "GL_ARB_occlusion_query"))
271 {
272 GLint bits;
273 glGetQueryiv_ = (PFNGLGETQUERYIVARBPROC)getprocaddress("glGetQueryivARB");
274 glGetQueryiv_(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB, &bits);
275 if(bits)
276 {
277 glGenQueries_ = (PFNGLGENQUERIESARBPROC) getprocaddress("glGenQueriesARB");
278 glDeleteQueries_ = (PFNGLDELETEQUERIESARBPROC) getprocaddress("glDeleteQueriesARB");
279 glBeginQuery_ = (PFNGLBEGINQUERYARBPROC) getprocaddress("glBeginQueryARB");
280 glEndQuery_ = (PFNGLENDQUERYARBPROC) getprocaddress("glEndQueryARB");
281 glGetQueryObjectiv_ = (PFNGLGETQUERYOBJECTIVARBPROC) getprocaddress("glGetQueryObjectivARB");
282 glGetQueryObjectuiv_ = (PFNGLGETQUERYOBJECTUIVARBPROC)getprocaddress("glGetQueryObjectuivARB");
283 hasOQ = true;
284 if(dbgexts) conoutf("\frUsing GL_ARB_occlusion_query extension.");
285 #if defined(__APPLE__) && SDL_BYTEORDER == SDL_BIG_ENDIAN
286 if(strstr(vendor, "ATI") && (osversion<0x1050)) ati_oq_bug = 1;
287 #endif
288 if(ati_oq_bug) conoutf("\frWARNING: Using ATI occlusion query bug workaround. (use \"/ati_oq_bug 0\" to disable if unnecessary)");
289 }
290 }
291 if(!hasOQ)
292 {
293 conoutf("\frWARNING: No occlusion query support! (large maps may be SLOW)");
294 zpass = 0;
295 extern int vacubesize;
296 vacubesize = 64;
297 waterreflect = 0;
298 }
299
300 extern int reservedynlighttc, reserveshadowmaptc, maxtexsize, batchlightmaps, ffdynlights;
301 if(strstr(vendor, "ATI"))
302 {
303 floatvtx = 1;
304 //conoutf("\frWARNING: ATI cards may show garbage in skybox. (use \"/ati_skybox_bug 1\" to fix)");
305
306 reservedynlighttc = 2;
307 reserveshadowmaptc = 3;
308 minimizetcusage = 1;
309 emulatefog = 1;
310 extern int depthfxprecision;
311 if(hasTF) depthfxprecision = 1;
312
313 //ati_texgen_bug = 1;
314 }
315 else if(strstr(vendor, "NVIDIA"))
316 {
317 reservevpparams = 10;
318 rtsharefb = 0; // work-around for strange driver stalls involving when using many FBOs
319 extern int filltjoints;
320 if(!strstr(exts, "GL_EXT_gpu_shader4")) filltjoints = 0; // DX9 or less NV cards seem to not cause many sparklies
321
322 nvidia_texgen_bug = 1;
323 if(hasFBO && !hasTF) nvidia_scissor_bug = 1; // 5200 bug, clearing with scissor on an FBO messes up on reflections, may affect lesser cards too
324 extern int fpdepthfx;
325 if(hasTF && (!strstr(renderer, "GeForce") || !checkseries(renderer, 6000, 6600)))
326 fpdepthfx = 1; // FP filtering causes software fallback on 6200?
327 }
328 else if(strstr(vendor, "Intel"))
329 {
330 avoidshaders = 1;
331 intel_quadric_bug = 1;
332 maxtexsize = 256;
333 reservevpparams = 20;
334 batchlightmaps = 0;
335 ffdynlights = 0;
336
337 if(!hasOQ) waterrefract = 0;
338
339 #ifdef __APPLE__
340 apple_vp_bug = 1;
341 #endif
342 }
343 else if(strstr(vendor, "Tungsten") || strstr(vendor, "Mesa") || strstr(vendor, "DRI") || strstr(vendor, "Microsoft") || strstr(vendor, "S3 Graphics"))
344 {
345 avoidshaders = 1;
346 floatvtx = 1;
347 maxtexsize = 256;
348 reservevpparams = 20;
349 batchlightmaps = 0;
350 ffdynlights = 0;
351
352 if(!hasOQ) waterrefract = 0;
353 }
354 //if(floatvtx) conoutf("\frWARNING: Using floating point vertexes. (use \"/floatvtx 0\" to disable)");
355
356 if(strstr(exts, "GL_ARB_vertex_program") && strstr(exts, "GL_ARB_fragment_program"))
357 {
358 hasVP = hasFP = true;
359 glGenPrograms_ = (PFNGLGENPROGRAMSARBPROC) getprocaddress("glGenProgramsARB");
360 glDeletePrograms_ = (PFNGLDELETEPROGRAMSARBPROC) getprocaddress("glDeleteProgramsARB");
361 glBindProgram_ = (PFNGLBINDPROGRAMARBPROC) getprocaddress("glBindProgramARB");
362 glProgramString_ = (PFNGLPROGRAMSTRINGARBPROC) getprocaddress("glProgramStringARB");
363 glGetProgramiv_ = (PFNGLGETPROGRAMIVARBPROC) getprocaddress("glGetProgramivARB");
364 glProgramEnvParameter4f_ = (PFNGLPROGRAMENVPARAMETER4FARBPROC) getprocaddress("glProgramEnvParameter4fARB");
365 glProgramEnvParameter4fv_ = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) getprocaddress("glProgramEnvParameter4fvARB");
366 glEnableVertexAttribArray_ = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) getprocaddress("glEnableVertexAttribArrayARB");
367 glDisableVertexAttribArray_ = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) getprocaddress("glDisableVertexAttribArrayARB");
368 glVertexAttribPointer_ = (PFNGLVERTEXATTRIBPOINTERARBPROC) getprocaddress("glVertexAttribPointerARB");
369
370 if(strstr(exts, "GL_ARB_shading_language_100") && strstr(exts, "GL_ARB_shader_objects") && strstr(exts, "GL_ARB_vertex_shader") && strstr(exts, "GL_ARB_fragment_shader"))
371 {
372 glCreateProgramObject_ = (PFNGLCREATEPROGRAMOBJECTARBPROC) getprocaddress("glCreateProgramObjectARB");
373 glDeleteObject_ = (PFNGLDELETEOBJECTARBPROC) getprocaddress("glDeleteObjectARB");
374 glUseProgramObject_ = (PFNGLUSEPROGRAMOBJECTARBPROC) getprocaddress("glUseProgramObjectARB");
375 glCreateShaderObject_ = (PFNGLCREATESHADEROBJECTARBPROC) getprocaddress("glCreateShaderObjectARB");
376 glShaderSource_ = (PFNGLSHADERSOURCEARBPROC) getprocaddress("glShaderSourceARB");
377 glCompileShader_ = (PFNGLCOMPILESHADERARBPROC) getprocaddress("glCompileShaderARB");
378 glGetObjectParameteriv_ = (PFNGLGETOBJECTPARAMETERIVARBPROC) getprocaddress("glGetObjectParameterivARB");
379 glAttachObject_ = (PFNGLATTACHOBJECTARBPROC) getprocaddress("glAttachObjectARB");
380 glGetInfoLog_ = (PFNGLGETINFOLOGARBPROC) getprocaddress("glGetInfoLogARB");
381 glLinkProgram_ = (PFNGLLINKPROGRAMARBPROC) getprocaddress("glLinkProgramARB");
382 glGetUniformLocation_ = (PFNGLGETUNIFORMLOCATIONARBPROC) getprocaddress("glGetUniformLocationARB");
383 glUniform4fv_ = (PFNGLUNIFORM4FVARBPROC) getprocaddress("glUniform4fvARB");
384 glUniform1i_ = (PFNGLUNIFORM1IARBPROC) getprocaddress("glUniform1iARB");
385
386 extern bool checkglslsupport();
387 if(checkglslsupport())
388 {
389 hasGLSL = true;
390 #ifdef __APPLE__
391 //if(osversion<0x1050) ??
392 apple_glsldepth_bug = 1;
393 #endif
394 if(apple_glsldepth_bug) conoutf("\frWARNING: Using Apple GLSL depth bug workaround. (use \"/apple_glsldepth_bug 0\" to disable if unnecessary");
395 }
396 }
397
398 if(strstr(vendor, "ATI")) ati_dph_bug = 1;
399 else if(strstr(vendor, "Tungsten")) mesa_program_bug = 1;
400
401 #ifdef __APPLE__
402 if(osversion>=0x1050) // fixed in 1055 for some hardware.. but not all.
403 {
404 apple_ff_bug = 1;
405 conoutf("\frWARNING: Using Leopard ARB_position_invariant bug workaround. (use \"/apple_ff_bug 0\" to disable if unnecessary)");
406 }
407 #endif
408
409 extern int matskel;
410 if(!avoidshaders) matskel = 0;
411 }
412
413 if(strstr(exts, "GL_NV_vertex_program2_option")) { usevp2 = 1; hasVP2 = true; }
414 if(strstr(exts, "GL_NV_vertex_program3")) { usevp3 = 1; hasVP3 = true; }
415
416 if(strstr(exts, "GL_EXT_gpu_program_parameters"))
417 {
418 glProgramEnvParameters4fv_ = (PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) getprocaddress("glProgramEnvParameters4fvEXT");
419 glProgramLocalParameters4fv_ = (PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC)getprocaddress("glProgramLocalParameters4fvEXT");
420 hasPP = true;
421 if(dbgexts) conoutf("\frUsing GL_EXT_gpu_program_parameters extension.");
422 }
423
424 if(strstr(exts, "GL_EXT_texture_rectangle") || strstr(exts, "GL_ARB_texture_rectangle"))
425 {
426 usetexrect = 1;
427 hasTR = true;
428 if(dbgexts) conoutf("\frUsing GL_ARB_texture_rectangle extension.");
429 }
430 else if(hasMT && hasVP && hasFP) conoutf("\frWARNING: No texture rectangle support. (no full screen shaders)");
431
432 if(strstr(exts, "GL_EXT_packed_depth_stencil") || strstr(exts, "GL_NV_packed_depth_stencil"))
433 {
434 hasDS = true;
435 if(dbgexts) conoutf("\frUsing GL_EXT_packed_depth_stencil extension.");
436 }
437
438 if(strstr(exts, "GL_EXT_blend_minmax"))
439 {
440 glBlendEquation_ = (PFNGLBLENDEQUATIONEXTPROC) getprocaddress("glBlendEquationEXT");
441 hasBE = true;
442 if(strstr(vendor, "ATI")) ati_minmax_bug = 1;
443 if(dbgexts) conoutf("\frUsing GL_EXT_blend_minmax extension.");
444 }
445
446 if(strstr(exts, "GL_EXT_blend_color"))
447 {
448 glBlendColor_ = (PFNGLBLENDCOLOREXTPROC) getprocaddress("glBlendColorEXT");
449 hasBC = true;
450 if(dbgexts) conoutf("\frUsing GL_EXT_blend_color extension.");
451 }
452
453 if(strstr(exts, "GL_ARB_texture_cube_map"))
454 {
455 GLint val;
456 glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &val);
457 hwcubetexsize = val;
458 hasCM = true;
459 if(dbgexts) conoutf("\frUsing GL_ARB_texture_cube_map extension.");
460 }
461 else conoutf("\frWARNING: No cube map texture support. (no reflective glass)");
462
463 extern int usenp2;
464 if(strstr(exts, "GL_ARB_texture_non_power_of_two"))
465 {
466 hasNP2 = true;
467 if(dbgexts) conoutf("\frUsing GL_ARB_texture_non_power_of_two extension.");
468 }
469 else if(usenp2) conoutf("\frWARNING: Non-power-of-two textures not supported");
470
471 if(strstr(exts, "GL_ARB_texture_compression") && strstr(exts, "GL_EXT_texture_compression_s3tc"))
472 {
473 glCompressedTexImage3D_ = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) getprocaddress("glCompressedTexImage3DARB");
474 glCompressedTexImage2D_ = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) getprocaddress("glCompressedTexImage2DARB");
475 glCompressedTexImage1D_ = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) getprocaddress("glCompressedTexImage1DARB");
476 glCompressedTexSubImage3D_ = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)getprocaddress("glCompressedTexSubImage3DARB");
477 glCompressedTexSubImage2D_ = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)getprocaddress("glCompressedTexSubImage2DARB");
478 glCompressedTexSubImage1D_ = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)getprocaddress("glCompressedTexSubImage1DARB");
479 glGetCompressedTexImage_ = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) getprocaddress("glGetCompressedTexImageARB");
480
481 hasTC = true;
482 if(dbgexts) conoutf("\frUsing GL_EXT_texture_compression_s3tc extension.");
483 }
484
485 if(strstr(exts, "GL_EXT_texture_filter_anisotropic"))
486 {
487 GLint val;
488 glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val);
489 hwmaxaniso = val;
490 hasAF = true;
491 if(dbgexts) conoutf("\frUsing GL_EXT_texture_filter_anisotropic extension.");
492 }
493
494 if(strstr(exts, "GL_SGIS_generate_mipmap"))
495 {
496 hasGM = true;
497 if(dbgexts) conoutf("\frUsing GL_SGIS_generate_mipmap extension.");
498 }
499
500 if(strstr(exts, "GL_ARB_depth_texture"))
501 {
502 hasSGIDT = hasDT = true;
503 if(dbgexts) conoutf("\frUsing GL_ARB_depth_texture extension.");
504 }
505 else if(strstr(exts, "GL_SGIX_depth_texture"))
506 {
507 hasSGIDT = true;
508 if(dbgexts) conoutf("\frUsing GL_SGIX_depth_texture extension.");
509 }
510
511 if(strstr(exts, "GL_ARB_shadow"))
512 {
513 hasSGISH = hasSH = true;
514 if(strstr(vendor, "NVIDIA")) hasNVPCF = true;
515 if(dbgexts) conoutf("\frUsing GL_ARB_shadow extension.");
516 }
517 else if(strstr(exts, "GL_SGIX_shadow"))
518 {
519 hasSGISH = true;
520 if(dbgexts) conoutf("\frUsing GL_SGIX_shadow extension.");
521 }
522
523 if(strstr(exts, "GL_EXT_rescale_normal"))
524 {
525 hasRN = true;
526 if(dbgexts) conoutf("\frUsing GL_EXT_rescale_normal extension.");
527 }
528
529 if(!hasSGIDT && !hasSGISH) shadowmap = 0;
530
531 if(strstr(exts, "GL_EXT_gpu_shader4") && !avoidshaders)
532 {
533 // on DX10 or above class cards (i.e. GF8 or RadeonHD) enable expensive features
534 extern int grass, motionblur, glare, maxdynlights, depthfxsize, depthfxrect, depthfxfilter, blurdepthfx;
535 grass = 1;
536 motionblur = 1;
537 if(hasOQ)
538 {
539 waterfallrefract = 1;
540 glare = 1;
541 maxdynlights = MAXDYNLIGHTS;
542 if(hasTR)
543 {
544 depthfxsize = 10;
545 depthfxrect = 1;
546 depthfxfilter = 0;
547 blurdepthfx = 0;
548 }
549 }
550 }
551
552 GLint val;
553 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &val);
554 hwtexsize = val;
555 }
556
glext(char * ext)557 void glext(char *ext)
558 {
559 const char *exts = (const char *)glGetString(GL_EXTENSIONS);
560 intret(strstr(exts, ext) ? 1 : 0);
561 }
562 COMMAND(glext, "s");
563
gl_init(int w,int h,int bpp,int depth,int fsaa)564 void gl_init(int w, int h, int bpp, int depth, int fsaa)
565 {
566 glViewport(0, 0, w, h);
567 glClearColor(0, 0, 0, 0);
568 glClearDepth(1);
569 glDepthFunc(GL_LESS);
570 glDisable(GL_DEPTH_TEST);
571 glShadeModel(GL_SMOOTH);
572
573
574 glDisable(GL_FOG);
575 glFogi(GL_FOG_MODE, GL_LINEAR);
576 glHint(GL_FOG_HINT, GL_NICEST);
577 GLfloat fogcolor[4] = { 0, 0, 0, 0 };
578 glFogfv(GL_FOG_COLOR, fogcolor);
579
580
581 glEnable(GL_LINE_SMOOTH);
582 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
583
584 glCullFace(GL_FRONT);
585 glDisable(GL_CULL_FACE);
586
587 #ifdef __APPLE__
588 if(sdl_backingstore_bug)
589 {
590 if(fsaa)
591 {
592 sdl_backingstore_bug = 1;
593 // since SDL doesn't add kCGLPFABackingStore to the pixelformat and so it isn't guaranteed to be preserved - only manifests when using fsaa?
594 //conoutf(CON_WARN, "WARNING: Using SDL backingstore workaround. (use \"/sdl_backingstore_bug 0\" to disable if unnecessary)");
595 }
596 else sdl_backingstore_bug = -1;
597 }
598 #endif
599
600 extern int useshaders;
601 if(!useshaders || (useshaders<0 && avoidshaders) || !hasMT || !hasVP || !hasFP)
602 {
603 if(!hasMT || !hasVP || !hasFP) conoutf("\frWARNING: No shader support! Using fixed-function fallback. (no fancy visuals for you)");
604 else if(useshaders<0 && !hasTF) conoutf("\frWARNING: Disabling shaders for extra performance. (use \"/shaders 1\" to enable shaders if desired)");
605 renderpath = R_FIXEDFUNCTION;
606 conoutf("rendering using the OpenGL fixed-function path.");
607 if(ati_texgen_bug) conoutf("\frWARNING: Using ATI texgen bug workaround. (use \"/ati_texgen_bug 0\" to disable if unnecessary)");
608 if(nvidia_texgen_bug) conoutf("\frWARNING: Using NVIDIA texgen bug workaround. (use \"/nvidia_texgen_bug 0\" to disable if unnecessary)");
609 }
610 else
611 {
612 renderpath = hasGLSL ? R_GLSLANG : R_ASMSHADER;
613 if(renderpath==R_GLSLANG) conoutf("rendering using the OpenGL GLSL shader path.");
614 else conoutf("rendering using the OpenGL assembly shader path.");
615 }
616
617 if(fsaa) glEnable(GL_MULTISAMPLE);
618
619 inittmus();
620 setuptexcompress();
621 }
622
cleanupgl()623 void cleanupgl()
624 {
625 if(glIsEnabled(GL_MULTISAMPLE)) glDisable(GL_MULTISAMPLE);
626
627 extern int nomasks, nolights, nowater;
628 nomasks = nolights = nowater = 0;
629
630 extern void cleanupmotionblur();
631 cleanupmotionblur();
632 }
633
634 VAR(wireframe, 0, 0, 1);
635
636 physent camera, *camera1 = &camera;
637 vec worldpos, camerapos, camdir, camright, camup;
638
findorientation(vec & o,float yaw,float pitch,vec & pos)639 void findorientation(vec &o, float yaw, float pitch, vec &pos)
640 {
641 vec dir;
642 vecfromyawpitch(yaw, pitch, 1, 0, dir);
643 if(raycubepos(o, dir, pos, 0, RAY_CLIPMAT|RAY_SKIPFIRST) == -1)
644 pos = dir.mul(2*hdr.worldsize).add(o); //otherwise gui won't work when outside of map
645 }
646
transplayer()647 void transplayer()
648 {
649 glLoadIdentity();
650
651 glRotatef(camera1->roll, 0, 0, 1);
652 glRotatef(camera1->pitch, -1, 0, 0);
653 glRotatef(camera1->yaw, 0, 1, 0);
654
655 // move from RH to Z-up LH quake style worldspace
656 glRotatef(-90, 1, 0, 0);
657 glScalef(1, -1, 1);
658
659 glTranslatef(-camera1->o.x, -camera1->o.y, -camera1->o.z);
660 }
661
662 float curfov = 100, fovy, aspect;
663 int farplane, xtraverts, xtravertsva;
664
665 VARW(fog, 16, 4000, INT_MAX-1);
666 bvec fogcolor(0x80, 0x99, 0xB3);
667 HVARFW(fogcolour, 0, 0x8099B3, 0xFFFFFF,
668 {
669 fogcolor = bvec((fogcolour>>16)&0xFF, (fogcolour>>8)&0xFF, fogcolour&0xFF);
670 });
671
vecfromcursor(float x,float y,float z,vec & dir)672 void vecfromcursor(float x, float y, float z, vec &dir)
673 {
674 vec4 dir1, dir2;
675 invmvpmatrix.transform(vec(x*2-1, 1-2*y, z*2-1), dir1);
676 invmvpmatrix.transform(vec(x*2-1, 1-2*y, -1), dir2);
677 dir = vec(dir1.x, dir1.y, dir1.z).div(dir1.w);
678 dir.sub(vec(dir2.x, dir2.y, dir2.z).div(dir2.w));
679 dir.normalize();
680 }
681
vectocursor(vec & v,float & x,float & y,float & z)682 void vectocursor(vec &v, float &x, float &y, float &z)
683 {
684 vec4 screenpos;
685 mvpmatrix.transform(v, screenpos);
686
687 x = screenpos.x/screenpos.w*0.5f + 0.5f;
688 y = 0.5f - screenpos.y/screenpos.w*0.5f;
689 z = screenpos.z/screenpos.w*0.5f + 0.5f;
690 }
691
692 FVAR(nearplane, 1e-3f, 0.54f, 1e3f);
693
project(float fovy,float aspect,int farplane,bool flipx,bool flipy,bool swapxy,float zscale)694 void project(float fovy, float aspect, int farplane, bool flipx, bool flipy, bool swapxy, float zscale)
695 {
696 glMatrixMode(GL_PROJECTION);
697 glLoadIdentity();
698 if(swapxy) glRotatef(90, 0, 0, 1);
699 if(flipx || flipy!=swapxy || zscale!=1) glScalef(flipx ? -1 : 1, flipy!=swapxy ? -1 : 1, zscale);
700 GLdouble ydist = nearplane * tan(fovy/2*RAD), xdist = ydist * aspect;
701 glFrustum(-xdist, xdist, -ydist, ydist, nearplane, farplane);
702 glMatrixMode(GL_MODELVIEW);
703 }
704
705 VAR(reflectclip, 0, 6, 64);
706
707 glmatrixf clipmatrix;
708
genclipmatrix(float a,float b,float c,float d)709 void genclipmatrix(float a, float b, float c, float d)
710 {
711 // transform the clip plane into camera space
712 float clip[4];
713 loopi(4) clip[i] = a*invmvmatrix[i*4 + 0] + b*invmvmatrix[i*4 + 1] + c*invmvmatrix[i*4 + 2] + d*invmvmatrix[i*4 + 3];
714
715 float x = ((clip[0]<0 ? -1 : (clip[0]>0 ? 1 : 0)) + projmatrix[8]) / projmatrix[0],
716 y = ((clip[1]<0 ? -1 : (clip[1]>0 ? 1 : 0)) + projmatrix[9]) / projmatrix[5],
717 w = (1 + projmatrix[10]) / projmatrix[14],
718 scale = 2 / (x*clip[0] + y*clip[1] - clip[2] + w*clip[3]);
719 clipmatrix = projmatrix;
720 clipmatrix[2] = clip[0]*scale;
721 clipmatrix[6] = clip[1]*scale;
722 clipmatrix[10] = clip[2]*scale + 1.0f;
723 clipmatrix[14] = clip[3]*scale;
724 }
725
setclipmatrix()726 void setclipmatrix()
727 {
728 glMatrixMode(GL_PROJECTION);
729 glPushMatrix();
730 glLoadMatrixf(clipmatrix.v);
731 glMatrixMode(GL_MODELVIEW);
732 }
733
undoclipmatrix()734 void undoclipmatrix()
735 {
736 glMatrixMode(GL_PROJECTION);
737 glPopMatrix();
738 glMatrixMode(GL_MODELVIEW);
739 }
740
741 FVAR(polygonoffsetfactor, -1e4f, -3.0f, 1e4f);
742 FVAR(polygonoffsetunits, -1e4f, -3.0f, 1e4f);
743 FVAR(depthoffset, -1e4f, 0.01f, 1e4f);
744
enablepolygonoffset(GLenum type)745 void enablepolygonoffset(GLenum type)
746 {
747 if(!depthoffset)
748 {
749 glPolygonOffset(polygonoffsetfactor, polygonoffsetunits);
750 glEnable(type);
751 return;
752 }
753
754 bool clipped = reflectz < 1e15f && reflectclip;
755
756 glmatrixf offsetmatrix = clipped ? clipmatrix : projmatrix;
757 offsetmatrix[14] += depthoffset * projmatrix[10];
758
759 glMatrixMode(GL_PROJECTION);
760 if(!clipped) glPushMatrix();
761 glLoadMatrixf(offsetmatrix.v);
762 glMatrixMode(GL_MODELVIEW);
763 }
764
disablepolygonoffset(GLenum type)765 void disablepolygonoffset(GLenum type)
766 {
767 if(!depthoffset)
768 {
769 glDisable(type);
770 return;
771 }
772
773 bool clipped = reflectz < 1e15f && reflectclip;
774
775 glMatrixMode(GL_PROJECTION);
776 if(clipped) glLoadMatrixf(clipmatrix.v);
777 else glPopMatrix();
778 glMatrixMode(GL_MODELVIEW);
779 }
780
calcspherescissor(const vec & center,float size,float & sx1,float & sy1,float & sx2,float & sy2)781 void calcspherescissor(const vec ¢er, float size, float &sx1, float &sy1, float &sx2, float &sy2)
782 {
783 vec worldpos(center);
784 if(reflecting) worldpos.z = 2*reflectz - worldpos.z;
785 vec e(mvmatrix.transformx(worldpos),
786 mvmatrix.transformy(worldpos),
787 mvmatrix.transformz(worldpos));
788 if(e.z > 2*size) { sx1 = sy1 = 1; sx2 = sy2 = -1; return; }
789 float zzrr = e.z*e.z - size*size,
790 dx = e.x*e.x + zzrr, dy = e.y*e.y + zzrr,
791 focaldist = 1.0f/tan(fovy*0.5f*RAD);
792 sx1 = sy1 = -1;
793 sx2 = sy2 = 1;
794 #define CHECKPLANE(c, dir, focaldist, low, high) \
795 do { \
796 float nzc = (cz*cz + 1) / (cz dir drt) - cz, \
797 pz = (d##c)/(nzc*e.c - e.z); \
798 if(pz > 0) \
799 { \
800 float c = (focaldist)*nzc, \
801 pc = pz*nzc; \
802 if(pc < e.c) low = c; \
803 else if(pc > e.c) high = c; \
804 } \
805 } while(0)
806 if(dx > 0)
807 {
808 float cz = e.x/e.z, drt = sqrtf(dx)/size;
809 CHECKPLANE(x, -, focaldist/aspect, sx1, sx2);
810 CHECKPLANE(x, +, focaldist/aspect, sx1, sx2);
811 }
812 if(dy > 0)
813 {
814 float cz = e.y/e.z, drt = sqrtf(dy)/size;
815 CHECKPLANE(y, -, focaldist, sy1, sy2);
816 CHECKPLANE(y, +, focaldist, sy1, sy2);
817 }
818 }
819
820 static int scissoring = 0;
821 static GLint oldscissor[4];
822
pushscissor(float sx1,float sy1,float sx2,float sy2)823 int pushscissor(float sx1, float sy1, float sx2, float sy2)
824 {
825 scissoring = 0;
826
827 if(sx1 <= -1 && sy1 <= -1 && sx2 >= 1 && sy2 >= 1) return 0;
828
829 sx1 = max(sx1, -1.0f);
830 sy1 = max(sy1, -1.0f);
831 sx2 = min(sx2, 1.0f);
832 sy2 = min(sy2, 1.0f);
833
834 GLint viewport[4];
835 glGetIntegerv(GL_VIEWPORT, viewport);
836 int sx = viewport[0] + int(floor((sx1+1)*0.5f*viewport[2])),
837 sy = viewport[1] + int(floor((sy1+1)*0.5f*viewport[3])),
838 sw = viewport[0] + int(ceil((sx2+1)*0.5f*viewport[2])) - sx,
839 sh = viewport[1] + int(ceil((sy2+1)*0.5f*viewport[3])) - sy;
840 if(sw <= 0 || sh <= 0) return 0;
841
842 if(glIsEnabled(GL_SCISSOR_TEST))
843 {
844 glGetIntegerv(GL_SCISSOR_BOX, oldscissor);
845 sw += sx;
846 sh += sy;
847 sx = max(sx, int(oldscissor[0]));
848 sy = max(sy, int(oldscissor[1]));
849 sw = min(sw, int(oldscissor[0] + oldscissor[2])) - sx;
850 sh = min(sh, int(oldscissor[1] + oldscissor[3])) - sy;
851 if(sw <= 0 || sh <= 0) return 0;
852 scissoring = 2;
853 }
854 else scissoring = 1;
855
856 glScissor(sx, sy, sw, sh);
857 if(scissoring<=1) glEnable(GL_SCISSOR_TEST);
858
859 return scissoring;
860 }
861
popscissor()862 void popscissor()
863 {
864 if(scissoring>1) glScissor(oldscissor[0], oldscissor[1], oldscissor[2], oldscissor[3]);
865 else if(scissoring) glDisable(GL_SCISSOR_TEST);
866 scissoring = 0;
867 }
868
setfogplane(const plane & p,bool flush)869 void setfogplane(const plane &p, bool flush)
870 {
871 static float fogselect[4] = {0, 0, 0, 0};
872 if(flush)
873 {
874 flushenvparamfv("fogselect", SHPARAM_VERTEX, 8, fogselect);
875 flushenvparamfv("fogplane", SHPARAM_VERTEX, 9, p.v);
876 }
877 else
878 {
879 setenvparamfv("fogselect", SHPARAM_VERTEX, 8, fogselect);
880 setenvparamfv("fogplane", SHPARAM_VERTEX, 9, p.v);
881 }
882 }
883
setfogplane(float scale,float z,bool flush,float fadescale,float fadeoffset)884 void setfogplane(float scale, float z, bool flush, float fadescale, float fadeoffset)
885 {
886 float fogselect[4] = {1, fadescale, fadeoffset, 0}, fogplane[4] = {0, 0, 0, 0};
887 if(scale || z)
888 {
889 fogselect[0] = 0;
890 fogplane[2] = scale;
891 fogplane[3] = -z;
892 }
893 if(flush)
894 {
895 flushenvparamfv("fogselect", SHPARAM_VERTEX, 8, fogselect);
896 flushenvparamfv("fogplane", SHPARAM_VERTEX, 9, fogplane);
897 }
898 else
899 {
900 setenvparamfv("fogselect", SHPARAM_VERTEX, 8, fogselect);
901 setenvparamfv("fogplane", SHPARAM_VERTEX, 9, fogplane);
902 }
903 }
904
findsurface(int fogmat,const vec & v,int & abovemat)905 static float findsurface(int fogmat, const vec &v, int &abovemat)
906 {
907 ivec o(v);
908 do
909 {
910 cube &c = lookupcube(o.x, o.y, o.z);
911 if(!c.ext || (c.ext->material&MATF_VOLUME) != fogmat)
912 {
913 abovemat = c.ext && isliquid(c.ext->material&MATF_VOLUME) ? c.ext->material&MATF_VOLUME : MAT_AIR;
914 return o.z;
915 }
916 o.z = lu.z + lusize;
917 }
918 while(o.z < hdr.worldsize);
919 abovemat = MAT_AIR;
920 return hdr.worldsize;
921 }
922
blendfog(int fogmat,float blend,float logblend,float & start,float & end,float * fogc)923 static void blendfog(int fogmat, float blend, float logblend, float &start, float &end, float *fogc)
924 {
925 switch(fogmat)
926 {
927 case MAT_WATER:
928 loopk(3) fogc[k] += blend*watercol[k]/255.0f;
929 end += logblend*min(fog, max(waterfog*4, 32));
930 break;
931
932 case MAT_LAVA:
933 loopk(3) fogc[k] += blend*lavacol[k]/255.0f;
934 end += logblend*min(fog, max(lavafog*4, 32));
935 break;
936
937 default:
938 loopk(3) fogc[k] += blend*fogcolor[k]/255.0f;
939 start += logblend*(fog+64)/8;
940 end += logblend*fog;
941 break;
942 }
943 }
944
setfog(int fogmat,float below=1,int abovemat=MAT_AIR)945 static void setfog(int fogmat, float below = 1, int abovemat = MAT_AIR)
946 {
947 float fogc[4] = { 0, 0, 0, 1 };
948 float start = 0, end = 0;
949 float logscale = 256, logblend = log(1 + (logscale - 1)*below) / log(logscale);
950
951 blendfog(fogmat, below, logblend, start, end, fogc);
952 if(below < 1) blendfog(abovemat, 1-below, 1-logblend, start, end, fogc);
953
954 glFogf(GL_FOG_START, start);
955 glFogf(GL_FOG_END, end);
956 glFogfv(GL_FOG_COLOR, fogc);
957 glClearColor(fogc[0], fogc[1], fogc[2], 1.0f);
958
959 if(renderpath!=R_FIXEDFUNCTION) setfogplane();
960 }
961
962 GLuint motiontex = 0;
963 int motionw = 0, motionh = 0, lastmotion = 0;
964
cleanupmotionblur()965 void cleanupmotionblur()
966 {
967 if(motiontex) { glDeleteTextures(1, &motiontex); motiontex = 0; }
968 motionw = motionh = 0;
969 lastmotion = 0;
970 }
971
972 VARFP(motionblur, 0, 0, 1, { if(!motionblur) cleanupmotionblur(); });
973 VARP(motionblurmillis, 1, 5, 1000);
974 FVARP(motionblurscale, 0, 1, 1);
975
addmotionblur()976 void addmotionblur()
977 {
978 extern int viewtype;
979 if(!motionblur || viewtype || !hasTR || max(screen->w, screen->h) > hwtexsize) return;
980
981 if(!motiontex || motionw != screen->w || motionh != screen->h)
982 {
983 if(!motiontex) glGenTextures(1, &motiontex);
984 motionw = screen->w;
985 motionh = screen->h;
986 lastmotion = 0;
987 createtexture(motiontex, motionw, motionh, NULL, 3, 0, GL_RGB, GL_TEXTURE_RECTANGLE_ARB);
988 }
989
990 float amount = min(hud::motionblur(motionblurscale), 1.0f);
991 if(amount <= 0)
992 {
993 lastmotion = 0;
994 return;
995 }
996
997 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, motiontex);
998
999 glMatrixMode(GL_PROJECTION);
1000 glPushMatrix();
1001 glLoadIdentity();
1002
1003 glMatrixMode(GL_MODELVIEW);
1004 glPushMatrix();
1005 glLoadIdentity();
1006
1007 glEnable(GL_BLEND);
1008 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1009
1010 glDisable(GL_TEXTURE_2D);
1011 glEnable(GL_TEXTURE_RECTANGLE_ARB);
1012
1013 rectshader->set();
1014
1015 glColor4f(1, 1, 1, lastmotion ? pow(amount, max(float(lastmillis - lastmotion)/motionblurmillis, 1.0f)) : 0);
1016 glBegin(GL_QUADS);
1017 glTexCoord2f( 0, 0); glVertex2f(-1, -1);
1018 glTexCoord2f(motionw, 0); glVertex2f( 1, -1);
1019 glTexCoord2f(motionw, motionh); glVertex2f( 1, 1);
1020 glTexCoord2f( 0, motionh); glVertex2f(-1, 1);
1021 glEnd();
1022
1023 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1024 glEnable(GL_TEXTURE_2D);
1025
1026 glDisable(GL_BLEND);
1027
1028 glMatrixMode(GL_PROJECTION);
1029 glPopMatrix();
1030
1031 glMatrixMode(GL_MODELVIEW);
1032 glPopMatrix();
1033
1034 if(lastmillis - lastmotion >= motionblurmillis)
1035 {
1036 lastmotion = lastmillis - lastmillis%motionblurmillis;
1037
1038 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, 0, 0, screen->w, screen->h);
1039 }
1040 }
1041
1042 bool dopostfx = false;
1043
invalidatepostfx()1044 void invalidatepostfx()
1045 {
1046 dopostfx = false;
1047 }
1048
blendfogoverlay(int fogmat,float blend,float * overlay)1049 static void blendfogoverlay(int fogmat, float blend, float *overlay)
1050 {
1051 float maxc;
1052 switch(fogmat)
1053 {
1054 case MAT_WATER:
1055 maxc = max(watercol[0], max(watercol[1], watercol[2]));
1056 loopk(3) overlay[k] += blend*max(0.4f, watercol[k]/min(32.0f + maxc*7.0f/8.0f, 255.0f));
1057 break;
1058
1059 case MAT_LAVA:
1060 maxc = max(lavacol[0], max(lavacol[1], lavacol[2]));
1061 loopk(3) overlay[k] += blend*max(0.4f, lavacol[k]/min(32.0f + maxc*7.0f/8.0f, 255.0f));
1062 break;
1063
1064 default:
1065 loopk(3) overlay[k] += blend;
1066 break;
1067 }
1068 }
1069
drawfogoverlay(int fogmat,float fogblend,int abovemat)1070 void drawfogoverlay(int fogmat, float fogblend, int abovemat)
1071 {
1072 notextureshader->set();
1073 glDisable(GL_TEXTURE_2D);
1074
1075 glEnable(GL_BLEND);
1076 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
1077 float overlay[3] = { 0, 0, 0 };
1078 blendfogoverlay(fogmat, fogblend, overlay);
1079 blendfogoverlay(abovemat, 1-fogblend, overlay);
1080
1081 glMatrixMode(GL_PROJECTION);
1082 glPushMatrix();
1083 glLoadIdentity();
1084
1085 glMatrixMode(GL_MODELVIEW);
1086 glPushMatrix();
1087 glLoadIdentity();
1088
1089 glColor3fv(overlay);
1090 glBegin(GL_QUADS);
1091 glVertex2f(-1, -1);
1092 glVertex2f(1, -1);
1093 glVertex2f(1, 1);
1094 glVertex2f(-1, 1);
1095 glEnd();
1096 glDisable(GL_BLEND);
1097
1098 glMatrixMode(GL_PROJECTION);
1099 glPopMatrix();
1100
1101 glMatrixMode(GL_MODELVIEW);
1102 glPopMatrix();
1103
1104 glEnable(GL_TEXTURE_2D);
1105 defaultshader->set();
1106 }
1107
1108 bool renderedgame = false, renderedavatar = false;
1109
rendergame()1110 void rendergame()
1111 {
1112 game::render();
1113 if(!shadowmapping) renderedgame = true;
1114 }
1115
renderavatar(bool early)1116 void renderavatar(bool early)
1117 {
1118 game::renderavatar(early);
1119 }
1120
1121 extern void viewproject(float zscale = 1);
1122
1123 VARP(skyboxglare, 0, 1, 1);
1124 FVAR(firstpersondepth, 0, 0.5f, 1);
1125
drawglare()1126 void drawglare()
1127 {
1128 glaring = true;
1129 refracting = -1;
1130
1131 float oldfogstart, oldfogend, oldfogcolor[4], zerofog[4] = { 0, 0, 0, 1 };
1132 glGetFloatv(GL_FOG_START, &oldfogstart);
1133 glGetFloatv(GL_FOG_END, &oldfogend);
1134 glGetFloatv(GL_FOG_COLOR, oldfogcolor);
1135
1136 glFogi(GL_FOG_START, (fog+64)/8);
1137 glFogi(GL_FOG_END, fog);
1138 glFogfv(GL_FOG_COLOR, zerofog);
1139
1140 glClearColor(0, 0, 0, 1);
1141 glClear((skyboxglare ? 0 : GL_COLOR_BUFFER_BIT) | GL_DEPTH_BUFFER_BIT);
1142
1143 rendergeom();
1144
1145 if(skyboxglare) drawskybox(farplane, false);
1146
1147 renderreflectedmapmodels();
1148 rendergame();
1149
1150 renderwater();
1151 rendermaterials();
1152 renderparticles();
1153
1154 if(game::thirdpersonview()) renderavatar(false);
1155 else
1156 {
1157 viewproject(firstpersondepth);
1158 renderavatar(false);
1159 viewproject();
1160 }
1161
1162 glFogf(GL_FOG_START, oldfogstart);
1163 glFogf(GL_FOG_END, oldfogend);
1164 glFogfv(GL_FOG_COLOR, oldfogcolor);
1165
1166 refracting = 0;
1167 glaring = false;
1168 }
1169
1170 VARP(reflectmms, 0, 1, 1);
1171
drawreflection(float z,bool refract,bool clear)1172 void drawreflection(float z, bool refract, bool clear)
1173 {
1174 float fogc[4] = { watercol[0]/255.0f, watercol[1]/255.0f, watercol[2]/255.0f, 1.0f };
1175
1176 if(refract && !waterfog)
1177 {
1178 glClearColor(fogc[0], fogc[1], fogc[2], 1.0f);
1179 glClear(GL_COLOR_BUFFER_BIT);
1180 return;
1181 }
1182
1183 reflectz = z < 0 ? 1e16f : z;
1184 reflecting = !refract;
1185 refracting = refract ? (z < 0 || camera1->o.z >= z ? -1 : 1) : 0;
1186 fading = renderpath!=R_FIXEDFUNCTION && waterrefract && waterfade && hasFBO && z>=0;
1187 fogging = refracting<0 && z>=0 && (renderpath!=R_FIXEDFUNCTION || refractfog);
1188
1189 float oldfogstart, oldfogend, oldfogcolor[4];
1190 if(renderpath==R_FIXEDFUNCTION && fogging) glDisable(GL_FOG);
1191 else
1192 {
1193 glGetFloatv(GL_FOG_START, &oldfogstart);
1194 glGetFloatv(GL_FOG_END, &oldfogend);
1195 glGetFloatv(GL_FOG_COLOR, oldfogcolor);
1196
1197 if(fogging)
1198 {
1199 glFogi(GL_FOG_START, 0);
1200 glFogi(GL_FOG_END, waterfog);
1201 glFogfv(GL_FOG_COLOR, fogc);
1202 }
1203 else
1204 {
1205 glFogi(GL_FOG_START, (fog+64)/8);
1206 glFogi(GL_FOG_END, fog);
1207 float fogc[4] = { fogcolor.x/255.0f, fogcolor.y/255.0f, fogcolor.z/255.0f, 1.0f };
1208 glFogfv(GL_FOG_COLOR, fogc);
1209 }
1210 }
1211
1212 if(clear)
1213 {
1214 glClearColor(fogc[0], fogc[1], fogc[2], 1.0f);
1215 glClear(GL_COLOR_BUFFER_BIT);
1216 }
1217
1218 if(reflecting)
1219 {
1220 glPushMatrix();
1221 glTranslatef(0, 0, 2*z);
1222 glScalef(1, 1, -1);
1223
1224 glCullFace(GL_BACK);
1225 }
1226
1227 if(reflectclip && z>=0)
1228 {
1229 float zoffset = reflectclip/4.0f, zclip;
1230 if(refracting<0)
1231 {
1232 zclip = z+zoffset;
1233 if(camera1->o.z<=zclip) zclip = z;
1234 }
1235 else
1236 {
1237 zclip = z-zoffset;
1238 if(camera1->o.z>=zclip && camera1->o.z<=z+4.0f) zclip = z;
1239 if(reflecting) zclip = 2*z - zclip;
1240 }
1241 genclipmatrix(0, 0, refracting>0 ? 1 : -1, refracting>0 ? -zclip : zclip);
1242 setclipmatrix();
1243 }
1244
1245
1246 renderreflectedgeom(refracting<0 && z>=0 && caustics, fogging);
1247
1248 if(reflecting || refracting>0 || z<0)
1249 {
1250 if(fading) glColorMask(COLORMASK, GL_TRUE);
1251 if(reflectclip && z>=0) undoclipmatrix();
1252 drawskybox(farplane, false);
1253 if(reflectclip && z>=0) setclipmatrix();
1254 if(fading) glColorMask(COLORMASK, GL_FALSE);
1255 }
1256 else if(fading) glColorMask(COLORMASK, GL_FALSE);
1257
1258 if(renderpath!=R_FIXEDFUNCTION && fogging) setfogplane(1, z);
1259 renderdecals();
1260
1261 if(reflectmms) renderreflectedmapmodels();
1262 rendergame();
1263
1264 if(renderpath!=R_FIXEDFUNCTION && fogging) setfogplane(1, z);
1265 if(refracting) rendergrass();
1266 rendermaterials();
1267 renderparticles();
1268
1269 if(game::thirdpersonview() || reflecting) renderavatar(false);
1270
1271 if(fading) glColorMask(COLORMASK, GL_TRUE);
1272
1273 if(renderpath!=R_FIXEDFUNCTION && fogging) setfogplane();
1274
1275 if(reflectclip && z>=0) undoclipmatrix();
1276
1277 if(reflecting)
1278 {
1279 glPopMatrix();
1280
1281 glCullFace(GL_FRONT);
1282 }
1283
1284 if(renderpath==R_FIXEDFUNCTION && fogging) glEnable(GL_FOG);
1285 else
1286 {
1287 glFogf(GL_FOG_START, oldfogstart);
1288 glFogf(GL_FOG_END, oldfogend);
1289 glFogfv(GL_FOG_COLOR, oldfogcolor);
1290 }
1291
1292 reflectz = 1e16f;
1293 refracting = 0;
1294 reflecting = fading = fogging = false;
1295 }
1296
1297 bool envmapping = false;
1298
drawcubemap(int size,int level,const vec & o,float yaw,float pitch,bool flipx,bool flipy,bool swapxy)1299 void drawcubemap(int size, int level, const vec &o, float yaw, float pitch, bool flipx, bool flipy, bool swapxy)
1300 {
1301 float fovx = 90.f, fovy = 90.f, aspect = 1.f;
1302 envmapping = true;
1303
1304 physent *oldcamera = camera1;
1305 static physent cmcamera;
1306 cmcamera = *camera1;
1307 cmcamera.reset();
1308 cmcamera.type = ENT_CAMERA;
1309 cmcamera.o = o;
1310 cmcamera.yaw = yaw;
1311 cmcamera.pitch = pitch;
1312 cmcamera.roll = 0;
1313 camera1 = &cmcamera;
1314
1315 defaultshader->set();
1316
1317 updatedynlights();
1318
1319 int fogmat = lookupmaterial(camera1->o)&MATF_VOLUME, abovemat = MAT_AIR;
1320 float fogblend = 1.0f, causticspass = 0.0f;
1321 if(fogmat==MAT_WATER || fogmat==MAT_LAVA)
1322 {
1323 float z = findsurface(fogmat, camera1->o, abovemat) - WATER_OFFSET;
1324 if(camera1->o.z < z + 1) fogblend = min(z + 1 - camera1->o.z, 1.0f);
1325 else fogmat = abovemat;
1326 if(level > 1 && caustics && fogmat==MAT_WATER && camera1->o.z < z)
1327 causticspass = renderpath==R_FIXEDFUNCTION ? 1.0f : min(z - camera1->o.z, 1.0f);
1328 }
1329 else
1330 {
1331 fogmat = MAT_AIR;
1332 }
1333 setfog(fogmat, fogblend, abovemat);
1334 if(level > 1 && fogmat != MAT_AIR)
1335 {
1336 float blend = abovemat==MAT_AIR ? fogblend : 1.0f;
1337 fovy += blend*sinf(lastmillis/1000.0)*2.0f;
1338 aspect += blend*sinf(lastmillis/1000.0+PI)*0.1f;
1339 }
1340
1341 int farplane = hdr.worldsize*2;
1342
1343 project(fovy, aspect, farplane, flipx, flipy, swapxy);
1344 transplayer();
1345
1346 glEnable(GL_FOG);
1347 glEnable(GL_CULL_FACE);
1348 glEnable(GL_DEPTH_TEST);
1349 glEnable(GL_TEXTURE_2D);
1350
1351 xtravertsva = xtraverts = glde = gbatches = 0;
1352
1353 if(level > 1 && !hasFBO)
1354 {
1355 if(dopostfx)
1356 {
1357 drawglaretex();
1358 drawdepthfxtex();
1359 drawreflections();
1360 }
1361 else dopostfx = true;
1362 }
1363
1364 visiblecubes(fovx, fovy);
1365
1366 if(level > 1 && shadowmap && !hasFBO) rendershadowmap();
1367
1368 glClear(GL_DEPTH_BUFFER_BIT);
1369
1370 if(limitsky()) drawskybox(farplane, true);
1371 rendergeom(level > 1 ? causticspass : 0);
1372 if(level > 1) queryreflections();
1373 if(level) generategrass();
1374 if(!limitsky()) drawskybox(farplane, false);
1375 if(level > 1) renderdecals();
1376
1377 rendermapmodels();
1378
1379 if(level) rendergame();
1380 if(level > 1)
1381 {
1382 if(hasFBO)
1383 {
1384 drawglaretex();
1385 drawdepthfxtex();
1386 drawreflections();
1387 }
1388 renderwater(); // water screws up for some reason
1389 }
1390 rendergrass();
1391 rendermaterials();
1392 renderparticles();
1393
1394 glDisable(GL_FOG);
1395 glDisable(GL_CULL_FACE);
1396 glDisable(GL_DEPTH_TEST);
1397
1398 if(level > 1) addglare();
1399
1400 glDisable(GL_TEXTURE_2D);
1401
1402 camera1 = oldcamera;
1403 envmapping = false;
1404 }
1405
1406 VARP(scr_virtw, 0, 1024, INT_MAX-1);
1407 VARP(scr_virth, 0, 768, INT_MAX-1);
1408 VARP(scr_minw, 0, 640, INT_MAX-1);
1409 VARP(scr_minh, 0, 480, INT_MAX-1);
1410
getscreenres(int & w,int & h)1411 void getscreenres(int &w, int &h)
1412 {
1413 float wk = 1, hk = 1;
1414 if(w < scr_virtw) wk = float(scr_virtw)/w;
1415 if(h < scr_virth) hk = float(scr_virth)/h;
1416 wk = hk = max(wk, hk);
1417 w = int(ceil(w*wk));
1418 h = int(ceil(h*hk));
1419 }
1420
gettextres(int & w,int & h)1421 void gettextres(int &w, int &h)
1422 {
1423 if(w < scr_minw || h < scr_minh)
1424 {
1425 if(scr_minw > w*scr_minh/h)
1426 {
1427 h = h*scr_minw/w;
1428 w = scr_minw;
1429 }
1430 else
1431 {
1432 w = w*scr_minh/h;
1433 h = scr_minh;
1434 }
1435 }
1436 }
1437
drawslice(float start,float length,float x,float y,float size)1438 void drawslice(float start, float length, float x, float y, float size)
1439 {
1440 float end = start + length,
1441 sx = cosf((start + 0.25f)*2*M_PI), sy = -sinf((start + 0.25f)*2*M_PI),
1442 ex = cosf((end + 0.25f)*2*M_PI), ey = -sinf((end + 0.25f)*2*M_PI);
1443 glBegin(GL_TRIANGLE_FAN);
1444 glTexCoord2f(0.5f, 0.5f); glVertex2f(x, y);
1445
1446 if(start < 0.125f || start >= 0.875f) { glTexCoord2f(0.5f + 0.5f*sx/sy, 0); glVertex2f(x + sx/sy*size, y - size); }
1447 else if(start < 0.375f) { glTexCoord2f(1, 0.5f - 0.5f*sy/sx); glVertex2f(x + size, y - sy/sx*size); }
1448 else if(start < 0.625f) { glTexCoord2f(0.5f - 0.5f*sx/sy, 1); glVertex2f(x - sx/sy*size, y + size); }
1449 else { glTexCoord2f(0, 0.5f + 0.5f*sy/sx); glVertex2f(x - size, y + sy/sx*size); }
1450
1451 if(start <= 0.125f && end >= 0.125f) { glTexCoord2f(1, 0); glVertex2f(x + size, y - size); }
1452 if(start <= 0.375f && end >= 0.375f) { glTexCoord2f(1, 1); glVertex2f(x + size, y + size); }
1453 if(start <= 0.625f && end >= 0.625f) { glTexCoord2f(0, 1); glVertex2f(x - size, y + size); }
1454 if(start <= 0.875f && end >= 0.875f) { glTexCoord2f(0, 0); glVertex2f(x - size, y - size); }
1455
1456 if(end < 0.125f || end >= 0.875f) { glTexCoord2f(0.5f + 0.5f*ex/ey, 0); glVertex2f(x + ex/ey*size, y - size); }
1457 else if(end < 0.375f) { glTexCoord2f(1, 0.5f - 0.5f*ey/ex); glVertex2f(x + size, y - ey/ex*size); }
1458 else if(end < 0.625f) { glTexCoord2f(0.5f - 0.5f*ex/ey, 1); glVertex2f(x - ex/ey*size, y + size); }
1459 else { glTexCoord2f(0, 0.5f + 0.5f*ey/ex); glVertex2f(x - size, y + ey/ex*size); }
1460 glEnd();
1461 }
1462
drawfadedslice(float start,float length,float x,float y,float size,float alpha,float r,float g,float b,float minsize)1463 void drawfadedslice(float start, float length, float x, float y, float size, float alpha, float r, float g, float b, float minsize)
1464 {
1465 float end = start + length,
1466 sx = cosf((start + 0.25f)*2*M_PI), sy = -sinf((start + 0.25f)*2*M_PI),
1467 ex = cosf((end + 0.25f)*2*M_PI), ey = -sinf((end + 0.25f)*2*M_PI);
1468
1469 #define SLICEVERT(ox, oy) \
1470 { \
1471 glTexCoord2f(0.5f + (ox)*0.5f, 0.5f + (oy)*0.5f); \
1472 glVertex2f(x + (ox)*size, y + (oy)*size); \
1473 }
1474 #define SLICESPOKE(ox, oy) \
1475 { \
1476 SLICEVERT((ox)*minsize, (oy)*minsize); \
1477 SLICEVERT(ox, oy); \
1478 }
1479
1480 glBegin(GL_TRIANGLE_STRIP);
1481 glColor4f(r, g, b, alpha);
1482 if(start < 0.125f || start >= 0.875f) SLICESPOKE(sx/sy, -1)
1483 else if(start < 0.375f) SLICESPOKE(1, -sy/sx)
1484 else if(start < 0.625f) SLICESPOKE(-sx/sy, 1)
1485 else SLICESPOKE(-1, sy/sx)
1486
1487 if(start <= 0.125f && end >= 0.125f) { glColor4f(r, g, b, alpha - alpha*(0.125f - start)/(end - start)); SLICESPOKE(1, -1) }
1488 if(start <= 0.375f && end >= 0.375f) { glColor4f(r, g, b, alpha - alpha*(0.375f - start)/(end - start)); SLICESPOKE(1, 1) }
1489 if(start <= 0.625f && end >= 0.625f) { glColor4f(r, g, b, alpha - alpha*(0.625f - start)/(end - start)); SLICESPOKE(-1, 1) }
1490 if(start <= 0.875f && end >= 0.875f) { glColor4f(r, g, b, alpha - alpha*(0.875f - start)/(end - start)); SLICESPOKE(-1, -1) }
1491
1492 glColor4f(r, g, b, 0);
1493 if(end < 0.125f || end >= 0.875f) SLICESPOKE(ex/ey, -1)
1494 else if(end < 0.375f) SLICESPOKE(1, -ey/ex)
1495 else if(end < 0.625f) SLICESPOKE(-ex/ey, 1)
1496 else SLICESPOKE(-1, ey/ex)
1497 glEnd();
1498 }
1499
1500 glmatrixf mvmatrix, projmatrix, mvpmatrix, invmvmatrix, invmvpmatrix;
1501
readmatrices()1502 void readmatrices()
1503 {
1504 glGetFloatv(GL_MODELVIEW_MATRIX, mvmatrix.v);
1505 glGetFloatv(GL_PROJECTION_MATRIX, projmatrix.v);
1506
1507 mvpmatrix.mul(projmatrix, mvmatrix);
1508 invmvmatrix.invert(mvmatrix);
1509 invmvpmatrix.invert(mvpmatrix);
1510 }
1511
1512 float cursorx = 0.5f, cursory = 0.5f;
1513 vec cursordir(0, 0, 0);
1514
1515 struct framebuffercopy
1516 {
1517 GLuint tex;
1518 GLenum target;
1519 int w, h;
1520
framebuffercopyframebuffercopy1521 framebuffercopy() : tex(0), target(GL_TEXTURE_2D), w(0), h(0) {}
1522
cleanupframebuffercopy1523 void cleanup()
1524 {
1525 if(!tex) return;
1526 glDeleteTextures(1, &tex);
1527 tex = 0;
1528 }
1529
setupframebuffercopy1530 void setup()
1531 {
1532 if(tex) return;
1533 glGenTextures(1, &tex);
1534 if(hasTR)
1535 {
1536 target = GL_TEXTURE_RECTANGLE_ARB;
1537 w = screen->w;
1538 h = screen->h;
1539 }
1540 else
1541 {
1542 target = GL_TEXTURE_2D;
1543 for(w = 1; w < screen->w; w *= 2);
1544 for(h = 1; h < screen->h; h *= 2);
1545 }
1546 createtexture(tex, w, h, NULL, 3, false, GL_RGB, target);
1547 }
1548
copyframebuffercopy1549 void copy()
1550 {
1551 if(target == GL_TEXTURE_RECTANGLE_ARB)
1552 {
1553 if(w != screen->w || h != screen->h) cleanup();
1554 }
1555 else if(w < screen->w || h < screen->h || w/2 >= screen->w || h/2 >= screen->h) cleanup();
1556 if(!tex) setup();
1557
1558 glBindTexture(target, tex);
1559 glCopyTexSubImage2D(target, 0, 0, 0, 0, 0, screen->w, screen->h);
1560 }
1561
drawframebuffercopy1562 void draw(float sx, float sy, float sw, float sh)
1563 {
1564 float tx = 0, ty = 0, tw = float(screen->w)/w, th = float(screen->h)/h;
1565 if(target == GL_TEXTURE_RECTANGLE_ARB)
1566 {
1567 glDisable(GL_TEXTURE_2D);
1568 glEnable(GL_TEXTURE_RECTANGLE_ARB);
1569 rectshader->set();
1570 tx *= w;
1571 ty *= h;
1572 tw *= w;
1573 th *= h;
1574 }
1575 glBindTexture(target, tex);
1576 glBegin(GL_QUADS);
1577 glTexCoord2f(tx, ty); glVertex2f(sx, sy);
1578 glTexCoord2f(tx+tw, ty); glVertex2f(sx+sw, sy);
1579 glTexCoord2f(tx+tw, ty+th); glVertex2f(sx+sw, sy+sh);
1580 glTexCoord2f(tx, ty+th); glVertex2f(sx, sy+sh);
1581 glEnd();
1582 if(target == GL_TEXTURE_RECTANGLE_ARB)
1583 {
1584 glEnable(GL_TEXTURE_2D);
1585 glDisable(GL_TEXTURE_RECTANGLE_ARB);
1586 defaultshader->set();
1587 }
1588 }
1589 };
1590
1591 #define DTR 0.0174532925
1592 enum { VW_NORMAL = 0, VW_MAGIC, VW_STEREO, VW_STEREO_BLEND = VW_STEREO, VW_STEREO_BLEND_REDCYAN, VW_STEREO_AVG, VW_MAX, VW_STEREO_REDCYAN = VW_MAX };
1593 enum { VP_LEFT, VP_RIGHT, VP_MAX, VP_CAMERA = VP_MAX };
1594
1595 framebuffercopy views[VP_MAX];
1596
1597 VARFP(viewtype, VW_NORMAL, VW_NORMAL, VW_MAX, loopi(VP_MAX) views[i].cleanup());
1598 FVARP(stereoblend, 0, 0.5f, 1);
1599 FVARP(stereodist, 0, 0.5f, 10000);
1600 FVARP(stereoplane, 1e-3f, 40.f, 1000);
1601 FVARP(stereonear, 0, 2.f, 10000);
1602
1603 int fogmat = MAT_AIR, abovemat = MAT_AIR;
1604 float fogblend = 1.0f, causticspass = 0.0f;
1605
1606 GLenum colormask[3] = { GL_TRUE, GL_TRUE, GL_TRUE };
1607
setcolormask(bool r,bool g,bool b)1608 void setcolormask(bool r, bool g, bool b)
1609 {
1610 colormask[0] = r ? GL_TRUE : GL_FALSE;
1611 colormask[1] = g ? GL_TRUE : GL_FALSE;
1612 colormask[2] = b ? GL_TRUE : GL_FALSE;
1613 }
1614
needsview(int v,int targtype)1615 bool needsview(int v, int targtype)
1616 {
1617 switch(v)
1618 {
1619 case VW_NORMAL: return targtype == VP_CAMERA;
1620 case VW_MAGIC: return targtype == VP_LEFT || targtype == VP_RIGHT;
1621 case VW_STEREO_BLEND:
1622 case VW_STEREO_BLEND_REDCYAN: return targtype >= VP_LEFT && targtype <= VP_CAMERA;
1623 case VW_STEREO_AVG:
1624 case VW_STEREO_REDCYAN: return targtype == VP_LEFT || targtype == VP_RIGHT;
1625 }
1626 return false;
1627 }
1628
copyview(int v,int targtype)1629 bool copyview(int v, int targtype)
1630 {
1631 switch(v)
1632 {
1633 case VW_MAGIC: return targtype == VP_LEFT || targtype == VP_RIGHT;
1634 case VW_STEREO_BLEND:
1635 case VW_STEREO_BLEND_REDCYAN: return targtype == VP_RIGHT;
1636 case VW_STEREO_AVG: return targtype == VP_LEFT;
1637 }
1638 return false;
1639 }
1640
clearview(int v,int targtype)1641 bool clearview(int v, int targtype)
1642 {
1643 switch(v)
1644 {
1645 case VW_STEREO_BLEND:
1646 case VW_STEREO_BLEND_REDCYAN: return targtype == VP_LEFT || targtype == VP_CAMERA;
1647 case VW_STEREO_REDCYAN: return targtype == VP_LEFT;
1648 }
1649 return true;
1650 }
1651
1652 static int curview = VP_CAMERA;
1653
viewproject(float zscale)1654 void viewproject(float zscale)
1655 {
1656 if(curview != VP_LEFT && curview != VP_RIGHT) project(fovy, aspect, farplane, false, false, false, zscale);
1657 else
1658 {
1659 glMatrixMode(GL_PROJECTION);
1660 glLoadIdentity();
1661 if(zscale != 1) glScalef(1, 1, zscale);
1662 float top = stereonear*tan(DTR*fovy/2), right = aspect*top, iod = stereodist/2, fs = iod*stereonear/stereoplane;
1663 glFrustum(curview == VP_LEFT ? -right+fs : -right-fs, curview == VP_LEFT ? right+fs : right-fs, -top, top, stereonear, farplane);
1664 glTranslatef(curview == VP_LEFT ? iod : -iod, 0.f, 0.f);
1665 glMatrixMode(GL_MODELVIEW);
1666 }
1667 }
1668
drawnoview()1669 void drawnoview()
1670 {
1671 xtravertsva = xtraverts = glde = gbatches = 0;
1672
1673 glMatrixMode(GL_MODELVIEW);
1674 glLoadIdentity();
1675 int w = screen->w, h = screen->h;
1676 gettextres(w, h);
1677 glMatrixMode(GL_PROJECTION);
1678 glLoadIdentity();
1679 glOrtho(0, w, h, 0, -1, 1);
1680
1681 glClearColor(0.f, 0.f, 0.f, 1);
1682 glClear(GL_COLOR_BUFFER_BIT);
1683
1684 glEnable(GL_TEXTURE_2D);
1685 defaultshader->set();
1686
1687 hud::update(screen->w, screen->h);
1688 hud::drawhud(true);
1689 if(UI::ready && (progressing || commandmillis<0)) UI::render();
1690 if(!progressing) hud::drawlast();
1691
1692 glDisable(GL_TEXTURE_2D);
1693 }
1694
drawview(int targtype)1695 void drawview(int targtype)
1696 {
1697 curview = targtype;
1698
1699 defaultshader->set();
1700 updatedynlights();
1701
1702 setfog(fogmat, fogblend, abovemat);
1703 viewproject();
1704 transplayer();
1705 if(targtype == VP_LEFT || targtype == VP_RIGHT)
1706 {
1707 if(viewtype >= VW_STEREO)
1708 {
1709 switch(viewtype)
1710 {
1711 case VW_STEREO_BLEND: setcolormask(targtype == VP_LEFT, false, targtype == VP_RIGHT); break;
1712 case VW_STEREO_AVG: setcolormask(targtype == VP_LEFT, true, targtype == VP_RIGHT); break;
1713 case VW_STEREO_BLEND_REDCYAN:
1714 case VW_STEREO_REDCYAN: setcolormask(targtype == VP_LEFT, targtype == VP_RIGHT, targtype == VP_RIGHT); break;
1715 }
1716 glColorMask(COLORMASK, GL_TRUE);
1717 }
1718 }
1719
1720 readmatrices();
1721
1722 glEnable(GL_FOG);
1723 glEnable(GL_CULL_FACE);
1724 glEnable(GL_DEPTH_TEST);
1725 glEnable(GL_TEXTURE_2D);
1726
1727 xtravertsva = xtraverts = glde = gbatches = 0;
1728
1729 if(!hasFBO)
1730 {
1731 if(dopostfx)
1732 {
1733 drawglaretex();
1734 drawdepthfxtex();
1735 drawreflections();
1736 }
1737 else dopostfx = true;
1738 }
1739
1740 visiblecubes(curfov, fovy);
1741 if(shadowmap && !hasFBO) rendershadowmap();
1742
1743 glClearColor(0, 0, 0, 0);
1744 glClear(GL_DEPTH_BUFFER_BIT|(wireframe && editmode && clearview(viewtype, targtype) ? GL_COLOR_BUFFER_BIT : 0)|(hasstencil ? GL_STENCIL_BUFFER_BIT : 0));
1745
1746 if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1747
1748 if(limitsky()) drawskybox(farplane, true);
1749
1750 rendergeom(causticspass);
1751 extern int outline, blankgeom;
1752 if(!wireframe && editmode && (outline || (fullbright && blankgeom))) renderoutline();
1753
1754 queryreflections();
1755 generategrass();
1756
1757 if(!limitsky()) drawskybox(farplane, false);
1758
1759 renderdecals(true);
1760 renderavatar(true);
1761
1762 rendermapmodels();
1763 rendergame();
1764
1765 if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1766
1767 if(hasFBO)
1768 {
1769 drawglaretex();
1770 drawdepthfxtex();
1771 drawreflections();
1772 }
1773
1774 if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1775
1776 renderwater();
1777 rendergrass();
1778
1779 rendermaterials();
1780 renderparticles(true);
1781
1782 if(game::thirdpersonview()) renderavatar(false);
1783 else
1784 {
1785 viewproject(0.5f);
1786 renderavatar(false);
1787 viewproject();
1788 }
1789
1790 if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1791
1792 glDisable(GL_FOG);
1793 glDisable(GL_CULL_FACE);
1794 glDisable(GL_DEPTH_TEST);
1795
1796 addmotionblur();
1797 addglare();
1798 if(fogmat==MAT_WATER || fogmat==MAT_LAVA) drawfogoverlay(fogmat, fogblend, abovemat);
1799 renderpostfx();
1800
1801 glDisable(GL_TEXTURE_2D);
1802 notextureshader->set();
1803 if(editmode)
1804 {
1805 glEnable(GL_DEPTH_TEST);
1806 glDepthMask(GL_FALSE);
1807
1808 renderblendbrush();
1809
1810 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1811 cursorupdate();
1812 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1813
1814 glDepthMask(GL_TRUE);
1815 glDisable(GL_DEPTH_TEST);
1816 }
1817
1818 glMatrixMode(GL_MODELVIEW);
1819 glLoadIdentity();
1820 int w = screen->w, h = screen->h;
1821 gettextres(w, h);
1822 glMatrixMode(GL_PROJECTION);
1823 glLoadIdentity();
1824 glOrtho(0, w, h, 0, -1, 1);
1825 glColor3f(1, 1, 1);
1826
1827 extern int debugsm;
1828 if(debugsm)
1829 {
1830 extern void viewshadowmap();
1831 viewshadowmap();
1832 }
1833
1834 extern int debugglare;
1835 if(debugglare)
1836 {
1837 extern void viewglaretex();
1838 viewglaretex();
1839 }
1840
1841 extern int debugdepthfx;
1842 if(debugdepthfx)
1843 {
1844 extern void viewdepthfxtex();
1845 viewdepthfxtex();
1846 }
1847
1848 glEnable(GL_TEXTURE_2D);
1849 defaultshader->set();
1850 hud::drawhud();
1851 render_texture_panel(w, h);
1852 if(commandmillis<0) UI::render();
1853 hud::drawlast();
1854 glDisable(GL_TEXTURE_2D);
1855
1856 renderedgame = false;
1857
1858 if(targtype == VP_LEFT || targtype == VP_RIGHT)
1859 {
1860 if(viewtype >= VW_STEREO)
1861 {
1862 setcolormask();
1863 glColorMask(COLORMASK, GL_TRUE);
1864 }
1865 }
1866 }
1867
gl_drawframe(int w,int h)1868 void gl_drawframe(int w, int h)
1869 {
1870 if(client::ready())
1871 {
1872 fogmat = lookupmaterial(camera1->o)&MATF_VOLUME;
1873 causticspass = 0.f;
1874 if(fogmat == MAT_WATER || fogmat == MAT_LAVA)
1875 {
1876 float z = findsurface(fogmat, camera1->o, abovemat) - WATER_OFFSET;
1877 if(camera1->o.z < z + 1) fogblend = min(z + 1 - camera1->o.z, 1.0f);
1878 else fogmat = abovemat;
1879 if(caustics && fogmat == MAT_WATER && camera1->o.z < z)
1880 causticspass = renderpath==R_FIXEDFUNCTION ? 1.0f : min(z - camera1->o.z, 1.0f);
1881
1882 float blend = abovemat == MAT_AIR ? fogblend : 1.0f;
1883 fovy += blend*sinf(lastmillis/1000.0)*2.0f;
1884 aspect += blend*sinf(lastmillis/1000.0+PI)*0.1f;
1885 }
1886 else fogmat = MAT_AIR;
1887
1888 farplane = hdr.worldsize*2;
1889 project(fovy, aspect, farplane);
1890 transplayer();
1891 readmatrices();
1892 game::project(w, h);
1893
1894 int copies = 0, oldcurtime = curtime;
1895 loopi(VP_MAX) if(needsview(viewtype, i))
1896 {
1897 drawview(i);
1898 if(copyview(viewtype, i))
1899 {
1900 views[i].copy();
1901 copies++;
1902 }
1903 curtime = 0;
1904 }
1905 if(needsview(viewtype, VP_CAMERA)) drawview(VP_CAMERA);
1906 curtime = oldcurtime;
1907
1908 if(!copies) return;
1909
1910 glMatrixMode(GL_MODELVIEW);
1911 glLoadIdentity();
1912 glMatrixMode(GL_PROJECTION);
1913 glLoadIdentity();
1914 glOrtho(0, 1, 0, 1, -1, 1);
1915 glDisable(GL_BLEND);
1916 glEnable(GL_TEXTURE_2D);
1917 defaultshader->set();
1918 glColor3f(1.f, 1.f, 1.f);
1919 switch(viewtype)
1920 {
1921 case VW_MAGIC:
1922 {
1923 views[VP_LEFT].draw(0, 0, 0.5f, 1);
1924 views[VP_RIGHT].draw(0.5f, 0, 0.5f, 1);
1925 break;
1926 }
1927 case VW_STEREO_BLEND:
1928 case VW_STEREO_BLEND_REDCYAN:
1929 {
1930 glEnable(GL_BLEND);
1931 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1932 if(viewtype == VW_STEREO_BLEND) glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE);
1933 glColor4f(1.f, 1.f, 1.f, stereoblend); views[VP_RIGHT].draw(0, 0, 1, 1);
1934 if(viewtype == VW_STEREO_BLEND) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1935 glDisable(GL_BLEND);
1936 break;
1937 }
1938 case VW_STEREO_AVG:
1939 {
1940 glEnable(GL_BLEND);
1941 if(hasBC)
1942 {
1943 glBlendFunc(GL_ONE, GL_CONSTANT_COLOR_EXT);
1944 glBlendColor_(0.f, 0.5f, 1.f, 1.f);
1945 }
1946 else
1947 {
1948 glDisable(GL_TEXTURE_2D);
1949 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
1950 glColor3f(0.f, 0.5f, 1.f);
1951 glBegin(GL_QUADS);
1952 glVertex2f(0, 0);
1953 glVertex2f(1, 0);
1954 glVertex2f(1, 1);
1955 glVertex2f(0, 1);
1956 glEnd();
1957 glEnable(GL_TEXTURE_2D);
1958 glBlendFunc(GL_ONE, GL_ONE);
1959 }
1960 glColor3f(1.f, 0.5f, 0.f);
1961 views[VP_LEFT].draw(0, 0, 1, 1);
1962 glDisable(GL_BLEND);
1963 break;
1964 }
1965 }
1966 glDisable(GL_TEXTURE_2D);
1967 }
1968 else drawnoview();
1969 }
1970
usetexturing(bool on)1971 void usetexturing(bool on)
1972 {
1973 if(on)
1974 {
1975 defaultshader->set();
1976 glEnable(GL_TEXTURE_2D);
1977 }
1978 else
1979 {
1980 notextureshader->set();
1981 glDisable(GL_TEXTURE_2D);
1982 }
1983 }
1984