1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1998-2020 by Sonic Team Junior.
4 //
5 // This program is free software distributed under the
6 // terms of the GNU General Public License, version 2.
7 // See the 'LICENSE' file for more details.
8 //-----------------------------------------------------------------------------
9 /// \file r_opengl.c
10 /// \brief OpenGL API for Sonic Robo Blast 2
11
12 #if defined (_WIN32)
13 //#define WIN32_LEAN_AND_MEAN
14 #define RPC_NO_WINDOWS_H
15 #include <windows.h>
16 #endif
17 #undef GETTEXT
18 #ifdef __GNUC__
19 #include <unistd.h>
20 #endif
21
22 #include <stdarg.h>
23 #include <math.h>
24 #include "r_opengl.h"
25 #include "r_vbo.h"
26
27 #if defined (HWRENDER) && !defined (NOROPENGL)
28
29 struct GLRGBAFloat
30 {
31 GLfloat red;
32 GLfloat green;
33 GLfloat blue;
34 GLfloat alpha;
35 };
36 typedef struct GLRGBAFloat GLRGBAFloat;
37 static const GLubyte white[4] = { 255, 255, 255, 255 };
38
39 // ==========================================================================
40 // CONSTANTS
41 // ==========================================================================
42
43 // With OpenGL 1.1+, the first texture should be 1
44 static GLuint NOTEXTURE_NUM = 0;
45
46 #define N_PI_DEMI (M_PIl/2.0f) //(1.5707963268f)
47
48 #define ASPECT_RATIO (1.0f) //(320.0f/200.0f)
49 #define FAR_CLIPPING_PLANE 32768.0f // Draw further! Tails 01-21-2001
50 static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE;
51
52 // **************************************************************************
53 // GLOBALS
54 // **************************************************************************
55
56
57 static GLuint tex_downloaded = 0;
58 static GLfloat fov = 90.0f;
59 static FBITFIELD CurrentPolyFlags;
60
61 // Linked list of all textures.
62 static FTextureInfo *TexCacheTail = NULL;
63 static FTextureInfo *TexCacheHead = NULL;
64
65 RGBA_t myPaletteData[256];
66 GLint screen_width = 0; // used by Draw2DLine()
67 GLint screen_height = 0;
68 GLbyte screen_depth = 0;
69 GLint textureformatGL = 0;
70 GLint maximumAnisotropy = 0;
71 static GLboolean MipMap = GL_FALSE;
72 static GLint min_filter = GL_LINEAR;
73 static GLint mag_filter = GL_LINEAR;
74 static GLint anisotropic_filter = 0;
75 static boolean model_lighting = false;
76
77 const GLubyte *gl_version = NULL;
78 const GLubyte *gl_renderer = NULL;
79 const GLubyte *gl_extensions = NULL;
80
81 //Hurdler: 04/10/2000: added for the kick ass coronas as Boris wanted;-)
82 static GLfloat modelMatrix[16];
83 static GLfloat projMatrix[16];
84 static GLint viewport[4];
85
86 // Sryder: NextTexAvail is broken for these because palette changes or changes to the texture filter or antialiasing
87 // flush all of the stored textures, leaving them unavailable at times such as between levels
88 // These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs
89 // can know when the textures aren't there, as textures are always considered resident in their virtual memory
90 static GLuint screentexture = 0;
91 static GLuint startScreenWipe = 0;
92 static GLuint endScreenWipe = 0;
93 static GLuint finalScreenTexture = 0;
94
95 // shortcut for ((float)1/i)
96 static const GLfloat byte2float[256] = {
97 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f,
98 0.031373f, 0.035294f, 0.039216f, 0.043137f, 0.047059f, 0.050980f, 0.054902f, 0.058824f,
99 0.062745f, 0.066667f, 0.070588f, 0.074510f, 0.078431f, 0.082353f, 0.086275f, 0.090196f,
100 0.094118f, 0.098039f, 0.101961f, 0.105882f, 0.109804f, 0.113725f, 0.117647f, 0.121569f,
101 0.125490f, 0.129412f, 0.133333f, 0.137255f, 0.141176f, 0.145098f, 0.149020f, 0.152941f,
102 0.156863f, 0.160784f, 0.164706f, 0.168627f, 0.172549f, 0.176471f, 0.180392f, 0.184314f,
103 0.188235f, 0.192157f, 0.196078f, 0.200000f, 0.203922f, 0.207843f, 0.211765f, 0.215686f,
104 0.219608f, 0.223529f, 0.227451f, 0.231373f, 0.235294f, 0.239216f, 0.243137f, 0.247059f,
105 0.250980f, 0.254902f, 0.258824f, 0.262745f, 0.266667f, 0.270588f, 0.274510f, 0.278431f,
106 0.282353f, 0.286275f, 0.290196f, 0.294118f, 0.298039f, 0.301961f, 0.305882f, 0.309804f,
107 0.313726f, 0.317647f, 0.321569f, 0.325490f, 0.329412f, 0.333333f, 0.337255f, 0.341176f,
108 0.345098f, 0.349020f, 0.352941f, 0.356863f, 0.360784f, 0.364706f, 0.368627f, 0.372549f,
109 0.376471f, 0.380392f, 0.384314f, 0.388235f, 0.392157f, 0.396078f, 0.400000f, 0.403922f,
110 0.407843f, 0.411765f, 0.415686f, 0.419608f, 0.423529f, 0.427451f, 0.431373f, 0.435294f,
111 0.439216f, 0.443137f, 0.447059f, 0.450980f, 0.454902f, 0.458824f, 0.462745f, 0.466667f,
112 0.470588f, 0.474510f, 0.478431f, 0.482353f, 0.486275f, 0.490196f, 0.494118f, 0.498039f,
113 0.501961f, 0.505882f, 0.509804f, 0.513726f, 0.517647f, 0.521569f, 0.525490f, 0.529412f,
114 0.533333f, 0.537255f, 0.541177f, 0.545098f, 0.549020f, 0.552941f, 0.556863f, 0.560784f,
115 0.564706f, 0.568627f, 0.572549f, 0.576471f, 0.580392f, 0.584314f, 0.588235f, 0.592157f,
116 0.596078f, 0.600000f, 0.603922f, 0.607843f, 0.611765f, 0.615686f, 0.619608f, 0.623529f,
117 0.627451f, 0.631373f, 0.635294f, 0.639216f, 0.643137f, 0.647059f, 0.650980f, 0.654902f,
118 0.658824f, 0.662745f, 0.666667f, 0.670588f, 0.674510f, 0.678431f, 0.682353f, 0.686275f,
119 0.690196f, 0.694118f, 0.698039f, 0.701961f, 0.705882f, 0.709804f, 0.713726f, 0.717647f,
120 0.721569f, 0.725490f, 0.729412f, 0.733333f, 0.737255f, 0.741177f, 0.745098f, 0.749020f,
121 0.752941f, 0.756863f, 0.760784f, 0.764706f, 0.768627f, 0.772549f, 0.776471f, 0.780392f,
122 0.784314f, 0.788235f, 0.792157f, 0.796078f, 0.800000f, 0.803922f, 0.807843f, 0.811765f,
123 0.815686f, 0.819608f, 0.823529f, 0.827451f, 0.831373f, 0.835294f, 0.839216f, 0.843137f,
124 0.847059f, 0.850980f, 0.854902f, 0.858824f, 0.862745f, 0.866667f, 0.870588f, 0.874510f,
125 0.878431f, 0.882353f, 0.886275f, 0.890196f, 0.894118f, 0.898039f, 0.901961f, 0.905882f,
126 0.909804f, 0.913726f, 0.917647f, 0.921569f, 0.925490f, 0.929412f, 0.933333f, 0.937255f,
127 0.941177f, 0.945098f, 0.949020f, 0.952941f, 0.956863f, 0.960784f, 0.964706f, 0.968628f,
128 0.972549f, 0.976471f, 0.980392f, 0.984314f, 0.988235f, 0.992157f, 0.996078f, 1.000000f
129 };
130
131 // -----------------+
132 // GL_DBG_Printf : Output debug messages to debug log if DEBUG_TO_FILE is defined,
133 // : else do nothing
134 // Returns :
135 // -----------------+
136
137 #ifdef DEBUG_TO_FILE
138 FILE *gllogstream;
139 #endif
140
GL_DBG_Printf(const char * format,...)141 FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
142 {
143 #ifdef DEBUG_TO_FILE
144 char str[4096] = "";
145 va_list arglist;
146
147 if (!gllogstream)
148 gllogstream = fopen("ogllog.txt", "w");
149
150 va_start(arglist, format);
151 vsnprintf(str, 4096, format, arglist);
152 va_end(arglist);
153
154 fwrite(str, strlen(str), 1, gllogstream);
155 #else
156 (void)format;
157 #endif
158 }
159
160 // -----------------+
161 // GL_MSG_Warning : Raises a warning.
162 // :
163 // Returns :
164 // -----------------+
165
GL_MSG_Warning(const char * format,...)166 static void GL_MSG_Warning(const char *format, ...)
167 {
168 char str[4096] = "";
169 va_list arglist;
170
171 va_start(arglist, format);
172 vsnprintf(str, 4096, format, arglist);
173 va_end(arglist);
174
175 #ifdef HAVE_SDL
176 CONS_Alert(CONS_WARNING, "%s", str);
177 #endif
178 #ifdef DEBUG_TO_FILE
179 if (!gllogstream)
180 gllogstream = fopen("ogllog.txt", "w");
181 fwrite(str, strlen(str), 1, gllogstream);
182 #endif
183 }
184
185 // -----------------+
186 // GL_MSG_Error : Raises an error.
187 // :
188 // Returns :
189 // -----------------+
190
GL_MSG_Error(const char * format,...)191 static void GL_MSG_Error(const char *format, ...)
192 {
193 char str[4096] = "";
194 va_list arglist;
195
196 va_start(arglist, format);
197 vsnprintf(str, 4096, format, arglist);
198 va_end(arglist);
199
200 #ifdef HAVE_SDL
201 CONS_Alert(CONS_ERROR, "%s", str);
202 #endif
203 #ifdef DEBUG_TO_FILE
204 if (!gllogstream)
205 gllogstream = fopen("ogllog.txt", "w");
206 fwrite(str, strlen(str), 1, gllogstream);
207 #endif
208 }
209
210 #ifdef STATIC_OPENGL
211 /* 1.0 functions */
212 /* Miscellaneous */
213 #define pglClearColor glClearColor
214 //glClear
215 #define pglColorMask glColorMask
216 #define pglAlphaFunc glAlphaFunc
217 #define pglBlendFunc glBlendFunc
218 #define pglCullFace glCullFace
219 #define pglPolygonOffset glPolygonOffset
220 #define pglScissor glScissor
221 #define pglEnable glEnable
222 #define pglDisable glDisable
223 #define pglGetFloatv glGetFloatv
224 //glGetIntegerv
225 //glGetString
226 #define pglHint glHint
227
228 /* Depth Buffer */
229 #define pglClearDepth glClearDepth
230 #define pglDepthFunc glDepthFunc
231 #define pglDepthMask glDepthMask
232 #define pglDepthRange glDepthRange
233
234 /* Transformation */
235 #define pglMatrixMode glMatrixMode
236 #define pglViewport glViewport
237 #define pglPushMatrix glPushMatrix
238 #define pglPopMatrix glPopMatrix
239 #define pglLoadIdentity glLoadIdentity
240 #define pglMultMatrixf glMultMatrixf
241 #define pglRotatef glRotatef
242 #define pglScalef glScalef
243 #define pglTranslatef glTranslatef
244
245 /* Drawing Functions */
246 #define pglColor4ubv glColor4ubv
247 #define pglVertexPointer glVertexPointer
248 #define pglNormalPointer glNormalPointer
249 #define pglTexCoordPointer glTexCoordPointer
250 #define pglColorPointer glColorPointer
251 #define pglDrawArrays glDrawArrays
252 #define pglDrawElements glDrawElements
253 #define pglEnableClientState glEnableClientState
254 #define pglDisableClientState glDisableClientState
255
256 /* Lighting */
257 #define pglShadeModel glShadeModel
258 #define pglLightfv glLightfv
259 #define pglLightModelfv glLightModelfv
260 #define pglMaterialfv glMaterialfv
261 #define pglMateriali glMateriali
262
263 /* Raster functions */
264 #define pglPixelStorei glPixelStorei
265 #define pglReadPixels glReadPixels
266
267 /* Texture mapping */
268 #define pglTexEnvi glTexEnvi
269 #define pglTexParameteri glTexParameteri
270 #define pglTexImage2D glTexImage2D
271 #define pglTexSubImage2D glTexSubImage2D
272
273 /* 1.1 functions */
274 /* texture objects */ //GL_EXT_texture_object
275 #define pglGenTextures glGenTextures
276 #define pglDeleteTextures glDeleteTextures
277 #define pglBindTexture glBindTexture
278 /* texture mapping */ //GL_EXT_copy_texture
279 #define pglCopyTexImage2D glCopyTexImage2D
280 #define pglCopyTexSubImage2D glCopyTexSubImage2D
281
282 #else //!STATIC_OPENGL
283
284 /* 1.0 functions */
285 /* Miscellaneous */
286 typedef void (APIENTRY * PFNglClearColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
287 static PFNglClearColor pglClearColor;
288 typedef void (APIENTRY * PFNglColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
289 static PFNglColorMask pglColorMask;
290 typedef void (APIENTRY * PFNglAlphaFunc) (GLenum func, GLclampf ref);
291 static PFNglAlphaFunc pglAlphaFunc;
292 typedef void (APIENTRY * PFNglBlendFunc) (GLenum sfactor, GLenum dfactor);
293 static PFNglBlendFunc pglBlendFunc;
294 typedef void (APIENTRY * PFNglCullFace) (GLenum mode);
295 static PFNglCullFace pglCullFace;
296 typedef void (APIENTRY * PFNglPolygonOffset) (GLfloat factor, GLfloat units);
297 static PFNglPolygonOffset pglPolygonOffset;
298 typedef void (APIENTRY * PFNglScissor) (GLint x, GLint y, GLsizei width, GLsizei height);
299 static PFNglScissor pglScissor;
300 typedef void (APIENTRY * PFNglEnable) (GLenum cap);
301 static PFNglEnable pglEnable;
302 typedef void (APIENTRY * PFNglDisable) (GLenum cap);
303 static PFNglDisable pglDisable;
304 typedef void (APIENTRY * PFNglGetFloatv) (GLenum pname, GLfloat *params);
305 static PFNglGetFloatv pglGetFloatv;
306
307 /* Depth Buffer */
308 typedef void (APIENTRY * PFNglClearDepth) (GLclampd depth);
309 static PFNglClearDepth pglClearDepth;
310 typedef void (APIENTRY * PFNglDepthFunc) (GLenum func);
311 static PFNglDepthFunc pglDepthFunc;
312 typedef void (APIENTRY * PFNglDepthMask) (GLboolean flag);
313 static PFNglDepthMask pglDepthMask;
314 typedef void (APIENTRY * PFNglDepthRange) (GLclampd near_val, GLclampd far_val);
315 static PFNglDepthRange pglDepthRange;
316
317 /* Transformation */
318 typedef void (APIENTRY * PFNglMatrixMode) (GLenum mode);
319 static PFNglMatrixMode pglMatrixMode;
320 typedef void (APIENTRY * PFNglViewport) (GLint x, GLint y, GLsizei width, GLsizei height);
321 static PFNglViewport pglViewport;
322 typedef void (APIENTRY * PFNglPushMatrix) (void);
323 static PFNglPushMatrix pglPushMatrix;
324 typedef void (APIENTRY * PFNglPopMatrix) (void);
325 static PFNglPopMatrix pglPopMatrix;
326 typedef void (APIENTRY * PFNglLoadIdentity) (void);
327 static PFNglLoadIdentity pglLoadIdentity;
328 typedef void (APIENTRY * PFNglMultMatrixf) (const GLfloat *m);
329 static PFNglMultMatrixf pglMultMatrixf;
330 typedef void (APIENTRY * PFNglRotatef) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
331 static PFNglRotatef pglRotatef;
332 typedef void (APIENTRY * PFNglScalef) (GLfloat x, GLfloat y, GLfloat z);
333 static PFNglScalef pglScalef;
334 typedef void (APIENTRY * PFNglTranslatef) (GLfloat x, GLfloat y, GLfloat z);
335 static PFNglTranslatef pglTranslatef;
336
337 /* Drawing Functions */
338 typedef void (APIENTRY * PFNglColor4ubv) (const GLubyte *v);
339 static PFNglColor4ubv pglColor4ubv;
340 typedef void (APIENTRY * PFNglVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
341 static PFNglVertexPointer pglVertexPointer;
342 typedef void (APIENTRY * PFNglNormalPointer) (GLenum type, GLsizei stride, const GLvoid *pointer);
343 static PFNglNormalPointer pglNormalPointer;
344 typedef void (APIENTRY * PFNglTexCoordPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
345 static PFNglTexCoordPointer pglTexCoordPointer;
346 typedef void (APIENTRY * PFNglColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
347 static PFNglColorPointer pglColorPointer;
348 typedef void (APIENTRY * PFNglDrawArrays) (GLenum mode, GLint first, GLsizei count);
349 static PFNglDrawArrays pglDrawArrays;
350 typedef void (APIENTRY * PFNglDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
351 static PFNglDrawElements pglDrawElements;
352 typedef void (APIENTRY * PFNglEnableClientState) (GLenum cap);
353 static PFNglEnableClientState pglEnableClientState;
354 typedef void (APIENTRY * PFNglDisableClientState) (GLenum cap);
355 static PFNglDisableClientState pglDisableClientState;
356
357 /* Lighting */
358 typedef void (APIENTRY * PFNglShadeModel) (GLenum mode);
359 static PFNglShadeModel pglShadeModel;
360 typedef void (APIENTRY * PFNglLightfv) (GLenum light, GLenum pname, GLfloat *params);
361 static PFNglLightfv pglLightfv;
362 typedef void (APIENTRY * PFNglLightModelfv) (GLenum pname, GLfloat *params);
363 static PFNglLightModelfv pglLightModelfv;
364 typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *params);
365 static PFNglMaterialfv pglMaterialfv;
366 typedef void (APIENTRY * PFNglMateriali) (GLint face, GLenum pname, GLint param);
367 static PFNglMateriali pglMateriali;
368
369 /* Raster functions */
370 typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
371 static PFNglPixelStorei pglPixelStorei;
372 typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
373 static PFNglReadPixels pglReadPixels;
374
375 /* Texture mapping */
376 typedef void (APIENTRY * PFNglTexEnvi) (GLenum target, GLenum pname, GLint param);
377 static PFNglTexEnvi pglTexEnvi;
378 typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param);
379 static PFNglTexParameteri pglTexParameteri;
380 typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
381 static PFNglTexImage2D pglTexImage2D;
382 typedef void (APIENTRY * PFNglTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
383 static PFNglTexSubImage2D pglTexSubImage2D;
384
385 /* 1.1 functions */
386 /* texture objects */ //GL_EXT_texture_object
387 typedef void (APIENTRY * PFNglGenTextures) (GLsizei n, const GLuint *textures);
388 static PFNglGenTextures pglGenTextures;
389 typedef void (APIENTRY * PFNglDeleteTextures) (GLsizei n, const GLuint *textures);
390 static PFNglDeleteTextures pglDeleteTextures;
391 typedef void (APIENTRY * PFNglBindTexture) (GLenum target, GLuint texture);
392 static PFNglBindTexture pglBindTexture;
393 /* texture mapping */ //GL_EXT_copy_texture
394 typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
395 static PFNglCopyTexImage2D pglCopyTexImage2D;
396 typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
397 static PFNglCopyTexSubImage2D pglCopyTexSubImage2D;
398 #endif
399 /* GLU functions */
400 typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
401 static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
402
403 /* 1.3 functions for multitexturing */
404 typedef void (APIENTRY *PFNglActiveTexture) (GLenum);
405 static PFNglActiveTexture pglActiveTexture;
406 typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
407 static PFNglMultiTexCoord2f pglMultiTexCoord2f;
408 typedef void (APIENTRY *PFNglMultiTexCoord2fv) (GLenum target, const GLfloat *v);
409 static PFNglMultiTexCoord2fv pglMultiTexCoord2fv;
410 typedef void (APIENTRY *PFNglClientActiveTexture) (GLenum);
411 static PFNglClientActiveTexture pglClientActiveTexture;
412
413 /* 1.5 functions for buffers */
414 typedef void (APIENTRY * PFNglGenBuffers) (GLsizei n, GLuint *buffers);
415 static PFNglGenBuffers pglGenBuffers;
416 typedef void (APIENTRY * PFNglBindBuffer) (GLenum target, GLuint buffer);
417 static PFNglBindBuffer pglBindBuffer;
418 typedef void (APIENTRY * PFNglBufferData) (GLenum target, GLsizei size, const GLvoid *data, GLenum usage);
419 static PFNglBufferData pglBufferData;
420 typedef void (APIENTRY * PFNglDeleteBuffers) (GLsizei n, const GLuint *buffers);
421 static PFNglDeleteBuffers pglDeleteBuffers;
422
423 /* 2.0 functions */
424 typedef void (APIENTRY * PFNglBlendEquation) (GLenum mode);
425 static PFNglBlendEquation pglBlendEquation;
426
427
428 /* 1.2 Parms */
429 /* GL_CLAMP_TO_EDGE_EXT */
430 #ifndef GL_CLAMP_TO_EDGE
431 #define GL_CLAMP_TO_EDGE 0x812F
432 #endif
433 #ifndef GL_TEXTURE_MIN_LOD
434 #define GL_TEXTURE_MIN_LOD 0x813A
435 #endif
436 #ifndef GL_TEXTURE_MAX_LOD
437 #define GL_TEXTURE_MAX_LOD 0x813B
438 #endif
439
440 /* 1.3 GL_TEXTUREi */
441 #ifndef GL_TEXTURE0
442 #define GL_TEXTURE0 0x84C0
443 #endif
444 #ifndef GL_TEXTURE1
445 #define GL_TEXTURE1 0x84C1
446 #endif
447
448 /* 1.5 Parms */
449 #ifndef GL_ARRAY_BUFFER
450 #define GL_ARRAY_BUFFER 0x8892
451 #endif
452 #ifndef GL_STATIC_DRAW
453 #define GL_STATIC_DRAW 0x88E4
454 #endif
455
SetupGLfunc(void)456 boolean SetupGLfunc(void)
457 {
458 #ifndef STATIC_OPENGL
459 #define GETOPENGLFUNC(func, proc) \
460 func = GetGLFunc(#proc); \
461 if (!func) \
462 { \
463 GL_MSG_Warning("failed to get OpenGL function: %s", #proc); \
464 } \
465
466 GETOPENGLFUNC(pglClearColor, glClearColor)
467
468 GETOPENGLFUNC(pglClear, glClear)
469 GETOPENGLFUNC(pglColorMask, glColorMask)
470 GETOPENGLFUNC(pglAlphaFunc, glAlphaFunc)
471 GETOPENGLFUNC(pglBlendFunc, glBlendFunc)
472 GETOPENGLFUNC(pglCullFace, glCullFace)
473 GETOPENGLFUNC(pglPolygonOffset, glPolygonOffset)
474 GETOPENGLFUNC(pglScissor, glScissor)
475 GETOPENGLFUNC(pglEnable, glEnable)
476 GETOPENGLFUNC(pglDisable, glDisable)
477 GETOPENGLFUNC(pglGetFloatv, glGetFloatv)
478 GETOPENGLFUNC(pglGetIntegerv, glGetIntegerv)
479 GETOPENGLFUNC(pglGetString, glGetString)
480
481 GETOPENGLFUNC(pglClearDepth, glClearDepth)
482 GETOPENGLFUNC(pglDepthFunc, glDepthFunc)
483 GETOPENGLFUNC(pglDepthMask, glDepthMask)
484 GETOPENGLFUNC(pglDepthRange, glDepthRange)
485
486 GETOPENGLFUNC(pglMatrixMode, glMatrixMode)
487 GETOPENGLFUNC(pglViewport, glViewport)
488 GETOPENGLFUNC(pglPushMatrix, glPushMatrix)
489 GETOPENGLFUNC(pglPopMatrix, glPopMatrix)
490 GETOPENGLFUNC(pglLoadIdentity, glLoadIdentity)
491 GETOPENGLFUNC(pglMultMatrixf, glMultMatrixf)
492 GETOPENGLFUNC(pglRotatef, glRotatef)
493 GETOPENGLFUNC(pglScalef, glScalef)
494 GETOPENGLFUNC(pglTranslatef, glTranslatef)
495
496 GETOPENGLFUNC(pglColor4ubv, glColor4ubv)
497
498 GETOPENGLFUNC(pglVertexPointer, glVertexPointer)
499 GETOPENGLFUNC(pglNormalPointer, glNormalPointer)
500 GETOPENGLFUNC(pglTexCoordPointer, glTexCoordPointer)
501 GETOPENGLFUNC(pglColorPointer, glColorPointer)
502 GETOPENGLFUNC(pglDrawArrays, glDrawArrays)
503 GETOPENGLFUNC(pglDrawElements, glDrawElements)
504 GETOPENGLFUNC(pglEnableClientState, glEnableClientState)
505 GETOPENGLFUNC(pglDisableClientState, glDisableClientState)
506
507 GETOPENGLFUNC(pglShadeModel, glShadeModel)
508 GETOPENGLFUNC(pglLightfv, glLightfv)
509 GETOPENGLFUNC(pglLightModelfv, glLightModelfv)
510 GETOPENGLFUNC(pglMaterialfv, glMaterialfv)
511 GETOPENGLFUNC(pglMateriali, glMateriali)
512
513 GETOPENGLFUNC(pglPixelStorei, glPixelStorei)
514 GETOPENGLFUNC(pglReadPixels, glReadPixels)
515
516 GETOPENGLFUNC(pglTexEnvi, glTexEnvi)
517 GETOPENGLFUNC(pglTexParameteri, glTexParameteri)
518 GETOPENGLFUNC(pglTexImage2D, glTexImage2D)
519 GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D)
520
521 GETOPENGLFUNC(pglGenTextures, glGenTextures)
522 GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures)
523 GETOPENGLFUNC(pglBindTexture, glBindTexture)
524
525 GETOPENGLFUNC(pglCopyTexImage2D, glCopyTexImage2D)
526 GETOPENGLFUNC(pglCopyTexSubImage2D, glCopyTexSubImage2D)
527
528 #undef GETOPENGLFUNC
529
530 #endif
531 return true;
532 }
533
534 static boolean gl_shadersenabled = false;
535 static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF;
536
537 #ifdef GL_SHADERS
538 typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum);
539 typedef void (APIENTRY *PFNglShaderSource) (GLuint, GLsizei, const GLchar**, GLint*);
540 typedef void (APIENTRY *PFNglCompileShader) (GLuint);
541 typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*);
542 typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*);
543 typedef void (APIENTRY *PFNglDeleteShader) (GLuint);
544 typedef GLuint (APIENTRY *PFNglCreateProgram) (void);
545 typedef void (APIENTRY *PFNglDeleteProgram) (GLuint);
546 typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint);
547 typedef void (APIENTRY *PFNglLinkProgram) (GLuint);
548 typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*);
549 typedef void (APIENTRY *PFNglUseProgram) (GLuint);
550 typedef void (APIENTRY *PFNglUniform1i) (GLint, GLint);
551 typedef void (APIENTRY *PFNglUniform1f) (GLint, GLfloat);
552 typedef void (APIENTRY *PFNglUniform2f) (GLint, GLfloat, GLfloat);
553 typedef void (APIENTRY *PFNglUniform3f) (GLint, GLfloat, GLfloat, GLfloat);
554 typedef void (APIENTRY *PFNglUniform4f) (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
555 typedef void (APIENTRY *PFNglUniform1fv) (GLint, GLsizei, const GLfloat*);
556 typedef void (APIENTRY *PFNglUniform2fv) (GLint, GLsizei, const GLfloat*);
557 typedef void (APIENTRY *PFNglUniform3fv) (GLint, GLsizei, const GLfloat*);
558 typedef GLint (APIENTRY *PFNglGetUniformLocation) (GLuint, const GLchar*);
559
560 static PFNglCreateShader pglCreateShader;
561 static PFNglShaderSource pglShaderSource;
562 static PFNglCompileShader pglCompileShader;
563 static PFNglGetShaderiv pglGetShaderiv;
564 static PFNglGetShaderInfoLog pglGetShaderInfoLog;
565 static PFNglDeleteShader pglDeleteShader;
566 static PFNglCreateProgram pglCreateProgram;
567 static PFNglDeleteProgram pglDeleteProgram;
568 static PFNglAttachShader pglAttachShader;
569 static PFNglLinkProgram pglLinkProgram;
570 static PFNglGetProgramiv pglGetProgramiv;
571 static PFNglUseProgram pglUseProgram;
572 static PFNglUniform1i pglUniform1i;
573 static PFNglUniform1f pglUniform1f;
574 static PFNglUniform2f pglUniform2f;
575 static PFNglUniform3f pglUniform3f;
576 static PFNglUniform4f pglUniform4f;
577 static PFNglUniform1fv pglUniform1fv;
578 static PFNglUniform2fv pglUniform2fv;
579 static PFNglUniform3fv pglUniform3fv;
580 static PFNglGetUniformLocation pglGetUniformLocation;
581
582 // 13062019
583 typedef enum
584 {
585 // lighting
586 gluniform_poly_color,
587 gluniform_tint_color,
588 gluniform_fade_color,
589 gluniform_lighting,
590 gluniform_fade_start,
591 gluniform_fade_end,
592
593 // misc. (custom shaders)
594 gluniform_leveltime,
595
596 gluniform_max,
597 } gluniform_t;
598
599 typedef struct gl_shader_s
600 {
601 GLuint program;
602 GLint uniforms[gluniform_max+1];
603 boolean custom;
604 } gl_shader_t;
605
606 static gl_shader_t gl_shaders[HWR_MAXSHADERS];
607 static gl_shader_t gl_usershaders[HWR_MAXSHADERS];
608 static shadersource_t gl_customshaders[HWR_MAXSHADERS];
609
610 // 09102020
611 typedef struct gl_shaderstate_s
612 {
613 gl_shader_t *current;
614 GLuint type;
615 GLuint program;
616 boolean changed;
617 } gl_shaderstate_t;
618 static gl_shaderstate_t gl_shaderstate;
619
620 // Shader info
621 static INT32 shader_leveltime = 0;
622
623 // Lactozilla: Shader functions
624 static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader);
625 static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum);
626 static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
627
628 static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
629
630 // ================
631 // Vertex shaders
632 // ================
633
634 //
635 // Generic vertex shader
636 //
637
638 #define GLSL_DEFAULT_VERTEX_SHADER \
639 "void main()\n" \
640 "{\n" \
641 "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
642 "gl_FrontColor = gl_Color;\n" \
643 "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
644 "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
645 "}\0"
646
647 // replicates the way fixed function lighting is used by the model lighting option,
648 // stores the lighting result to gl_Color
649 // (ambient lighting of 0.75 and diffuse lighting from above)
650 #define GLSL_MODEL_LIGHTING_VERTEX_SHADER \
651 "void main()\n" \
652 "{\n" \
653 "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \
654 "float light = 0.75 + max(nDotVP, 0.0);\n" \
655 "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
656 "gl_FrontColor = vec4(light, light, light, 1.0);\n" \
657 "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
658 "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
659 "}\0"
660
661 // ==================
662 // Fragment shaders
663 // ==================
664
665 //
666 // Generic fragment shader
667 //
668
669 #define GLSL_DEFAULT_FRAGMENT_SHADER \
670 "uniform sampler2D tex;\n" \
671 "uniform vec4 poly_color;\n" \
672 "void main(void) {\n" \
673 "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
674 "}\0"
675
676 //
677 // Software fragment shader
678 //
679
680 #define GLSL_DOOM_COLORMAP \
681 "float R_DoomColormap(float light, float z)\n" \
682 "{\n" \
683 "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \
684 "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
685 "float startmap = (15.0 - lightnum) * 4.0;\n" \
686 "float scale = 160.0 / (lightz + 1.0);\n" \
687 "return startmap - scale * 0.5;\n" \
688 "}\n"
689
690 #define GLSL_DOOM_LIGHT_EQUATION \
691 "float R_DoomLightingEquation(float light)\n" \
692 "{\n" \
693 "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
694 "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \
695 "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \
696 "}\n"
697
698 #define GLSL_SOFTWARE_TINT_EQUATION \
699 "if (tint_color.a > 0.0) {\n" \
700 "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \
701 "float strength = sqrt(9.0 * tint_color.a);\n" \
702 "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \
703 "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \
704 "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \
705 "}\n"
706
707 #define GLSL_SOFTWARE_FADE_EQUATION \
708 "float darkness = R_DoomLightingEquation(lighting);\n" \
709 "if (fade_start != 0.0 || fade_end != 31.0) {\n" \
710 "float fs = fade_start / 31.0;\n" \
711 "float fe = fade_end / 31.0;\n" \
712 "float fd = fe - fs;\n" \
713 "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
714 "}\n" \
715 "final_color = mix(final_color, fade_color, darkness);\n"
716
717 #define GLSL_SOFTWARE_FRAGMENT_SHADER \
718 "uniform sampler2D tex;\n" \
719 "uniform vec4 poly_color;\n" \
720 "uniform vec4 tint_color;\n" \
721 "uniform vec4 fade_color;\n" \
722 "uniform float lighting;\n" \
723 "uniform float fade_start;\n" \
724 "uniform float fade_end;\n" \
725 GLSL_DOOM_COLORMAP \
726 GLSL_DOOM_LIGHT_EQUATION \
727 "void main(void) {\n" \
728 "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
729 "vec4 base_color = texel * poly_color;\n" \
730 "vec4 final_color = base_color;\n" \
731 GLSL_SOFTWARE_TINT_EQUATION \
732 GLSL_SOFTWARE_FADE_EQUATION \
733 "final_color.a = texel.a * poly_color.a;\n" \
734 "gl_FragColor = final_color;\n" \
735 "}\0"
736
737 // same as above but multiplies results with the lighting value from the
738 // accompanying vertex shader (stored in gl_Color)
739 #define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \
740 "uniform sampler2D tex;\n" \
741 "uniform vec4 poly_color;\n" \
742 "uniform vec4 tint_color;\n" \
743 "uniform vec4 fade_color;\n" \
744 "uniform float lighting;\n" \
745 "uniform float fade_start;\n" \
746 "uniform float fade_end;\n" \
747 GLSL_DOOM_COLORMAP \
748 GLSL_DOOM_LIGHT_EQUATION \
749 "void main(void) {\n" \
750 "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
751 "vec4 base_color = texel * poly_color;\n" \
752 "vec4 final_color = base_color;\n" \
753 GLSL_SOFTWARE_TINT_EQUATION \
754 GLSL_SOFTWARE_FADE_EQUATION \
755 "final_color *= gl_Color;\n" \
756 "final_color.a = texel.a * poly_color.a;\n" \
757 "gl_FragColor = final_color;\n" \
758 "}\0"
759
760 //
761 // Water surface shader
762 //
763 // Mostly guesstimated, rather than the rest being built off Software science.
764 // Still needs to distort things underneath/around the water...
765 //
766
767 #define GLSL_WATER_FRAGMENT_SHADER \
768 "uniform sampler2D tex;\n" \
769 "uniform vec4 poly_color;\n" \
770 "uniform vec4 tint_color;\n" \
771 "uniform vec4 fade_color;\n" \
772 "uniform float lighting;\n" \
773 "uniform float fade_start;\n" \
774 "uniform float fade_end;\n" \
775 "uniform float leveltime;\n" \
776 "const float freq = 0.025;\n" \
777 "const float amp = 0.025;\n" \
778 "const float speed = 2.0;\n" \
779 "const float pi = 3.14159;\n" \
780 GLSL_DOOM_COLORMAP \
781 GLSL_DOOM_LIGHT_EQUATION \
782 "void main(void) {\n" \
783 "float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
784 "float a = -pi * (z * freq) + (leveltime * speed);\n" \
785 "float sdistort = sin(a) * amp;\n" \
786 "float cdistort = cos(a) * amp;\n" \
787 "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \
788 "vec4 base_color = texel * poly_color;\n" \
789 "vec4 final_color = base_color;\n" \
790 GLSL_SOFTWARE_TINT_EQUATION \
791 GLSL_SOFTWARE_FADE_EQUATION \
792 "final_color.a = texel.a * poly_color.a;\n" \
793 "gl_FragColor = final_color;\n" \
794 "}\0"
795
796 //
797 // Fog block shader
798 //
799 // Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
800 //
801
802 #define GLSL_FOG_FRAGMENT_SHADER \
803 "uniform vec4 tint_color;\n" \
804 "uniform vec4 fade_color;\n" \
805 "uniform float lighting;\n" \
806 "uniform float fade_start;\n" \
807 "uniform float fade_end;\n" \
808 GLSL_DOOM_COLORMAP \
809 GLSL_DOOM_LIGHT_EQUATION \
810 "void main(void) {\n" \
811 "vec4 base_color = gl_Color;\n" \
812 "vec4 final_color = base_color;\n" \
813 GLSL_SOFTWARE_TINT_EQUATION \
814 GLSL_SOFTWARE_FADE_EQUATION \
815 "gl_FragColor = final_color;\n" \
816 "}\0"
817
818 //
819 // Sky fragment shader
820 // Modulates poly_color with gl_Color
821 //
822 #define GLSL_SKY_FRAGMENT_SHADER \
823 "uniform sampler2D tex;\n" \
824 "uniform vec4 poly_color;\n" \
825 "void main(void) {\n" \
826 "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
827 "}\0"
828
829 // ================
830 // Shader sources
831 // ================
832
833 static struct {
834 const char *vertex;
835 const char *fragment;
836 } const gl_shadersources[] = {
837 // Default shader
838 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_DEFAULT_FRAGMENT_SHADER},
839
840 // Floor shader
841 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
842
843 // Wall shader
844 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
845
846 // Sprite shader
847 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
848
849 // Model shader
850 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
851
852 // Model shader + diffuse lighting from above
853 {GLSL_MODEL_LIGHTING_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER},
854
855 // Water shader
856 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER},
857
858 // Fog shader
859 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER},
860
861 // Sky shader
862 {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER},
863
864 {NULL, NULL},
865 };
866
867 #endif // GL_SHADERS
868
SetupGLFunc4(void)869 void SetupGLFunc4(void)
870 {
871 pglActiveTexture = GetGLFunc("glActiveTexture");
872 pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f");
873 pglClientActiveTexture = GetGLFunc("glClientActiveTexture");
874 pglMultiTexCoord2fv = GetGLFunc("glMultiTexCoord2fv");
875
876 /* 1.5 funcs */
877 pglGenBuffers = GetGLFunc("glGenBuffers");
878 pglBindBuffer = GetGLFunc("glBindBuffer");
879 pglBufferData = GetGLFunc("glBufferData");
880 pglDeleteBuffers = GetGLFunc("glDeleteBuffers");
881
882 /* 2.0 funcs */
883 pglBlendEquation = GetGLFunc("glBlendEquation");
884
885 #ifdef GL_SHADERS
886 pglCreateShader = GetGLFunc("glCreateShader");
887 pglShaderSource = GetGLFunc("glShaderSource");
888 pglCompileShader = GetGLFunc("glCompileShader");
889 pglGetShaderiv = GetGLFunc("glGetShaderiv");
890 pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog");
891 pglDeleteShader = GetGLFunc("glDeleteShader");
892 pglCreateProgram = GetGLFunc("glCreateProgram");
893 pglDeleteProgram = GetGLFunc("glDeleteProgram");
894 pglAttachShader = GetGLFunc("glAttachShader");
895 pglLinkProgram = GetGLFunc("glLinkProgram");
896 pglGetProgramiv = GetGLFunc("glGetProgramiv");
897 pglUseProgram = GetGLFunc("glUseProgram");
898 pglUniform1i = GetGLFunc("glUniform1i");
899 pglUniform1f = GetGLFunc("glUniform1f");
900 pglUniform2f = GetGLFunc("glUniform2f");
901 pglUniform3f = GetGLFunc("glUniform3f");
902 pglUniform4f = GetGLFunc("glUniform4f");
903 pglUniform1fv = GetGLFunc("glUniform1fv");
904 pglUniform2fv = GetGLFunc("glUniform2fv");
905 pglUniform3fv = GetGLFunc("glUniform3fv");
906 pglGetUniformLocation = GetGLFunc("glGetUniformLocation");
907 #endif
908
909 // GLU
910 pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps");
911 }
912
HWRAPI(CompileShaders)913 EXPORT boolean HWRAPI(CompileShaders) (void)
914 {
915 #ifdef GL_SHADERS
916 GLint i;
917
918 if (!pglUseProgram)
919 return false;
920
921 gl_customshaders[SHADER_DEFAULT].vertex = NULL;
922 gl_customshaders[SHADER_DEFAULT].fragment = NULL;
923
924 for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++)
925 {
926 gl_shader_t *shader, *usershader;
927 const GLchar *vert_shader = gl_shadersources[i].vertex;
928 const GLchar *frag_shader = gl_shadersources[i].fragment;
929
930 if (i >= HWR_MAXSHADERS)
931 break;
932
933 shader = &gl_shaders[i];
934 usershader = &gl_usershaders[i];
935
936 if (shader->program)
937 pglDeleteProgram(shader->program);
938 if (usershader->program)
939 pglDeleteProgram(usershader->program);
940
941 shader->program = 0;
942 usershader->program = 0;
943
944 if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader))
945 shader->program = 0;
946
947 // Compile custom shader
948 if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment))
949 continue;
950
951 // 18032019
952 if (gl_customshaders[i].vertex)
953 vert_shader = gl_customshaders[i].vertex;
954 if (gl_customshaders[i].fragment)
955 frag_shader = gl_customshaders[i].fragment;
956
957 if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader))
958 {
959 GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i));
960 usershader->program = 0;
961 }
962 }
963
964 return true;
965 #else
966 return false;
967 #endif
968 }
969
970 //
971 // Shader info
972 // Those are given to the uniforms.
973 //
974
HWRAPI(SetShaderInfo)975 EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value)
976 {
977 #ifdef GL_SHADERS
978 switch (info)
979 {
980 case HWD_SHADERINFO_LEVELTIME:
981 shader_leveltime = value;
982 break;
983 default:
984 break;
985 }
986 #else
987 (void)info;
988 (void)value;
989 #endif
990 }
991
992 //
993 // Custom shader loading
994 //
HWRAPI(LoadCustomShader)995 EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment)
996 {
997 #ifdef GL_SHADERS
998 shadersource_t *shader;
999
1000 if (!pglUseProgram)
1001 return;
1002
1003 if (number < 1 || number > HWR_MAXSHADERS)
1004 I_Error("LoadCustomShader: cannot load shader %d (min 1, max %d)", number, HWR_MAXSHADERS);
1005 else if (code == NULL)
1006 I_Error("LoadCustomShader: empty shader");
1007
1008 shader = &gl_customshaders[number];
1009
1010 #define COPYSHADER(source) { \
1011 if (shader->source) \
1012 free(shader->source); \
1013 shader->source = malloc(size+1); \
1014 strncpy(shader->source, code, size); \
1015 shader->source[size] = 0; \
1016 }
1017
1018 if (isfragment)
1019 COPYSHADER(fragment)
1020 else
1021 COPYSHADER(vertex)
1022
1023 #else
1024 (void)number;
1025 (void)shader;
1026 (void)size;
1027 (void)fragment;
1028 #endif
1029 }
1030
HWRAPI(SetShader)1031 EXPORT void HWRAPI(SetShader) (int type)
1032 {
1033 #ifdef GL_SHADERS
1034 if (gl_allowshaders != HWD_SHADEROPTION_OFF)
1035 {
1036 gl_shader_t *shader = gl_shaderstate.current;
1037
1038 // If using model lighting, set the appropriate shader.
1039 // However don't override a custom shader.
1040 if (type == SHADER_MODEL && model_lighting
1041 && !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom))
1042 type = SHADER_MODEL_LIGHTING;
1043
1044 if ((shader == NULL) || (GLuint)type != gl_shaderstate.type)
1045 {
1046 gl_shader_t *baseshader = &gl_shaders[type];
1047 gl_shader_t *usershader = &gl_usershaders[type];
1048
1049 if (usershader->program)
1050 shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader;
1051 else
1052 shader = baseshader;
1053
1054 gl_shaderstate.current = shader;
1055 gl_shaderstate.type = type;
1056 gl_shaderstate.changed = true;
1057 }
1058
1059 if (gl_shaderstate.program != shader->program)
1060 {
1061 gl_shaderstate.program = shader->program;
1062 gl_shaderstate.changed = true;
1063 }
1064
1065 gl_shadersenabled = (shader->program != 0);
1066 return;
1067 }
1068 #else
1069 (void)type;
1070 #endif
1071 gl_shadersenabled = false;
1072 }
1073
HWRAPI(UnSetShader)1074 EXPORT void HWRAPI(UnSetShader) (void)
1075 {
1076 #ifdef GL_SHADERS
1077 gl_shaderstate.current = NULL;
1078 gl_shaderstate.type = 0;
1079 gl_shaderstate.program = 0;
1080
1081 if (pglUseProgram)
1082 pglUseProgram(0);
1083 #endif
1084
1085 gl_shadersenabled = false;
1086 }
1087
HWRAPI(CleanShaders)1088 EXPORT void HWRAPI(CleanShaders) (void)
1089 {
1090 INT32 i;
1091
1092 for (i = 1; i < HWR_MAXSHADERS; i++)
1093 {
1094 shadersource_t *shader = &gl_customshaders[i];
1095
1096 if (shader->vertex)
1097 free(shader->vertex);
1098
1099 if (shader->fragment)
1100 free(shader->fragment);
1101
1102 shader->vertex = NULL;
1103 shader->fragment = NULL;
1104 }
1105 }
1106
1107 // -----------------+
1108 // SetNoTexture : Disable texture
1109 // -----------------+
SetNoTexture(void)1110 static void SetNoTexture(void)
1111 {
1112 // Disable texture.
1113 if (tex_downloaded != NOTEXTURE_NUM)
1114 {
1115 if (NOTEXTURE_NUM == 0)
1116 pglGenTextures(1, &NOTEXTURE_NUM);
1117 pglBindTexture(GL_TEXTURE_2D, NOTEXTURE_NUM);
1118 tex_downloaded = NOTEXTURE_NUM;
1119 }
1120 }
1121
GLPerspective(GLfloat fovy,GLfloat aspect)1122 static void GLPerspective(GLfloat fovy, GLfloat aspect)
1123 {
1124 GLfloat m[4][4] =
1125 {
1126 { 1.0f, 0.0f, 0.0f, 0.0f},
1127 { 0.0f, 1.0f, 0.0f, 0.0f},
1128 { 0.0f, 0.0f, 1.0f,-1.0f},
1129 { 0.0f, 0.0f, 0.0f, 0.0f},
1130 };
1131 const GLfloat zNear = NEAR_CLIPPING_PLANE;
1132 const GLfloat zFar = FAR_CLIPPING_PLANE;
1133 const GLfloat radians = (GLfloat)(fovy / 2.0f * M_PIl / 180.0f);
1134 const GLfloat sine = sin(radians);
1135 const GLfloat deltaZ = zFar - zNear;
1136 GLfloat cotangent;
1137
1138 if ((fabsf((float)deltaZ) < 1.0E-36f) || fpclassify(sine) == FP_ZERO || fpclassify(aspect) == FP_ZERO)
1139 {
1140 return;
1141 }
1142 cotangent = cosf(radians) / sine;
1143
1144 m[0][0] = cotangent / aspect;
1145 m[1][1] = cotangent;
1146 m[2][2] = -(zFar + zNear) / deltaZ;
1147 m[3][2] = -2.0f * zNear * zFar / deltaZ;
1148
1149 pglMultMatrixf(&m[0][0]);
1150 }
1151
GLProject(GLfloat objX,GLfloat objY,GLfloat objZ,GLfloat * winX,GLfloat * winY,GLfloat * winZ)1152 static void GLProject(GLfloat objX, GLfloat objY, GLfloat objZ,
1153 GLfloat* winX, GLfloat* winY, GLfloat* winZ)
1154 {
1155 GLfloat in[4], out[4];
1156 int i;
1157
1158 for (i=0; i<4; i++)
1159 {
1160 out[i] =
1161 objX * modelMatrix[0*4+i] +
1162 objY * modelMatrix[1*4+i] +
1163 objZ * modelMatrix[2*4+i] +
1164 modelMatrix[3*4+i];
1165 }
1166 for (i=0; i<4; i++)
1167 {
1168 in[i] =
1169 out[0] * projMatrix[0*4+i] +
1170 out[1] * projMatrix[1*4+i] +
1171 out[2] * projMatrix[2*4+i] +
1172 out[3] * projMatrix[3*4+i];
1173 }
1174 if (fpclassify(in[3]) == FP_ZERO) return;
1175 in[0] /= in[3];
1176 in[1] /= in[3];
1177 in[2] /= in[3];
1178 /* Map x, y and z to range 0-1 */
1179 in[0] = in[0] * 0.5f + 0.5f;
1180 in[1] = in[1] * 0.5f + 0.5f;
1181 in[2] = in[2] * 0.5f + 0.5f;
1182
1183 /* Map x,y to viewport */
1184 in[0] = in[0] * viewport[2] + viewport[0];
1185 in[1] = in[1] * viewport[3] + viewport[1];
1186
1187 *winX=in[0];
1188 *winY=in[1];
1189 *winZ=in[2];
1190 }
1191
1192 // -----------------+
1193 // SetModelView :
1194 // -----------------+
SetModelView(GLint w,GLint h)1195 void SetModelView(GLint w, GLint h)
1196 {
1197 // GL_DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h);
1198
1199 // The screen textures need to be flushed if the width or height change so that they be remade for the correct size
1200 if (screen_width != w || screen_height != h)
1201 FlushScreenTextures();
1202
1203 screen_width = w;
1204 screen_height = h;
1205
1206 pglViewport(0, 0, w, h);
1207
1208 pglMatrixMode(GL_PROJECTION);
1209 pglLoadIdentity();
1210
1211 pglMatrixMode(GL_MODELVIEW);
1212 pglLoadIdentity();
1213
1214 GLPerspective(fov, ASPECT_RATIO);
1215 //pglScalef(1.0f, 320.0f/200.0f, 1.0f); // gl_scalefrustum (ORIGINAL_ASPECT)
1216
1217 // added for new coronas' code (without depth buffer)
1218 pglGetIntegerv(GL_VIEWPORT, viewport);
1219 pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
1220 }
1221
1222
1223 // -----------------+
1224 // SetStates : Set permanent states
1225 // -----------------+
SetStates(void)1226 void SetStates(void)
1227 {
1228 #ifdef GL_LIGHT_MODEL_AMBIENT
1229 GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
1230 #endif
1231
1232 // GL_DBG_Printf("SetStates()\n");
1233
1234 // Hurdler: not necessary, is it?
1235 pglShadeModel(GL_SMOOTH); // iterate vertice colors
1236 //pglShadeModel(GL_FLAT);
1237
1238 pglEnable(GL_TEXTURE_2D); // two-dimensional texturing
1239
1240 pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1241
1242 pglEnable(GL_ALPHA_TEST);
1243 pglAlphaFunc(GL_NOTEQUAL, 0.0f);
1244
1245 //pglBlendFunc(GL_ONE, GL_ZERO); // copy pixel to frame buffer (opaque)
1246 pglEnable(GL_BLEND); // enable color blending
1247
1248 pglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1249
1250 //pglDisable(GL_DITHER); // faB: ??? (undocumented in OpenGL 1.1)
1251 // Hurdler: yes, it is!
1252 pglEnable(GL_DEPTH_TEST); // check the depth buffer
1253 pglDepthMask(GL_TRUE); // enable writing to depth buffer
1254 pglClearDepth(1.0f);
1255 pglDepthRange(0.0f, 1.0f);
1256 pglDepthFunc(GL_LEQUAL);
1257
1258 // this set CurrentPolyFlags to the actual configuration
1259 CurrentPolyFlags = 0xffffffff;
1260 SetBlend(0);
1261
1262 tex_downloaded = 0;
1263 SetNoTexture();
1264
1265 pglPolygonOffset(-1.0f, -1.0f);
1266
1267 //pglEnable(GL_CULL_FACE);
1268 //pglCullFace(GL_FRONT);
1269
1270 pglDisable(GL_FOG);
1271
1272 // Lighting for models
1273 #ifdef GL_LIGHT_MODEL_AMBIENT
1274 pglLightModelfv(GL_LIGHT_MODEL_AMBIENT, LightDiffuse);
1275 pglEnable(GL_LIGHT0);
1276 #endif
1277
1278 // bp : when no t&l :)
1279 pglLoadIdentity();
1280 pglScalef(1.0f, 1.0f, -1.0f);
1281 pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
1282 }
1283
1284
1285 // -----------------+
1286 // DeleteTexture : Deletes a texture from the GPU and frees its data
1287 // -----------------+
HWRAPI(DeleteTexture)1288 EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *pTexInfo)
1289 {
1290 FTextureInfo *head = TexCacheHead;
1291
1292 if (!pTexInfo)
1293 return;
1294 else if (pTexInfo->downloaded)
1295 pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded);
1296
1297 while (head)
1298 {
1299 if (head->downloaded == pTexInfo->downloaded)
1300 {
1301 if (head->next)
1302 head->next->prev = head->prev;
1303 else // no next -> tail is being deleted -> update TexCacheTail
1304 TexCacheTail = head->prev;
1305 if (head->prev)
1306 head->prev->next = head->next;
1307 else // no prev -> head is being deleted -> update TexCacheHead
1308 TexCacheHead = head->next;
1309 free(head);
1310 break;
1311 }
1312
1313 head = head->next;
1314 }
1315
1316 pTexInfo->downloaded = 0;
1317 }
1318
1319
1320 // -----------------+
1321 // Flush : flush OpenGL textures
1322 // : Clear list of downloaded mipmaps
1323 // -----------------+
Flush(void)1324 void Flush(void)
1325 {
1326 //GL_DBG_Printf ("HWR_Flush()\n");
1327
1328 while (TexCacheHead)
1329 {
1330 FTextureInfo *pTexInfo = TexCacheHead;
1331 GLMipmap_t *texture = pTexInfo->texture;
1332
1333 if (pTexInfo->downloaded)
1334 {
1335 pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded);
1336 pTexInfo->downloaded = 0;
1337 }
1338
1339 if (texture)
1340 texture->downloaded = 0;
1341
1342 TexCacheHead = pTexInfo->next;
1343 free(pTexInfo);
1344 }
1345
1346 TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL
1347 tex_downloaded = 0;
1348 }
1349
1350
1351 // -----------------+
1352 // isExtAvailable : Look if an OpenGL extension is available
1353 // Returns : true if extension available
1354 // -----------------+
isExtAvailable(const char * extension,const GLubyte * start)1355 INT32 isExtAvailable(const char *extension, const GLubyte *start)
1356 {
1357 GLubyte *where, *terminator;
1358
1359 if (!extension || !start) return 0;
1360 where = (GLubyte *) strchr(extension, ' ');
1361 if (where || *extension == '\0')
1362 return 0;
1363
1364 for (;;)
1365 {
1366 where = (GLubyte *) strstr((const char *) start, extension);
1367 if (!where)
1368 break;
1369 terminator = where + strlen(extension);
1370 if (where == start || *(where - 1) == ' ')
1371 if (*terminator == ' ' || *terminator == '\0')
1372 return 1;
1373 start = terminator;
1374 }
1375 return 0;
1376 }
1377
1378
1379 // -----------------+
1380 // Init : Initialise the OpenGL interface API
1381 // Returns :
1382 // -----------------+
HWRAPI(Init)1383 EXPORT boolean HWRAPI(Init) (void)
1384 {
1385 return LoadGL();
1386 }
1387
1388
1389 // -----------------+
1390 // ClearMipMapCache : Flush OpenGL textures from memory
1391 // -----------------+
HWRAPI(ClearMipMapCache)1392 EXPORT void HWRAPI(ClearMipMapCache) (void)
1393 {
1394 // GL_DBG_Printf ("HWR_Flush(exe)\n");
1395 Flush();
1396 }
1397
1398
1399 // -----------------+
1400 // ReadRect : Read a rectangle region of the truecolor framebuffer
1401 // : store pixels as 16bit 565 RGB
1402 // Returns : 16bit 565 RGB pixel array stored in dst_data
1403 // -----------------+
HWRAPI(ReadRect)1404 EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
1405 INT32 dst_stride, UINT16 * dst_data)
1406 {
1407 INT32 i;
1408 // GL_DBG_Printf ("ReadRect()\n");
1409 if (dst_stride == width*3)
1410 {
1411 GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
1412 GLubyte *row = malloc(dst_stride);
1413 if (!row) return;
1414 pglPixelStorei(GL_PACK_ALIGNMENT, 1);
1415 pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
1416 pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1417 for(i = 0; i < height/2; i++)
1418 {
1419 memcpy(row, top, dst_stride);
1420 memcpy(top, bottom, dst_stride);
1421 memcpy(bottom, row, dst_stride);
1422 top += dst_stride;
1423 bottom -= dst_stride;
1424 }
1425 free(row);
1426 }
1427 else
1428 {
1429 INT32 j;
1430 GLubyte *image = malloc(width*height*3*sizeof (*image));
1431 if (!image) return;
1432 pglPixelStorei(GL_PACK_ALIGNMENT, 1);
1433 pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
1434 pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1435 for (i = height-1; i >= 0; i--)
1436 {
1437 for (j = 0; j < width; j++)
1438 {
1439 dst_data[(height-1-i)*width+j] =
1440 (UINT16)(
1441 ((image[(i*width+j)*3]>>3)<<11) |
1442 ((image[(i*width+j)*3+1]>>2)<<5) |
1443 ((image[(i*width+j)*3+2]>>3)));
1444 }
1445 }
1446 free(image);
1447 }
1448 }
1449
1450
1451 // -----------------+
1452 // GClipRect : Defines the 2D hardware clipping window
1453 // -----------------+
HWRAPI(GClipRect)1454 EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip)
1455 {
1456 // GL_DBG_Printf ("GClipRect(%d, %d, %d, %d)\n", minx, miny, maxx, maxy);
1457
1458 pglViewport(minx, screen_height-maxy, maxx-minx, maxy-miny);
1459 NEAR_CLIPPING_PLANE = nearclip;
1460
1461 //pglScissor(minx, screen_height-maxy, maxx-minx, maxy-miny);
1462 pglMatrixMode(GL_PROJECTION);
1463 pglLoadIdentity();
1464 GLPerspective(fov, ASPECT_RATIO);
1465 pglMatrixMode(GL_MODELVIEW);
1466
1467 // added for new coronas' code (without depth buffer)
1468 pglGetIntegerv(GL_VIEWPORT, viewport);
1469 pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
1470 }
1471
1472
1473 // -----------------+
1474 // ClearBuffer : Clear the color/alpha/depth buffer(s)
1475 // -----------------+
HWRAPI(ClearBuffer)1476 EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask,
1477 FBOOLEAN DepthMask,
1478 FRGBAFloat * ClearColor)
1479 {
1480 // GL_DBG_Printf ("ClearBuffer(%d)\n", alpha);
1481 GLbitfield ClearMask = 0;
1482
1483 if (ColorMask)
1484 {
1485 if (ClearColor)
1486 pglClearColor(ClearColor->red,
1487 ClearColor->green,
1488 ClearColor->blue,
1489 ClearColor->alpha);
1490 ClearMask |= GL_COLOR_BUFFER_BIT;
1491 }
1492 if (DepthMask)
1493 {
1494 pglClearDepth(1.0f); //Hurdler: all that are permanen states
1495 pglDepthRange(0.0f, 1.0f);
1496 pglDepthFunc(GL_LEQUAL);
1497 ClearMask |= GL_DEPTH_BUFFER_BIT;
1498 }
1499
1500 SetBlend(DepthMask ? PF_Occlude | CurrentPolyFlags : CurrentPolyFlags&~PF_Occlude);
1501
1502 pglClear(ClearMask);
1503 pglEnableClientState(GL_VERTEX_ARRAY); // We always use this one
1504 pglEnableClientState(GL_TEXTURE_COORD_ARRAY); // And mostly this one, too
1505 }
1506
1507
1508 // -----------------+
1509 // HWRAPI Draw2DLine: Render a 2D line
1510 // -----------------+
HWRAPI(Draw2DLine)1511 EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1,
1512 F2DCoord * v2,
1513 RGBA_t Color)
1514 {
1515 // GL_DBG_Printf ("DrawLine() (%f %f %f) %d\n", v1->x, -v1->y, -v1->z, v1->argb);
1516 GLfloat p[12];
1517 GLfloat dx, dy;
1518 GLfloat angle;
1519
1520 // BP: we should reflect the new state in our variable
1521 //SetBlend(PF_Modulated|PF_NoTexture);
1522
1523 pglDisable(GL_TEXTURE_2D);
1524
1525 // This is the preferred, 'modern' way of rendering lines -- creating a polygon.
1526 if (fabsf(v2->x - v1->x) > FLT_EPSILON)
1527 angle = (float)atan((v2->y-v1->y)/(v2->x-v1->x));
1528 else
1529 angle = (float)N_PI_DEMI;
1530 dx = (float)sin(angle) / (float)screen_width;
1531 dy = (float)cos(angle) / (float)screen_height;
1532
1533 p[0] = v1->x - dx; p[1] = -(v1->y + dy); p[2] = 1;
1534 p[3] = v2->x - dx; p[4] = -(v2->y + dy); p[5] = 1;
1535 p[6] = v2->x + dx; p[7] = -(v2->y - dy); p[8] = 1;
1536 p[9] = v1->x + dx; p[10] = -(v1->y - dy); p[11] = 1;
1537
1538 pglDisableClientState(GL_TEXTURE_COORD_ARRAY);
1539 pglColor4ubv((GLubyte*)&Color.s);
1540 pglVertexPointer(3, GL_FLOAT, 0, p);
1541 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1542
1543 pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
1544 pglEnable(GL_TEXTURE_2D);
1545 }
1546
1547
1548 // -----------------+
1549 // SetBlend : Set render mode
1550 // -----------------+
1551 // PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0,
1552 // is it faster when pixels are discarded ?
1553
Clamp2D(GLenum pname)1554 static void Clamp2D(GLenum pname)
1555 {
1556 pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP); // fallback clamp
1557 pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP_TO_EDGE);
1558 }
1559
SetBlendEquation(GLenum mode)1560 static void SetBlendEquation(GLenum mode)
1561 {
1562 if (pglBlendEquation)
1563 pglBlendEquation(mode);
1564 }
1565
SetBlendMode(FBITFIELD flags)1566 static void SetBlendMode(FBITFIELD flags)
1567 {
1568 // Set blending function
1569 switch (flags)
1570 {
1571 case PF_Translucent & PF_Blending:
1572 pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
1573 break;
1574 case PF_Masked & PF_Blending:
1575 // Hurdler: does that mean lighting is only made by alpha src?
1576 // it sounds ok, but not for polygonsmooth
1577 pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture
1578 break;
1579 case PF_Additive & PF_Blending:
1580 case PF_Subtractive & PF_Blending:
1581 case PF_ReverseSubtract & PF_Blending:
1582 pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest
1583 break;
1584 case PF_Environment & PF_Blending:
1585 pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1586 break;
1587 case PF_Multiplicative & PF_Blending:
1588 pglBlendFunc(GL_DST_COLOR, GL_ZERO);
1589 break;
1590 case PF_Fog & PF_Fog:
1591 // Sryder: Fog
1592 // multiplies input colour by input alpha, and destination colour by input colour, then adds them
1593 pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR);
1594 break;
1595 default: // must be 0, otherwise it's an error
1596 // No blending
1597 pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending
1598 break;
1599 }
1600
1601 // Set blending equation
1602 switch (flags)
1603 {
1604 case PF_Subtractive & PF_Blending:
1605 SetBlendEquation(GL_FUNC_SUBTRACT);
1606 break;
1607 case PF_ReverseSubtract & PF_Blending:
1608 // good for shadow
1609 // not really but what else ?
1610 SetBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
1611 break;
1612 default:
1613 SetBlendEquation(GL_FUNC_ADD);
1614 break;
1615 }
1616
1617 // Alpha test
1618 switch (flags)
1619 {
1620 case PF_Masked & PF_Blending:
1621 pglAlphaFunc(GL_GREATER, 0.5f);
1622 break;
1623 case PF_Translucent & PF_Blending:
1624 case PF_Additive & PF_Blending:
1625 case PF_Subtractive & PF_Blending:
1626 case PF_ReverseSubtract & PF_Blending:
1627 case PF_Environment & PF_Blending:
1628 case PF_Multiplicative & PF_Blending:
1629 pglAlphaFunc(GL_NOTEQUAL, 0.0f);
1630 break;
1631 case PF_Fog & PF_Fog:
1632 pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments
1633 break;
1634 default:
1635 pglAlphaFunc(GL_GREATER, 0.5f);
1636 break;
1637 }
1638 }
1639
HWRAPI(SetBlend)1640 EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags)
1641 {
1642 FBITFIELD Xor;
1643 Xor = CurrentPolyFlags^PolyFlags;
1644 if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible))
1645 {
1646 if (Xor & PF_Blending) // if blending mode must be changed
1647 SetBlendMode(PolyFlags & PF_Blending);
1648
1649 if (Xor & PF_NoAlphaTest)
1650 {
1651 if (PolyFlags & PF_NoAlphaTest)
1652 pglDisable(GL_ALPHA_TEST);
1653 else
1654 pglEnable(GL_ALPHA_TEST); // discard 0 alpha pixels (holes in texture)
1655 }
1656
1657 if (Xor & PF_Decal)
1658 {
1659 if (PolyFlags & PF_Decal)
1660 pglEnable(GL_POLYGON_OFFSET_FILL);
1661 else
1662 pglDisable(GL_POLYGON_OFFSET_FILL);
1663 }
1664
1665 if (Xor & PF_NoDepthTest)
1666 {
1667 if (PolyFlags & PF_NoDepthTest)
1668 pglDepthFunc(GL_ALWAYS); //pglDisable(GL_DEPTH_TEST);
1669 else
1670 pglDepthFunc(GL_LEQUAL); //pglEnable(GL_DEPTH_TEST);
1671 }
1672
1673 if (Xor & PF_RemoveYWrap)
1674 {
1675 if (PolyFlags & PF_RemoveYWrap)
1676 Clamp2D(GL_TEXTURE_WRAP_T);
1677 }
1678
1679 if (Xor & PF_ForceWrapX)
1680 {
1681 if (PolyFlags & PF_ForceWrapX)
1682 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1683 }
1684
1685 if (Xor & PF_ForceWrapY)
1686 {
1687 if (PolyFlags & PF_ForceWrapY)
1688 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1689 }
1690
1691 if (Xor & PF_Modulated)
1692 {
1693 #if defined (__unix__) || defined (UNIXCOMMON)
1694 if (oglflags & GLF_NOTEXENV)
1695 {
1696 if (!(PolyFlags & PF_Modulated))
1697 pglColor4ubv(white);
1698 }
1699 else
1700 #endif
1701 if (PolyFlags & PF_Modulated)
1702 { // mix texture colour with Surface->PolyColor
1703 pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1704 }
1705 else
1706 { // colour from texture is unchanged before blending
1707 pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1708 }
1709 }
1710
1711 if (Xor & PF_Occlude) // depth test but (no) depth write
1712 {
1713 if (PolyFlags&PF_Occlude)
1714 {
1715 pglDepthMask(1);
1716 }
1717 else
1718 pglDepthMask(0);
1719 }
1720 ////Hurdler: not used if we don't define POLYSKY
1721 if (Xor & PF_Invisible)
1722 {
1723 if (PolyFlags&PF_Invisible)
1724 pglBlendFunc(GL_ZERO, GL_ONE); // transparent blending
1725 else
1726 { // big hack: (TODO: manage that better)
1727 // we test only for PF_Masked because PF_Invisible is only used
1728 // (for now) with it (yeah, that's crappy, sorry)
1729 if ((PolyFlags&PF_Blending)==PF_Masked)
1730 pglBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1731 }
1732 }
1733 if (PolyFlags & PF_NoTexture)
1734 {
1735 SetNoTexture();
1736 }
1737 }
1738 CurrentPolyFlags = PolyFlags;
1739 }
1740
1741 // -----------------+
1742 // UpdateTexture : Updates the texture data.
1743 // -----------------+
HWRAPI(UpdateTexture)1744 EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
1745 {
1746 // Download a mipmap
1747 boolean updatemipmap = true;
1748 static RGBA_t tex[2048*2048];
1749 const GLvoid *ptex = tex;
1750 INT32 w, h;
1751 GLuint texnum = 0;
1752
1753 if (!pTexInfo->downloaded)
1754 {
1755 pglGenTextures(1, &texnum);
1756 pTexInfo->downloaded = texnum;
1757 updatemipmap = false;
1758 }
1759 else
1760 texnum = pTexInfo->downloaded;
1761
1762 //GL_DBG_Printf ("DownloadMipmap %d %x\n",(INT32)texnum,pTexInfo->data);
1763
1764 w = pTexInfo->width;
1765 h = pTexInfo->height;
1766
1767 if ((pTexInfo->format == GL_TEXFMT_P_8) ||
1768 (pTexInfo->format == GL_TEXFMT_AP_88))
1769 {
1770 const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
1771 INT32 i, j;
1772
1773 for (j = 0; j < h; j++)
1774 {
1775 for (i = 0; i < w; i++)
1776 {
1777 if ((*pImgData == HWR_PATCHES_CHROMAKEY_COLORINDEX) &&
1778 (pTexInfo->flags & TF_CHROMAKEYED))
1779 {
1780 tex[w*j+i].s.red = 0;
1781 tex[w*j+i].s.green = 0;
1782 tex[w*j+i].s.blue = 0;
1783 tex[w*j+i].s.alpha = 0;
1784 pTexInfo->flags |= TF_TRANSPARENT; // there is a hole in it
1785 }
1786 else
1787 {
1788 tex[w*j+i].s.red = myPaletteData[*pImgData].s.red;
1789 tex[w*j+i].s.green = myPaletteData[*pImgData].s.green;
1790 tex[w*j+i].s.blue = myPaletteData[*pImgData].s.blue;
1791 tex[w*j+i].s.alpha = myPaletteData[*pImgData].s.alpha;
1792 }
1793
1794 pImgData++;
1795
1796 if (pTexInfo->format == GL_TEXFMT_AP_88)
1797 {
1798 if (!(pTexInfo->flags & TF_CHROMAKEYED))
1799 tex[w*j+i].s.alpha = *pImgData;
1800 pImgData++;
1801 }
1802
1803 }
1804 }
1805 }
1806 else if (pTexInfo->format == GL_TEXFMT_RGBA)
1807 {
1808 // corona test : passed as ARGB 8888, which is not in glide formats
1809 // Hurdler: not used for coronas anymore, just for dynamic lighting
1810 ptex = pTexInfo->data;
1811 }
1812 else if (pTexInfo->format == GL_TEXFMT_ALPHA_INTENSITY_88)
1813 {
1814 const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
1815 INT32 i, j;
1816
1817 for (j = 0; j < h; j++)
1818 {
1819 for (i = 0; i < w; i++)
1820 {
1821 tex[w*j+i].s.red = *pImgData;
1822 tex[w*j+i].s.green = *pImgData;
1823 tex[w*j+i].s.blue = *pImgData;
1824 pImgData++;
1825 tex[w*j+i].s.alpha = *pImgData;
1826 pImgData++;
1827 }
1828 }
1829 }
1830 else if (pTexInfo->format == GL_TEXFMT_ALPHA_8) // Used for fade masks
1831 {
1832 const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
1833 INT32 i, j;
1834
1835 for (j = 0; j < h; j++)
1836 {
1837 for (i = 0; i < w; i++)
1838 {
1839 tex[w*j+i].s.red = 255; // 255 because the fade mask is modulated with the screen texture, so alpha affects it while the colours don't
1840 tex[w*j+i].s.green = 255;
1841 tex[w*j+i].s.blue = 255;
1842 tex[w*j+i].s.alpha = *pImgData;
1843 pImgData++;
1844 }
1845 }
1846 }
1847 else
1848 GL_MSG_Warning ("SetTexture(bad format) %ld\n", pTexInfo->format);
1849
1850 // the texture number was already generated by pglGenTextures
1851 pglBindTexture(GL_TEXTURE_2D, texnum);
1852 tex_downloaded = texnum;
1853
1854 // disable texture filtering on any texture that has holes so there's no dumb borders or blending issues
1855 if (pTexInfo->flags & TF_TRANSPARENT)
1856 {
1857 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1858 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1859 }
1860 else
1861 {
1862 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
1863 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
1864 }
1865
1866 if (pTexInfo->format == GL_TEXFMT_ALPHA_INTENSITY_88)
1867 {
1868 //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1869 if (MipMap)
1870 {
1871 pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1872 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
1873 if (pTexInfo->flags & TF_TRANSPARENT)
1874 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
1875 else
1876 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4);
1877 //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR);
1878 }
1879 else
1880 {
1881 if (updatemipmap)
1882 pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1883 else
1884 pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1885 }
1886 }
1887 else if (pTexInfo->format == GL_TEXFMT_ALPHA_8)
1888 {
1889 //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1890 if (MipMap)
1891 {
1892 pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1893 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
1894 if (pTexInfo->flags & TF_TRANSPARENT)
1895 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
1896 else
1897 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4);
1898 //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR);
1899 }
1900 else
1901 {
1902 if (updatemipmap)
1903 pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1904 else
1905 pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1906 }
1907 }
1908 else
1909 {
1910 if (MipMap)
1911 {
1912 pgluBuild2DMipmaps(GL_TEXTURE_2D, textureformatGL, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1913 // Control the mipmap level of detail
1914 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail
1915 if (pTexInfo->flags & TF_TRANSPARENT)
1916 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
1917 else
1918 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5);
1919 }
1920 else
1921 {
1922 if (updatemipmap)
1923 pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1924 else
1925 pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
1926 }
1927 }
1928
1929 if (pTexInfo->flags & TF_WRAPX)
1930 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1931 else
1932 Clamp2D(GL_TEXTURE_WRAP_S);
1933
1934 if (pTexInfo->flags & TF_WRAPY)
1935 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1936 else
1937 Clamp2D(GL_TEXTURE_WRAP_T);
1938
1939 if (maximumAnisotropy)
1940 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic_filter);
1941 }
1942
1943 // -----------------+
1944 // SetTexture : The mipmap becomes the current texture source
1945 // -----------------+
HWRAPI(SetTexture)1946 EXPORT void HWRAPI(SetTexture) (GLMipmap_t *pTexInfo)
1947 {
1948 if (!pTexInfo)
1949 {
1950 SetNoTexture();
1951 return;
1952 }
1953 else if (pTexInfo->downloaded)
1954 {
1955 if (pTexInfo->downloaded != tex_downloaded)
1956 {
1957 pglBindTexture(GL_TEXTURE_2D, pTexInfo->downloaded);
1958 tex_downloaded = pTexInfo->downloaded;
1959 }
1960 }
1961 else
1962 {
1963 FTextureInfo *newTex = calloc(1, sizeof (*newTex));
1964
1965 UpdateTexture(pTexInfo);
1966
1967 newTex->texture = pTexInfo;
1968 newTex->downloaded = (UINT32)pTexInfo->downloaded;
1969 newTex->width = (UINT32)pTexInfo->width;
1970 newTex->height = (UINT32)pTexInfo->height;
1971 newTex->format = (UINT32)pTexInfo->format;
1972
1973 // insertion at the tail
1974 if (TexCacheTail)
1975 {
1976 newTex->prev = TexCacheTail;
1977 TexCacheTail->next = newTex;
1978 TexCacheTail = newTex;
1979 }
1980 else // initialization of the linked list
1981 TexCacheTail = TexCacheHead = newTex;
1982 }
1983 }
1984
Shader_SetUniforms(FSurfaceInfo * Surface,GLRGBAFloat * poly,GLRGBAFloat * tint,GLRGBAFloat * fade)1985 static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade)
1986 {
1987 #ifdef GL_SHADERS
1988 gl_shader_t *shader = gl_shaderstate.current;
1989
1990 if (gl_shadersenabled && (shader != NULL) && pglUseProgram)
1991 {
1992 if (!shader->program)
1993 {
1994 pglUseProgram(0);
1995 return;
1996 }
1997
1998 if (gl_shaderstate.changed)
1999 {
2000 pglUseProgram(shader->program);
2001 gl_shaderstate.changed = false;
2002 }
2003
2004 // Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f)
2005 if (poly == NULL)
2006 poly = &shader_defaultcolor;
2007 if (tint == NULL)
2008 tint = &shader_defaultcolor;
2009 if (fade == NULL)
2010 fade = &shader_defaultcolor;
2011
2012 #define UNIFORM_1(uniform, a, function) \
2013 if (uniform != -1) \
2014 function (uniform, a);
2015
2016 #define UNIFORM_2(uniform, a, b, function) \
2017 if (uniform != -1) \
2018 function (uniform, a, b);
2019
2020 #define UNIFORM_3(uniform, a, b, c, function) \
2021 if (uniform != -1) \
2022 function (uniform, a, b, c);
2023
2024 #define UNIFORM_4(uniform, a, b, c, d, function) \
2025 if (uniform != -1) \
2026 function (uniform, a, b, c, d);
2027
2028 // polygon
2029 UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f);
2030 UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f);
2031 UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f);
2032
2033 if (Surface != NULL)
2034 {
2035 UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f);
2036 UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f);
2037 UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f);
2038 }
2039
2040 UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)shader_leveltime) / TICRATE, pglUniform1f);
2041
2042 #undef UNIFORM_1
2043 #undef UNIFORM_2
2044 #undef UNIFORM_3
2045 #undef UNIFORM_4
2046 }
2047 #else
2048 (void)Surface;
2049 (void)poly;
2050 (void)tint;
2051 (void)fade;
2052 #endif
2053 }
2054
Shader_CompileProgram(gl_shader_t * shader,GLint i,const GLchar * vert_shader,const GLchar * frag_shader)2055 static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader)
2056 {
2057 GLuint gl_vertShader, gl_fragShader;
2058 GLint result;
2059
2060 //
2061 // Load and compile vertex shader
2062 //
2063 gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
2064 if (!gl_vertShader)
2065 {
2066 GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i));
2067 return false;
2068 }
2069
2070 pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
2071 pglCompileShader(gl_vertShader);
2072
2073 // check for compile errors
2074 pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
2075 if (result == GL_FALSE)
2076 {
2077 Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
2078 pglDeleteShader(gl_vertShader);
2079 return false;
2080 }
2081
2082 //
2083 // Load and compile fragment shader
2084 //
2085 gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
2086 if (!gl_fragShader)
2087 {
2088 GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i));
2089 pglDeleteShader(gl_vertShader);
2090 pglDeleteShader(gl_fragShader);
2091 return false;
2092 }
2093
2094 pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
2095 pglCompileShader(gl_fragShader);
2096
2097 // check for compile errors
2098 pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
2099 if (result == GL_FALSE)
2100 {
2101 Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
2102 pglDeleteShader(gl_vertShader);
2103 pglDeleteShader(gl_fragShader);
2104 return false;
2105 }
2106
2107 shader->program = pglCreateProgram();
2108 pglAttachShader(shader->program, gl_vertShader);
2109 pglAttachShader(shader->program, gl_fragShader);
2110 pglLinkProgram(shader->program);
2111
2112 // check link status
2113 pglGetProgramiv(shader->program, GL_LINK_STATUS, &result);
2114
2115 // delete the shader objects
2116 pglDeleteShader(gl_vertShader);
2117 pglDeleteShader(gl_fragShader);
2118
2119 // couldn't link?
2120 if (result != GL_TRUE)
2121 {
2122 GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i));
2123 pglDeleteProgram(shader->program);
2124 return false;
2125 }
2126
2127 // 13062019
2128 #define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform);
2129
2130 // lighting
2131 shader->uniforms[gluniform_poly_color] = GETUNI("poly_color");
2132 shader->uniforms[gluniform_tint_color] = GETUNI("tint_color");
2133 shader->uniforms[gluniform_fade_color] = GETUNI("fade_color");
2134 shader->uniforms[gluniform_lighting] = GETUNI("lighting");
2135 shader->uniforms[gluniform_fade_start] = GETUNI("fade_start");
2136 shader->uniforms[gluniform_fade_end] = GETUNI("fade_end");
2137
2138 // misc. (custom shaders)
2139 shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
2140
2141 #undef GETUNI
2142
2143 return true;
2144 }
2145
Shader_CompileError(const char * message,GLuint program,INT32 shadernum)2146 static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum)
2147 {
2148 GLchar *infoLog = NULL;
2149 GLint logLength;
2150
2151 pglGetShaderiv(program, GL_INFO_LOG_LENGTH, &logLength);
2152
2153 if (logLength)
2154 {
2155 infoLog = malloc(logLength);
2156 pglGetShaderInfoLog(program, logLength, NULL, infoLog);
2157 }
2158
2159 GL_MSG_Error("Shader_CompileProgram: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : ""));
2160
2161 if (infoLog)
2162 free(infoLog);
2163 }
2164
2165 // code that is common between DrawPolygon and DrawIndexedTriangles
2166 // the corona thing is there too, i have no idea if that stuff works with DrawIndexedTriangles and batching
PreparePolygon(FSurfaceInfo * pSurf,FOutVector * pOutVerts,FBITFIELD PolyFlags)2167 static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD PolyFlags)
2168 {
2169 static GLRGBAFloat poly = {0,0,0,0};
2170 static GLRGBAFloat tint = {0,0,0,0};
2171 static GLRGBAFloat fade = {0,0,0,0};
2172
2173 if ((PolyFlags & PF_Corona) && (oglflags & GLF_NOZBUFREAD))
2174 PolyFlags &= ~(PF_NoDepthTest|PF_Corona);
2175
2176 SetBlend(PolyFlags); //TODO: inline (#pragma..)
2177
2178 if (pSurf)
2179 {
2180 // If modulated, mix the surface colour to the texture
2181 if (CurrentPolyFlags & PF_Modulated)
2182 pglColor4ubv((GLubyte*)&pSurf->PolyColor.s);
2183
2184 // If the surface is either modulated or colormapped, or both
2185 if (CurrentPolyFlags & (PF_Modulated | PF_ColorMapped))
2186 {
2187 poly.red = byte2float[pSurf->PolyColor.s.red];
2188 poly.green = byte2float[pSurf->PolyColor.s.green];
2189 poly.blue = byte2float[pSurf->PolyColor.s.blue];
2190 poly.alpha = byte2float[pSurf->PolyColor.s.alpha];
2191 }
2192
2193 // Only if the surface is colormapped
2194 if (CurrentPolyFlags & PF_ColorMapped)
2195 {
2196 tint.red = byte2float[pSurf->TintColor.s.red];
2197 tint.green = byte2float[pSurf->TintColor.s.green];
2198 tint.blue = byte2float[pSurf->TintColor.s.blue];
2199 tint.alpha = byte2float[pSurf->TintColor.s.alpha];
2200
2201 fade.red = byte2float[pSurf->FadeColor.s.red];
2202 fade.green = byte2float[pSurf->FadeColor.s.green];
2203 fade.blue = byte2float[pSurf->FadeColor.s.blue];
2204 fade.alpha = byte2float[pSurf->FadeColor.s.alpha];
2205 }
2206 }
2207
2208 // this test is added for new coronas' code (without depth buffer)
2209 // I think I should do a separate function for drawing coronas, so it will be a little faster
2210 if (PolyFlags & PF_Corona) // check to see if we need to draw the corona
2211 {
2212 FUINT i;
2213 FUINT j;
2214
2215 //rem: all 8 (or 8.0f) values are hard coded: it can be changed to a higher value
2216 GLfloat buf[8][8];
2217 GLfloat cx, cy, cz;
2218 GLfloat px = 0.0f, py = 0.0f, pz = -1.0f;
2219 GLfloat scalef = 0.0f;
2220
2221 GLubyte c[4];
2222
2223 float alpha;
2224
2225 cx = (pOutVerts[0].x + pOutVerts[2].x) / 2.0f; // we should change the coronas' ...
2226 cy = (pOutVerts[0].y + pOutVerts[2].y) / 2.0f; // ... code so its only done once.
2227 cz = pOutVerts[0].z;
2228
2229 // I dont know if this is slow or not
2230 GLProject(cx, cy, cz, &px, &py, &pz);
2231 //GL_DBG_Printf("Projection: (%f, %f, %f)\n", px, py, pz);
2232
2233 if ((pz < 0.0l) ||
2234 (px < -8.0l) ||
2235 (py < viewport[1]-8.0l) ||
2236 (px > viewport[2]+8.0l) ||
2237 (py > viewport[1]+viewport[3]+8.0l))
2238 return;
2239
2240 // the damned slow glReadPixels functions :(
2241 pglReadPixels((INT32)px-4, (INT32)py, 8, 8, GL_DEPTH_COMPONENT, GL_FLOAT, buf);
2242 //GL_DBG_Printf("DepthBuffer: %f %f\n", buf[0][0], buf[3][3]);
2243
2244 for (i = 0; i < 8; i++)
2245 for (j = 0; j < 8; j++)
2246 scalef += (pz > buf[i][j]+0.00005f) ? 0 : 1;
2247
2248 // quick test for screen border (not 100% correct, but looks ok)
2249 if (px < 4) scalef -= (GLfloat)(8*(4-px));
2250 if (py < viewport[1]+4) scalef -= (GLfloat)(8*(viewport[1]+4-py));
2251 if (px > viewport[2]-4) scalef -= (GLfloat)(8*(4-(viewport[2]-px)));
2252 if (py > viewport[1]+viewport[3]-4) scalef -= (GLfloat)(8*(4-(viewport[1]+viewport[3]-py)));
2253
2254 scalef /= 64;
2255 //GL_DBG_Printf("Scale factor: %f\n", scalef);
2256
2257 if (scalef < 0.05f)
2258 return;
2259
2260 // GLubyte c[4];
2261 c[0] = pSurf->PolyColor.s.red;
2262 c[1] = pSurf->PolyColor.s.green;
2263 c[2] = pSurf->PolyColor.s.blue;
2264
2265 alpha = byte2float[pSurf->PolyColor.s.alpha];
2266 alpha *= scalef; // change the alpha value (it seems better than changing the size of the corona)
2267 c[3] = (unsigned char)(alpha * 255);
2268 pglColor4ubv(c);
2269 }
2270
2271 Shader_SetUniforms(pSurf, &poly, &tint, &fade);
2272 }
2273
2274 // -----------------+
2275 // DrawPolygon : Render a polygon, set the texture, set render mode
2276 // -----------------+
HWRAPI(DrawPolygon)2277 EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags)
2278 {
2279 PreparePolygon(pSurf, pOutVerts, PolyFlags);
2280
2281 pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x);
2282 pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s);
2283 pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts);
2284
2285 if (PolyFlags & PF_RemoveYWrap)
2286 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
2287
2288 if (PolyFlags & PF_ForceWrapX)
2289 Clamp2D(GL_TEXTURE_WRAP_S);
2290
2291 if (PolyFlags & PF_ForceWrapY)
2292 Clamp2D(GL_TEXTURE_WRAP_T);
2293 }
2294
HWRAPI(DrawIndexedTriangles)2295 EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, UINT32 *IndexArray)
2296 {
2297 PreparePolygon(pSurf, pOutVerts, PolyFlags);
2298
2299 pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x);
2300 pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s);
2301 pglDrawElements(GL_TRIANGLES, iNumPts, GL_UNSIGNED_INT, IndexArray);
2302
2303 // the DrawPolygon variant of this has some code about polyflags and wrapping here but havent noticed any problems from omitting it?
2304 }
2305
2306 static const boolean gl_ext_arb_vertex_buffer_object = true;
2307
2308 #define NULL_VBO_VERTEX ((gl_skyvertex_t*)NULL)
2309 #define sky_vbo_x (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->x : &sky->data[0].x)
2310 #define sky_vbo_u (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->u : &sky->data[0].u)
2311 #define sky_vbo_r (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->r : &sky->data[0].r)
2312
HWRAPI(RenderSkyDome)2313 EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky)
2314 {
2315 int i, j;
2316
2317 Shader_SetUniforms(NULL, NULL, NULL, NULL);
2318
2319 // Build the sky dome! Yes!
2320 if (sky->rebuild)
2321 {
2322 // delete VBO when already exists
2323 if (gl_ext_arb_vertex_buffer_object)
2324 {
2325 if (sky->vbo)
2326 pglDeleteBuffers(1, &sky->vbo);
2327 }
2328
2329 if (gl_ext_arb_vertex_buffer_object)
2330 {
2331 // generate a new VBO and get the associated ID
2332 pglGenBuffers(1, &sky->vbo);
2333
2334 // bind VBO in order to use
2335 pglBindBuffer(GL_ARRAY_BUFFER, sky->vbo);
2336
2337 // upload data to VBO
2338 pglBufferData(GL_ARRAY_BUFFER, sky->vertex_count * sizeof(sky->data[0]), sky->data, GL_STATIC_DRAW);
2339 }
2340
2341 sky->rebuild = false;
2342 }
2343
2344 // bind VBO in order to use
2345 if (gl_ext_arb_vertex_buffer_object)
2346 pglBindBuffer(GL_ARRAY_BUFFER, sky->vbo);
2347
2348 // activate and specify pointers to arrays
2349 pglVertexPointer(3, GL_FLOAT, sizeof(sky->data[0]), sky_vbo_x);
2350 pglTexCoordPointer(2, GL_FLOAT, sizeof(sky->data[0]), sky_vbo_u);
2351 pglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(sky->data[0]), sky_vbo_r);
2352
2353 // activate color arrays
2354 pglEnableClientState(GL_COLOR_ARRAY);
2355
2356 // set transforms
2357 pglScalef(1.0f, (float)sky->height / 200.0f, 1.0f);
2358 pglRotatef(270.0f, 0.0f, 1.0f, 0.0f);
2359
2360 for (j = 0; j < 2; j++)
2361 {
2362 for (i = 0; i < sky->loopcount; i++)
2363 {
2364 gl_skyloopdef_t *loop = &sky->loops[i];
2365 unsigned int mode = 0;
2366
2367 if (j == 0 ? loop->use_texture : !loop->use_texture)
2368 continue;
2369
2370 switch (loop->mode)
2371 {
2372 case HWD_SKYLOOP_FAN:
2373 mode = GL_TRIANGLE_FAN;
2374 break;
2375 case HWD_SKYLOOP_STRIP:
2376 mode = GL_TRIANGLE_STRIP;
2377 break;
2378 default:
2379 continue;
2380 }
2381
2382 pglDrawArrays(mode, loop->vertexindex, loop->vertexcount);
2383 }
2384 }
2385
2386 pglScalef(1.0f, 1.0f, 1.0f);
2387 pglColor4ubv(white);
2388
2389 // bind with 0, so, switch back to normal pointer operation
2390 if (gl_ext_arb_vertex_buffer_object)
2391 pglBindBuffer(GL_ARRAY_BUFFER, 0);
2392
2393 // deactivate color array
2394 pglDisableClientState(GL_COLOR_ARRAY);
2395 }
2396
2397 // ==========================================================================
2398 //
2399 // ==========================================================================
HWRAPI(SetSpecialState)2400 EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
2401 {
2402 switch (IdState)
2403 {
2404 case HWD_SET_MODEL_LIGHTING:
2405 model_lighting = Value;
2406 break;
2407
2408 case HWD_SET_SHADERS:
2409 gl_allowshaders = (hwdshaderoption_t)Value;
2410 break;
2411
2412 case HWD_SET_TEXTUREFILTERMODE:
2413 switch (Value)
2414 {
2415 case HWD_SET_TEXTUREFILTER_TRILINEAR:
2416 min_filter = GL_LINEAR_MIPMAP_LINEAR;
2417 mag_filter = GL_LINEAR;
2418 MipMap = GL_TRUE;
2419 break;
2420 case HWD_SET_TEXTUREFILTER_BILINEAR:
2421 min_filter = mag_filter = GL_LINEAR;
2422 MipMap = GL_FALSE;
2423 break;
2424 case HWD_SET_TEXTUREFILTER_POINTSAMPLED:
2425 min_filter = mag_filter = GL_NEAREST;
2426 MipMap = GL_FALSE;
2427 break;
2428 case HWD_SET_TEXTUREFILTER_MIXED1:
2429 min_filter = GL_NEAREST;
2430 mag_filter = GL_LINEAR;
2431 MipMap = GL_FALSE;
2432 break;
2433 case HWD_SET_TEXTUREFILTER_MIXED2:
2434 min_filter = GL_LINEAR;
2435 mag_filter = GL_NEAREST;
2436 MipMap = GL_FALSE;
2437 break;
2438 case HWD_SET_TEXTUREFILTER_MIXED3:
2439 min_filter = GL_LINEAR_MIPMAP_LINEAR;
2440 mag_filter = GL_NEAREST;
2441 MipMap = GL_TRUE;
2442 break;
2443 default:
2444 mag_filter = GL_LINEAR;
2445 min_filter = GL_NEAREST;
2446 }
2447 if (!pgluBuild2DMipmaps)
2448 {
2449 MipMap = GL_FALSE;
2450 min_filter = GL_LINEAR;
2451 }
2452 Flush(); //??? if we want to change filter mode by texture, remove this
2453 break;
2454
2455 case HWD_SET_TEXTUREANISOTROPICMODE:
2456 anisotropic_filter = min(Value,maximumAnisotropy);
2457 if (maximumAnisotropy)
2458 Flush(); //??? if we want to change filter mode by texture, remove this
2459 break;
2460
2461 default:
2462 break;
2463 }
2464 }
2465
2466 static float *vertBuffer = NULL;
2467 static float *normBuffer = NULL;
2468 static size_t lerpBufferSize = 0;
2469 static short *vertTinyBuffer = NULL;
2470 static char *normTinyBuffer = NULL;
2471 static size_t lerpTinyBufferSize = 0;
2472
2473 // Static temporary buffer for doing frame interpolation
2474 // 'size' is the vertex size
AllocLerpBuffer(size_t size)2475 static void AllocLerpBuffer(size_t size)
2476 {
2477 if (lerpBufferSize >= size)
2478 return;
2479
2480 if (vertBuffer != NULL)
2481 free(vertBuffer);
2482
2483 if (normBuffer != NULL)
2484 free(normBuffer);
2485
2486 lerpBufferSize = size;
2487 vertBuffer = malloc(lerpBufferSize);
2488 normBuffer = malloc(lerpBufferSize);
2489 }
2490
2491 // Static temporary buffer for doing frame interpolation
2492 // 'size' is the vertex size
AllocLerpTinyBuffer(size_t size)2493 static void AllocLerpTinyBuffer(size_t size)
2494 {
2495 if (lerpTinyBufferSize >= size)
2496 return;
2497
2498 if (vertTinyBuffer != NULL)
2499 free(vertTinyBuffer);
2500
2501 if (normTinyBuffer != NULL)
2502 free(normTinyBuffer);
2503
2504 lerpTinyBufferSize = size;
2505 vertTinyBuffer = malloc(lerpTinyBufferSize);
2506 normTinyBuffer = malloc(lerpTinyBufferSize / 2);
2507 }
2508
2509 #ifndef GL_STATIC_DRAW
2510 #define GL_STATIC_DRAW 0x88E4
2511 #endif
2512
2513 #ifndef GL_ARRAY_BUFFER
2514 #define GL_ARRAY_BUFFER 0x8892
2515 #endif
2516
CreateModelVBO(mesh_t * mesh,mdlframe_t * frame)2517 static void CreateModelVBO(mesh_t *mesh, mdlframe_t *frame)
2518 {
2519 int bufferSize = sizeof(vbo64_t)*mesh->numTriangles * 3;
2520 vbo64_t *buffer = (vbo64_t*)malloc(bufferSize);
2521 vbo64_t *bufPtr = buffer;
2522
2523 float *vertPtr = frame->vertices;
2524 float *normPtr = frame->normals;
2525 float *tanPtr = frame->tangents;
2526 float *uvPtr = mesh->uvs;
2527 float *lightPtr = mesh->lightuvs;
2528 char *colorPtr = frame->colors;
2529
2530 int i;
2531 for (i = 0; i < mesh->numTriangles * 3; i++)
2532 {
2533 bufPtr->x = *vertPtr++;
2534 bufPtr->y = *vertPtr++;
2535 bufPtr->z = *vertPtr++;
2536
2537 bufPtr->nx = *normPtr++;
2538 bufPtr->ny = *normPtr++;
2539 bufPtr->nz = *normPtr++;
2540
2541 bufPtr->s0 = *uvPtr++;
2542 bufPtr->t0 = *uvPtr++;
2543
2544 if (tanPtr != NULL)
2545 {
2546 bufPtr->tan0 = *tanPtr++;
2547 bufPtr->tan1 = *tanPtr++;
2548 bufPtr->tan2 = *tanPtr++;
2549 }
2550
2551 if (lightPtr != NULL)
2552 {
2553 bufPtr->s1 = *lightPtr++;
2554 bufPtr->t1 = *lightPtr++;
2555 }
2556
2557 if (colorPtr)
2558 {
2559 bufPtr->r = *colorPtr++;
2560 bufPtr->g = *colorPtr++;
2561 bufPtr->b = *colorPtr++;
2562 bufPtr->a = *colorPtr++;
2563 }
2564 else
2565 {
2566 bufPtr->r = 255;
2567 bufPtr->g = 255;
2568 bufPtr->b = 255;
2569 bufPtr->a = 255;
2570 }
2571
2572 bufPtr++;
2573 }
2574
2575 pglGenBuffers(1, &frame->vboID);
2576 pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
2577 pglBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
2578 free(buffer);
2579
2580 // Don't leave the array buffer bound to the model,
2581 // since this is called mid-frame
2582 pglBindBuffer(GL_ARRAY_BUFFER, 0);
2583 }
2584
CreateModelVBOTiny(mesh_t * mesh,tinyframe_t * frame)2585 static void CreateModelVBOTiny(mesh_t *mesh, tinyframe_t *frame)
2586 {
2587 int bufferSize = sizeof(vbotiny_t)*mesh->numTriangles * 3;
2588 vbotiny_t *buffer = (vbotiny_t*)malloc(bufferSize);
2589 vbotiny_t *bufPtr = buffer;
2590
2591 short *vertPtr = frame->vertices;
2592 char *normPtr = frame->normals;
2593 float *uvPtr = mesh->uvs;
2594 char *tanPtr = frame->tangents;
2595
2596 int i;
2597 for (i = 0; i < mesh->numVertices; i++)
2598 {
2599 bufPtr->x = *vertPtr++;
2600 bufPtr->y = *vertPtr++;
2601 bufPtr->z = *vertPtr++;
2602
2603 bufPtr->nx = *normPtr++;
2604 bufPtr->ny = *normPtr++;
2605 bufPtr->nz = *normPtr++;
2606
2607 bufPtr->s0 = *uvPtr++;
2608 bufPtr->t0 = *uvPtr++;
2609
2610 if (tanPtr)
2611 {
2612 bufPtr->tanx = *tanPtr++;
2613 bufPtr->tany = *tanPtr++;
2614 bufPtr->tanz = *tanPtr++;
2615 }
2616
2617 bufPtr++;
2618 }
2619
2620 pglGenBuffers(1, &frame->vboID);
2621 pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
2622 pglBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
2623 free(buffer);
2624
2625 // Don't leave the array buffer bound to the model,
2626 // since this is called mid-frame
2627 pglBindBuffer(GL_ARRAY_BUFFER, 0);
2628 }
2629
HWRAPI(CreateModelVBOs)2630 EXPORT void HWRAPI(CreateModelVBOs) (model_t *model)
2631 {
2632 int i;
2633 for (i = 0; i < model->numMeshes; i++)
2634 {
2635 mesh_t *mesh = &model->meshes[i];
2636
2637 if (mesh->frames)
2638 {
2639 int j;
2640 for (j = 0; j < model->meshes[i].numFrames; j++)
2641 {
2642 mdlframe_t *frame = &mesh->frames[j];
2643 if (frame->vboID)
2644 pglDeleteBuffers(1, &frame->vboID);
2645 frame->vboID = 0;
2646 CreateModelVBO(mesh, frame);
2647 }
2648 }
2649 else if (mesh->tinyframes)
2650 {
2651 int j;
2652 for (j = 0; j < model->meshes[i].numFrames; j++)
2653 {
2654 tinyframe_t *frame = &mesh->tinyframes[j];
2655 if (frame->vboID)
2656 pglDeleteBuffers(1, &frame->vboID);
2657 frame->vboID = 0;
2658 CreateModelVBOTiny(mesh, frame);
2659 }
2660 }
2661 }
2662 }
2663
2664 #define BUFFER_OFFSET(i) ((void*)(i))
2665
DrawModelEx(model_t * model,INT32 frameIndex,INT32 duration,INT32 tics,INT32 nextFrameIndex,FTransform * pos,float scale,UINT8 flipped,UINT8 hflipped,FSurfaceInfo * Surface)2666 static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
2667 {
2668 static GLRGBAFloat poly = {0,0,0,0};
2669 static GLRGBAFloat tint = {0,0,0,0};
2670 static GLRGBAFloat fade = {0,0,0,0};
2671
2672 float pol = 0.0f;
2673 float scalex, scaley, scalez;
2674
2675 boolean useTinyFrames;
2676
2677 boolean useVBO = true;
2678
2679 FBITFIELD flags;
2680 int i;
2681
2682 // Because otherwise, scaling the screen negatively vertically breaks the lighting
2683 GLfloat LightPos[] = {0.0f, 1.0f, 0.0f, 0.0f};
2684 #ifdef GL_LIGHT_MODEL_AMBIENT
2685 GLfloat ambient[4];
2686 GLfloat diffuse[4];
2687 #endif
2688
2689 // Affect input model scaling
2690 scale *= 0.5f;
2691 scalex = scale;
2692 scaley = scale;
2693 scalez = scale;
2694
2695 if (duration != 0 && duration != -1 && tics != -1) // don't interpolate if instantaneous or infinite in length
2696 {
2697 UINT32 newtime = (duration - tics); // + 1;
2698
2699 pol = (newtime)/(float)duration;
2700
2701 if (pol > 1.0f)
2702 pol = 1.0f;
2703
2704 if (pol < 0.0f)
2705 pol = 0.0f;
2706 }
2707
2708 poly.red = byte2float[Surface->PolyColor.s.red];
2709 poly.green = byte2float[Surface->PolyColor.s.green];
2710 poly.blue = byte2float[Surface->PolyColor.s.blue];
2711 poly.alpha = byte2float[Surface->PolyColor.s.alpha];
2712
2713 #ifdef GL_LIGHT_MODEL_AMBIENT
2714 if (model_lighting)
2715 {
2716 if (!gl_shadersenabled)
2717 {
2718 ambient[0] = poly.red;
2719 ambient[1] = poly.green;
2720 ambient[2] = poly.blue;
2721 ambient[3] = poly.alpha;
2722
2723 diffuse[0] = poly.red;
2724 diffuse[1] = poly.green;
2725 diffuse[2] = poly.blue;
2726 diffuse[3] = poly.alpha;
2727
2728 if (ambient[0] > 0.75f)
2729 ambient[0] = 0.75f;
2730 if (ambient[1] > 0.75f)
2731 ambient[1] = 0.75f;
2732 if (ambient[2] > 0.75f)
2733 ambient[2] = 0.75f;
2734
2735 pglLightfv(GL_LIGHT0, GL_POSITION, LightPos);
2736
2737 pglEnable(GL_LIGHTING);
2738 pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
2739 pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
2740 }
2741 pglShadeModel(GL_SMOOTH);
2742 }
2743 #endif
2744 else
2745 pglColor4ubv((GLubyte*)&Surface->PolyColor.s);
2746
2747 tint.red = byte2float[Surface->TintColor.s.red];
2748 tint.green = byte2float[Surface->TintColor.s.green];
2749 tint.blue = byte2float[Surface->TintColor.s.blue];
2750 tint.alpha = byte2float[Surface->TintColor.s.alpha];
2751
2752 fade.red = byte2float[Surface->FadeColor.s.red];
2753 fade.green = byte2float[Surface->FadeColor.s.green];
2754 fade.blue = byte2float[Surface->FadeColor.s.blue];
2755 fade.alpha = byte2float[Surface->FadeColor.s.alpha];
2756
2757 flags = (Surface->PolyFlags | PF_Modulated);
2758 if (Surface->PolyFlags & (PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative))
2759 flags |= PF_Occlude;
2760 else if (Surface->PolyColor.s.alpha == 0xFF)
2761 flags |= (PF_Occlude | PF_Masked);
2762
2763 SetBlend(flags);
2764 Shader_SetUniforms(Surface, &poly, &tint, &fade);
2765
2766 pglEnable(GL_CULL_FACE);
2767 pglEnable(GL_NORMALIZE);
2768
2769 #ifdef USE_FTRANSFORM_MIRROR
2770 // flipped is if the object is vertically flipped
2771 // hflipped is if the object is horizontally flipped
2772 // pos->flip is if the screen is flipped vertically
2773 // pos->mirror is if the screen is flipped horizontally
2774 // XOR all the flips together to figure out what culling to use!
2775 {
2776 boolean reversecull = (flipped ^ hflipped ^ pos->flip ^ pos->mirror);
2777 if (reversecull)
2778 pglCullFace(GL_FRONT);
2779 else
2780 pglCullFace(GL_BACK);
2781 }
2782 #else
2783 // pos->flip is if the screen is flipped too
2784 if (flipped ^ hflipped ^ pos->flip) // If one or three of these are active, but not two, invert the model's culling
2785 {
2786 pglCullFace(GL_FRONT);
2787 }
2788 else
2789 {
2790 pglCullFace(GL_BACK);
2791 }
2792 #endif
2793
2794 pglPushMatrix(); // should be the same as glLoadIdentity
2795 //Hurdler: now it seems to work
2796 pglTranslatef(pos->x, pos->z, pos->y);
2797 if (flipped)
2798 scaley = -scaley;
2799 if (hflipped)
2800 scalez = -scalez;
2801
2802 #ifdef USE_FTRANSFORM_ANGLEZ
2803 pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart
2804 #endif
2805 pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
2806 pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f);
2807
2808 if (pos->roll)
2809 {
2810 float roll = (1.0f * pos->rollflip);
2811 pglTranslatef(pos->centerx, pos->centery, 0);
2812 if (pos->rotaxis == 2) // Z
2813 pglRotatef(pos->rollangle, 0.0f, 0.0f, roll);
2814 else if (pos->rotaxis == 1) // Y
2815 pglRotatef(pos->rollangle, 0.0f, roll, 0.0f);
2816 else // X
2817 pglRotatef(pos->rollangle, roll, 0.0f, 0.0f);
2818 pglTranslatef(-pos->centerx, -pos->centery, 0);
2819 }
2820
2821 pglScalef(scalex, scaley, scalez);
2822
2823 useTinyFrames = model->meshes[0].tinyframes != NULL;
2824
2825 if (useTinyFrames)
2826 pglScalef(1 / 64.0f, 1 / 64.0f, 1 / 64.0f);
2827
2828 // Don't use the VBO if it does not have the correct texture coordinates.
2829 // (Can happen when model uses a sprite as a texture and the sprite changes)
2830 // Comparing floats with the != operator here should be okay because they
2831 // are just copies of glpatches' max_s and max_t values.
2832 // Instead of the != operator, memcmp is used to avoid a compiler warning.
2833 if (memcmp(&(model->vbo_max_s), &(model->max_s), sizeof(model->max_s)) != 0 ||
2834 memcmp(&(model->vbo_max_t), &(model->max_t), sizeof(model->max_t)) != 0)
2835 useVBO = false;
2836
2837 pglEnableClientState(GL_NORMAL_ARRAY);
2838
2839 for (i = 0; i < model->numMeshes; i++)
2840 {
2841 mesh_t *mesh = &model->meshes[i];
2842
2843 if (useTinyFrames)
2844 {
2845 tinyframe_t *frame = &mesh->tinyframes[frameIndex % mesh->numFrames];
2846 tinyframe_t *nextframe = NULL;
2847
2848 if (nextFrameIndex != -1)
2849 nextframe = &mesh->tinyframes[nextFrameIndex % mesh->numFrames];
2850
2851 if (!nextframe || fpclassify(pol) == FP_ZERO)
2852 {
2853 if (useVBO)
2854 {
2855 pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
2856 pglVertexPointer(3, GL_SHORT, sizeof(vbotiny_t), BUFFER_OFFSET(0));
2857 pglNormalPointer(GL_BYTE, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short)*3));
2858 pglTexCoordPointer(2, GL_FLOAT, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short) * 3 + sizeof(char) * 6));
2859
2860 pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
2861 pglBindBuffer(GL_ARRAY_BUFFER, 0);
2862 }
2863 else
2864 {
2865 pglVertexPointer(3, GL_SHORT, 0, frame->vertices);
2866 pglNormalPointer(GL_BYTE, 0, frame->normals);
2867 pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
2868 pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
2869 }
2870 }
2871 else
2872 {
2873 short *vertPtr;
2874 char *normPtr;
2875 int j = 0;
2876
2877 // Dangit, I soooo want to do this in a GLSL shader...
2878 AllocLerpTinyBuffer(mesh->numVertices * sizeof(short) * 3);
2879 vertPtr = vertTinyBuffer;
2880 normPtr = normTinyBuffer;
2881
2882 for (j = 0; j < mesh->numVertices * 3; j++)
2883 {
2884 // Interpolate
2885 *vertPtr++ = (short)(frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j])));
2886 *normPtr++ = (char)(frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j])));
2887 }
2888
2889 pglVertexPointer(3, GL_SHORT, 0, vertTinyBuffer);
2890 pglNormalPointer(GL_BYTE, 0, normTinyBuffer);
2891 pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
2892 pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
2893 }
2894 }
2895 else
2896 {
2897 mdlframe_t *frame = &mesh->frames[frameIndex % mesh->numFrames];
2898 mdlframe_t *nextframe = NULL;
2899
2900 if (nextFrameIndex != -1)
2901 nextframe = &mesh->frames[nextFrameIndex % mesh->numFrames];
2902
2903 if (!nextframe || fpclassify(pol) == FP_ZERO)
2904 {
2905 if (useVBO)
2906 {
2907 pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
2908 pglVertexPointer(3, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(0));
2909 pglNormalPointer(GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 3));
2910 pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 6));
2911
2912 pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);
2913 // No tinyframes, no mesh indices
2914 //pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
2915 pglBindBuffer(GL_ARRAY_BUFFER, 0);
2916 }
2917 else
2918 {
2919 pglVertexPointer(3, GL_FLOAT, 0, frame->vertices);
2920 pglNormalPointer(GL_FLOAT, 0, frame->normals);
2921 pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
2922 pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);
2923 }
2924 }
2925 else
2926 {
2927 float *vertPtr;
2928 float *normPtr;
2929 int j = 0;
2930
2931 // Dangit, I soooo want to do this in a GLSL shader...
2932 AllocLerpBuffer(mesh->numVertices * sizeof(float) * 3);
2933 vertPtr = vertBuffer;
2934 normPtr = normBuffer;
2935 //int j = 0;
2936
2937 for (j = 0; j < mesh->numVertices * 3; j++)
2938 {
2939 // Interpolate
2940 *vertPtr++ = frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j]));
2941 *normPtr++ = frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j]));
2942 }
2943
2944 pglVertexPointer(3, GL_FLOAT, 0, vertBuffer);
2945 pglNormalPointer(GL_FLOAT, 0, normBuffer);
2946 pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
2947 pglDrawArrays(GL_TRIANGLES, 0, mesh->numVertices);
2948 }
2949 }
2950 }
2951
2952 pglDisableClientState(GL_NORMAL_ARRAY);
2953
2954 pglPopMatrix(); // should be the same as glLoadIdentity
2955 pglDisable(GL_CULL_FACE);
2956 pglDisable(GL_NORMALIZE);
2957
2958 #ifdef GL_LIGHT_MODEL_AMBIENT
2959 if (model_lighting)
2960 {
2961 if (!gl_shadersenabled)
2962 pglDisable(GL_LIGHTING);
2963 pglShadeModel(GL_FLAT);
2964 }
2965 #endif
2966 }
2967
2968 // -----------------+
2969 // HWRAPI DrawModel : Draw a model
2970 // -----------------+
HWRAPI(DrawModel)2971 EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
2972 {
2973 DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface);
2974 }
2975
2976 // -----------------+
2977 // SetTransform :
2978 // -----------------+
HWRAPI(SetTransform)2979 EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
2980 {
2981 static boolean special_splitscreen;
2982 boolean shearing = false;
2983 float used_fov;
2984
2985 pglLoadIdentity();
2986
2987 if (stransform)
2988 {
2989 used_fov = stransform->fovxangle;
2990 #ifdef USE_FTRANSFORM_MIRROR
2991 // mirroring from Kart
2992 if (stransform->mirror)
2993 pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez);
2994 else
2995 #endif
2996 if (stransform->flip)
2997 pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez);
2998 else
2999 pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez);
3000
3001 if (stransform->roll)
3002 pglRotatef(stransform->rollangle, 0.0f, 0.0f, 1.0f);
3003 pglRotatef(stransform->anglex , 1.0f, 0.0f, 0.0f);
3004 pglRotatef(stransform->angley+270.0f, 0.0f, 1.0f, 0.0f);
3005 pglTranslatef(-stransform->x, -stransform->z, -stransform->y);
3006
3007 special_splitscreen = stransform->splitscreen;
3008 shearing = stransform->shearing;
3009 }
3010 else
3011 {
3012 used_fov = fov;
3013 pglScalef(1.0f, 1.0f, -1.0f);
3014 }
3015
3016 pglMatrixMode(GL_PROJECTION);
3017 pglLoadIdentity();
3018
3019 // Simulate Software's y-shearing
3020 // https://zdoom.org/wiki/Y-shearing
3021 if (shearing)
3022 {
3023 float fdy = stransform->viewaiming * 2;
3024 if (stransform->flip)
3025 fdy *= -1.0f;
3026 pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f);
3027 }
3028
3029 if (special_splitscreen)
3030 {
3031 used_fov = atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI;
3032 GLPerspective(used_fov, 2*ASPECT_RATIO);
3033 }
3034 else
3035 GLPerspective(used_fov, ASPECT_RATIO);
3036
3037 pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer)
3038 pglMatrixMode(GL_MODELVIEW);
3039
3040 pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
3041
3042 }
3043
HWRAPI(GetTextureUsed)3044 EXPORT INT32 HWRAPI(GetTextureUsed) (void)
3045 {
3046 FTextureInfo *tmp = TexCacheHead;
3047 INT32 res = 0;
3048
3049 while (tmp)
3050 {
3051 // Figure out the correct bytes-per-pixel for this texture
3052 // I don't know which one the game actually _uses_ but this
3053 // follows format2bpp in hw_cache.c
3054 int bpp = 1;
3055 int format = tmp->format;
3056 if (format == GL_TEXFMT_RGBA)
3057 bpp = 4;
3058 else if (format == GL_TEXFMT_ALPHA_INTENSITY_88 || format == GL_TEXFMT_AP_88)
3059 bpp = 2;
3060
3061 // Add it up!
3062 res += tmp->height*tmp->width*bpp;
3063 tmp = tmp->next;
3064 }
3065
3066 return res;
3067 }
3068
HWRAPI(PostImgRedraw)3069 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
3070 {
3071 INT32 x, y;
3072 float float_x, float_y, float_nextx, float_nexty;
3073 float xfix, yfix;
3074 INT32 texsize = 2048;
3075
3076 const float blackBack[16] =
3077 {
3078 -16.0f, -16.0f, 6.0f,
3079 -16.0f, 16.0f, 6.0f,
3080 16.0f, 16.0f, 6.0f,
3081 16.0f, -16.0f, 6.0f
3082 };
3083
3084 // Use a power of two texture, dammit
3085 if(screen_width <= 1024)
3086 texsize = 1024;
3087 if(screen_width <= 512)
3088 texsize = 512;
3089
3090 // X/Y stretch fix for all resolutions(!)
3091 xfix = (float)(texsize)/((float)((screen_width)/(float)(SCREENVERTS-1)));
3092 yfix = (float)(texsize)/((float)((screen_height)/(float)(SCREENVERTS-1)));
3093
3094 pglDisable(GL_DEPTH_TEST);
3095 pglDisable(GL_BLEND);
3096
3097 // const float blackBack[16]
3098
3099 // Draw a black square behind the screen texture,
3100 // so nothing shows through the edges
3101 pglColor4ubv(white);
3102
3103 pglVertexPointer(3, GL_FLOAT, 0, blackBack);
3104 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3105
3106 pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
3107 for(x=0;x<SCREENVERTS-1;x++)
3108 {
3109 for(y=0;y<SCREENVERTS-1;y++)
3110 {
3111 float stCoords[8];
3112 float vertCoords[12];
3113
3114 // Used for texture coordinates
3115 // Annoying magic numbers to scale the square texture to
3116 // a non-square screen..
3117 float_x = (float)(x/(xfix));
3118 float_y = (float)(y/(yfix));
3119 float_nextx = (float)(x+1)/(xfix);
3120 float_nexty = (float)(y+1)/(yfix);
3121
3122 // float stCoords[8];
3123 stCoords[0] = float_x;
3124 stCoords[1] = float_y;
3125 stCoords[2] = float_x;
3126 stCoords[3] = float_nexty;
3127 stCoords[4] = float_nextx;
3128 stCoords[5] = float_nexty;
3129 stCoords[6] = float_nextx;
3130 stCoords[7] = float_y;
3131
3132 pglTexCoordPointer(2, GL_FLOAT, 0, stCoords);
3133
3134 // float vertCoords[12];
3135 vertCoords[0] = points[x][y][0];
3136 vertCoords[1] = points[x][y][1];
3137 vertCoords[2] = 4.4f;
3138 vertCoords[3] = points[x][y + 1][0];
3139 vertCoords[4] = points[x][y + 1][1];
3140 vertCoords[5] = 4.4f;
3141 vertCoords[6] = points[x + 1][y + 1][0];
3142 vertCoords[7] = points[x + 1][y + 1][1];
3143 vertCoords[8] = 4.4f;
3144 vertCoords[9] = points[x + 1][y][0];
3145 vertCoords[10] = points[x + 1][y][1];
3146 vertCoords[11] = 4.4f;
3147
3148 pglVertexPointer(3, GL_FLOAT, 0, vertCoords);
3149
3150 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3151 }
3152 }
3153
3154 pglEnable(GL_DEPTH_TEST);
3155 pglEnable(GL_BLEND);
3156 }
3157
3158 // Sryder: This needs to be called whenever the screen changes resolution in order to reset the screen textures to use
3159 // a new size
HWRAPI(FlushScreenTextures)3160 EXPORT void HWRAPI(FlushScreenTextures) (void)
3161 {
3162 pglDeleteTextures(1, &screentexture);
3163 pglDeleteTextures(1, &startScreenWipe);
3164 pglDeleteTextures(1, &endScreenWipe);
3165 pglDeleteTextures(1, &finalScreenTexture);
3166 screentexture = 0;
3167 startScreenWipe = 0;
3168 endScreenWipe = 0;
3169 finalScreenTexture = 0;
3170 }
3171
3172 // Create Screen to fade from
HWRAPI(StartScreenWipe)3173 EXPORT void HWRAPI(StartScreenWipe) (void)
3174 {
3175 INT32 texsize = 2048;
3176 boolean firstTime = (startScreenWipe == 0);
3177
3178 // Use a power of two texture, dammit
3179 if(screen_width <= 512)
3180 texsize = 512;
3181 else if(screen_width <= 1024)
3182 texsize = 1024;
3183
3184 // Create screen texture
3185 if (firstTime)
3186 pglGenTextures(1, &startScreenWipe);
3187 pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
3188
3189 if (firstTime)
3190 {
3191 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3192 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3193 Clamp2D(GL_TEXTURE_WRAP_S);
3194 Clamp2D(GL_TEXTURE_WRAP_T);
3195 pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
3196 }
3197 else
3198 pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
3199
3200 tex_downloaded = startScreenWipe;
3201 }
3202
3203 // Create Screen to fade to
HWRAPI(EndScreenWipe)3204 EXPORT void HWRAPI(EndScreenWipe)(void)
3205 {
3206 INT32 texsize = 2048;
3207 boolean firstTime = (endScreenWipe == 0);
3208
3209 // Use a power of two texture, dammit
3210 if(screen_width <= 512)
3211 texsize = 512;
3212 else if(screen_width <= 1024)
3213 texsize = 1024;
3214
3215 // Create screen texture
3216 if (firstTime)
3217 pglGenTextures(1, &endScreenWipe);
3218 pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
3219
3220 if (firstTime)
3221 {
3222 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3223 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3224 Clamp2D(GL_TEXTURE_WRAP_S);
3225 Clamp2D(GL_TEXTURE_WRAP_T);
3226 pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
3227 }
3228 else
3229 pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
3230
3231 tex_downloaded = endScreenWipe;
3232 }
3233
3234
3235 // Draw the last scene under the intermission
HWRAPI(DrawIntermissionBG)3236 EXPORT void HWRAPI(DrawIntermissionBG)(void)
3237 {
3238 float xfix, yfix;
3239 INT32 texsize = 2048;
3240
3241 const float screenVerts[12] =
3242 {
3243 -1.0f, -1.0f, 1.0f,
3244 -1.0f, 1.0f, 1.0f,
3245 1.0f, 1.0f, 1.0f,
3246 1.0f, -1.0f, 1.0f
3247 };
3248
3249 float fix[8];
3250
3251 if(screen_width <= 1024)
3252 texsize = 1024;
3253 if(screen_width <= 512)
3254 texsize = 512;
3255
3256 xfix = 1/((float)(texsize)/((float)((screen_width))));
3257 yfix = 1/((float)(texsize)/((float)((screen_height))));
3258
3259 // const float screenVerts[12]
3260
3261 // float fix[8];
3262 fix[0] = 0.0f;
3263 fix[1] = 0.0f;
3264 fix[2] = 0.0f;
3265 fix[3] = yfix;
3266 fix[4] = xfix;
3267 fix[5] = yfix;
3268 fix[6] = xfix;
3269 fix[7] = 0.0f;
3270
3271 pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
3272
3273 pglBindTexture(GL_TEXTURE_2D, screentexture);
3274 pglColor4ubv(white);
3275
3276 pglTexCoordPointer(2, GL_FLOAT, 0, fix);
3277 pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
3278 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3279
3280 tex_downloaded = screentexture;
3281 }
3282
3283 // Do screen fades!
HWRAPI(DoScreenWipe)3284 EXPORT void HWRAPI(DoScreenWipe)(void)
3285 {
3286 INT32 texsize = 2048;
3287 float xfix, yfix;
3288
3289 INT32 fademaskdownloaded = tex_downloaded; // the fade mask that has been set
3290
3291 const float screenVerts[12] =
3292 {
3293 -1.0f, -1.0f, 1.0f,
3294 -1.0f, 1.0f, 1.0f,
3295 1.0f, 1.0f, 1.0f,
3296 1.0f, -1.0f, 1.0f
3297 };
3298
3299 float fix[8];
3300
3301 const float defaultST[8] =
3302 {
3303 0.0f, 1.0f,
3304 0.0f, 0.0f,
3305 1.0f, 0.0f,
3306 1.0f, 1.0f
3307 };
3308
3309 // Use a power of two texture, dammit
3310 if(screen_width <= 1024)
3311 texsize = 1024;
3312 if(screen_width <= 512)
3313 texsize = 512;
3314
3315 xfix = 1/((float)(texsize)/((float)((screen_width))));
3316 yfix = 1/((float)(texsize)/((float)((screen_height))));
3317
3318 // const float screenVerts[12]
3319
3320 // float fix[8];
3321 fix[0] = 0.0f;
3322 fix[1] = 0.0f;
3323 fix[2] = 0.0f;
3324 fix[3] = yfix;
3325 fix[4] = xfix;
3326 fix[5] = yfix;
3327 fix[6] = xfix;
3328 fix[7] = 0.0f;
3329
3330 pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
3331
3332 SetBlend(PF_Modulated|PF_NoDepthTest);
3333 pglEnable(GL_TEXTURE_2D);
3334
3335 // Draw the original screen
3336 pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
3337 pglColor4ubv(white);
3338 pglTexCoordPointer(2, GL_FLOAT, 0, fix);
3339 pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
3340 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3341
3342 SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest);
3343
3344 // Draw the end screen that fades in
3345 pglActiveTexture(GL_TEXTURE0);
3346 pglEnable(GL_TEXTURE_2D);
3347 pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
3348 pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3349
3350 pglActiveTexture(GL_TEXTURE1);
3351 pglEnable(GL_TEXTURE_2D);
3352 pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded);
3353
3354 pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3355
3356 // const float defaultST[8]
3357
3358 pglClientActiveTexture(GL_TEXTURE0);
3359 pglTexCoordPointer(2, GL_FLOAT, 0, fix);
3360 pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
3361 pglClientActiveTexture(GL_TEXTURE1);
3362 pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
3363 pglTexCoordPointer(2, GL_FLOAT, 0, defaultST);
3364 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3365
3366 pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit
3367 pglDisableClientState(GL_TEXTURE_COORD_ARRAY);
3368
3369 pglActiveTexture(GL_TEXTURE0);
3370 pglClientActiveTexture(GL_TEXTURE0);
3371 tex_downloaded = endScreenWipe;
3372 }
3373
3374 // Create a texture from the screen.
HWRAPI(MakeScreenTexture)3375 EXPORT void HWRAPI(MakeScreenTexture) (void)
3376 {
3377 INT32 texsize = 2048;
3378 boolean firstTime = (screentexture == 0);
3379
3380 // Use a power of two texture, dammit
3381 if(screen_width <= 512)
3382 texsize = 512;
3383 else if(screen_width <= 1024)
3384 texsize = 1024;
3385
3386 // Create screen texture
3387 if (firstTime)
3388 pglGenTextures(1, &screentexture);
3389 pglBindTexture(GL_TEXTURE_2D, screentexture);
3390
3391 if (firstTime)
3392 {
3393 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3394 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3395 Clamp2D(GL_TEXTURE_WRAP_S);
3396 Clamp2D(GL_TEXTURE_WRAP_T);
3397 pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
3398 }
3399 else
3400 pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
3401
3402 tex_downloaded = screentexture;
3403 }
3404
HWRAPI(MakeScreenFinalTexture)3405 EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
3406 {
3407 INT32 texsize = 2048;
3408 boolean firstTime = (finalScreenTexture == 0);
3409
3410 // Use a power of two texture, dammit
3411 if(screen_width <= 512)
3412 texsize = 512;
3413 else if(screen_width <= 1024)
3414 texsize = 1024;
3415
3416 // Create screen texture
3417 if (firstTime)
3418 pglGenTextures(1, &finalScreenTexture);
3419 pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
3420
3421 if (firstTime)
3422 {
3423 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3424 pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3425 Clamp2D(GL_TEXTURE_WRAP_S);
3426 Clamp2D(GL_TEXTURE_WRAP_T);
3427 pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
3428 }
3429 else
3430 pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
3431
3432 tex_downloaded = finalScreenTexture;
3433 }
3434
HWRAPI(DrawScreenFinalTexture)3435 EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
3436 {
3437 float xfix, yfix;
3438 float origaspect, newaspect;
3439 float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen
3440 FRGBAFloat clearColour;
3441 INT32 texsize = 2048;
3442
3443 float off[12];
3444 float fix[8];
3445
3446 if(screen_width <= 1024)
3447 texsize = 1024;
3448 if(screen_width <= 512)
3449 texsize = 512;
3450
3451 xfix = 1/((float)(texsize)/((float)((screen_width))));
3452 yfix = 1/((float)(texsize)/((float)((screen_height))));
3453
3454 origaspect = (float)screen_width / screen_height;
3455 newaspect = (float)width / height;
3456 if (origaspect < newaspect)
3457 {
3458 xoff = origaspect / newaspect;
3459 yoff = 1;
3460 }
3461 else if (origaspect > newaspect)
3462 {
3463 xoff = 1;
3464 yoff = newaspect / origaspect;
3465 }
3466
3467 // float off[12];
3468 off[0] = -xoff;
3469 off[1] = -yoff;
3470 off[2] = 1.0f;
3471 off[3] = -xoff;
3472 off[4] = yoff;
3473 off[5] = 1.0f;
3474 off[6] = xoff;
3475 off[7] = yoff;
3476 off[8] = 1.0f;
3477 off[9] = xoff;
3478 off[10] = -yoff;
3479 off[11] = 1.0f;
3480
3481 // float fix[8];
3482 fix[0] = 0.0f;
3483 fix[1] = 0.0f;
3484 fix[2] = 0.0f;
3485 fix[3] = yfix;
3486 fix[4] = xfix;
3487 fix[5] = yfix;
3488 fix[6] = xfix;
3489 fix[7] = 0.0f;
3490
3491 pglViewport(0, 0, width, height);
3492
3493 clearColour.red = clearColour.green = clearColour.blue = 0;
3494 clearColour.alpha = 1;
3495 ClearBuffer(true, false, &clearColour);
3496 pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
3497
3498 pglColor4ubv(white);
3499
3500 pglTexCoordPointer(2, GL_FLOAT, 0, fix);
3501 pglVertexPointer(3, GL_FLOAT, 0, off);
3502
3503 pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3504 tex_downloaded = finalScreenTexture;
3505 }
3506
3507 #endif //HWRENDER
3508