blob: 94b5c0b6fe4fc634593e02d4bfd5b4389dc66efd [file] [log] [blame]
/* Direct3D Device
* Copyright (c) 1998 Lionel ULMER
*
* This file contains the MESA implementation of all the D3D devices that
* Wine supports.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <string.h>
#include <math.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winerror.h"
#include "objbase.h"
#include "ddraw.h"
#include "d3d.h"
#include "wine/debug.h"
#include "mesa_private.h"
#include "main.h"
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
#undef COMPUTE_FPS
/* x11drv GDI escapes */
#define X11DRV_ESCAPE 6789
enum x11drv_escape_codes
{
X11DRV_GET_DISPLAY, /* get X11 display for a DC */
X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
X11DRV_GET_FONT, /* get current X font for a DC */
};
/* They are non-static as they are used by Direct3D in the creation function */
const GUID IID_D3DDEVICE_OpenGL = {
0x31416d44,
0x86ae,
0x11d2,
{ 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
};
const float id_mat[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
static void draw_primitive_strided(IDirect3DDeviceImpl *This,
D3DPRIMITIVETYPE d3dptPrimitiveType,
DWORD d3dvtVertexType,
LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
DWORD dwVertexCount,
LPWORD dwIndices,
DWORD dwIndexCount,
DWORD dwFlags) ;
static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
/* retrieve the X display to use on a given DC */
inline static Display *get_display( HDC hdc )
{
Display *display;
enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
sizeof(display), (LPSTR)&display )) display = NULL;
return display;
}
#define UNLOCK_TEX_SIZE 256
#define DEPTH_RANGE_BIT (0x00000001 << 0)
#define VIEWPORT_BIT (0x00000001 << 1)
static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
DWORD opt_bitmap = 0x00000000;
if (gl_d3d_dev->unlock_tex == 0) {
glGenTextures(1, &gl_d3d_dev->unlock_tex);
glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
*initial = TRUE;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
} else {
glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
}
if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
}
if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
d3ddevice_set_ortho(d3d_dev);
}
if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
(d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
glEnable(GL_TEXTURE_2D);
glEnable(GL_SCISSOR_TEST);
if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
(d3d_dev->active_viewport.dvMaxZ != 1.0)) {
glDepthRange(0.0, 1.0);
opt_bitmap |= DEPTH_RANGE_BIT;
}
if ((d3d_dev->active_viewport.dwX != 0) ||
(d3d_dev->active_viewport.dwY != 0) ||
(d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
(d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
opt_bitmap |= VIEWPORT_BIT;
}
glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
pRect->right - pRect->left, pRect->bottom - pRect->top);
if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
if (use_alpha) {
if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
if (((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) != 0x00) ||
((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]) != D3DCMP_GREATER)) {
glAlphaFunc(GL_GREATER, 0.0);
}
} else {
if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
}
if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
if (gl_d3d_dev->current_tex_env != GL_REPLACE)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
return opt_bitmap;
}
static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
/* And restore all the various states modified by this code */
if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
glEnable(GL_ALPHA_TEST);
else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
glDisable(GL_ALPHA_TEST);
if (use_alpha) {
if (((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) != 0x00) ||
((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]) != D3DCMP_GREATER)) {
glAlphaFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]),
(d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) / 255.0);
}
}
if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
glDisable(GL_SCISSOR_TEST);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
if (opt_bitmap & DEPTH_RANGE_BIT) {
glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
}
if (opt_bitmap & VIEWPORT_BIT) {
glViewport(d3d_dev->active_viewport.dwX,
d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
}
if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
}
/* This is a hack to prevent querying the current texture from GL. Basically, at the next
DrawPrimitive call, this will bind the correct texture to this stage. */
gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
}
/* retrieve the X drawable to use on a given DC */
inline static Drawable get_drawable( HDC hdc )
{
Drawable drawable;
enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
return drawable;
}
#ifdef COMPUTE_FPS
#define MEASUREMENT_WINDOW 5
#define NUMBER_OF_WINDOWS 10
static LONGLONG perf_freq;
static LONGLONG perf_storage[NUMBER_OF_WINDOWS];
static LONGLONG prev_time = 0;
static unsigned int current_window;
static unsigned int measurements_in_window;
static unsigned int valid_windows;
#endif
static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
{
IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
ENTER_GL();
if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_BACK]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK]);
}
gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
LEAVE_GL();
#ifdef COMPUTE_FPS
{
LONGLONG current_time;
LONGLONG frame_duration;
QueryPerformanceCounter((LARGE_INTEGER *) &current_time);
if (prev_time != 0) {
LONGLONG total_time = 0;
int tot_meas;
frame_duration = current_time - prev_time;
prev_time = current_time;
perf_storage[current_window] += frame_duration;
measurements_in_window++;
if (measurements_in_window >= MEASUREMENT_WINDOW) {
current_window++;
valid_windows++;
if (valid_windows < NUMBER_OF_WINDOWS) {
int i;
tot_meas = valid_windows * MEASUREMENT_WINDOW;
for (i = 0; i < valid_windows; i++) {
total_time += perf_storage[i];
}
} else {
int i;
tot_meas = NUMBER_OF_WINDOWS * MEASUREMENT_WINDOW;
for (i = 0; i < NUMBER_OF_WINDOWS; i++) {
total_time += perf_storage[i];
}
}
DPRINTF("FPS : %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time);
if (current_window >= NUMBER_OF_WINDOWS) {
current_window = 0;
}
perf_storage[current_window] = 0;
measurements_in_window = 0;
}
} else {
prev_time = current_time;
memset(perf_storage, 0, sizeof(perf_storage));
current_window = 0;
valid_windows = 0;
measurements_in_window = 0;
QueryPerformanceFrequency((LARGE_INTEGER *) &perf_freq);
}
}
#endif
return TRUE;
}
/*******************************************************************************
* OpenGL static functions
*/
static void set_context(IDirect3DDeviceImpl* This)
{
IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
ENTER_GL();
if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
ERR("Error in setting current context (context %p drawable %ld)!\n",
glThis->gl_context, glThis->drawable);
}
LEAVE_GL();
}
static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
{
pc->dwSize = sizeof(*pc);
pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL;
pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
pc->dwSrcBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
pc->dwAlphaCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
pc->dwStippleWidth = 32;
pc->dwStippleHeight = 32;
}
static void fill_opengl_caps(D3DDEVICEDESC *d1)
{
/* GLint maxlight; */
d1->dwSize = sizeof(*d1);
d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
| D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
d1->dcmColorModel = D3DCOLOR_RGB;
d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
/* D3D 7 capabilities */
D3DDEVCAPS_DRAWPRIMITIVES2 | D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_HWRASTERIZATION;
d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
d1->bClipping = TRUE;
d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
fill_opengl_primcaps(&(d1->dpcLineCaps));
fill_opengl_primcaps(&(d1->dpcTriCaps));
d1->dwDeviceRenderBitDepth = DDBD_16|DDBD_24|DDBD_32;
d1->dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32;
d1->dwMaxBufferSize = 0;
d1->dwMaxVertexCount = 65536;
d1->dwMinTextureWidth = 1;
d1->dwMinTextureHeight = 1;
d1->dwMaxTextureWidth = 1024;
d1->dwMaxTextureHeight = 1024;
d1->dwMinStippleWidth = 1;
d1->dwMinStippleHeight = 1;
d1->dwMaxStippleWidth = 32;
d1->dwMaxStippleHeight = 32;
d1->dwMaxTextureRepeat = 16;
d1->dwMaxTextureAspectRatio = 1024;
d1->dwMaxAnisotropy = 0;
d1->dvGuardBandLeft = 0.0;
d1->dvGuardBandRight = 0.0;
d1->dvGuardBandTop = 0.0;
d1->dvGuardBandBottom = 0.0;
d1->dvExtentsAdjust = 0.0;
d1->dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
d1->dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
d1->dwTextureOpCaps = 0; /* TODO add proper caps according to OpenGL multi-texture stuff */
d1->wMaxTextureBlendStages = 1; /* TODO add proper caps according to OpenGL multi-texture stuff */
d1->wMaxSimultaneousTextures = 1; /* TODO add proper caps according to OpenGL multi-texture stuff */
}
static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
{
D3DDEVICEDESC d1;
/* Copy first D3D1/2/3 capabilities */
fill_opengl_caps(&d1);
/* And fill the D3D7 one with it */
d->dwDevCaps = d1.dwDevCaps;
d->dpcLineCaps = d1.dpcLineCaps;
d->dpcTriCaps = d1.dpcTriCaps;
d->dwDeviceRenderBitDepth = d1.dwDeviceRenderBitDepth;
d->dwDeviceZBufferBitDepth = d1.dwDeviceZBufferBitDepth;
d->dwMinTextureWidth = d1.dwMinTextureWidth;
d->dwMinTextureHeight = d1.dwMinTextureHeight;
d->dwMaxTextureWidth = d1.dwMaxTextureWidth;
d->dwMaxTextureHeight = d1.dwMaxTextureHeight;
d->dwMaxTextureRepeat = d1.dwMaxTextureRepeat;
d->dwMaxTextureAspectRatio = d1.dwMaxTextureAspectRatio;
d->dwMaxAnisotropy = d1.dwMaxAnisotropy;
d->dvGuardBandLeft = d1.dvGuardBandLeft;
d->dvGuardBandTop = d1.dvGuardBandTop;
d->dvGuardBandRight = d1.dvGuardBandRight;
d->dvGuardBandBottom = d1.dvGuardBandBottom;
d->dvExtentsAdjust = d1.dvExtentsAdjust;
d->dwStencilCaps = d1.dwStencilCaps;
d->dwFVFCaps = d1.dwFVFCaps;
d->dwTextureOpCaps = d1.dwTextureOpCaps;
d->wMaxTextureBlendStages = d1.wMaxTextureBlendStages;
d->wMaxSimultaneousTextures = d1.wMaxSimultaneousTextures;
d->dwMaxActiveLights = d1.dlcLightingCaps.dwNumLights;
d->dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
d->deviceGUID = IID_IDirect3DTnLHalDevice;
d->wMaxUserClipPlanes = 1;
d->wMaxVertexBlendMatrices = 0;
d->dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG | D3DVTXPCAPS_DIRECTIONALLIGHTS |
D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
d->dwReserved1 = 0;
d->dwReserved2 = 0;
d->dwReserved3 = 0;
d->dwReserved4 = 0;
}
HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
{
D3DDEVICEDESC dref, d1, d2;
HRESULT ret_value;
/* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
Let's put the string in a sufficiently sized array in writable memory. */
char device_name[50];
strcpy(device_name,"direct3d");
fill_opengl_caps(&dref);
if (version > 1) {
/* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
d1 = dref;
d2 = dref;
ret_value = cb((LPIID) &IID_IDirect3DRefDevice, "WINE Reference Direct3DX using OpenGL", device_name, &d1, &d2, context);
if (ret_value != D3DENUMRET_OK)
return ret_value;
}
TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
d1 = dref;
d2 = dref;
ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, "WINE Direct3DX using OpenGL", device_name, &d1, &d2, context);
if (ret_value != D3DENUMRET_OK)
return ret_value;
return D3DENUMRET_OK;
}
HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
{
D3DDEVICEDESC7 ddesc;
fill_opengl_caps_7(&ddesc);
TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
return cb("WINE Direct3D7 using OpenGL", "Wine D3D7 device", &ddesc, context);
}
ULONG WINAPI
GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, This->ref);
if (!--(This->ref)) {
int i;
IDirectDrawSurfaceImpl *surface = This->surface, *surf;
/* Release texture associated with the device */
for (i = 0; i < MAX_TEXTURES; i++) {
if (This->current_texture[i] != NULL)
IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
}
/* Look for the front buffer and override its surface's Flip method (if in double buffering) */
for (surf = surface; surf != NULL; surf = surf->surface_owner) {
if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
surf->aux_ctx = NULL;
surf->aux_data = NULL;
surf->aux_flip = NULL;
break;
}
}
for (surf = surface; surf != NULL; surf = surf->surface_owner) {
IDirectDrawSurfaceImpl *surf2;
for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
for (; surf2 != NULL; surf2 = surf2->next_attached) {
if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
/* Override the Lock / Unlock function for all these surfaces */
surf2->lock_update = surf2->lock_update_prev;
surf2->unlock_update = surf2->unlock_update_prev;
/* And install also the blt / bltfast overrides */
surf2->aux_blt = NULL;
surf2->aux_bltfast = NULL;
}
surf2->d3ddevice = NULL;
}
}
/* And warn the D3D object that this device is no longer active... */
This->d3d->d3d_removed_device(This->d3d, This);
HeapFree(GetProcessHeap(), 0, This->world_mat);
HeapFree(GetProcessHeap(), 0, This->view_mat);
HeapFree(GetProcessHeap(), 0, This->proj_mat);
if (glThis->surface_ptr)
HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
DeleteCriticalSection(&(This->crit));
ENTER_GL();
if (glThis->unlock_tex)
glDeleteTextures(1, &(glThis->unlock_tex));
glXDestroyContext(glThis->display, glThis->gl_context);
LEAVE_GL();
HeapFree(GetProcessHeap(), 0, This->clipping_planes);
HeapFree(GetProcessHeap(), 0, This);
return 0;
}
return This->ref;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
LPD3DDEVICEDESC lpD3DHWDevDesc,
LPD3DDEVICEDESC lpD3DHELDevDesc)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
D3DDEVICEDESC desc;
DWORD dwSize;
TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
fill_opengl_caps(&desc);
dwSize = lpD3DHWDevDesc->dwSize;
memset(lpD3DHWDevDesc, 0, dwSize);
memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
dwSize = lpD3DHELDevDesc->dwSize;
memset(lpD3DHELDevDesc, 0, dwSize);
memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
TRACE(" returning caps : (no dump function yet)\n");
return DD_OK;
}
static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
LPD3DENUMPIXELFORMATSCALLBACK cb_2,
LPVOID context)
{
DDSURFACEDESC sdesc;
LPDDPIXELFORMAT pformat;
/* Do the texture enumeration */
sdesc.dwSize = sizeof(DDSURFACEDESC);
sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
pformat = &(sdesc.ddpfPixelFormat);
pformat->dwSize = sizeof(DDPIXELFORMAT);
pformat->dwFourCC = 0;
TRACE("Enumerating GL_RGBA unpacked (32)\n");
pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
pformat->u1.dwRGBBitCount = 32;
pformat->u2.dwRBitMask = 0x00FF0000;
pformat->u3.dwGBitMask = 0x0000FF00;
pformat->u4.dwBBitMask = 0x000000FF;
pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGB unpacked (32)\n");
pformat->dwFlags = DDPF_RGB;
pformat->u1.dwRGBBitCount = 32;
pformat->u2.dwRBitMask = 0x00FF0000;
pformat->u3.dwGBitMask = 0x0000FF00;
pformat->u4.dwBBitMask = 0x000000FF;
pformat->u5.dwRGBAlphaBitMask = 0x00000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGB unpacked (24)\n");
pformat->dwFlags = DDPF_RGB;
pformat->u1.dwRGBBitCount = 24;
pformat->u2.dwRBitMask = 0x00FF0000;
pformat->u3.dwGBitMask = 0x0000FF00;
pformat->u4.dwBBitMask = 0x000000FF;
pformat->u5.dwRGBAlphaBitMask = 0x00000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
/* Note : even if this is an 'emulated' texture format, it needs to be first
as some dumb applications seem to rely on that. */
TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
pformat->u1.dwRGBBitCount = 16;
pformat->u2.dwRBitMask = 0x00007C00;
pformat->u3.dwGBitMask = 0x000003E0;
pformat->u4.dwBBitMask = 0x0000001F;
pformat->u5.dwRGBAlphaBitMask = 0x00008000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
pformat->u1.dwRGBBitCount = 16;
pformat->u2.dwRBitMask = 0x00000F00;
pformat->u3.dwGBitMask = 0x000000F0;
pformat->u4.dwBBitMask = 0x0000000F;
pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
pformat->dwFlags = DDPF_RGB;
pformat->u1.dwRGBBitCount = 16;
pformat->u2.dwRBitMask = 0x0000F800;
pformat->u3.dwGBitMask = 0x000007E0;
pformat->u4.dwBBitMask = 0x0000001F;
pformat->u5.dwRGBAlphaBitMask = 0x00000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
pformat->dwFlags = DDPF_RGB;
pformat->u1.dwRGBBitCount = 16;
pformat->u2.dwRBitMask = 0x00007C00;
pformat->u3.dwGBitMask = 0x000003E0;
pformat->u4.dwBBitMask = 0x0000001F;
pformat->u5.dwRGBAlphaBitMask = 0x00000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
#if 0
/* This is a compromise : some games choose the first 16 bit texture format with alpha they
find enumerated, others the last one. And both want to have the ARGB one.
So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
*/
/* See argument about the RGBA format for 'packed' texture formats */
TRACE("Enumerating GL_RGBA unpacked (32)\n");
pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
pformat->u1.dwRGBBitCount = 32;
pformat->u2.dwRBitMask = 0xFF000000;
pformat->u3.dwGBitMask = 0x00FF0000;
pformat->u4.dwBBitMask = 0x0000FF00;
pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
pformat->u1.dwRGBBitCount = 16;
pformat->u2.dwRBitMask = 0x0000F000;
pformat->u3.dwGBitMask = 0x00000F00;
pformat->u4.dwBBitMask = 0x000000F0;
pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
pformat->u1.dwRGBBitCount = 16;
pformat->u2.dwRBitMask = 0x0000F800;
pformat->u3.dwGBitMask = 0x000007C0;
pformat->u4.dwBBitMask = 0x0000003E;
pformat->u5.dwRGBAlphaBitMask = 0x00000001;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
#endif
TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
pformat->dwFlags = DDPF_RGB;
pformat->u1.dwRGBBitCount = 8;
pformat->u2.dwRBitMask = 0x000000E0;
pformat->u3.dwGBitMask = 0x0000001C;
pformat->u4.dwBBitMask = 0x00000003;
pformat->u5.dwRGBAlphaBitMask = 0x00000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("Enumerating Paletted (8)\n");
pformat->dwFlags = DDPF_PALETTEINDEXED8;
pformat->u1.dwRGBBitCount = 8;
pformat->u2.dwRBitMask = 0x00000000;
pformat->u3.dwGBitMask = 0x00000000;
pformat->u4.dwBBitMask = 0x00000000;
pformat->u5.dwRGBAlphaBitMask = 0x00000000;
if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
TRACE("End of enumeration\n");
return DD_OK;
}
HRESULT
d3ddevice_find(IDirectDrawImpl *d3d,
LPD3DFINDDEVICESEARCH lpD3DDFS,
LPD3DFINDDEVICERESULT lplpD3DDevice)
{
D3DDEVICEDESC desc;
if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
(lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
}
if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
(IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
(IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
TRACE(" no match for this GUID.\n");
return DDERR_INVALIDPARAMS;
}
}
/* Now return our own GUID */
lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
fill_opengl_caps(&desc);
lplpD3DDevice->ddHwDesc = desc;
lplpD3DDevice->ddSwDesc = desc;
TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
return D3D_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
LPVOID lpArg)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg);
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
LPVOID lpArg)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg);
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
D3DRENDERSTATETYPE dwRenderStateType,
DWORD dwRenderState)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
/* Call the render state functions */
store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
set_render_state(This, dwRenderStateType, &This->state_block);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
D3DRENDERSTATETYPE dwRenderStateType,
LPDWORD lpdwRenderState)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
/* Call the render state functions */
get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
D3DLIGHTSTATETYPE dwLightStateType,
DWORD dwLightState)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX))
TRACE("Unexpected Light State Type\n");
return DDERR_INVALIDPARAMS;
if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
if (mat != NULL) {
mat->activate(mat);
} else {
ERR(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
}
} else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
switch (dwLightState) {
case D3DCOLOR_MONO:
ERR("DDCOLOR_MONO should not happen!\n");
break;
case D3DCOLOR_RGB:
/* We are already in this mode */
break;
default:
ERR("Unknown color model!\n");
break;
}
} else {
D3DRENDERSTATETYPE rs;
switch (dwLightStateType) {
case D3DLIGHTSTATE_AMBIENT: /* 2 */
rs = D3DRENDERSTATE_AMBIENT;
break;
case D3DLIGHTSTATE_FOGMODE: /* 4 */
rs = D3DRENDERSTATE_FOGVERTEXMODE;
break;
case D3DLIGHTSTATE_FOGSTART: /* 5 */
rs = D3DRENDERSTATE_FOGSTART;
break;
case D3DLIGHTSTATE_FOGEND: /* 6 */
rs = D3DRENDERSTATE_FOGEND;
break;
case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
rs = D3DRENDERSTATE_FOGDENSITY;
break;
case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
rs = D3DRENDERSTATE_COLORVERTEX;
break;
default:
break;
}
IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
rs,dwLightState);
}
return DD_OK;
}
static void draw_primitive_start_GL(D3DPRIMITIVETYPE d3dpt)
{
switch (d3dpt) {
case D3DPT_POINTLIST:
TRACE("Start POINTS\n");
glBegin(GL_POINTS);
break;
case D3DPT_LINELIST:
TRACE("Start LINES\n");
glBegin(GL_LINES);
break;
case D3DPT_LINESTRIP:
TRACE("Start LINE_STRIP\n");
glBegin(GL_LINE_STRIP);
break;
case D3DPT_TRIANGLELIST:
TRACE("Start TRIANGLES\n");
glBegin(GL_TRIANGLES);
break;
case D3DPT_TRIANGLESTRIP:
TRACE("Start TRIANGLE_STRIP\n");
glBegin(GL_TRIANGLE_STRIP);
break;
case D3DPT_TRIANGLEFAN:
TRACE("Start TRIANGLE_FAN\n");
glBegin(GL_TRIANGLE_FAN);
break;
default:
FIXME("Unhandled primitive %08x\n", d3dpt);
break;
}
}
/* This function calculate the Z coordinate from Zproj */
static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
{
float a,b,c,d;
/* Assume that X = Y = 0 and W = 1 */
a = This->proj_mat->_33;
b = This->proj_mat->_34;
c = This->proj_mat->_43;
d = This->proj_mat->_44;
/* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
* So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
* And finally Z = (d * Zproj - c) / (a - b * Zproj)
*/
return (d*Zproj - c) / (a - b*Zproj);
}
static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
int i;
TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
for (i = 0; i < 3; i++) {
BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
DWORD elt;
for (elt = 0; elt < 0x10000; elt++) {
/* We apply the fog transformation and cache the result */
DWORD fog_intensity = elt & 0xFF;
DWORD vertex_color = (elt >> 8) & 0xFF;
fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
}
}
}
static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
BOOLEAN vertex_transformed,
BOOLEAN vertex_lit) {
IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
/* Puts GL in the correct lighting / transformation mode */
if ((vertex_transformed == FALSE) &&
(glThis->transform_state != GL_TRANSFORM_NORMAL)) {
/* Need to put the correct transformation again if we go from Transformed
vertices to non-transformed ones.
*/
This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
This->world_mat, This->view_mat, This->proj_mat);
glThis->transform_state = GL_TRANSFORM_NORMAL;
} else if ((vertex_transformed == TRUE) &&
(glThis->transform_state != GL_TRANSFORM_ORTHO)) {
/* Set our orthographic projection */
if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
glThis->transform_state = GL_TRANSFORM_ORTHO;
d3ddevice_set_ortho(This);
}
}
/* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
if no fogging state change occured */
if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
if (vertex_transformed == TRUE) {
if (glThis->fogging != 0) {
glDisable(GL_FOG);
glThis->fogging = 0;
}
/* Now check if our fog_table still corresponds to the current vertex color.
Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) ||
(glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) ||
(glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
/* We need to rebuild our fog table.... */
build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
}
} else {
if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break;
case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break;
case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break;
}
if (vertex_lit == FALSE) {
glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
} else {
/* Special case of 'pixel fog' */
glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
}
if (glThis->fogging == 0) {
glEnable(GL_FOG);
glThis->fogging = 1;
}
} else {
if (glThis->fogging != 0) {
glDisable(GL_FOG);
glThis->fogging = 0;
}
}
}
} else {
if (glThis->fogging != 0) {
glDisable(GL_FOG);
glThis->fogging = 0;
}
}
/* Handle the 'no-normal' case */
if ((vertex_lit == FALSE) && (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE)) {
if (glThis->lighting == 0) {
glEnable(GL_LIGHTING);
glThis->lighting = 1;
}
} else {
if (glThis->lighting != 0) {
glDisable(GL_LIGHTING);
glThis->lighting = 0;
}
}
/* Handle the code for pre-vertex material properties */
if (vertex_transformed == FALSE) {
if ((This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
(This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
(This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
(This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
(This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
glEnable(GL_COLOR_MATERIAL);
}
}
}
}
inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
{
D3DDRAWPRIMITIVESTRIDEDDATA strided;
switch (d3dvt) {
case D3DVT_VERTEX: {
strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
strided.position.dwStride = sizeof(D3DVERTEX);
strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
strided.normal.dwStride = sizeof(D3DVERTEX);
strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
} break;
case D3DVT_LVERTEX: {
strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
strided.position.dwStride = sizeof(D3DLVERTEX);
strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
strided.diffuse.dwStride = sizeof(D3DLVERTEX);
strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
strided.specular.dwStride = sizeof(D3DLVERTEX);
strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
} break;
case D3DVT_TLVERTEX: {
strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
strided.position.dwStride = sizeof(D3DTLVERTEX);
strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
strided.specular.dwStride = sizeof(D3DTLVERTEX);
strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
} break;
default:
FIXME("Unhandled vertex type %08x\n", d3dvt);
break;
}
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
D3DVERTEXTYPE d3dvtVertexType,
LPVOID lpvVertices,
DWORD dwVertexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
D3DVERTEXTYPE d3dvtVertexType,
LPVOID lpvVertices,
DWORD dwVertexCount,
LPWORD dwIndices,
DWORD dwIndexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
LPD3DEXECUTEBUFFERDESC lpDesc,
LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
IUnknown* pUnkOuter)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
IDirect3DExecuteBufferImpl *ret;
HRESULT ret_value;
TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
*lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
return ret_value;
}
/* These are the various handler used in the generic path */
inline static void handle_xyz(D3DVALUE *coords) {
glVertex3fv(coords);
}
inline static void handle_xyzrhw(D3DVALUE *coords) {
if (coords[3] < 1e-8)
glVertex3fv(coords);
else {
GLfloat w = 1.0 / coords[3];
glVertex4f(coords[0] * w,
coords[1] * w,
coords[2] * w,
w);
}
}
inline static void handle_normal(D3DVALUE *coords) {
glNormal3fv(coords);
}
inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
if ((sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == TRUE) ||
(sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1] == TRUE)) {
glColor4ub((*color >> 16) & 0xFF,
(*color >> 8) & 0xFF,
(*color >> 0) & 0xFF,
(*color >> 24) & 0xFF);
} else {
glColor3ub((*color >> 16) & 0xFF,
(*color >> 8) & 0xFF,
(*color >> 0) & 0xFF);
}
}
inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
glColor4ub((*color >> 16) & 0xFF,
(*color >> 8) & 0xFF,
(*color >> 0) & 0xFF,
(*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
}
inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
if ((lighted == FALSE) &&
(sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
(sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
handle_diffuse_base(sb, color);
}
if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
handle_diffuse_base(sb, color);
}
if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
(sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
handle_diffuse_base(sb, color);
}
if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
handle_diffuse_base(sb, color);
}
} else {
handle_diffuse_base(sb, color);
}
}
inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
if ((lighted == FALSE) &&
(sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
(sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
handle_specular_base(sb, color);
}
if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
handle_specular_base(sb, color);
}
if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
(sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
handle_specular_base(sb, color);
}
if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
handle_specular_base(sb, color);
}
}
/* No else here as we do not know how to handle 'specular' on its own in any case.. */
}
inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
if (lighted == TRUE) {
DWORD color = *color_d;
if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
/* Special case where the specular value is used to do fogging */
BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
color &= 0xFF000000; /* Only keep the alpha component */
color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0;
color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8;
color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
}
if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE) {
/* Standard specular value in transformed mode. TODO */
}
handle_diffuse_base(sb, &color);
} else {
if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) {
handle_diffuse(sb, color_d, FALSE);
handle_specular(sb, color_s, FALSE);
} else {
/* In that case, only put the diffuse color... */
handle_diffuse_base(sb, color_d);
}
}
}
inline static void handle_texture(D3DVALUE *coords) {
glTexCoord2fv(coords);
}
inline static void handle_textures(D3DVALUE *coords, int tex_index) {
/* For the moment, draw only the first texture.. */
if (tex_index == 0) glTexCoord2fv(coords);
}
static void draw_primitive_strided(IDirect3DDeviceImpl *This,
D3DPRIMITIVETYPE d3dptPrimitiveType,
DWORD d3dvtVertexType,
LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
DWORD dwVertexCount,
LPWORD dwIndices,
DWORD dwIndexCount,
DWORD dwFlags)
{
BOOLEAN vertex_lighted = FALSE;
IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
int num_active_stages = 0;
/* I put the trace before the various locks... So as to better understand where locks occur :-) */
if (TRACE_ON(ddraw)) {
TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
}
/* This is to prevent 'thread contention' between a thread locking the device and another
doing 3D display on it... */
EnterCriticalSection(&(This->crit));
ENTER_GL();
if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
}
glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
/* Just a hack for now.. Will have to find better algorithm :-/ */
if ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
vertex_lighted = TRUE;
} else {
if ((d3dvtVertexType & D3DFVF_NORMAL) == 0) glNormal3f(0.0, 0.0, 0.0);
}
/* Compute the number of active texture stages and set the various texture parameters */
num_active_stages = draw_primitive_handle_textures(This);
draw_primitive_handle_GL_state(This,
(d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
vertex_lighted);
draw_primitive_start_GL(d3dptPrimitiveType);
/* Some fast paths first before the generic case.... */
if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
int index;
for (index = 0; index < dwIndexCount; index++) {
int i = (dwIndices == NULL) ? index : dwIndices[index];
D3DVALUE *normal =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
D3DVALUE *tex_coord =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
D3DVALUE *position =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
handle_normal(normal);
handle_texture(tex_coord);
handle_xyz(position);
TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
position[0], position[1], position[2],
normal[0], normal[1], normal[2],
tex_coord[0], tex_coord[1]);
}
} else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
int index;
for (index = 0; index < dwIndexCount; index++) {
int i = (dwIndices == NULL) ? index : dwIndices[index];
DWORD *color_d =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
DWORD *color_s =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
D3DVALUE *tex_coord =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
D3DVALUE *position =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
handle_texture(tex_coord);
handle_xyzrhw(position);
TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
position[0], position[1], position[2], position[3],
(*color_d >> 16) & 0xFF,
(*color_d >> 8) & 0xFF,
(*color_d >> 0) & 0xFF,
(*color_d >> 24) & 0xFF,
(*color_s >> 16) & 0xFF,
(*color_s >> 8) & 0xFF,
(*color_s >> 0) & 0xFF,
(*color_s >> 24) & 0xFF,
tex_coord[0], tex_coord[1]);
}
} else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
/* This is the 'slow path' but that should support all possible vertex formats out there...
Note that people should write a fast path for all vertex formats out there...
*/
int index;
int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
for (index = 0; index < dwIndexCount; index++) {
int i = (dwIndices == NULL) ? index : dwIndices[index];
int tex_stage;
if (d3dvtVertexType & D3DFVF_NORMAL) {
D3DVALUE *normal =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
handle_normal(normal);
}
if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
DWORD *color_d =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
DWORD *color_s =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
} else {
if (d3dvtVertexType & D3DFVF_SPECULAR) {
DWORD *color_s =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
handle_specular(&(This->state_block), color_s, vertex_lighted);
} else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
DWORD *color_d =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
handle_diffuse(&(This->state_block), color_d, vertex_lighted);
}
}
for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0xFFFF0000;
if (tex_index >= num_tex_index) {
handle_textures((D3DVALUE *) no_index, tex_stage);
} else {
D3DVALUE *tex_coord =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
handle_textures(tex_coord, tex_stage);
}
}
if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
D3DVALUE *position =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
handle_xyz(position);
} else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
D3DVALUE *position =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
handle_xyzrhw(position);
}
if (TRACE_ON(ddraw_geom)) {
int tex_index;
if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
D3DVALUE *position =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
} else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
D3DVALUE *position =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
}
if (d3dvtVertexType & D3DFVF_NORMAL) {
D3DVALUE *normal =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
}
if (d3dvtVertexType & D3DFVF_DIFFUSE) {
DWORD *color_d =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
(*color_d >> 16) & 0xFF,
(*color_d >> 8) & 0xFF,
(*color_d >> 0) & 0xFF,
(*color_d >> 24) & 0xFF);
}
if (d3dvtVertexType & D3DFVF_SPECULAR) {
DWORD *color_s =
(DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
(*color_s >> 16) & 0xFF,
(*color_s >> 8) & 0xFF,
(*color_s >> 0) & 0xFF,
(*color_s >> 24) & 0xFF);
}
for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
D3DVALUE *tex_coord =
(D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) +
i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
}
TRACE_(ddraw_geom)("\n");
}
}
} else {
ERR(" matrix weighting not handled yet....\n");
}
glEnd();
/* Whatever the case, disable the color material stuff */
glDisable(GL_COLOR_MATERIAL);
LEAVE_GL();
TRACE("End\n");
LeaveCriticalSection(&(This->crit));
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
DWORD d3dvtVertexType,
LPVOID lpvVertices,
DWORD dwVertexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
D3DDRAWPRIMITIVESTRIDEDDATA strided;
TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
DWORD d3dvtVertexType,
LPVOID lpvVertices,
DWORD dwVertexCount,
LPWORD dwIndices,
DWORD dwIndexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
D3DDRAWPRIMITIVESTRIDEDDATA strided;
TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
DWORD dwVertexType,
LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
DWORD dwVertexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
DWORD dwVertexType,
LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
DWORD dwVertexCount,
LPWORD lpIndex,
DWORD dwIndexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
DWORD dwStartVertex,
DWORD dwNumVertices,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
D3DDRAWPRIMITIVESTRIDEDDATA strided;
TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
if (vb_impl->processed == TRUE) {
IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
&(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
} else {
convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
}
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
D3DPRIMITIVETYPE d3dptPrimitiveType,
LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
DWORD dwStartVertex,
DWORD dwNumVertices,
LPWORD lpwIndices,
DWORD dwIndexCount,
DWORD dwFlags)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
D3DDRAWPRIMITIVESTRIDEDDATA strided;
TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
if (TRACE_ON(ddraw)) {
TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
}
if (vb_impl->processed == TRUE) {
IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
&(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
} else {
convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
}
return DD_OK;
}
/* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
static BOOLEAN
handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
{
BOOLEAN is_complement = FALSE;
BOOLEAN is_alpha_replicate = FALSE;
BOOLEAN handled = TRUE;
GLenum src;
BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
int num;
if (is_color) {
if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
else {
handled = FALSE;
num = 0;
}
if (tex_op == D3DTOP_SELECTARG2) {
num = 1 - num;
}
} else {
if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
else {
handled = FALSE;
num = 0;
}
if (tex_op == D3DTOP_SELECTARG2) {
num = 1 - num;
}
}
if (dwState & D3DTA_COMPLEMENT) {
is_complement = TRUE;
}
if (dwState & D3DTA_ALPHAREPLICATE) {
is_alpha_replicate = TRUE;
}
dwState &= D3DTA_SELECTMASK;
if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
dwState = D3DTA_DIFFUSE;
}
switch (dwState) {
case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
case D3DTA_TEXTURE: src = GL_TEXTURE; break;
case D3DTA_TFACTOR: {
/* Get the constant value from the current rendering state */
GLfloat color[4];
DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
color[0] = ((col >> 16) & 0xFF) / 255.0f;
color[1] = ((col >> 8) & 0xFF) / 255.0f;
color[2] = ((col >> 0) & 0xFF) / 255.0f;
color[3] = ((col >> 24) & 0xFF) / 255.0f;
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
src = GL_CONSTANT_EXT;
} break;
default: src = GL_TEXTURE; handled = FALSE; break;
}
if (is_color) {
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
if (is_alpha_replicate) {
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
} else {
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
}
} else {
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
}
return handled;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
DWORD dwStage,
D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
DWORD dwState)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
const char *type;
DWORD prev_state;
TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
if (dwStage > 0) return DD_OK; /* We nothing in this case for now */
switch (d3dTexStageStateType) {
#define GEN_CASE(a) case a: type = #a; break
GEN_CASE(D3DTSS_COLOROP);
GEN_CASE(D3DTSS_COLORARG1);
GEN_CASE(D3DTSS_COLORARG2);
GEN_CASE(D3DTSS_ALPHAOP);
GEN_CASE(D3DTSS_ALPHAARG1);
GEN_CASE(D3DTSS_ALPHAARG2);
GEN_CASE(D3DTSS_BUMPENVMAT00);
GEN_CASE(D3DTSS_BUMPENVMAT01);
GEN_CASE(D3DTSS_BUMPENVMAT10);
GEN_CASE(D3DTSS_BUMPENVMAT11);
GEN_CASE(D3DTSS_TEXCOORDINDEX);
GEN_CASE(D3DTSS_ADDRESS);
GEN_CASE(D3DTSS_ADDRESSU);
GEN_CASE(D3DTSS_ADDRESSV);
GEN_CASE(D3DTSS_BORDERCOLOR);
GEN_CASE(D3DTSS_MAGFILTER);
GEN_CASE(D3DTSS_MINFILTER);
GEN_CASE(D3DTSS_MIPFILTER);
GEN_CASE(D3DTSS_MIPMAPLODBIAS);
GEN_CASE(D3DTSS_MAXMIPLEVEL);
GEN_CASE(D3DTSS_MAXANISOTROPY);
GEN_CASE(D3DTSS_BUMPENVLSCALE);
GEN_CASE(D3DTSS_BUMPENVLOFFSET);
GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
#undef GEN_CASE
default: type = "UNKNOWN";
}
/* Store the values in the state array */
prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
/* Some special cases when one state modifies more than one... */
if (d3dTexStageStateType == D3DTSS_ADDRESS) {
This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
}
ENTER_GL();
switch (d3dTexStageStateType) {
case D3DTSS_MINFILTER:
case D3DTSS_MIPFILTER:
if (TRACE_ON(ddraw)) {
if (d3dTexStageStateType == D3DTSS_MINFILTER) {
switch ((D3DTEXTUREMINFILTER) dwState) {
case D3DTFN_POINT: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
}
} else {
switch ((D3DTEXTUREMIPFILTER) dwState) {
case D3DTFP_NONE: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
case D3DTFP_POINT: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
}
}
}
break;
case D3DTSS_MAGFILTER:
if (TRACE_ON(ddraw)) {
switch ((D3DTEXTUREMAGFILTER) dwState) {
case D3DTFG_POINT: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_POINT\n"); break;
case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_LINEAR\n"); break;
default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
}
}
break;
case D3DTSS_ADDRESS:
case D3DTSS_ADDRESSU:
case D3DTSS_ADDRESSV: {
switch ((D3DTEXTUREADDRESS) dwState) {
case D3DTADDRESS_WRAP: TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
case D3DTADDRESS_CLAMP: TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
#if defined(GL_VERSION_1_4)
case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); break;
#elif defined(GL_ARB_texture_mirrored_repeat)
case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); break;
#endif
default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
}
} break;
case D3DTSS_ALPHAOP:
case D3DTSS_COLOROP: {
int scale = 1;
GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
const char *value;
int handled = 1;
switch (dwState) {
#define GEN_CASE(a) case a: value = #a; break
GEN_CASE(D3DTOP_DISABLE);
GEN_CASE(D3DTOP_SELECTARG1);
GEN_CASE(D3DTOP_SELECTARG2);
GEN_CASE(D3DTOP_MODULATE);
GEN_CASE(D3DTOP_MODULATE2X);
GEN_CASE(D3DTOP_MODULATE4X);
GEN_CASE(D3DTOP_ADD);
GEN_CASE(D3DTOP_ADDSIGNED);
GEN_CASE(D3DTOP_ADDSIGNED2X);
GEN_CASE(D3DTOP_SUBTRACT);
GEN_CASE(D3DTOP_ADDSMOOTH);
GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
GEN_CASE(D3DTOP_BLENDFACTORALPHA);
GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
GEN_CASE(D3DTOP_PREMODULATE);
GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
GEN_CASE(D3DTOP_BUMPENVMAP);
GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
GEN_CASE(D3DTOP_DOTPRODUCT3);
GEN_CASE(D3DTOP_FORCE_DWORD);
#undef GEN_CASE
default: value = "UNKNOWN";
}
if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE) && (dwStage == 0)) {
glDisable(GL_TEXTURE_2D);
TRACE(" disabling 2D texturing.\n");
} else {
/* Re-enable texturing */
if ((dwStage == 0) && (This->current_texture[0] != NULL)) {
glEnable(GL_TEXTURE_2D);
TRACE(" enabling 2D texturing.\n");
}
/* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
if (dwState != D3DTOP_DISABLE) {
if (glThis->current_tex_env != GL_COMBINE_EXT) {
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glThis->current_tex_env = GL_COMBINE_EXT;
}
}
/* Now set up the operand correctly */
switch (dwState) {
case D3DTOP_DISABLE:
/* Contrary to the docs, alpha can be disabled when colorop is enabled
and it works, so ignore this op */
TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
break;
case D3DTOP_SELECTARG1:
case D3DTOP_SELECTARG2:
glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
break;
case D3DTOP_MODULATE4X:
scale = scale * 2; /* Drop through */
case D3DTOP_MODULATE2X:
scale = scale * 2; /* Drop through */
case D3DTOP_MODULATE:
glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
break;
case D3DTOP_ADD:
glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
break;
case D3DTOP_ADDSIGNED2X:
scale = scale * 2; /* Drop through */
case D3DTOP_ADDSIGNED:
glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
break;
/* For the four blending modes, use the Arg2 parameter */
case D3DTOP_BLENDDIFFUSEALPHA:
case D3DTOP_BLENDTEXTUREALPHA:
case D3DTOP_BLENDFACTORALPHA:
case D3DTOP_BLENDCURRENTALPHA: {
GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
switch (dwState) {
case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
case D3DTOP_BLENDFACTORALPHA: src = GL_CONSTANT_EXT;
case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
}
glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
} break;
default:
handled = FALSE;
break;
}
}
if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
/* Switch the arguments if needed... */
if (d3dTexStageStateType == D3DTSS_COLOROP) {
handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
dwState);
handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
dwState);
} else {
handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
dwState);
handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
dwState);
}
}
if (handled) {
if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
} else {
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
}
TRACE(" Stage type is : %s => %s\n", type, value);
} else {
FIXME(" Unhandled stage type is : %s => %s\n", type, value);
}
} break;
case D3DTSS_COLORARG1:
case D3DTSS_COLORARG2:
case D3DTSS_ALPHAARG1:
case D3DTSS_ALPHAARG2: {
const char *value, *value_comp = "", *value_alpha = "";
BOOLEAN handled;
D3DTEXTUREOP tex_op;
switch (dwState & D3DTA_SELECTMASK) {
#define GEN_CASE(a) case a: value = #a; break
GEN_CASE(D3DTA_DIFFUSE);
GEN_CASE(D3DTA_CURRENT);
GEN_CASE(D3DTA_TEXTURE);
GEN_CASE(D3DTA_TFACTOR);
GEN_CASE(D3DTA_SPECULAR);
#undef GEN_CASE
default: value = "UNKNOWN";
}
if (dwState & D3DTA_COMPLEMENT) {
value_comp = " | D3DTA_COMPLEMENT";
}
if (dwState & D3DTA_ALPHAREPLICATE) {
value_alpha = " | D3DTA_ALPHAREPLICATE";
}
if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
} else {
tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
}
handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
if (handled) {
TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
} else {
FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
}
} break;
case D3DTSS_MIPMAPLODBIAS: {
D3DVALUE value = *((D3DVALUE *) &dwState);
BOOLEAN handled = TRUE;
if (value != 0.0)
handled = FALSE;
if (handled) {
TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
} else {
FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
}
} break;
case D3DTSS_MAXMIPLEVEL:
TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
break;
case D3DTSS_BORDERCOLOR:
TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
((dwState >> 16) & 0xFF),
((dwState >> 8) & 0xFF),
((dwState >> 0) & 0xFF),
((dwState >> 24) & 0xFF));
break;
case D3DTSS_TEXCOORDINDEX: {
BOOLEAN handled = TRUE;
const char *value;
switch (dwState & 0xFFFF0000) {
#define GEN_CASE(a) case a: value = #a; break
GEN_CASE(D3DTSS_TCI_PASSTHRU);
GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
#undef GEN_CASE
default: value = "UNKNOWN";
}
if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
handled = FALSE;
if (handled) {
TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
} else {
FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
}
} break;
case D3DTSS_TEXTURETRANSFORMFLAGS: {
const char *projected = "", *value;
BOOLEAN handled = TRUE;
switch (dwState & 0xFF) {
#define GEN_CASE(a) case a: value = #a; break
GEN_CASE(D3DTTFF_DISABLE);
GEN_CASE(D3DTTFF_COUNT1);
GEN_CASE(D3DTTFF_COUNT2);
GEN_CASE(D3DTTFF_COUNT3);
GEN_CASE(D3DTTFF_COUNT4);
#undef GEN_CASE
default: value = "UNKNOWN";
}
if (dwState & D3DTTFF_PROJECTED) {
projected = " | D3DTTFF_PROJECTED";
handled = FALSE;
}
if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
}
if (handled == TRUE) {
TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
} else {
FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
}
} break;
default:
FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
break;
}
LEAVE_GL();
return DD_OK;
}
static DWORD
draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
{
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
DWORD stage;
for (stage = 0; stage < MAX_TEXTURES; stage++) {
IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
/* First check if we need to bind any other texture for this stage */
if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
if (This->current_texture[stage] == NULL) {
TRACE(" disabling 2D texturing for stage %ld.\n", stage);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
} else {
GLenum tex_name = ((IDirect3DTextureGLImpl *) surf_ptr->tex_private)->tex_name;
if (glThis->current_bound_texture[stage] == NULL) {
if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
TRACE(" enabling 2D texturing and");
glEnable(GL_TEXTURE_2D);
}
}
TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
glBindTexture(GL_TEXTURE_2D, tex_name);
}
glThis->current_bound_texture[stage] = This->current_texture[stage];
} else {
if (glThis->current_bound_texture[stage] == NULL) {
TRACE(" displaying without texturing activated for stage %ld.\n", stage);
} else {
TRACE(" using already bound texture id %d for stage %ld.\n",
((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
}
}
/* If no texure valid for this stage, go out of the loop */
if (This->current_texture[stage] == NULL) break;
/* Then check if we need to flush this texture to GL or not (ie did it change) ?.
This will also update the various texture parameters if needed.
*/
gltex_upload_texture(surf_ptr, This, stage);
}
return stage;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
DWORD dwStage,
LPDIRECTDRAWSURFACE7 lpTexture2)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
if (dwStage > 0) return DD_OK;
if (This->current_texture[dwStage] != NULL) {
IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
}
if (lpTexture2 == NULL) {
This->current_texture[dwStage] = NULL;
} else {
IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
This->current_texture[dwStage] = tex_impl;
}
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
LPD3DDEVICEDESC7 lpD3DHELDevDesc)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
fill_opengl_caps_7(lpD3DHELDevDesc);
TRACE(" returning caps : no dump function yet.\n");
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
LPD3DMATERIAL7 lpMat)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
if (TRACE_ON(ddraw)) {
TRACE(" material is : \n");
dump_D3DMATERIAL7(lpMat);
}
This->current_material = *lpMat;
ENTER_GL();
glMaterialfv(GL_FRONT_AND_BACK,
GL_DIFFUSE,
(float *) &(This->current_material.u.diffuse));
glMaterialfv(GL_FRONT_AND_BACK,
GL_AMBIENT,
(float *) &(This->current_material.u1.ambient));
glMaterialfv(GL_FRONT_AND_BACK,
GL_SPECULAR,
(float *) &(This->current_material.u2.specular));
glMaterialfv(GL_FRONT_AND_BACK,
GL_EMISSION,
(float *) &(This->current_material.u3.emissive));
glMaterialf(GL_FRONT_AND_BACK,
GL_SHININESS,
This->current_material.u4.power); /* Not sure about this... */
LEAVE_GL();
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
DWORD dwLightIndex,
LPD3DLIGHT7 lpLight)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
if (TRACE_ON(ddraw)) {
TRACE(" setting light : \n");
dump_D3DLIGHT7(lpLight);
}
if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
This->set_lights |= 0x00000001 << dwLightIndex;
This->light_parameters[dwLightIndex] = *lpLight;
/* Some checks to print out nice warnings :-) */
switch (lpLight->dltType) {
case D3DLIGHT_DIRECTIONAL:
case D3DLIGHT_POINT:
/* These are handled properly... */
break;
case D3DLIGHT_SPOT:
if ((lpLight->dvTheta != 0.0) ||
(lpLight->dvTheta != lpLight->dvPhi)) {
ERR("dvTheta not fully supported yet !\n");
}
break;
default:
ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
}
/* This will force the Light setting on next drawing of primitives */
glThis->transform_state = GL_TRANSFORM_NONE;
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
DWORD dwLightIndex,
BOOL bEnable)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
ENTER_GL();
if (bEnable) {
if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
/* Set the default parameters.. */
TRACE(" setting default light parameters...\n");
GL_IDirect3DDeviceImpl_7_SetLight(iface, dwLightIndex, &(This->light_parameters[dwLightIndex]));
}
glEnable(GL_LIGHT0 + dwLightIndex);
if ((This->active_lights & (0x00000001 << dwLightIndex)) == 0) {
/* This light gets active... Need to update its parameters to GL before the next drawing */
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
This->active_lights |= 0x00000001 << dwLightIndex;
glThis->transform_state = GL_TRANSFORM_NONE;
}
} else {
glDisable(GL_LIGHT0 + dwLightIndex);
This->active_lights &= ~(0x00000001 << dwLightIndex);
}
LEAVE_GL();
return DD_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation)
{
ICOM_THIS(IDirect3DDeviceImpl,iface);
IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
if (dwIndex >= This->max_clipping_planes) {
return DDERR_INVALIDPARAMS;
}
TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
/* This is to force the reset of the transformation matrices on the next drawing.
* This is needed to use the correct matrices for the various clipping planes.
*/
glThis->transform_state = GL_TRANSFORM_NONE;
return D3D_OK;
}
HRESULT WINAPI
GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
LPD3DVIEWPORT7 lpData)
{
ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
if (TRACE_ON(ddraw)) {
TRACE(" viewport is : \n");
TRACE(" - dwX = %ld dwY = %ld\n",
lpData->dwX, lpData->dwY);
TRACE(" - dwWidth = %ld dwHeight = %ld\n",
lpData->dwWidth, lpData->dwHeight);
TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
lpData->dvMinZ, lpData->dvMaxZ);
}
ENTER_GL();
/* Set the viewport */
if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
(lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
}
if ((lpData->dwX != This->active_viewport.dwX) ||
(lpData->dwY != This->active_viewport.dwY) ||
(lpData->dwWidth != This->active_viewport.dwWidth) ||
(lpData->dwHeight != This->active_viewport.dwHeight)) {
glViewport(lpData->dwX,
This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
lpData->dwWidth, lpData->dwHeight);
}
LEAVE_GL();
This->active_viewport = *lpData;
return DD_OK;
}
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
# define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun))
#else
# define XCAST(fun) (void*)
#endif
ICOM_VTABLE(IDirect3DDevice7) VTABLE_IDirect3DDevice7 =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
};
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
#undef XCAST
#endif
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
# define XCAST(fun) (typeof(VTABLE_IDirect3DDevice3.fun))
#else
# define XCAST(fun) (void*)
#endif
ICOM_VTABLE(IDirect3DDevice3) VTABLE_IDirect3DDevice3 =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
XCAST(GetLightState) Main_IDirect3DDeviceImpl_3_2T_GetLightState,
XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
};
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
#undef XCAST
#endif
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
# define XCAST(fun) (typeof(VTABLE_IDirect3DDevice2.fun))
#else
# define XCAST(fun) (void*)
#endif
ICOM_VTABLE(IDirect3DDevice2) VTABLE_IDirect3DDevice2 =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
};
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
#undef XCAST
#endif
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
# define XCAST(fun) (typeof(VTABLE_IDirect3DDevice.fun))
#else
# define XCAST(fun) (void*)
#endif
ICOM_VTABLE(IDirect3DDevice) VTABLE_IDirect3DDevice =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
};
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
#undef XCAST
#endif
static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
WINE_GL_BUFFER_TYPE buffer_type,
DWORD dwCount,
LPD3DRECT lpRects,
DWORD dwFlags,
DWORD dwColor,
D3DVALUE dvZ,
DWORD dwStencil)
{
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
GLbitfield bitfield = 0;
D3DRECT rect;
int i;
TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
if (TRACE_ON(ddraw)) {
if (dwCount > 0) {
int i;
TRACE(" rectangles : \n");
for (i = 0; i < dwCount; i++) {
TRACE(" - %ld x %ld %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
}
}
}
if (dwCount == 0) {
dwCount = 1;
rect.u1.x1 = 0;
rect.u2.y1 = 0;
rect.u3.x2 = This->surface->surface_desc.dwWidth;
rect.u4.y2 = This->surface->surface_desc.dwHeight;
lpRects = &rect;
}
/* Clears the screen */
ENTER_GL();
if (dwFlags & D3DCLEAR_TARGET) {
if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
/* TODO: optimize here the case where Clear changes all the screen... */
This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
}
glThis->state[buffer_type] = SURFACE_GL;
}
if (dwFlags & D3DCLEAR_ZBUFFER) {
bitfield |= GL_DEPTH_BUFFER_BIT;
if (glThis->depth_mask == FALSE) {
glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
}
if (dvZ != glThis->prev_clear_Z) {
glClearDepth(dvZ);
glThis->prev_clear_Z = dvZ;
}
TRACE(" depth value : %f\n", dvZ);
}
if (dwFlags & D3DCLEAR_STENCIL) {
bitfield |= GL_STENCIL_BUFFER_BIT;
if (dwStencil != glThis->prev_clear_stencil) {
glClearStencil(dwStencil);
glThis->prev_clear_stencil = dwStencil;
}
TRACE(" stencil value : %ld\n", dwStencil);
}
if (dwFlags & D3DCLEAR_TARGET) {
bitfield |= GL_COLOR_BUFFER_BIT;
if (dwColor != glThis->prev_clear_color) {
glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
((dwColor >> 8) & 0xFF) / 255.0,
((dwColor >> 0) & 0xFF) / 255.0,
((dwColor >> 24) & 0xFF) / 255.0);
glThis->prev_clear_color = dwColor;
}
TRACE(" color value (ARGB) : %08lx\n", dwColor);
}
glEnable(GL_SCISSOR_TEST);
for (i = 0; i < dwCount; i++) {
glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
glClear(bitfield);
}
glDisable(GL_SCISSOR_TEST);
if (dwFlags & D3DCLEAR_ZBUFFER) {
if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
}
LEAVE_GL();
return DD_OK;
}
static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
DWORD dwCount,
LPD3DRECT lpRects,
DWORD dwFlags,
DWORD dwColor,
D3DVALUE dvZ,
DWORD dwStencil)
{
return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
}
static HRESULT
setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
{
IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
WINE_GL_BUFFER_TYPE buffer_type;
/* First check if we BLT to the backbuffer... */
if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
buffer_type = WINE_GL_BUFFER_BACK;
} else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
buffer_type = WINE_GL_BUFFER_FRONT;
} else {
ERR("Only BLT override to front or back-buffer is supported for now !\n");
return DDERR_INVALIDPARAMS;
}
if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
(rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
(rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
(rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
(rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
/* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
* GL to do it.
*/
return DDERR_INVALIDPARAMS;
}
*buffer_type_p = buffer_type;
return DD_OK;
}
HRESULT
d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
DWORD dwFlags, LPDDBLTFX lpbltfx)
{
WINE_GL_BUFFER_TYPE buffer_type;
D3DRECT rect;
if (rdst) {
rect.u1.x1 = rdst->left;
rect.u2.y1 = rdst->top;
rect.u3.x2 = rdst->right;
rect.u4.y2 = rdst->bottom;
} else {
rect.u1.x1 = 0;
rect.u2.y1 = 0;
rect.u3.x2 = This->surface_desc.dwWidth;
rect.u4.y2 = This->surface_desc.dwHeight;
}
if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
if (dwFlags & DDBLT_COLORFILL) {
/* This is easy to handle for the D3D Device... */
DWORD color;
GLenum prev_draw;
/* The color as given in the Blt function is in the format of the frame-buffer...
* 'clear' expect it in ARGB format => we need to do some conversion :-)
*/
if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
if (This->palette) {
color = ((0xFF000000) |
(This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
(This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
(This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
} else {
color = 0xFF000000;
}
} else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
(((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
(This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
(This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
(This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
(This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
if (lpbltfx->u5.dwFillColor == 0xFFFF) {
color = 0xFFFFFFFF;
} else {
color = ((0xFF000000) |
((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
((lpbltfx->u5.dwFillColor & 0x001F) << 3));
}
} else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
(This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
(This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
(This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
(This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
color = 0xFF000000 | lpbltfx->u5.dwFillColor;
} else {
ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
return DDERR_INVALIDPARAMS;
}
} else {
ERR("Wrong surface type for BLT override !\n");
return DDERR_INVALIDPARAMS;
}
TRACE(" executing D3D Device override.\n");
ENTER_GL();
glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
if (buffer_type == WINE_GL_BUFFER_FRONT)
glDrawBuffer(GL_FRONT);
else
glDrawBuffer(GL_BACK);
d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
glDrawBuffer(prev_draw);
LEAVE_GL();
return DD_OK;
} else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
/* Normal blit without any special case... */
if (src != NULL) {
/* And which has a SRC surface */
IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
(src_impl->d3ddevice == This->d3ddevice) &&
((dwFlags & DDBLT_KEYSRC) == 0)) {
/* Both are 3D devices and using the same GL device and the Blt is without color-keying */
D3DRECT src_rect;
int width, height;
GLenum prev_draw;
WINE_GL_BUFFER_TYPE src_buffer_type;
IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
BOOLEAN initial = FALSE;
DWORD opt_bitmap;
int x, y;
if (rsrc) {
src_rect.u1.x1 = rsrc->left;
src_rect.u2.y1 = rsrc->top;
src_rect.u3.x2 = rsrc->right;
src_rect.u4.y2 = rsrc->bottom;
} else {
src_rect.u1.x1 = 0;
src_rect.u2.y1 = 0;
src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
}
width = src_rect.u3.x2 - src_rect.u1.x1;
height = src_rect.u4.y2 - src_rect.u2.y1;
if ((width != (rect.u3.x2 - rect.u1.x1)) ||
(height != (rect.u4.y2 - rect.u2.y1))) {
FIXME(" buffer to buffer copy not supported with stretching yet !\n");
return DDERR_INVALIDPARAMS;
}
/* First check if we BLT from the backbuffer... */
if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
src_buffer_type = WINE_GL_BUFFER_BACK;
} else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
src_buffer_type = WINE_GL_BUFFER_FRONT;
} else {
ERR("Unexpected case in direct buffer to buffer copy !\n");
return DDERR_INVALIDPARAMS;
}
TRACE(" using direct buffer to buffer copy.\n");
ENTER_GL();
opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
LEAVE_GL();
return DDERR_INVALIDPARAMS;
}
glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
if (buffer_type == WINE_GL_BUFFER_FRONT)
glDrawBuffer(GL_FRONT);
else
glDrawBuffer(GL_BACK);
if (src_buffer_type == WINE_GL_BUFFER_FRONT)
glReadBuffer(GL_FRONT);
else
glReadBuffer(GL_BACK);
/* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
And directly re-draws this on the destination buffer. */
for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
int get_height;
if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
else
get_height = UNLOCK_TEX_SIZE;
for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
int get_width;
if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
else
get_width = UNLOCK_TEX_SIZE;
glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
0, UNLOCK_TEX_SIZE - get_height,
src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
get_width, get_height);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3d(rect.u1.x1 + x,
rect.u2.y1 + y + UNLOCK_TEX_SIZE,
0.5);
glTexCoord2f(1.0, 0.0);
glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
rect.u2.y1 + y + UNLOCK_TEX_SIZE,
0.5);
glTexCoord2f(1.0, 1.0);
glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
rect.u2.y1 + y,
0.5);
glTexCoord2f(0.0, 1.0);
glVertex3d(rect.u1.x1 + x,
rect.u2.y1 + y,
0.5);
glEnd();
}
}
upload_surface_to_tex_memory_release();
d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
glDrawBuffer(prev_draw);
LEAVE_GL();
return DD_OK;
} else {
/* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
(this prevents calling glReadPixels) */
D3DRECT src_rect;
int width, height;
GLenum prev_draw;
IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
BOOLEAN initial = FALSE;
DWORD opt_bitmap;
int x, y;
double x_stretch, y_stretch;
if (dwFlags & DDBLT_KEYSRC) {
/* As I have no game using this, did not bother to do it yet as I cannot test it anyway */
FIXME(" Blt overide with color-keying not supported yet.\n");
return DDERR_INVALIDPARAMS;
}
if (rsrc) {
src_rect.u1.x1 = rsrc->left;
src_rect.u2.y1 = rsrc->top;
src_rect.u3.x2 = rsrc->right;
src_rect.u4.y2 = rsrc->bottom;
} else {
src_rect.u1.x1 = 0;
src_rect.u2.y1 = 0;
src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
}
width = src_rect.u3.x2 - src_rect.u1.x1;
height = src_rect.u4.y2 - src_rect.u2.y1;
x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
TRACE(" using memory to buffer Blt overide.\n");
ENTER_GL();
opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
ERR(" unsupported pixel format at memory to buffer Blt overide.\n");
LEAVE_GL();
return DDERR_INVALIDPARAMS;
}
glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
if (buffer_type == WINE_GL_BUFFER_FRONT)
glDrawBuffer(GL_FRONT);
else
glDrawBuffer(GL_BACK);
/* Now the serious stuff happens. This is basically the same code that for the memory
flush to frame buffer ... with stretching and different rectangles added :-) */
for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
RECT flush_rect;
flush_rect.top = src_rect.u2.y1 + y;
flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
src_rect.u4.y2 :
(src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
flush_rect.left = src_rect.u1.x1 + x;
flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
src_rect.u3.x2 :
(src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3d(rect.u1.x1 + (x * x_stretch),
rect.u2.y1 + (y * y_stretch),
0.5);
glTexCoord2f(1.0, 0.0);
glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
rect.u2.y1 + (y * y_stretch),
0.5);
glTexCoord2f(1.0, 1.0);
glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
0.5);
glTexCoord2f(0.0, 1.0);
glVertex3d(rect.u1.x1 + (x * x_stretch),
rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
0.5);
glEnd();
}
}
upload_surface_to_tex_memory_release();
d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
glDrawBuffer(prev_draw);
LEAVE_GL();
return DD_OK;
}
}
}
return DDERR_INVALIDPARAMS;
}
HRESULT
d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
DWORD dsty, LPDIRECTDRAWSURFACE7 src,
LPRECT rsrc, DWORD trans)
{
RECT rsrc2;
RECT rdst;
IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
WINE_GL_BUFFER_TYPE buffer_type;
GLenum prev_draw;
DWORD opt_bitmap;
BOOLEAN initial;
int width, height, x, y;
/* Cannot support DSTCOLORKEY blitting... */
if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
if (rsrc == NULL) {
WARN("rsrc is NULL - getting the whole surface !!\n");
rsrc = &rsrc2;
rsrc->left = rsrc->top = 0;
rsrc->right = src_impl->surface_desc.dwWidth;
rsrc->bottom = src_impl->surface_desc.dwHeight;
} else {
rsrc2 = *rsrc;
rsrc = &rsrc2;
}
rdst.left = dstx;
rdst.top = dsty;
rdst.right = dstx + (rsrc->right - rsrc->left);
if (rdst.right > This->surface_desc.dwWidth) {
rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
rdst.right = This->surface_desc.dwWidth;
}
rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
if (rdst.bottom > This->surface_desc.dwHeight) {
rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
rdst.bottom = This->surface_desc.dwHeight;
}
width = rsrc->right - rsrc->left;
height = rsrc->bottom - rsrc->top;
if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
TRACE(" using BltFast memory to frame buffer overide.\n");
ENTER_GL();
opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
ERR(" unsupported pixel format at memory to buffer Blt overide.\n");
LEAVE_GL();
return DDERR_INVALIDPARAMS;
}
glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
if (buffer_type == WINE_GL_BUFFER_FRONT)
glDrawBuffer(GL_FRONT);
else
glDrawBuffer(GL_BACK);
/* Now the serious stuff happens. This is basically the same code that for the memory
flush to frame buffer but with different rectangles for source and destination :-) */
for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
RECT flush_rect;
flush_rect.top = rsrc->top + y;
flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
rsrc->bottom :
(rsrc->top + y + UNLOCK_TEX_SIZE));
for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
flush_rect.left = rsrc->left + x;
flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
rsrc->right :
(rsrc->left + x + UNLOCK_TEX_SIZE));
upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3d(rdst.left + x,
rdst.top + y,
0.5);
glTexCoord2f(1.0, 0.0);
glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
rdst.top + y,
0.5);
glTexCoord2f(1.0, 1.0);
glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
rdst.top + (y + UNLOCK_TEX_SIZE),
0.5);
glTexCoord2f(0.0, 1.0);
glVertex3d(rdst.left + x,
rdst.top + (y + UNLOCK_TEX_SIZE),
0.5);
glEnd();
}
}
upload_surface_to_tex_memory_release();
d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
((buffer_type == WINE_GL_BUFFER_BACK) && (prev_draw == GL_FRONT)))
glDrawBuffer(prev_draw);
LEAVE_GL();
return DD_OK;
}
void
d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
{
GLfloat height, width;
GLfloat trans_mat[16];
TRACE("(%p)\n", This);
width = This->surface->surface_desc.dwWidth;
height = This->surface->surface_desc.dwHeight;
/* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
to OpenGL screen coordinates (ie the upper left corner is not the same).
For Z, the mystery is what should it be mapped to ? Ie should the resulting range be between
-1.0 and 1.0 (as the X and Y coordinates) or between 0.0 and 1.0 ? */
trans_mat[ 0] = 2.0 / width; trans_mat[ 4] = 0.0; trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] = 1.0;
trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0; trans_mat[14] = -1.0;
trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0; trans_mat[15] = 1.0;
ENTER_GL();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
Correctness Tips section).
Basically, from what I understood, if the game does not filter the font texture,
as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
one and we will have strange artifacts (as the rounding and stuff may give different results
for different pixels, ie sometimes take the left pixel, sometimes the right).
*/
glTranslatef(0.375, 0.375, 0);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(trans_mat);
LEAVE_GL();
}
void
d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
{
TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
ENTER_GL();
if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf((float *) view_mat);
/* Now also re-loads all the Lights and Clipping Planes using the new matrices */
if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
GLint i;
DWORD runner;
for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
GLdouble plane[4];
plane[0] = This->clipping_planes[i].plane[0];
plane[1] = This->clipping_planes[i].plane[1];
plane[2] = This->clipping_planes[i].plane[2];
plane[3] = This->clipping_planes[i].plane[3];
glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
}
}
}
if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
GLint i;
DWORD runner;
for (i = 0, runner = 0x00000001; i < MAX_LIGHTS; i++, runner <<= 1) {
if (runner & This->active_lights) {
switch (This->light_parameters[i].dltType) {
case D3DLIGHT_DIRECTIONAL: {
float direction[4];
float cut_off = 180.0;
glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
direction[0] = This->light_parameters[i].dvDirection.u1.x;
direction[1] = This->light_parameters[i].dvDirection.u2.y;
direction[2] = This->light_parameters[i].dvDirection.u3.z;
direction[3] = 0.0;
glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
} break;
case D3DLIGHT_POINT: {
float position[4];
float cut_off = 180.0;
glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
position[0] = This->light_parameters[i].dvPosition.u1.x;
position[1] = This->light_parameters[i].dvPosition.u2.y;
position[2] = This->light_parameters[i].dvPosition.u3.z;
position[3] = 1.0;
glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
} break;
case D3DLIGHT_SPOT: {
float direction[4];
float position[4];
float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
glLightfv(GL_LIGHT0 + i, GL_AMBIENT, (float *) &(This->light_parameters[i].dcvAmbient));
glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, (float *) &(This->light_parameters[i].dcvDiffuse));
glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
direction[0] = This->light_parameters[i].dvDirection.u1.x;
direction[1] = This->light_parameters[i].dvDirection.u2.y;
direction[2] = This->light_parameters[i].dvDirection.u3.z;
direction[3] = 0.0;
glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
position[0] = This->light_parameters[i].dvPosition.u1.x;
position[1] = This->light_parameters[i].dvPosition.u2.y;
position[2] = This->light_parameters[i].dvPosition.u3.z;
position[3] = 1.0;
glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &(This->light_parameters[i].dvFalloff));
} break;
default:
/* No warning here as it's already done at light setting */
break;
}
}
}
}
glMultMatrixf((float *) world_mat);
}
if ((matrices & PROJMAT_CHANGED) != 0) {
glMatrixMode(GL_PROJECTION);
glLoadMatrixf((float *) proj_mat);
}
LEAVE_GL();
}
void
d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
{
IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
DWORD tex_mat, tex_stage;
TRACE("(%p,%08lx)\n", This, matrices);
if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
/* This will force an update of the transform state at the next drawing. */
glThis->transform_state = GL_TRANSFORM_NONE;
}
}
if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
{
ENTER_GL();
for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
if (matrices & tex_mat) {
if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
if (tex_stage == 0) {
/* No multi-texturing support for now ... */
glMatrixMode(GL_TEXTURE);
glLoadMatrixf((float *) This->tex_mat[tex_stage]);
if (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE))) {
This->tex_mat_is_identity[tex_stage] = FALSE;
} else {
This->tex_mat_is_identity[tex_stage] = TRUE;
}
}
} else {
if (tex_stage == 0) {
if (This->tex_mat_is_identity[tex_stage] == FALSE) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
This->tex_mat_is_identity[tex_stage] = TRUE;
}
}
}
}
}
LEAVE_GL();
}
}
/* TODO for both these functions :
- change / restore OpenGL parameters for pictures transfers in case they are ever modified
by other OpenGL code in D3D
- handle the case where no 'Begin / EndScene' was done between two locks
- handle the rectangles in the unlock too
- handle pitch correctly...
*/
static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
{
IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
WINE_GL_BUFFER_TYPE buffer_type;
RECT loc_rect;
if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
buffer_type = WINE_GL_BUFFER_FRONT;
if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
(gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
ERR("Change of front buffer.. Expect graphic corruptions !\n");
}
gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
} else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
buffer_type = WINE_GL_BUFFER_BACK;
if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
(gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
ERR("Change of back buffer.. Expect graphic corruptions !\n");
}
gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
} else {
ERR("Wrong surface type for locking !\n");
return;
}
if (pRect == NULL) {
loc_rect.top = 0;
loc_rect.left = 0;
loc_rect.bottom = This->surface_desc.dwHeight;
loc_rect.right = This->surface_desc.dwWidth;
pRect = &loc_rect;
}
/* Try to acquire the device critical section */
EnterCriticalSection(&(d3d_dev->crit));
if (gl_d3d_dev->lock_rect_valid[buffer_type] == TRUE) {
ERR("Two consecutive locks on %s buffer... Expect problems !\n",
(buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
}
gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
/* Check if the new rectangle is in the previous one or not.
If it is not, flush first the previous locks on screen.
*/
if ((pRect->top < gl_d3d_dev->lock_rect[buffer_type].top) ||
(pRect->left < gl_d3d_dev->lock_rect[buffer_type].left) ||
(pRect->right > gl_d3d_dev->lock_rect[buffer_type].right) ||
(pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
(buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
pRect->left, pRect->top, pRect->right, pRect->bottom,
gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
}
gl_d3d_dev->state[buffer_type] = SURFACE_GL;
gl_d3d_dev->lock_rect[buffer_type] = *pRect;
}
/* In the other case, do not upgrade the locking rectangle as it's no need... */
} else {
gl_d3d_dev->lock_rect[buffer_type] = *pRect;
}
if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
/* If the surface is already in memory, no need to do anything here... */
GLenum buffer_format;
GLenum buffer_color;
int y;
char *dst;
TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
pRect->left, pRect->top, pRect->right, pRect->bottom);
/* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
may only write to the device... But when we will blit it back to the screen, we need
also to blit correctly the parts the application did not overwrite... */
if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
(((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
(This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
(This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
(This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
(This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
buffer_format = GL_UNSIGNED_SHORT_5_6_5;
buffer_color = GL_RGB;
} else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
(This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
(This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
(This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
buffer_format = GL_UNSIGNED_BYTE;
buffer_color = GL_RGB;
} else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
(This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
(This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
(This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
buffer_color = GL_BGRA;
} else {
ERR(" unsupported pixel format at device locking.\n");
return;
}
} else {
ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
return;
}
ENTER_GL();
if (buffer_type == WINE_GL_BUFFER_FRONT)
/* Application wants to lock the front buffer */
glReadBuffer(GL_FRONT);
else
/* Application wants to lock the back buffer */
glReadBuffer(GL_BACK);
dst = ((char *)This->surface_desc.lpSurface) +
(pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
for (y = (This->surface_desc.dwHeight - pRect->top - 1);
y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
y--) {
glReadPixels(pRect->left, y,
pRect->right - pRect->left, 1,
buffer_color, buffer_format, dst);
dst += This->surface_desc.u1.lPitch;
}
gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
#if 0
/* I keep this code here as it's very useful to debug :-) */
{
static int flush_count = 0;
char buf[128];
FILE *f;
if ((++flush_count % 50) == 0) {
sprintf(buf, "lock_%06d.pnm", flush_count);
f = fopen(buf, "wb");
DDRAW_dump_surface_to_disk(This, f);
}
}
#endif
LEAVE_GL();
}
}
static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
RECT loc_rect;
IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
int x, y;
BOOLEAN initial = FALSE;
DWORD opt_bitmap;
/* Note : no need here to lock the 'device critical section' as we are already protected by
the GL critical section. */
if (pRect == NULL) {
loc_rect.top = 0;
loc_rect.left = 0;
loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
pRect = &loc_rect;
}
TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
ERR(" unsupported pixel format at frame buffer flush.\n");
return;
}
for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
RECT flush_rect;
flush_rect.top = y;
flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
/* First, upload the texture... */
flush_rect.left = x;
flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right) ? pRect->right : (x + UNLOCK_TEX_SIZE);
upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3d(x, y, 0.5);
glTexCoord2f(1.0, 0.0);
glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
glTexCoord2f(1.0, 1.0);
glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
glTexCoord2f(0.0, 1.0);
glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
glEnd();
}
}
upload_surface_to_tex_memory_release();
d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
#if 0
/* I keep this code here as it's very useful to debug :-) */
{
static int flush_count = 0;
char buf[128];
FILE *f;
if ((++flush_count % 50) == 0) {
sprintf(buf, "flush_%06d.pnm", flush_count);
f = fopen(buf, "wb");
DDRAW_dump_surface_to_disk(surf, f);
}
}
#endif
}
static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
{
WINE_GL_BUFFER_TYPE buffer_type;
IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
buffer_type = WINE_GL_BUFFER_FRONT;
} else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
buffer_type = WINE_GL_BUFFER_BACK;
} else {
ERR("Wrong surface type for locking !\n");
return;
}
if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
(buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
}
gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
/* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
if (buffer_type == WINE_GL_BUFFER_FRONT) {
GLenum prev_draw;
TRACE(" flushing front buffer immediatly on screen.\n");
ENTER_GL();
glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
glDrawBuffer(GL_FRONT);
/* Note: we do not use the application provided lock rectangle but our own stored at
lock time. This is because in old D3D versions, the 'lock' parameter did not
exist.
*/
d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_FRONT]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT]);
glDrawBuffer(prev_draw);
LEAVE_GL();
} else {
gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
}
}
/* And 'frees' the device critical section */
LeaveCriticalSection(&(d3d_dev->crit));
}
static void
apply_texture_state(IDirect3DDeviceImpl *This)
{
int stage, state;
/* Initialize texture stages states */
for (stage = 0; stage < MAX_TEXTURES; stage++) {
for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
if (This->state_block.set_flags.texture_stage_state[stage][state] == TRUE) {
IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
stage, state + 1, This->state_block.texture_stage_state[stage][state]);
}
}
}
}
HRESULT
d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface)
{
IDirect3DDeviceImpl *object;
IDirect3DDeviceGLImpl *gl_object;
IDirectDrawSurfaceImpl *surf;
HDC device_context;
XVisualInfo *vis;
int num;
int tex_num;
XVisualInfo template;
GLenum buffer = GL_FRONT;
int light;
GLint max_clipping_planes = 0;
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
if (object == NULL) return DDERR_OUTOFMEMORY;
gl_object = (IDirect3DDeviceGLImpl *) object;
object->ref = 1;
object->d3d = d3d;
object->surface = surface;
object->set_context = set_context;
object->clear = d3ddevice_clear_back;
object->set_matrices = d3ddevice_set_matrices;
object->matrices_updated = d3ddevice_matrices_updated;
object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
InitializeCriticalSection(&(object->crit));
TRACE(" device critical section : %p\n", &(object->crit));
device_context = GetDC(surface->ddraw_owner->window);
gl_object->display = get_display(device_context);
gl_object->drawable = get_drawable(device_context);
ReleaseDC(surface->ddraw_owner->window,device_context);
ENTER_GL();
template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
if (vis == NULL) {
HeapFree(GetProcessHeap(), 0, object);
ERR("No visual found !\n");
LEAVE_GL();
return DDERR_INVALIDPARAMS;
} else {
TRACE(" visual found\n");
}
gl_object->gl_context = glXCreateContext(gl_object->display, vis,
NULL, GL_TRUE);
if (gl_object->gl_context == NULL) {
HeapFree(GetProcessHeap(), 0, object);
ERR("Error in context creation !\n");
LEAVE_GL();
return DDERR_INVALIDPARAMS;
} else {
TRACE(" context created (%p)\n", gl_object->gl_context);
}
/* Look for the front buffer and override its surface's Flip method (if in double buffering) */
for (surf = surface; surf != NULL; surf = surf->surface_owner) {
if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
surf->aux_ctx = (LPVOID) object;
surf->aux_data = (LPVOID) gl_object->drawable;
surf->aux_flip = opengl_flip;
buffer = GL_BACK;
break;
}
}
/* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
if (surf == NULL) {
TRACE(" no double buffering : drawing on the front buffer\n");
buffer = GL_FRONT;
}
for (surf = surface; surf != NULL; surf = surf->surface_owner) {
IDirectDrawSurfaceImpl *surf2;
for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
for (; surf2 != NULL; surf2 = surf2->next_attached) {
TRACE(" checking surface %p :", surf2);
if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
/* Override the Lock / Unlock function for all these surfaces */
surf2->lock_update_prev = surf2->lock_update;
surf2->lock_update = d3ddevice_lock_update;
surf2->unlock_update_prev = surf2->unlock_update;
surf2->unlock_update = d3ddevice_unlock_update;
/* And install also the blt / bltfast overrides */
surf2->aux_blt = d3ddevice_blt;
surf2->aux_bltfast = d3ddevice_bltfast;
TRACE(" overiding direct surface access.\n");
} else {
TRACE(" no overide.\n");
}
surf2->d3ddevice = object;
}
}
/* Set the various light parameters */
for (light = 0; light < MAX_LIGHTS; light++) {
/* Only set the fields that are not zero-created */
object->light_parameters[light].dltType = D3DLIGHT_DIRECTIONAL;
object->light_parameters[light].dcvDiffuse.u1.r = 1.0;
object->light_parameters[light].dcvDiffuse.u2.g = 1.0;
object->light_parameters[light].dcvDiffuse.u3.b = 1.0;
object->light_parameters[light].dvDirection.u3.z = 1.0;
}
/* Allocate memory for the matrices */
object->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
object->view_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
object->proj_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
memcpy(object->world_mat, id_mat, 16 * sizeof(float));
memcpy(object->view_mat , id_mat, 16 * sizeof(float));
memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
object->tex_mat[tex_num] = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
object->tex_mat_is_identity[tex_num] = TRUE;
}
/* Initialisation */
TRACE(" setting current context\n");
object->set_context(object);
TRACE(" current context set\n");
/* allocate the clipping planes */
glGetIntegerv(GL_MAX_CLIP_PLANES,&max_clipping_planes);
if (max_clipping_planes>32) {
object->max_clipping_planes=32;
} else {
object->max_clipping_planes = max_clipping_planes;
}
TRACE(" capable of %d clipping planes\n", (int)object->max_clipping_planes );
object->clipping_planes = (d3d7clippingplane*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
glHint(GL_FOG_HINT,GL_NICEST);
/* Initialize the various GL contexts to be in sync with what we store locally */
glClearDepth(0.0);
glClearStencil(0);
glClearColor(0.0, 0.0, 0.0, 0.0);
glDepthMask(GL_TRUE);
gl_object->depth_mask = TRUE;
glEnable(GL_DEPTH_TEST);
gl_object->depth_test = TRUE;
glDisable(GL_ALPHA_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_FOG);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
gl_object->current_tex_env = GL_REPLACE;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDrawBuffer(buffer);
glReadBuffer(buffer);
/* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
LEAVE_GL();
gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
/* fill_device_capabilities(d3d->ddraw); */
ICOM_INIT_INTERFACE(object, IDirect3DDevice, VTABLE_IDirect3DDevice);
ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
*obj = object;
TRACE(" creating implementation at %p.\n", *obj);
/* And finally warn D3D that this device is now present */
object->d3d->d3d_added_device(object->d3d, object);
/* FIXME: Should handle other versions than just 7 */
InitDefaultStateBlock(&object->state_block, 7);
/* Apply default render state and texture stage state values */
apply_render_state(object, &object->state_block);
apply_texture_state(object);
/* And fill the fog table with the default fog value */
build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
return DD_OK;
}