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 &center, 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