1 /* Direct3D Common functions
2 * Copyright (c) 1998 Lionel ULMER
4 * This file contains all MESA common code
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
29 #include "wine/debug.h"
31 #include "mesa_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
35 GLenum convert_D3D_compare_to_GL(D3DCMPFUNC dwRenderState)
37 switch (dwRenderState) {
38 case D3DCMP_NEVER: return GL_NEVER;
39 case D3DCMP_LESS: return GL_LESS;
40 case D3DCMP_EQUAL: return GL_EQUAL;
41 case D3DCMP_LESSEQUAL: return GL_LEQUAL;
42 case D3DCMP_GREATER: return GL_GREATER;
43 case D3DCMP_NOTEQUAL: return GL_NOTEQUAL;
44 case D3DCMP_GREATEREQUAL: return GL_GEQUAL;
45 case D3DCMP_ALWAYS: return GL_ALWAYS;
46 default: ERR("Unexpected compare type %d !\n", dwRenderState);
51 GLenum convert_D3D_stencilop_to_GL(D3DSTENCILOP dwRenderState)
53 switch (dwRenderState) {
54 case D3DSTENCILOP_KEEP: return GL_KEEP;
55 case D3DSTENCILOP_ZERO: return GL_ZERO;
56 case D3DSTENCILOP_REPLACE: return GL_REPLACE;
57 case D3DSTENCILOP_INCRSAT: return GL_INCR;
58 case D3DSTENCILOP_DECRSAT: return GL_DECR;
59 case D3DSTENCILOP_INVERT: return GL_INVERT;
60 case D3DSTENCILOP_INCR: WARN("D3DSTENCILOP_INCR not properly handled !\n"); return GL_INCR;
61 case D3DSTENCILOP_DECR: WARN("D3DSTENCILOP_DECR not properly handled !\n"); return GL_DECR;
62 default: ERR("Unexpected compare type %d !\n", dwRenderState);
67 GLenum convert_D3D_blendop_to_GL(D3DBLEND dwRenderState)
69 switch ((D3DBLEND) dwRenderState) {
70 case D3DBLEND_ZERO: return GL_ZERO;
71 case D3DBLEND_ONE: return GL_ONE;
72 case D3DBLEND_SRCALPHA: return GL_SRC_ALPHA;
73 case D3DBLEND_INVSRCALPHA: return GL_ONE_MINUS_SRC_ALPHA;
74 case D3DBLEND_DESTALPHA: return GL_DST_ALPHA;
75 case D3DBLEND_INVDESTALPHA: return GL_ONE_MINUS_DST_ALPHA;
76 case D3DBLEND_DESTCOLOR: return GL_DST_COLOR;
77 case D3DBLEND_INVDESTCOLOR: return GL_ONE_MINUS_DST_COLOR;
78 case D3DBLEND_SRCALPHASAT: return GL_SRC_ALPHA_SATURATE;
79 case D3DBLEND_SRCCOLOR: return GL_SRC_COLOR;
80 case D3DBLEND_INVSRCCOLOR: return GL_ONE_MINUS_SRC_COLOR;
81 default: ERR("Unhandled blend mode %d !\n", dwRenderState); return GL_ZERO;
85 void set_render_state(IDirect3DDeviceImpl* This,
86 D3DRENDERSTATETYPE dwRenderStateType, STATEBLOCK *lpStateBlock)
88 DWORD dwRenderState = lpStateBlock->render_state[dwRenderStateType - 1];
89 IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
91 TRACE("%s = %08lx\n", _get_renderstate(dwRenderStateType), dwRenderState);
93 /* First, all the stipple patterns */
94 if ((dwRenderStateType >= D3DRENDERSTATE_STIPPLEPATTERN00) &&
95 (dwRenderStateType <= D3DRENDERSTATE_STIPPLEPATTERN31)) {
96 ERR("Unhandled dwRenderStateType stipple %d!\n",dwRenderStateType);
100 /* All others state variables */
101 switch (dwRenderStateType) {
102 case D3DRENDERSTATE_TEXTUREHANDLE: { /* 1 */
103 IDirectDrawSurfaceImpl *tex = (IDirectDrawSurfaceImpl*) dwRenderState;
105 IDirect3DDevice7_SetTexture(ICOM_INTERFACE(This, IDirect3DDevice7),
107 ICOM_INTERFACE(tex, IDirectDrawSurface7));
110 case D3DRENDERSTATE_TEXTUREADDRESSU: /* 44 */
111 case D3DRENDERSTATE_TEXTUREADDRESSV: /* 45 */
112 case D3DRENDERSTATE_TEXTUREADDRESS: { /* 3 */
113 D3DTEXTURESTAGESTATETYPE d3dTexStageStateType;
115 if (dwRenderStateType == D3DRENDERSTATE_TEXTUREADDRESS) d3dTexStageStateType = D3DTSS_ADDRESS;
116 else if (dwRenderStateType == D3DRENDERSTATE_TEXTUREADDRESSU) d3dTexStageStateType = D3DTSS_ADDRESSU;
117 else d3dTexStageStateType = D3DTSS_ADDRESSV;
119 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
120 0, d3dTexStageStateType,
124 case D3DRENDERSTATE_TEXTUREPERSPECTIVE: /* 4 */
126 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
128 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
131 case D3DRENDERSTATE_WRAPU: /* 5 */
132 case D3DRENDERSTATE_WRAPV: /* 6 */
133 case D3DRENDERSTATE_WRAP0: /* 128 */
134 case D3DRENDERSTATE_WRAP1: /* 129 */
135 case D3DRENDERSTATE_WRAP2: /* 130 */
136 case D3DRENDERSTATE_WRAP3: /* 131 */
137 case D3DRENDERSTATE_WRAP4: /* 132 */
138 case D3DRENDERSTATE_WRAP5: /* 133 */
139 case D3DRENDERSTATE_WRAP6: /* 134 */
140 case D3DRENDERSTATE_WRAP7: /* 135 */
142 ERR("Texture WRAP modes unsupported by OpenGL.. Expect graphical glitches !\n");
145 case D3DRENDERSTATE_ZENABLE: /* 7 */
146 /* To investigate : in OpenGL, if we disable the depth test, the Z buffer will NOT be
147 updated either.. No idea about what happens in D3D.
149 Maybe replacing the Z function by ALWAYS would be a better idea. */
150 if (dwRenderState == D3DZB_TRUE)
151 glEnable(GL_DEPTH_TEST);
152 else if (dwRenderState == D3DZB_FALSE)
153 glDisable(GL_DEPTH_TEST);
155 glEnable(GL_DEPTH_TEST);
156 WARN(" w-buffering not supported.\n");
160 case D3DRENDERSTATE_FILLMODE: /* 8 */
161 switch ((D3DFILLMODE) dwRenderState) {
163 glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);
165 case D3DFILL_WIREFRAME:
166 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
169 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
172 ERR("Unhandled fill mode %ld !\n",dwRenderState);
176 case D3DRENDERSTATE_SHADEMODE: /* 9 */
177 switch ((D3DSHADEMODE) dwRenderState) {
179 glShadeModel(GL_FLAT);
181 case D3DSHADE_GOURAUD:
182 glShadeModel(GL_SMOOTH);
185 ERR("Unhandled shade mode %ld !\n",dwRenderState);
189 case D3DRENDERSTATE_ZWRITEENABLE: /* 14 */
191 glDepthMask(GL_TRUE);
193 glDepthMask(GL_FALSE);
196 case D3DRENDERSTATE_ALPHATESTENABLE: /* 15 */
198 glEnable(GL_ALPHA_TEST);
200 glDisable(GL_ALPHA_TEST);
203 case D3DRENDERSTATE_TEXTUREMAG: { /* 17 */
204 DWORD tex_mag = 0xFFFFFFFF;
206 switch ((D3DTEXTUREFILTER) dwRenderState) {
207 case D3DFILTER_NEAREST:
208 tex_mag = D3DTFG_POINT;
210 case D3DFILTER_LINEAR:
211 tex_mag = D3DTFG_LINEAR;
214 ERR("Unhandled texture mag %ld !\n",dwRenderState);
217 if (tex_mag != 0xFFFFFFFF) {
218 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7), 0, D3DTSS_MAGFILTER, tex_mag);
222 case D3DRENDERSTATE_TEXTUREMIN: { /* 18 */
223 DWORD tex_min = 0xFFFFFFFF;
225 switch ((D3DTEXTUREFILTER) dwRenderState) {
226 case D3DFILTER_NEAREST:
227 tex_min = D3DTFN_POINT;
229 case D3DFILTER_LINEAR:
230 tex_min = D3DTFN_LINEAR;
233 ERR("Unhandled texture min %ld !\n",dwRenderState);
236 if (tex_min != 0xFFFFFFFF) {
237 IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7), 0, D3DTSS_MINFILTER, tex_min);
241 case D3DRENDERSTATE_SRCBLEND: /* 19 */
242 case D3DRENDERSTATE_DESTBLEND: /* 20 */
243 glBlendFunc(convert_D3D_blendop_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_SRCBLEND - 1]),
244 convert_D3D_blendop_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_DESTBLEND - 1]));
247 case D3DRENDERSTATE_TEXTUREMAPBLEND: { /* 21 */
248 IDirect3DDevice7 *d3ddev = ICOM_INTERFACE(This, IDirect3DDevice7);
250 switch ((D3DTEXTUREBLEND) dwRenderState) {
251 case D3DTBLEND_DECAL:
252 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
254 case D3DTBLEND_DECALALPHA:
255 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
257 case D3DTBLEND_MODULATE:
258 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
260 case D3DTBLEND_MODULATEALPHA:
261 IDirect3DDevice7_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
262 IDirect3DDevice7_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
263 IDirect3DDevice7_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG2, D3DTA_CURRENT);
264 IDirect3DDevice7_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
265 IDirect3DDevice7_SetTextureStageState(d3ddev, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
266 IDirect3DDevice7_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
269 ERR("Unhandled texture environment %ld !\n",dwRenderState);
273 case D3DRENDERSTATE_CULLMODE: /* 22 */
274 switch ((D3DCULL) dwRenderState) {
276 glDisable(GL_CULL_FACE);
279 glEnable(GL_CULL_FACE);
284 glEnable(GL_CULL_FACE);
289 ERR("Unhandled cull mode %ld !\n",dwRenderState);
293 case D3DRENDERSTATE_ZFUNC: /* 23 */
294 glDepthFunc(convert_D3D_compare_to_GL(dwRenderState));
297 case D3DRENDERSTATE_ALPHAREF: /* 24 */
298 case D3DRENDERSTATE_ALPHAFUNC: /* 25 */
299 glAlphaFunc(convert_D3D_compare_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_ALPHAFUNC - 1]),
300 (lpStateBlock->render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) / 255.0);
303 case D3DRENDERSTATE_DITHERENABLE: /* 26 */
307 glDisable(GL_DITHER);
310 case D3DRENDERSTATE_ALPHABLENDENABLE: /* 27 */
318 case D3DRENDERSTATE_FOGENABLE: /* 28 */
319 /* Nothing to do here. Only the storage matters :-) */
322 case D3DRENDERSTATE_SPECULARENABLE: /* 29 */
324 ERR(" Specular Lighting not supported yet.\n");
327 case D3DRENDERSTATE_SUBPIXEL: /* 31 */
328 case D3DRENDERSTATE_SUBPIXELX: /* 32 */
329 /* We do not support this anyway, so why protest :-) */
332 case D3DRENDERSTATE_STIPPLEDALPHA: /* 33 */
334 ERR(" Stippled Alpha not supported yet.\n");
337 case D3DRENDERSTATE_FOGCOLOR: { /* 34 */
339 color[0] = ((dwRenderState >> 16) & 0xFF)/255.0f;
340 color[1] = ((dwRenderState >> 8) & 0xFF)/255.0f;
341 color[2] = ((dwRenderState >> 0) & 0xFF)/255.0f;
342 color[3] = ((dwRenderState >> 24) & 0xFF)/255.0f;
343 glFogfv(GL_FOG_COLOR,color);
344 /* Note: glFogiv does not seem to work */
347 case D3DRENDERSTATE_FOGTABLEMODE: /* 35 */
348 case D3DRENDERSTATE_FOGVERTEXMODE: /* 140 */
349 case D3DRENDERSTATE_FOGSTART: /* 36 */
350 case D3DRENDERSTATE_FOGEND: /* 37 */
351 /* Nothing to do here. Only the storage matters :-) */
354 case D3DRENDERSTATE_FOGDENSITY: /* 38 */
355 glFogi(GL_FOG_DENSITY,*(float*)&dwRenderState);
358 case D3DRENDERSTATE_COLORKEYENABLE: /* 41 */
359 /* This needs to be fixed. */
366 case D3DRENDERSTATE_ZBIAS: /* 47 */
367 /* This is a tad bit hacky.. But well, no idea how to do it better in OpenGL :-/ */
368 if (dwRenderState == 0) {
369 glDisable(GL_POLYGON_OFFSET_FILL);
370 glDisable(GL_POLYGON_OFFSET_LINE);
371 glDisable(GL_POLYGON_OFFSET_POINT);
373 glEnable(GL_POLYGON_OFFSET_FILL);
374 glEnable(GL_POLYGON_OFFSET_LINE);
375 glEnable(GL_POLYGON_OFFSET_POINT);
376 glPolygonOffset(1.0, dwRenderState * 1.0);
380 case D3DRENDERSTATE_FLUSHBATCH: /* 50 */
383 case D3DRENDERSTATE_STENCILENABLE: /* 52 */
385 glEnable(GL_STENCIL_TEST);
387 glDisable(GL_STENCIL_TEST);
390 case D3DRENDERSTATE_STENCILFAIL: /* 53 */
391 case D3DRENDERSTATE_STENCILZFAIL: /* 54 */
392 case D3DRENDERSTATE_STENCILPASS: /* 55 */
393 glStencilOp(convert_D3D_stencilop_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_STENCILFAIL - 1]),
394 convert_D3D_stencilop_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_STENCILZFAIL - 1]),
395 convert_D3D_stencilop_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_STENCILPASS - 1]));
398 case D3DRENDERSTATE_STENCILFUNC: /* 56 */
399 case D3DRENDERSTATE_STENCILREF: /* 57 */
400 case D3DRENDERSTATE_STENCILMASK: /* 58 */
401 glStencilFunc(convert_D3D_compare_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_STENCILFUNC - 1]),
402 lpStateBlock->render_state[D3DRENDERSTATE_STENCILREF - 1],
403 lpStateBlock->render_state[D3DRENDERSTATE_STENCILMASK - 1]);
406 case D3DRENDERSTATE_STENCILWRITEMASK: /* 59 */
407 glStencilMask(dwRenderState);
410 case D3DRENDERSTATE_TEXTUREFACTOR: /* 60 */
411 /* Only the storage matters... */
414 case D3DRENDERSTATE_CLIPPING: /* 136 */
415 case D3DRENDERSTATE_CLIPPLANEENABLE: { /* 152 */
419 if (dwRenderStateType == D3DRENDERSTATE_CLIPPING) {
420 mask = ((dwRenderState) ?
421 (This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) : (0x00000000));
423 mask = dwRenderState;
425 for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner = (runner << 1)) {
428 glGetIntegerv(GL_CLIP_PLANE0 + i, &enabled);
429 if (enabled == GL_FALSE) {
430 glEnable(GL_CLIP_PLANE0 + i);
431 /* Need to force a transform change so that this clipping plane parameters are sent
434 glThis->transform_state = GL_TRANSFORM_NONE;
437 glDisable(GL_CLIP_PLANE0 + i);
443 case D3DRENDERSTATE_LIGHTING: /* 137 */
445 glEnable(GL_LIGHTING);
447 glDisable(GL_LIGHTING);
450 case D3DRENDERSTATE_AMBIENT: { /* 139 */
453 light[0] = ((dwRenderState >> 16) & 0xFF) / 255.0;
454 light[1] = ((dwRenderState >> 8) & 0xFF) / 255.0;
455 light[2] = ((dwRenderState >> 0) & 0xFF) / 255.0;
456 light[3] = ((dwRenderState >> 24) & 0xFF) / 255.0;
457 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
460 case D3DRENDERSTATE_COLORVERTEX: /* 141 */
461 /* Nothing to do here.. Only storage matters */
464 case D3DRENDERSTATE_LOCALVIEWER: /* 142 */
466 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
468 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
471 case D3DRENDERSTATE_NORMALIZENORMALS: /* 143 */
473 glEnable(GL_NORMALIZE);
474 glEnable(GL_RESCALE_NORMAL);
476 glDisable(GL_NORMALIZE);
477 glDisable(GL_RESCALE_NORMAL);
481 case D3DRENDERSTATE_DIFFUSEMATERIALSOURCE: /* 145 */
482 case D3DRENDERSTATE_SPECULARMATERIALSOURCE: /* 146 */
483 case D3DRENDERSTATE_AMBIENTMATERIALSOURCE: /* 147 */
484 case D3DRENDERSTATE_EMISSIVEMATERIALSOURCE: /* 148 */
485 /* Nothing to do here. Only the storage matters :-) */
489 ERR("Unhandled dwRenderStateType %s (%08x) value : %08lx !\n",
490 _get_renderstate(dwRenderStateType), dwRenderStateType, dwRenderState);
496 void store_render_state(IDirect3DDeviceImpl *This,
497 D3DRENDERSTATETYPE dwRenderStateType, DWORD dwRenderState, STATEBLOCK *lpStateBlock)
499 TRACE("%s = %08lx\n", _get_renderstate(dwRenderStateType), dwRenderState);
501 /* Some special cases first.. */
502 if (dwRenderStateType == D3DRENDERSTATE_SRCBLEND) {
503 if (dwRenderState == D3DBLEND_BOTHSRCALPHA) {
504 lpStateBlock->render_state[D3DRENDERSTATE_SRCBLEND - 1] = D3DBLEND_SRCALPHA;
505 lpStateBlock->render_state[D3DRENDERSTATE_DESTBLEND - 1] = D3DBLEND_SRCALPHA;
507 } else if (dwRenderState == D3DBLEND_BOTHINVSRCALPHA) {
508 lpStateBlock->render_state[D3DRENDERSTATE_SRCBLEND - 1] = D3DBLEND_INVSRCALPHA;
509 lpStateBlock->render_state[D3DRENDERSTATE_DESTBLEND - 1] = D3DBLEND_INVSRCALPHA;
512 } else if (dwRenderStateType == D3DRENDERSTATE_TEXTUREADDRESS) {
513 lpStateBlock->render_state[D3DRENDERSTATE_TEXTUREADDRESSU - 1] = dwRenderState;
514 lpStateBlock->render_state[D3DRENDERSTATE_TEXTUREADDRESSV - 1] = dwRenderState;
515 } else if (dwRenderStateType == D3DRENDERSTATE_WRAPU) {
517 lpStateBlock->render_state[D3DRENDERSTATE_WRAP0] |= D3DWRAP_U;
519 lpStateBlock->render_state[D3DRENDERSTATE_WRAP0] &= ~D3DWRAP_U;
520 } else if (dwRenderStateType == D3DRENDERSTATE_WRAPV) {
522 lpStateBlock->render_state[D3DRENDERSTATE_WRAP0] |= D3DWRAP_V;
524 lpStateBlock->render_state[D3DRENDERSTATE_WRAP0] &= ~D3DWRAP_V;
528 lpStateBlock->render_state[dwRenderStateType - 1] = dwRenderState;
531 void get_render_state(IDirect3DDeviceImpl *This,
532 D3DRENDERSTATETYPE dwRenderStateType, LPDWORD lpdwRenderState, STATEBLOCK *lpStateBlock)
534 *lpdwRenderState = lpStateBlock->render_state[dwRenderStateType - 1];
536 TRACE("%s = %08lx\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
539 void apply_render_state(IDirect3DDeviceImpl *This, STATEBLOCK *lpStateBlock)
542 TRACE("(%p,%p)\n", This, lpStateBlock);
543 for(i = 0; i < HIGHEST_RENDER_STATE; i++)
544 if (lpStateBlock->set_flags.render_state[i])
545 set_render_state(This, i + 1, lpStateBlock);
549 /* Texture management code.
551 - upload_surface_to_tex_memory_init initialize the code and computes the GL formats
552 according to the surface description.
554 - upload_surface_to_tex_memory does the real upload. If one buffer is split over
555 multiple textures, this can be called multiple times after the '_init' call. 'rect'
556 can be NULL if the whole buffer needs to be upload.
558 - upload_surface_to_tex_memory_release does the clean-up.
560 These functions are called in the following cases :
561 - texture management (ie to upload a D3D texture to GL when it changes).
562 - flush of the 'in-memory' frame buffer to the GL frame buffer using the texture
564 - use of the texture engine to simulate Blits to the 3D Device.
572 CONVERT_CK_4444_ARGB,
577 CONVERT_CK_8888_ARGB,
581 /* Note : we suppose that all the code calling this is protected by the GL lock... Otherwise bad things
583 static GLenum current_format;
584 static GLenum current_pixel_format;
585 static CONVERT_TYPES convert_type;
586 static IDirectDrawSurfaceImpl *current_surface;
587 static GLuint current_level;
588 static DWORD current_tex_width;
589 static DWORD current_tex_height;
591 HRESULT upload_surface_to_tex_memory_init(IDirectDrawSurfaceImpl *surf_ptr, GLuint level, GLenum *current_internal_format,
592 BOOLEAN need_to_alloc, BOOLEAN need_alpha_ck, DWORD tex_width, DWORD tex_height)
594 const DDPIXELFORMAT * const src_pf = &(surf_ptr->surface_desc.u4.ddpfPixelFormat);
596 BOOL colorkey_active = need_alpha_ck && (surf_ptr->surface_desc.dwFlags & DDSD_CKSRCBLT);
597 GLenum internal_format = GL_LUMINANCE; /* A bogus value to be sure to have a nice Mesa warning :-) */
598 BYTE bpp = GET_BPP(surf_ptr->surface_desc);
599 BOOL sub_texture = TRUE;
601 current_surface = surf_ptr;
602 current_level = level;
604 /* First, do some sanity checks ... */
605 if ((surf_ptr->surface_desc.u1.lPitch % bpp) != 0) {
606 FIXME("Warning : pitch is not a multiple of BPP - not supported yet !\n");
609 /* Note: we only check width here as you cannot have width non-zero while height is set to zero */
610 if (tex_width == 0) {
613 tex_width = surf_ptr->surface_desc.dwWidth;
614 tex_height = surf_ptr->surface_desc.dwHeight;
617 current_tex_width = tex_width;
618 current_tex_height = tex_height;
620 if (src_pf->dwFlags & DDPF_PALETTEINDEXED8) {
624 current_format = GL_RGBA;
625 internal_format = GL_RGBA;
626 current_pixel_format = GL_UNSIGNED_BYTE;
627 convert_type = CONVERT_PALETTED;
628 } else if (src_pf->dwFlags & DDPF_RGB) {
632 if (src_pf->u1.dwRGBBitCount == 8) {
633 if ((src_pf->dwFlags & DDPF_ALPHAPIXELS) &&
634 (src_pf->u5.dwRGBAlphaBitMask != 0x00)) {
637 if ((src_pf->u2.dwRBitMask == 0xE0) &&
638 (src_pf->u3.dwGBitMask == 0x1C) &&
639 (src_pf->u4.dwBBitMask == 0x03)) {
640 /* **********************
641 GL_UNSIGNED_BYTE_3_3_2
642 ********************** */
643 if (colorkey_active) {
644 /* This texture format will never be used.. So do not care about color keying
645 up until the point in time it will be needed :-) */
646 FIXME(" ColorKeying not supported in the RGB 332 format !");
648 current_format = GL_RGB;
649 internal_format = GL_RGB;
650 current_pixel_format = GL_UNSIGNED_BYTE_3_3_2;
651 convert_type = NO_CONVERSION;
656 } else if (src_pf->u1.dwRGBBitCount == 16) {
657 if ((src_pf->dwFlags & DDPF_ALPHAPIXELS) &&
658 (src_pf->u5.dwRGBAlphaBitMask != 0x0000)) {
659 if ((src_pf->u2.dwRBitMask == 0xF800) &&
660 (src_pf->u3.dwGBitMask == 0x07C0) &&
661 (src_pf->u4.dwBBitMask == 0x003E) &&
662 (src_pf->u5.dwRGBAlphaBitMask == 0x0001)) {
663 current_format = GL_RGBA;
664 internal_format = GL_RGBA;
665 current_pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
666 if (colorkey_active) {
667 convert_type = CONVERT_CK_5551;
669 convert_type = NO_CONVERSION;
671 } else if ((src_pf->u2.dwRBitMask == 0xF000) &&
672 (src_pf->u3.dwGBitMask == 0x0F00) &&
673 (src_pf->u4.dwBBitMask == 0x00F0) &&
674 (src_pf->u5.dwRGBAlphaBitMask == 0x000F)) {
675 current_format = GL_RGBA;
676 internal_format = GL_RGBA;
677 current_pixel_format = GL_UNSIGNED_SHORT_4_4_4_4;
678 if (colorkey_active) {
679 convert_type = CONVERT_CK_4444;
681 convert_type = NO_CONVERSION;
683 } else if ((src_pf->u2.dwRBitMask == 0x0F00) &&
684 (src_pf->u3.dwGBitMask == 0x00F0) &&
685 (src_pf->u4.dwBBitMask == 0x000F) &&
686 (src_pf->u5.dwRGBAlphaBitMask == 0xF000)) {
687 if (colorkey_active) {
688 convert_type = CONVERT_CK_4444_ARGB;
689 current_format = GL_RGBA;
690 internal_format = GL_RGBA;
691 current_pixel_format = GL_UNSIGNED_SHORT_4_4_4_4;
693 convert_type = NO_CONVERSION;
694 current_format = GL_BGRA;
695 internal_format = GL_RGBA;
696 current_pixel_format = GL_UNSIGNED_SHORT_4_4_4_4_REV;
698 } else if ((src_pf->u2.dwRBitMask == 0x7C00) &&
699 (src_pf->u3.dwGBitMask == 0x03E0) &&
700 (src_pf->u4.dwBBitMask == 0x001F) &&
701 (src_pf->u5.dwRGBAlphaBitMask == 0x8000)) {
702 if (colorkey_active) {
703 convert_type = CONVERT_CK_1555;
704 current_format = GL_RGBA;
705 internal_format = GL_RGBA;
706 current_pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
708 convert_type = NO_CONVERSION;
709 current_format = GL_BGRA;
710 internal_format = GL_RGBA;
711 current_pixel_format = GL_UNSIGNED_SHORT_1_5_5_5_REV;
717 if ((src_pf->u2.dwRBitMask == 0xF800) &&
718 (src_pf->u3.dwGBitMask == 0x07E0) &&
719 (src_pf->u4.dwBBitMask == 0x001F)) {
720 if (colorkey_active) {
721 convert_type = CONVERT_CK_565;
722 current_format = GL_RGBA;
723 internal_format = GL_RGBA;
724 current_pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
726 convert_type = NO_CONVERSION;
727 current_format = GL_RGB;
728 internal_format = GL_RGB;
729 current_pixel_format = GL_UNSIGNED_SHORT_5_6_5;
731 } else if ((src_pf->u2.dwRBitMask == 0x7C00) &&
732 (src_pf->u3.dwGBitMask == 0x03E0) &&
733 (src_pf->u4.dwBBitMask == 0x001F)) {
734 convert_type = CONVERT_555;
735 current_format = GL_RGBA;
736 internal_format = GL_RGBA;
737 current_pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
742 } else if (src_pf->u1.dwRGBBitCount == 24) {
743 if ((src_pf->dwFlags & DDPF_ALPHAPIXELS) &&
744 (src_pf->u5.dwRGBAlphaBitMask != 0x000000)) {
747 if ((src_pf->u2.dwRBitMask == 0xFF0000) &&
748 (src_pf->u3.dwGBitMask == 0x00FF00) &&
749 (src_pf->u4.dwBBitMask == 0x0000FF)) {
750 if (colorkey_active) {
751 convert_type = CONVERT_CK_RGB24;
752 current_format = GL_RGBA;
753 internal_format = GL_RGBA;
754 current_pixel_format = GL_UNSIGNED_INT_8_8_8_8;
756 convert_type = NO_CONVERSION;
757 current_format = GL_BGR;
758 internal_format = GL_RGB;
759 current_pixel_format = GL_UNSIGNED_BYTE;
765 } else if (src_pf->u1.dwRGBBitCount == 32) {
766 if ((src_pf->dwFlags & DDPF_ALPHAPIXELS) &&
767 (src_pf->u5.dwRGBAlphaBitMask != 0x00000000)) {
768 if ((src_pf->u2.dwRBitMask == 0xFF000000) &&
769 (src_pf->u3.dwGBitMask == 0x00FF0000) &&
770 (src_pf->u4.dwBBitMask == 0x0000FF00) &&
771 (src_pf->u5.dwRGBAlphaBitMask == 0x000000FF)) {
772 if (colorkey_active) {
773 convert_type = CONVERT_CK_8888;
775 convert_type = NO_CONVERSION;
777 current_format = GL_RGBA;
778 internal_format = GL_RGBA;
779 current_pixel_format = GL_UNSIGNED_INT_8_8_8_8;
780 } else if ((src_pf->u2.dwRBitMask == 0x00FF0000) &&
781 (src_pf->u3.dwGBitMask == 0x0000FF00) &&
782 (src_pf->u4.dwBBitMask == 0x000000FF) &&
783 (src_pf->u5.dwRGBAlphaBitMask == 0xFF000000)) {
784 if (colorkey_active) {
785 convert_type = CONVERT_CK_8888_ARGB;
786 current_format = GL_RGBA;
787 internal_format = GL_RGBA;
788 current_pixel_format = GL_UNSIGNED_INT_8_8_8_8;
790 convert_type = NO_CONVERSION;
791 current_format = GL_BGRA;
792 internal_format = GL_RGBA;
793 current_pixel_format = GL_UNSIGNED_INT_8_8_8_8_REV;
799 if ((src_pf->u2.dwRBitMask == 0x00FF0000) &&
800 (src_pf->u3.dwGBitMask == 0x0000FF00) &&
801 (src_pf->u4.dwBBitMask == 0x000000FF)) {
802 if (need_alpha_ck == TRUE) {
803 convert_type = CONVERT_RGB32_888;
804 current_format = GL_RGBA;
805 internal_format = GL_RGBA;
806 current_pixel_format = GL_UNSIGNED_INT_8_8_8_8;
808 convert_type = NO_CONVERSION;
809 current_format = GL_BGRA;
810 internal_format = GL_RGBA;
811 current_pixel_format = GL_UNSIGNED_INT_8_8_8_8_REV;
825 ERR("Unsupported pixel format for textures : \n");
827 DDRAW_dump_pixelformat(src_pf);
829 return DDERR_INVALIDPIXELFORMAT;
831 if ((need_to_alloc) ||
832 (internal_format != *current_internal_format)) {
833 glTexImage2D(GL_TEXTURE_2D, level, internal_format,
834 tex_width, tex_height, 0,
835 current_format, current_pixel_format, NULL);
836 *current_internal_format = internal_format;
840 if ((sub_texture == TRUE) && (convert_type == NO_CONVERSION)) {
841 glPixelStorei(GL_UNPACK_ROW_LENGTH, surf_ptr->surface_desc.u1.lPitch / bpp);
843 if (surf_ptr->surface_desc.u1.lPitch == (surf_ptr->surface_desc.dwWidth * bpp)) {
844 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
846 glPixelStorei(GL_UNPACK_ROW_LENGTH, surf_ptr->surface_desc.u1.lPitch / bpp);
854 HRESULT upload_surface_to_tex_memory(RECT *rect, DWORD xoffset, DWORD yoffset, void **temp_buffer)
856 const DDSURFACEDESC * const src_d = (DDSURFACEDESC *)&(current_surface->surface_desc);
857 void *surf_buffer = NULL;
860 BYTE bpp = GET_BPP(current_surface->surface_desc);
866 lrect.bottom = current_tex_height;
867 lrect.right = current_tex_width;
871 width = rect->right - rect->left;
872 height = rect->bottom - rect->top;
874 /* Used when converting stuff */
875 line_increase = src_d->dwWidth - width;
877 switch (convert_type) {
878 case CONVERT_PALETTED: {
879 IDirectDrawPaletteImpl* pal = current_surface->palette;
883 BYTE *src = (BYTE *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
886 /* Upload a black texture. The real one will be uploaded on palette change */
887 WARN("Palettized texture Loading with a NULL palette !\n");
888 memset(table, 0, 256 * 4);
890 /* Get the surface's palette */
891 for (i = 0; i < 256; i++) {
892 table[i][0] = pal->palents[i].peRed;
893 table[i][1] = pal->palents[i].peGreen;
894 table[i][2] = pal->palents[i].peBlue;
895 if ((src_d->dwFlags & DDSD_CKSRCBLT) &&
896 (i >= src_d->ddckCKSrcBlt.dwColorSpaceLowValue) &&
897 (i <= src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
898 /* We should maybe here put a more 'neutral' color than the standard bright purple
899 one often used by application to prevent the nice purple borders when bi-linear
907 if (*temp_buffer == NULL)
908 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
909 current_tex_width * current_tex_height * sizeof(DWORD));
910 dst = (BYTE *) *temp_buffer;
912 for (y = 0; y < height; y++) {
913 for (x = 0; x < width; x++) {
915 *dst++ = table[color][0];
916 *dst++ = table[color][1];
917 *dst++ = table[color][2];
918 *dst++ = table[color][3];
920 src += line_increase;
924 case CONVERT_CK_565: {
925 /* Converting the 565 format in 5551 packed to emulate color-keying.
927 Note : in all these conversion, it would be best to average the averaging
928 pixels to get the color of the pixel that will be color-keyed to
929 prevent 'color bleeding'. This will be done later on if ever it is
932 Note2: when using color-keying + alpha, are the alpha bits part of the
936 WORD *src = (WORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
938 if (*temp_buffer == NULL)
939 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
940 current_tex_width * current_tex_height * sizeof(WORD));
941 dst = (WORD *) *temp_buffer;
943 for (y = 0; y < height; y++) {
944 for (x = 0; x < width; x++) {
946 *dst = ((color & 0xFFC0) | ((color & 0x1F) << 1));
947 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
948 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
952 src += line_increase;
956 case CONVERT_CK_5551: {
957 /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
959 WORD *src = (WORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
961 if (*temp_buffer == NULL)
962 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
963 current_tex_width * current_tex_height * sizeof(WORD));
964 dst = (WORD *) *temp_buffer;
966 for (y = 0; y < height; y++) {
967 for (x = 0; x < width; x++) {
969 *dst = color & 0xFFFE;
970 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
971 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
972 *dst |= color & 0x0001;
975 src += line_increase;
979 case CONVERT_CK_4444: {
980 /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
982 WORD *src = (WORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
984 if (*temp_buffer == NULL)
985 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
986 current_tex_width * current_tex_height * sizeof(WORD));
987 dst = (WORD *) *temp_buffer;
989 for (y = 0; y < height; y++) {
990 for (x = 0; x < width; x++) {
992 *dst = color & 0xFFF0;
993 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
994 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
995 *dst |= color & 0x000F;
998 src += line_increase;
1002 case CONVERT_CK_4444_ARGB: {
1003 /* Move the four Alpha bits... */
1005 WORD *src = (WORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
1007 if (*temp_buffer == NULL)
1008 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1009 current_tex_width * current_tex_height * sizeof(WORD));
1010 dst = (WORD *) *temp_buffer;
1012 for (y = 0; y < height; y++) {
1013 for (x = 0; x < width; x++) {
1014 WORD color = *src++;
1015 *dst = (color & 0x0FFF) << 4;
1016 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1017 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1018 *dst |= (color & 0xF000) >> 12;
1021 src += line_increase;
1025 case CONVERT_CK_1555: {
1027 WORD *src = (WORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
1029 if (*temp_buffer == NULL)
1030 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1031 current_tex_width * current_tex_height * sizeof(WORD));
1032 dst = (WORD *) *temp_buffer;
1034 for (y = 0; y < height; y++) {
1035 for (x = 0; x < width; x++) {
1036 WORD color = *src++;
1037 *dst = (color & 0x7FFF) << 1;
1038 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1039 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1040 *dst |= (color & 0x8000) >> 15;
1043 src += line_increase;
1048 /* Converting the 0555 format in 5551 packed */
1050 WORD *src = (WORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
1052 if (*temp_buffer == NULL)
1053 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1054 current_tex_width * current_tex_height * sizeof(WORD));
1055 dst = (WORD *) *temp_buffer;
1057 if (src_d->dwFlags & DDSD_CKSRCBLT) {
1058 for (y = 0; y < height; y++) {
1059 for (x = 0; x < width; x++) {
1060 WORD color = *src++;
1061 *dst = (color & 0x7FFF) << 1;
1062 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1063 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1067 src += line_increase;
1070 for (y = 0; y < height; y++) {
1071 for (x = 0; x < width; x++) {
1072 WORD color = *src++;
1073 *dst++ = ((color & 0x7FFF) << 1) | 0x0001;
1075 src += line_increase;
1081 case CONVERT_CK_RGB24: {
1082 /* This is a pain :-) */
1084 BYTE *src = (BYTE *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top));
1087 if (*temp_buffer == NULL)
1088 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1089 current_tex_width * current_tex_height * sizeof(DWORD));
1090 dst = (DWORD *) *temp_buffer;
1092 for (y = 0; y < height; y++) {
1093 for (x = 0; x < width; x++) {
1094 DWORD color = *((DWORD *) src) & 0x00FFFFFF;
1097 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1098 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1102 src += 3 * line_increase;
1106 case CONVERT_CK_8888: {
1107 /* Just use the alpha component to handle color-keying... */
1109 DWORD *src = (DWORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
1111 if (*temp_buffer == NULL)
1112 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1113 current_tex_width * current_tex_height * sizeof(DWORD));
1114 dst = (DWORD *) *temp_buffer;
1116 for (y = 0; y < height; y++) {
1117 for (x = 0; x < width; x++) {
1118 DWORD color = *src++;
1119 *dst = color & 0xFFFFFF00;
1120 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1121 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1122 *dst |= color & 0x000000FF;
1125 src += line_increase;
1129 case CONVERT_CK_8888_ARGB: {
1131 DWORD *src = (DWORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
1133 if (*temp_buffer == NULL)
1134 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1135 current_tex_width * current_tex_height * sizeof(DWORD));
1136 dst = (DWORD *) *temp_buffer;
1138 for (y = 0; y < height; y++) {
1139 for (x = 0; x < width; x++) {
1140 DWORD color = *src++;
1141 *dst = (color & 0x00FFFFFF) << 8;
1142 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1143 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1144 *dst |= (color & 0xFF000000) >> 24;
1147 src += line_increase;
1151 case CONVERT_RGB32_888: {
1152 /* Just add an alpha component and handle color-keying... */
1154 DWORD *src = (DWORD *) (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top)), *dst;
1156 if (*temp_buffer == NULL)
1157 *temp_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1158 current_tex_width * current_tex_height * sizeof(DWORD));
1159 dst = (DWORD *) *temp_buffer;
1161 if (src_d->dwFlags & DDSD_CKSRCBLT) {
1162 for (y = 0; y < height; y++) {
1163 for (x = 0; x < width; x++) {
1164 DWORD color = *src++;
1166 if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
1167 (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
1171 src += line_increase;
1174 for (y = 0; y < height; y++) {
1175 for (x = 0; x < width; x++) {
1176 *dst++ = (*src++ << 8) | 0xFF;
1178 src += line_increase;
1184 /* Nothing to do here as the name suggests... Just set-up the buffer correctly */
1185 surf_buffer = (((BYTE *) src_d->lpSurface) + (bpp * rect->left) + (src_d->u1.lPitch * rect->top));
1189 if (convert_type != NO_CONVERSION) {
1190 surf_buffer = *temp_buffer;
1191 if (width != current_tex_width) {
1192 /* Overide the default PixelStore parameter if only using part of the actual texture */
1193 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1197 glTexSubImage2D(GL_TEXTURE_2D,
1202 current_pixel_format,
1208 HRESULT upload_surface_to_tex_memory_release(void)
1210 current_surface = NULL;