1 /* 2 * Compatibility functions for older GL implementations 3 * 4 * Copyright 2008 Stefan Dösinger for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include "wine/port.h" 23 24 #include <stdio.h> 25 #ifdef HAVE_FLOAT_H 26 # include <float.h> 27 #endif 28 29 #include "wined3d_private.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(gl_compat); 32 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); 33 34 /* Start GL_ARB_multitexture emulation */ 35 static void WINE_GLAPI wine_glMultiTexCoord1fARB(GLenum target, GLfloat s) { 36 if(target != GL_TEXTURE0) { 37 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 38 return; 39 } 40 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord1f(s); 41 } 42 43 static void WINE_GLAPI wine_glMultiTexCoord1fvARB(GLenum target, const GLfloat *v) { 44 if(target != GL_TEXTURE0) { 45 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 46 return; 47 } 48 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord1fv(v); 49 } 50 51 static void WINE_GLAPI wine_glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) { 52 if(target != GL_TEXTURE0) { 53 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 54 return; 55 } 56 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord2f(s, t); 57 } 58 59 static void WINE_GLAPI wine_glMultiTexCoord2fvARB(GLenum target, const GLfloat *v) { 60 if(target != GL_TEXTURE0) { 61 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 62 return; 63 } 64 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord2fv(v); 65 } 66 67 static void WINE_GLAPI wine_glMultiTexCoord3fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r) { 68 if(target != GL_TEXTURE0) { 69 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 70 return; 71 } 72 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord3f(s, t, r); 73 } 74 75 static void WINE_GLAPI wine_glMultiTexCoord3fvARB(GLenum target, const GLfloat *v) { 76 if(target != GL_TEXTURE0) { 77 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 78 return; 79 } 80 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord3fv(v); 81 } 82 83 static void WINE_GLAPI wine_glMultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) { 84 if(target != GL_TEXTURE0) { 85 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 86 return; 87 } 88 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord4f(s, t, r, q); 89 } 90 91 static void WINE_GLAPI wine_glMultiTexCoord4fvARB(GLenum target, const GLfloat *v) { 92 if(target != GL_TEXTURE0) { 93 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 94 return; 95 } 96 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord4fv(v); 97 } 98 99 static void WINE_GLAPI wine_glMultiTexCoord2svARB(GLenum target, const GLshort *v) { 100 if(target != GL_TEXTURE0) { 101 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 102 return; 103 } 104 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord2sv(v); 105 } 106 107 static void WINE_GLAPI wine_glMultiTexCoord4svARB(GLenum target, const GLshort *v) { 108 if(target != GL_TEXTURE0) { 109 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 110 return; 111 } 112 context_get_current()->gl_info->gl_ops.gl.p_glTexCoord4sv(v); 113 } 114 115 static void WINE_GLAPI wine_glActiveTexture(GLenum texture) 116 { 117 if(texture != GL_TEXTURE0) { 118 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 119 return; 120 } 121 } 122 123 static void WINE_GLAPI wine_glClientActiveTextureARB(GLenum texture) { 124 if(texture != GL_TEXTURE0) { 125 ERR("Texture unit > 0 used, but GL_ARB_multitexture is not supported\n"); 126 return; 127 } 128 } 129 130 static void (WINE_GLAPI *old_multitex_glGetIntegerv) (GLenum pname, GLint* params) = NULL; 131 static void WINE_GLAPI wine_glGetIntegerv(GLenum pname, GLint* params) { 132 switch(pname) { 133 case GL_ACTIVE_TEXTURE: *params = 0; break; 134 case GL_MAX_TEXTURE_UNITS_ARB: *params = 1; break; 135 default: old_multitex_glGetIntegerv(pname, params); 136 } 137 } 138 139 static void (WINE_GLAPI *old_multitex_glGetFloatv) (GLenum pname, GLfloat* params) = NULL; 140 static void WINE_GLAPI wine_glGetFloatv(GLenum pname, GLfloat* params) { 141 if (pname == GL_ACTIVE_TEXTURE) *params = 0.0f; 142 else old_multitex_glGetFloatv(pname, params); 143 } 144 145 static void (WINE_GLAPI *old_multitex_glGetDoublev) (GLenum pname, GLdouble* params) = NULL; 146 static void WINE_GLAPI wine_glGetDoublev(GLenum pname, GLdouble* params) { 147 if(pname == GL_ACTIVE_TEXTURE) *params = 0.0; 148 else old_multitex_glGetDoublev(pname, params); 149 } 150 151 /* Start GL_EXT_fogcoord emulation */ 152 static void (WINE_GLAPI *old_fogcoord_glEnable) (GLenum cap) = NULL; 153 static void WINE_GLAPI wine_glEnable(GLenum cap) { 154 if(cap == GL_FOG) { 155 struct wined3d_context *ctx = context_get_current(); 156 ctx->fog_enabled = 1; 157 if(ctx->gl_fog_source != GL_FRAGMENT_DEPTH_EXT) return; 158 } 159 old_fogcoord_glEnable(cap); 160 } 161 162 static void (WINE_GLAPI *old_fogcoord_glDisable) (GLenum cap) = NULL; 163 static void WINE_GLAPI wine_glDisable(GLenum cap) { 164 if(cap == GL_FOG) { 165 struct wined3d_context *ctx = context_get_current(); 166 ctx->fog_enabled = 0; 167 if(ctx->gl_fog_source != GL_FRAGMENT_DEPTH_EXT) return; 168 } 169 old_fogcoord_glDisable(cap); 170 } 171 172 static void (WINE_GLAPI *old_fogcoord_glFogi) (GLenum pname, GLint param) = NULL; 173 static void WINE_GLAPI wine_glFogi(GLenum pname, GLint param) { 174 struct wined3d_context *ctx = context_get_current(); 175 176 if(pname == GL_FOG_COORDINATE_SOURCE_EXT) { 177 ctx->gl_fog_source = param; 178 if(param == GL_FRAGMENT_DEPTH_EXT) { 179 if(ctx->fog_enabled) old_fogcoord_glEnable(GL_FOG); 180 } else { 181 WARN_(d3d_perf)("Fog coords activated, but not supported. Using slow emulation\n"); 182 old_fogcoord_glDisable(GL_FOG); 183 } 184 } else { 185 if(pname == GL_FOG_START) { 186 ctx->fogstart = (float) param; 187 } else if(pname == GL_FOG_END) { 188 ctx->fogend = (float) param; 189 } 190 old_fogcoord_glFogi(pname, param); 191 } 192 } 193 194 static void (WINE_GLAPI *old_fogcoord_glFogiv) (GLenum pname, const GLint *param) = NULL; 195 static void WINE_GLAPI wine_glFogiv(GLenum pname, const GLint *param) { 196 struct wined3d_context *ctx = context_get_current(); 197 if(pname == GL_FOG_COORDINATE_SOURCE_EXT) { 198 ctx->gl_fog_source = *param; 199 if(*param == GL_FRAGMENT_DEPTH_EXT) { 200 if(ctx->fog_enabled) old_fogcoord_glEnable(GL_FOG); 201 } else { 202 WARN_(d3d_perf)("Fog coords activated, but not supported. Using slow emulation\n"); 203 old_fogcoord_glDisable(GL_FOG); 204 } 205 } else { 206 if(pname == GL_FOG_START) { 207 ctx->fogstart = (float) *param; 208 } else if(pname == GL_FOG_END) { 209 ctx->fogend = (float) *param; 210 } 211 old_fogcoord_glFogiv(pname, param); 212 } 213 } 214 215 static void (WINE_GLAPI *old_fogcoord_glFogf) (GLenum pname, GLfloat param) = NULL; 216 static void WINE_GLAPI wine_glFogf(GLenum pname, GLfloat param) { 217 struct wined3d_context *ctx = context_get_current(); 218 if(pname == GL_FOG_COORDINATE_SOURCE_EXT) { 219 ctx->gl_fog_source = (GLint) param; 220 if(param == GL_FRAGMENT_DEPTH_EXT) { 221 if(ctx->fog_enabled) old_fogcoord_glEnable(GL_FOG); 222 } else { 223 WARN_(d3d_perf)("Fog coords activated, but not supported. Using slow emulation\n"); 224 old_fogcoord_glDisable(GL_FOG); 225 } 226 } else { 227 if(pname == GL_FOG_START) { 228 ctx->fogstart = param; 229 } else if(pname == GL_FOG_END) { 230 ctx->fogend = param; 231 } 232 old_fogcoord_glFogf(pname, param); 233 } 234 } 235 236 static void (WINE_GLAPI *old_fogcoord_glFogfv) (GLenum pname, const GLfloat *param) = NULL; 237 static void WINE_GLAPI wine_glFogfv(GLenum pname, const GLfloat *param) { 238 struct wined3d_context *ctx = context_get_current(); 239 if(pname == GL_FOG_COORDINATE_SOURCE_EXT) { 240 ctx->gl_fog_source = (GLint) *param; 241 if(*param == GL_FRAGMENT_DEPTH_EXT) { 242 if(ctx->fog_enabled) old_fogcoord_glEnable(GL_FOG); 243 } else { 244 WARN_(d3d_perf)("Fog coords activated, but not supported. Using slow emulation\n"); 245 old_fogcoord_glDisable(GL_FOG); 246 } 247 } else { 248 if(pname == GL_FOG_COLOR) { 249 ctx->fogcolor[0] = param[0]; 250 ctx->fogcolor[1] = param[1]; 251 ctx->fogcolor[2] = param[2]; 252 ctx->fogcolor[3] = param[3]; 253 } else if(pname == GL_FOG_START) { 254 ctx->fogstart = *param; 255 } else if(pname == GL_FOG_END) { 256 ctx->fogend = *param; 257 } 258 old_fogcoord_glFogfv(pname, param); 259 } 260 } 261 262 static void (WINE_GLAPI *old_fogcoord_glVertex4f) (GLfloat x, GLfloat y, GLfloat z, GLfloat w) = NULL; 263 static void (WINE_GLAPI *old_fogcoord_glColor4f) (GLfloat r, GLfloat g, GLfloat b, GLfloat a) = NULL; 264 265 static void WINE_GLAPI wine_glVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) { 266 struct wined3d_context *ctx = context_get_current(); 267 268 /* This can be called from draw_test_quad() and at that point there is no 269 * wined3d_context current. */ 270 if (!ctx) 271 { 272 old_fogcoord_glVertex4f(x, y, z, w); 273 return; 274 } 275 if(ctx->gl_fog_source == GL_FOG_COORDINATE_EXT && ctx->fog_enabled) { 276 GLfloat c[4] = {ctx->color[0], ctx->color[1], ctx->color[2], ctx->color[3]}; 277 GLfloat i; 278 279 i = (ctx->fogend - ctx->fog_coord_value) / (ctx->fogend - ctx->fogstart); 280 c[0] = i * c[0] + (1.0f - i) * ctx->fogcolor[0]; 281 c[1] = i * c[1] + (1.0f - i) * ctx->fogcolor[1]; 282 c[2] = i * c[2] + (1.0f - i) * ctx->fogcolor[2]; 283 284 old_fogcoord_glColor4f(c[0], c[1], c[2], c[3]); 285 old_fogcoord_glVertex4f(x, y, z, w); 286 } else { 287 old_fogcoord_glVertex4f(x, y, z, w); 288 } 289 } 290 291 static void WINE_GLAPI wine_glVertex4fv(const GLfloat *pos) { 292 wine_glVertex4f(pos[0], pos[1], pos[2], pos[3]); 293 } 294 295 static void WINE_GLAPI wine_glVertex3f(GLfloat x, GLfloat y, GLfloat z) { 296 wine_glVertex4f(x, y, z, 1.0f); 297 } 298 299 static void WINE_GLAPI wine_glVertex3fv(const GLfloat *pos) { 300 wine_glVertex4f(pos[0], pos[1], pos[2], 1.0f); 301 } 302 303 static void WINE_GLAPI wine_glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { 304 struct wined3d_context *ctx = context_get_current(); 305 306 /* This can be called from draw_test_quad() and at that point there is no 307 * wined3d_context current. */ 308 if (!ctx) 309 { 310 old_fogcoord_glColor4f(r, g, b, a); 311 return; 312 } 313 ctx->color[0] = r; 314 ctx->color[1] = g; 315 ctx->color[2] = b; 316 ctx->color[3] = a; 317 old_fogcoord_glColor4f(r, g, b, a); 318 } 319 320 static void WINE_GLAPI wine_glColor4fv(const GLfloat *c) { 321 wine_glColor4f(c[0], c[1], c[2], c[3]); 322 } 323 324 static void WINE_GLAPI wine_glColor3f(GLfloat r, GLfloat g, GLfloat b) { 325 wine_glColor4f(r, g, b, 1.0f); 326 } 327 328 static void WINE_GLAPI wine_glColor3fv(const GLfloat *c) { 329 wine_glColor4f(c[0], c[1], c[2], 1.0f); 330 } 331 332 static void WINE_GLAPI wine_glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) { 333 wine_glColor4f(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); 334 } 335 336 /* In D3D the fog coord is a UBYTE, so there's no problem with using the single 337 * precision function 338 */ 339 static void WINE_GLAPI wine_glFogCoordfEXT(GLfloat f) { 340 struct wined3d_context *ctx = context_get_current(); 341 ctx->fog_coord_value = f; 342 } 343 static void WINE_GLAPI wine_glFogCoorddEXT(GLdouble f) { 344 wine_glFogCoordfEXT((GLfloat) f); 345 } 346 static void WINE_GLAPI wine_glFogCoordfvEXT(const GLfloat *f) { 347 wine_glFogCoordfEXT(*f); 348 } 349 static void WINE_GLAPI wine_glFogCoorddvEXT(const GLdouble *f) { 350 wine_glFogCoordfEXT((GLfloat) *f); 351 } 352 353 /* End GL_EXT_fog_coord emulation */ 354 355 void install_gl_compat_wrapper(struct wined3d_gl_info *gl_info, enum wined3d_gl_extension ext) 356 { 357 switch (ext) 358 { 359 case ARB_MULTITEXTURE: 360 if (gl_info->supported[ARB_MULTITEXTURE]) 361 return; 362 if (gl_info->gl_ops.ext.p_glActiveTexture == wine_glActiveTexture) 363 { 364 FIXME("ARB_multitexture emulation hooks already applied.\n"); 365 return; 366 } 367 TRACE("Applying GL_ARB_multitexture emulation hooks.\n"); 368 gl_info->gl_ops.ext.p_glActiveTexture = wine_glActiveTexture; 369 gl_info->gl_ops.ext.p_glClientActiveTextureARB = wine_glClientActiveTextureARB; 370 gl_info->gl_ops.ext.p_glMultiTexCoord1fARB = wine_glMultiTexCoord1fARB; 371 gl_info->gl_ops.ext.p_glMultiTexCoord1fvARB = wine_glMultiTexCoord1fvARB; 372 gl_info->gl_ops.ext.p_glMultiTexCoord2fARB = wine_glMultiTexCoord2fARB; 373 gl_info->gl_ops.ext.p_glMultiTexCoord2fvARB = wine_glMultiTexCoord2fvARB; 374 gl_info->gl_ops.ext.p_glMultiTexCoord3fARB = wine_glMultiTexCoord3fARB; 375 gl_info->gl_ops.ext.p_glMultiTexCoord3fvARB = wine_glMultiTexCoord3fvARB; 376 gl_info->gl_ops.ext.p_glMultiTexCoord4fARB = wine_glMultiTexCoord4fARB; 377 gl_info->gl_ops.ext.p_glMultiTexCoord4fvARB = wine_glMultiTexCoord4fvARB; 378 gl_info->gl_ops.ext.p_glMultiTexCoord2svARB = wine_glMultiTexCoord2svARB; 379 gl_info->gl_ops.ext.p_glMultiTexCoord4svARB = wine_glMultiTexCoord4svARB; 380 old_multitex_glGetIntegerv = gl_info->gl_ops.gl.p_glGetIntegerv; 381 gl_info->gl_ops.gl.p_glGetIntegerv = wine_glGetIntegerv; 382 old_multitex_glGetFloatv = gl_info->gl_ops.gl.p_glGetFloatv; 383 gl_info->gl_ops.gl.p_glGetFloatv = wine_glGetFloatv; 384 old_multitex_glGetDoublev = gl_info->gl_ops.gl.p_glGetDoublev; 385 gl_info->gl_ops.gl.p_glGetDoublev = wine_glGetDoublev; 386 gl_info->supported[ARB_MULTITEXTURE] = TRUE; 387 return; 388 389 case EXT_FOG_COORD: 390 /* This emulation isn't perfect. There are a number of potential problems, but they should 391 * not matter in practise: 392 * 393 * Fog vs fragment shader: If we are using GL_ARB_fragment_program with the fog option, the 394 * glDisable(GL_FOG) here won't matter. However, if we have GL_ARB_fragment_program, it is pretty 395 * unlikely that we don't have GL_EXT_fog_coord. Besides, we probably have GL_ARB_vertex_program 396 * too, which would allow fog coord emulation in a fixed function vertex pipeline replacement. 397 * 398 * Fog vs texture: We apply the fog in the vertex color. An app could set up texturing settings which 399 * ignore the vertex color, thus effectively disabling our fog. However, in D3D this type of fog is 400 * a per-vertex fog too, so the apps shouldn't do that. 401 * 402 * Fog vs lighting: The app could in theory use D3DFOG_NONE table and D3DFOG_NONE vertex fog with 403 * untransformed vertices. That enables lighting and fog coords at the same time, and the lighting 404 * calculations could affect the already blended in fog color. There's nothing we can do against that, 405 * but most apps using fog color do their own lighting too and often even use RHW vertices. So live 406 * with it. 407 */ 408 if (gl_info->supported[EXT_FOG_COORD]) 409 return; 410 if (gl_info->gl_ops.gl.p_glFogi == wine_glFogi) 411 { 412 FIXME("EXT_fog_coord emulation hooks already applied.\n"); 413 return; 414 } 415 TRACE("Applying GL_ARB_fog_coord emulation hooks\n"); 416 417 /* This probably means that the implementation doesn't advertise the extension, but implicitly supports 418 * it via the GL core version, or someone messed around in the extension table in directx.c. Add version- 419 * dependent loading for this extension if we ever hit this situation 420 */ 421 if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) 422 { 423 FIXME("GL implementation supports GL_ARB_fragment_program but not GL_EXT_fog_coord\n"); 424 FIXME("The fog coord emulation will most likely fail\n"); 425 } 426 else if (gl_info->supported[ARB_FRAGMENT_SHADER]) 427 { 428 FIXME("GL implementation supports GL_ARB_fragment_shader but not GL_EXT_fog_coord\n"); 429 FIXME("The fog coord emulation will most likely fail\n"); 430 } 431 432 old_fogcoord_glFogi = gl_info->gl_ops.gl.p_glFogi; 433 gl_info->gl_ops.gl.p_glFogi = wine_glFogi; 434 old_fogcoord_glFogiv = gl_info->gl_ops.gl.p_glFogiv; 435 gl_info->gl_ops.gl.p_glFogiv = wine_glFogiv; 436 old_fogcoord_glFogf = gl_info->gl_ops.gl.p_glFogf; 437 gl_info->gl_ops.gl.p_glFogf = wine_glFogf; 438 old_fogcoord_glFogfv = gl_info->gl_ops.gl.p_glFogfv; 439 gl_info->gl_ops.gl.p_glFogfv = wine_glFogfv; 440 old_fogcoord_glEnable = glEnableWINE; 441 glEnableWINE = wine_glEnable; 442 old_fogcoord_glDisable = glDisableWINE; 443 glDisableWINE = wine_glDisable; 444 445 old_fogcoord_glVertex4f = gl_info->gl_ops.gl.p_glVertex4f; 446 gl_info->gl_ops.gl.p_glVertex4f = wine_glVertex4f; 447 gl_info->gl_ops.gl.p_glVertex4fv = wine_glVertex4fv; 448 gl_info->gl_ops.gl.p_glVertex3f = wine_glVertex3f; 449 gl_info->gl_ops.gl.p_glVertex3fv = wine_glVertex3fv; 450 451 old_fogcoord_glColor4f = gl_info->gl_ops.gl.p_glColor4f; 452 gl_info->gl_ops.gl.p_glColor4f = wine_glColor4f; 453 gl_info->gl_ops.gl.p_glColor4fv = wine_glColor4fv; 454 gl_info->gl_ops.gl.p_glColor3f = wine_glColor3f; 455 gl_info->gl_ops.gl.p_glColor3fv = wine_glColor3fv; 456 gl_info->gl_ops.gl.p_glColor4ub = wine_glColor4ub; 457 458 gl_info->gl_ops.ext.p_glFogCoordfEXT = wine_glFogCoordfEXT; 459 gl_info->gl_ops.ext.p_glFogCoordfvEXT = wine_glFogCoordfvEXT; 460 gl_info->gl_ops.ext.p_glFogCoorddEXT = wine_glFogCoorddEXT; 461 gl_info->gl_ops.ext.p_glFogCoorddvEXT = wine_glFogCoorddvEXT; 462 gl_info->supported[EXT_FOG_COORD] = TRUE; 463 return; 464 465 default: 466 FIXME("Extension %u emulation not supported.\n", ext); 467 } 468 } 469