device.c 295 KB
Newer Older
1 2 3
/*
 * IWineD3DDevice implementation
 *
4
 * Copyright 2002 Lionel Ulmer
5
 * Copyright 2002-2005 Jason Edmeades
6 7
 * Copyright 2003-2004 Raphael Junqueira
 * Copyright 2004 Christian Costa
8
 * Copyright 2005 Oliver Stieber
9
 * Copyright 2006 Stefan Dsinger for CodeWeavers
10
 * Copyright 2006 Henri Verbeet
11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * 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
24
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 26 27
 */

#include "config.h"
28
#include <stdio.h>
29 30 31
#ifdef HAVE_FLOAT_H
# include <float.h>
#endif
32 33 34
#include "wined3d_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35
WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36
#define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37

38 39 40
/* Define the default light parameters as specified by MSDN */
const WINED3DLIGHT WINED3D_default_light = {

41 42 43 44 45 46 47 48 49 50 51
    WINED3DLIGHT_DIRECTIONAL, /* Type */
    { 1.0, 1.0, 1.0, 0.0 },   /* Diffuse r,g,b,a */
    { 0.0, 0.0, 0.0, 0.0 },   /* Specular r,g,b,a */
    { 0.0, 0.0, 0.0, 0.0 },   /* Ambient r,g,b,a, */
    { 0.0, 0.0, 0.0 },        /* Position x,y,z */
    { 0.0, 0.0, 1.0 },        /* Direction x,y,z */
    0.0,                      /* Range */
    0.0,                      /* Falloff */
    0.0, 0.0, 0.0,            /* Attenuation 0,1,2 */
    0.0,                      /* Theta */
    0.0                       /* Phi */
52 53
};

Oliver Stieber's avatar
Oliver Stieber committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
/* 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 */
};

/* 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;
}

74 75 76
/* allocate one pbuffer per surface */
BOOL pbuffer_per_surface = FALSE;

77 78 79
/* static function declarations */
static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);

80
static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
81

82 83
static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);

84
/* helper macros */
85
#define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
86

87
#define D3DCREATEOBJECTINSTANCE(object, type) { \
88 89 90 91 92 93 94 95 96
    object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
    D3DMEMCHECK(object, pp##type); \
    object->lpVtbl = &IWineD3D##type##_Vtbl;  \
    object->wineD3DDevice = This; \
    object->parent       = parent; \
    object->ref          = 1; \
    *pp##type = (IWineD3D##type *) object; \
}

97 98 99 100 101 102 103 104 105 106
#define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
    object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
    D3DMEMCHECK(object, pp##type); \
    object->lpVtbl = &IWineD3D##type##_Vtbl;  \
    object->parent       = parent; \
    object->ref          = 1; \
    object->baseShader.device = (IWineD3DDevice*) This; \
    *pp##type = (IWineD3D##type *) object; \
}

107
#define  D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
108 109 110
    object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
    D3DMEMCHECK(object, pp##type); \
    object->lpVtbl = &IWineD3D##type##_Vtbl;  \
111 112 113 114 115 116 117
    object->resource.wineD3DDevice   = This; \
    object->resource.parent          = parent; \
    object->resource.resourceType    = d3dtype; \
    object->resource.ref             = 1; \
    object->resource.pool            = Pool; \
    object->resource.format          = Format; \
    object->resource.usage           = Usage; \
118 119
    object->resource.size            = _size; \
    /* Check that we have enough video ram left */ \
120
    if (Pool == WINED3DPOOL_DEFAULT) { \
121 122
        if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
            WARN("Out of 'bogus' video memory\n"); \
123
            HeapFree(GetProcessHeap(), 0, object); \
124
            *pp##type = NULL; \
125
            return WINED3DERR_OUTOFVIDEOMEMORY; \
126 127 128
        } \
        globalChangeGlRam(_size); \
    } \
129 130
    object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
    if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
131 132 133
        FIXME("Out of memory!\n"); \
        HeapFree(GetProcessHeap(), 0, object); \
        *pp##type = NULL; \
134
        return WINED3DERR_OUTOFVIDEOMEMORY; \
135
    } \
136
    *pp##type = (IWineD3D##type *) object; \
137
    IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
138
    TRACE("(%p) : Created resource %p\n", This, object); \
139 140
}

141
#define D3DINITIALIZEBASETEXTURE(_basetexture) { \
142
    _basetexture.levels     = Levels; \
143
    _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
144
    _basetexture.LOD        = 0; \
145
    _basetexture.dirty      = TRUE; \
146 147
}

148
/**********************************************************
149
 * Global variable / Constants follow
150
 **********************************************************/
151
const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};  /* When needed for comparisons */
152

153 154 155
/**********************************************************
 * Utility functions follow
 **********************************************************/
156
/* Convert the WINED3DLIGHT properties into equivalent gl lights */
157
static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
158 159 160 161 162 163 164 165

    float quad_att;
    float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
166
    glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

    /* Diffuse: */
    colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
    colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
    colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
    colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
    glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
    checkGLcall("glLightfv");

    /* Specular */
    colRGBA[0] = lightInfo->OriginalParms.Specular.r;
    colRGBA[1] = lightInfo->OriginalParms.Specular.g;
    colRGBA[2] = lightInfo->OriginalParms.Specular.b;
    colRGBA[3] = lightInfo->OriginalParms.Specular.a;
    glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
    checkGLcall("glLightfv");

    /* Ambient */
    colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
    colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
    colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
    colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
    glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
    checkGLcall("glLightfv");

    /* Attenuation - Are these right? guessing... */
    glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION,  lightInfo->OriginalParms.Attenuation0);
    checkGLcall("glLightf");
    glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION,    lightInfo->OriginalParms.Attenuation1);
    checkGLcall("glLightf");

198
    if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
199
        quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
200 201 202 203
    } else {
        quad_att = 0; /*  0 or  MAX?  (0 seems to be ok) */
    }

204 205 206 207 208
    if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
    glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
    checkGLcall("glLightf");

    switch (lightInfo->OriginalParms.Type) {
209
    case WINED3DLIGHT_POINT:
210 211 212 213 214 215 216 217
        /* Position */
        glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
        checkGLcall("glLightfv");
        glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
        checkGLcall("glLightf");
        /* FIXME: Range */
        break;

218
    case WINED3DLIGHT_SPOT:
219 220 221 222 223 224 225 226 227 228 229 230 231
        /* Position */
        glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
        checkGLcall("glLightfv");
        /* Direction */
        glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
        checkGLcall("glLightfv");
        glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
        checkGLcall("glLightf");
        glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
        checkGLcall("glLightf");
        /* FIXME: Range */
        break;

232
    case WINED3DLIGHT_DIRECTIONAL:
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
        /* Direction */
        glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
        checkGLcall("glLightfv");
        glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
        checkGLcall("glLightf");
        glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
        checkGLcall("glLightf");
        break;

    default:
        FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
    }

    /* Restore the modelview matrix */
    glPopMatrix();
}
249

250 251 252 253 254 255 256 257 258
/**********************************************************
 * GLSL helper functions follow
 **********************************************************/

/** Attach a GLSL pixel or vertex shader object to the shader program */
static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
259 260 261
    if (This->stateBlock->glsl_program && shaderObj != 0) {
        TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
        GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
        checkGLcall("glAttachObjectARB");
    }
}

/** Sets the GLSL program ID for the given pixel and vertex shader combination.
 * It sets the programId on the current StateBlock (because it should be called
 * inside of the DrawPrimitive() part of the render loop).
 *
 * If a program for the given combination does not exist, create one, and store
 * the program in the list.  If it creates a program, it will link the given 
 * objects, too.
 * 
 * We keep the shader programs around on a list because linking
 * shader objects together is an expensive operation.  It's much
 * faster to loop through a list of pre-compiled & linked programs
 * each time that the application sets a new pixel or vertex shader
 * than it is to re-link them together at that time.
 *
 * The list will be deleted in IWineD3DDevice::Release().
 */
void set_glsl_shader_program(IWineD3DDevice *iface) {

    IWineD3DDeviceImpl *This               = (IWineD3DDeviceImpl *)iface;
    IWineD3DPixelShader  *pshader          = This->stateBlock->pixelShader;
    IWineD3DVertexShader *vshader          = This->stateBlock->vertexShader;
    struct glsl_shader_prog_link *curLink  = NULL;
    struct glsl_shader_prog_link *newLink  = NULL;
    struct list *ptr                       = NULL;
    GLhandleARB programId                  = 0;
291 292
    int i;
    char glsl_name[8];
293 294 295 296 297 298 299 300 301
    
    ptr = list_head( &This->glsl_shader_progs );
    while (ptr) {
        /* At least one program exists - see if it matches our ps/vs combination */
        curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
        if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
            /* Existing Program found, use it */
            TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n", 
                   curLink->programId);
302
            This->stateBlock->glsl_program = curLink;
303 304 305 306 307
            return;
        }
        /* This isn't the entry we need - try the next one */
        ptr = list_next( &This->glsl_shader_progs, ptr );
    }
308

309 310 311
    /* If we get to this point, then no matching program exists, so we create one */
    programId = GL_EXTCALL(glCreateProgramObjectARB());
    TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
312 313 314 315

    /* Allocate a new link for the list of programs */
    newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
    newLink->programId    = programId;
316
    This->stateBlock->glsl_program = newLink;
317 318
   
    /* Attach GLSL vshader */ 
319
    if (NULL != vshader && This->vs_selected_mode == SHADER_GLSL) {
320 321 322
        int i;
        int max_attribs = 16;   /* TODO: Will this always be the case? It is at the moment... */
        char tmp_name[10];
323 324
    
        TRACE("Attaching vertex shader to GLSL program\n");    
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
        attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
        
        /* Bind vertex attributes to a corresponding index number to match
         * the same index numbers as ARB_vertex_programs (makes loading
         * vertex attributes simpler).  With this method, we can use the
         * exact same code to load the attributes later for both ARB and 
         * GLSL shaders.
         * 
         * We have to do this here because we need to know the Program ID
         * in order to make the bindings work, and it has to be done prior
         * to linking the GLSL program. */
        for (i = 0; i < max_attribs; ++i) {
             snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
             GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
        }
        checkGLcall("glBindAttribLocationARB");
341
        newLink->vertexShader = vshader;
342 343
    }
    
344
    /* Attach GLSL pshader */
345
    if (NULL != pshader && This->ps_selected_mode == SHADER_GLSL) {
346
        TRACE("Attaching pixel shader to GLSL program\n");
347
        attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
348 349 350
        newLink->pixelShader = pshader;
    }    

351 352 353 354 355
    /* Link the program */
    TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
    GL_EXTCALL(glLinkProgramARB(programId));
    print_glsl_info_log(&GLINFO_LOCATION, programId);
    list_add_head( &This->glsl_shader_progs, &newLink->entry);
356 357 358 359 360 361 362 363 364 365 366 367

    newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
    for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
        snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
        newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
    }
    newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
    for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
        snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
        newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
    }

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
    return;
}

/** Detach the GLSL pixel or vertex shader object from the shader program */
static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    if (shaderObj != 0 && programId != 0) {
        TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
        GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
        checkGLcall("glDetachObjectARB");
    }
}

/** Delete a GLSL shader program */
static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    
    if (obj != 0) {
        TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
        GL_EXTCALL(glDeleteObjectARB(obj));
        checkGLcall("glDeleteObjectARB");
    }
}

/** Delete the list of linked programs this shader is associated with.
 * Also at this point, check to see if there are any objects left attached
 * to each GLSL program.  If not, delete the GLSL program object.
 * This will be run when a device is released. */
static void delete_glsl_shader_list(IWineD3DDevice* iface) {
    
    struct list *ptr                       = NULL;
    struct glsl_shader_prog_link *curLink  = NULL;
    IWineD3DDeviceImpl *This               = (IWineD3DDeviceImpl *)iface;
    
    int numAttached = 0;
    int i;
    GLhandleARB objList[2];   /* There should never be more than 2 objects attached 
                                 (one pixel shader and one vertex shader at most) */
    
    ptr = list_head( &This->glsl_shader_progs );
    while (ptr) {
        /* First, get the current item,
         * save the link to the next pointer, 
         * detach and delete shader objects,
         * then de-allocate the list item's memory */
        curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
        ptr = list_next( &This->glsl_shader_progs, ptr );

        /* See if this object is still attached to the program - it may have been detached already */
        GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
        TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
        for (i = 0; i < numAttached; i++) {
            detach_glsl_shader(iface, objList[i], curLink->programId);
        }
        
        delete_glsl_shader_program(iface, curLink->programId);

428 429 430 431
        /* Free the uniform locations */
        HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
        HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);

432 433 434 435 436 437
        /* Free the memory for this list item */    
        HeapFree(GetProcessHeap(), 0, curLink);
    }
}


438
/* Apply the current values to the specified texture stage */
439
static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
440 441 442
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    float col[4];

443 444 445 446
    union {
        float f;
        DWORD d;
    } tmpvalue;
447

448 449 450 451
    /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
    clamping, MIPLOD, etc. This will work for up to 16 samplers.
    */
   
452
    if (Sampler >= GL_LIMITS(sampler_stages)) {
453
        FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
454 455
        return;
    }
456
    VTRACE(("Activating appropriate texture state %d\n", Sampler));
457 458
    if (GL_SUPPORT(ARB_MULTITEXTURE)) {
        ENTER_GL();
459
        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
460
        checkGLcall("glActiveTextureARB");
461 462 463 464 465 466
        LEAVE_GL();
        /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
    } else if (Sampler > 0) {
        FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
        return;
    }
467

468 469 470 471 472 473
    /* TODO: change this to a lookup table
        LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
        LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
        etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
        especially when there are a number of groups of states. */

474
    TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490

    /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list  */
#define APPLY_STATE(_state)     IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
/* these are the only two supported states that need to be applied */
    APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
    APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
#if 0 /* not supported at the moment */
    APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
    APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
    APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
    APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
    APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
    APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
    APPLY_STATE(WINED3DTSS_RESULTARG);
    APPLY_STATE(WINED3DTSS_CONSTANT);
#endif
491
    /* a quick sanity check in case someone forgot to update this function */
492 493
    if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
        FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
494
    }
495
#undef APPLY_STATE
496

497 498 499 500 501 502 503
    /* apply any sampler states that always need applying */
    if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
        tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
        glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
                GL_TEXTURE_LOD_BIAS_EXT,
                tmpvalue.f);
        checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
504 505
    }

506
    D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
507 508 509
    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
    checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");

510 511
    /* TODO: NV_POINT_SPRITE */
    if (GL_SUPPORT(ARB_POINT_SPRITE)) {
512
        if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
513 514 515 516
           /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
           glDisable(GL_POINT_SMOOTH);

           /* Centre the texture on the vertex */
517
           VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
518 519
           glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);

520
           VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
521 522
           glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
           checkGLcall("glTexEnvf(...)");
523
           VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
524 525 526
           glEnable( GL_POINT_SPRITE_ARB );
           checkGLcall("glEnable(...)");
        } else {
527
           VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
528 529 530 531 532
           glDisable( GL_POINT_SPRITE_ARB );
           checkGLcall("glEnable(...)");
        }
    }

533
    TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
534 535 536 537 538 539
}

/**********************************************************
 * IUnknown parts follows
 **********************************************************/

540
static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
541
{
542
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
543

544
    TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
545
    if (IsEqualGUID(riid, &IID_IUnknown)
546
        || IsEqualGUID(riid, &IID_IWineD3DBase)
547 548 549
        || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
        IUnknown_AddRef(iface);
        *ppobj = This;
550
        return S_OK;
551
    }
552
    *ppobj = NULL;
553 554 555
    return E_NOINTERFACE;
}

556
static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
557 558 559
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    ULONG refCount = InterlockedIncrement(&This->ref);

560
    TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
561 562 563
    return refCount;
}

564
static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
565 566 567
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    ULONG refCount = InterlockedDecrement(&This->ref);

568
    TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
569 570

    if (!refCount) {
571 572 573 574
        if (This->fbo) {
            GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
        }

575
        /* TODO: Clean up all the surfaces and textures! */
576 577
        /* NOTE: You must release the parent if the object was created via a callback
        ** ***************************/
578

579
        /* Delete any GLSL shader programs that may exist */
580 581
        if (This->vs_selected_mode == SHADER_GLSL ||
            This->ps_selected_mode == SHADER_GLSL)
582 583
            delete_glsl_shader_list(iface);
    
584 585 586 587 588 589 590 591 592 593 594 595 596 597
        /* Release the update stateblock */
        if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
            if(This->updateStateBlock != This->stateBlock)
                FIXME("(%p) Something's still holding the Update stateblock\n",This);
        }
        This->updateStateBlock = NULL;
        { /* because were not doing proper internal refcounts releasing the primary state block
            causes recursion with the extra checks in ResourceReleased, to avoid this we have
            to set this->stateBlock = NULL; first */
            IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
            This->stateBlock = NULL;

            /* Release the stateblock */
            if(IWineD3DStateBlock_Release(stateBlock) > 0){
598 599
                    FIXME("(%p) Something's still holding the Update stateblock\n",This);
            }
600
        }
Oliver Stieber's avatar
Oliver Stieber committed
601

602 603 604 605
        if (This->resources != NULL ) {
            FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
            dumpResources(This->resources);
        }
Oliver Stieber's avatar
Oliver Stieber committed
606

607

608
        IWineD3D_Release(This->wineD3D);
609
        This->wineD3D = NULL;
610
        HeapFree(GetProcessHeap(), 0, This);
611
        TRACE("Freed device  %p\n", This);
612
        This = NULL;
613 614
    }
    return refCount;
615 616
}

617 618 619
/**********************************************************
 * IWineD3DDevice implementation follows
 **********************************************************/
620
static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
621 622 623
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    *pParent = This->parent;
    IUnknown_AddRef(This->parent);
624
    return WINED3D_OK;
625 626
}

627 628 629 630
static void CreateVBO(IWineD3DVertexBufferImpl *object) {
    IWineD3DDeviceImpl *This = object->resource.wineD3DDevice;  /* Needed for GL_EXTCALL */
    GLenum error, glUsage;
    DWORD vboUsage = object->resource.usage;
631 632 633 634 635
    if(object->Flags & VBFLAG_VBOCREATEFAIL) {
        WARN("Creating a vbo failed once, not trying again\n");
        return;
    }

636
    TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p  Usage(%s)\n", object, debug_d3dusage(vboUsage));
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

    ENTER_GL();
    /* Make sure that the gl error is cleared. Do not use checkGLcall
      * here because checkGLcall just prints a fixme and continues. However,
      * if an error during VBO creation occurs we can fall back to non-vbo operation
      * with full functionality(but performance loss)
      */
    while(glGetError() != GL_NO_ERROR);

    /* Basically the FVF parameter passed to CreateVertexBuffer is no good
      * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
      * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
      * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
      * to check if the rhw and color values are in the correct format.
      */

    GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
    error = glGetError();
    if(object->vbo == 0 || error != GL_NO_ERROR) {
        WARN("Failed to create a VBO with error %d\n", error);
        goto error;
    }

    GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
    error = glGetError();
    if(error != GL_NO_ERROR) {
        WARN("Failed to bind the VBO, error %d\n", error);
        goto error;
    }

    /* Transformed vertices are horribly inflexible. If the app specifies an
      * vertex buffer with transformed vertices in default pool without DYNAMIC
      * usage assume DYNAMIC usage and print a warning. The app will have to update
      * the vertices regularily for them to be useful
      */
672
    if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
673 674 675 676 677 678 679 680 681 682 683 684 685 686
        !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
        WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
        vboUsage |= WINED3DUSAGE_DYNAMIC;
    }

    /* Don't use static, because dx apps tend to update the buffer
      * quite often even if they specify 0 usage
      */
    switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
        case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
            TRACE("Gl usage = GL_STREAM_DRAW\n");
            glUsage = GL_STREAM_DRAW_ARB;
            break;
        case D3DUSAGE_WRITEONLY:
687
            TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
688 689 690 691 692 693 694
            glUsage = GL_DYNAMIC_DRAW_ARB;
            break;
        case D3DUSAGE_DYNAMIC:
            TRACE("Gl usage = GL_STREAM_COPY\n");
            glUsage = GL_STREAM_COPY_ARB;
            break;
        default:
695
            TRACE("Gl usage = GL_DYNAMIC_COPY\n");
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
            glUsage = GL_DYNAMIC_COPY_ARB;
            break;
    }

    /* Reserve memory for the buffer. The amount of data won't change
      * so we are safe with calling glBufferData once with a NULL ptr and
      * calling glBufferSubData on updates
      */
    GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
    error = glGetError();
    if(error != GL_NO_ERROR) {
        WARN("glBufferDataARB failed with error %d\n", error);
        goto error;
    }

    LEAVE_GL();

    return;
    error:
    /* Clean up all vbo init, but continue because we can work without a vbo :-) */
    FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
    if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
    object->vbo = 0;
719
    object->Flags |= VBFLAG_VBOCREATEFAIL;
720 721 722 723
    LEAVE_GL();
    return;
}

724
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage, 
725
                             DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
726
                             IUnknown *parent) {
727
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728
    IWineD3DVertexBufferImpl *object;
729
    WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
730 731
    int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
    BOOL conv;
732
    D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
733

734
    TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
735 736 737 738
    *ppVertexBuffer = (IWineD3DVertexBuffer *)object;

    if(Size == 0) return WINED3DERR_INVALIDCALL;

739
    if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
740 741 742
        object->resource.allocatedMemory  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
    }
    object->fvf = FVF;
743

744 745 746 747 748 749 750 751
    /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
     * drawStridedFast (half-life 2).
     *
     * Basically converting the vertices in the buffer is quite expensive, and observations
     * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
     * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
     *
     * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
752
     * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
753 754 755 756 757 758
     * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
     * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
     * dx7 apps.
     * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
     * more. In this call we can convert dx7 buffers too.
     */
759
    conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
760 761 762 763
    if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && 
        (dxVersion > 7 || !conv) ) {
        CreateVBO(object);

764
        /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
765 766 767 768
        if(dxVersion == 7 && object->vbo) {
            HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
            object->resource.allocatedMemory = NULL;
        }
769

770
    }
771
    return WINED3D_OK;
772
}
773

774
static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage, 
775
                                                    WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
776 777
                                                    HANDLE *sharedHandle, IUnknown *parent) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
778 779 780
    IWineD3DIndexBufferImpl *object;
    TRACE("(%p) Creating index buffer\n", This);
    
781
    /* Allocate the storage for the device */
782
    D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
783
    
784
    /*TODO: use VBO's */
785
    if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
786 787
        object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
    }
788

789
    TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format, 
790
                           debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
791 792
    *ppIndexBuffer = (IWineD3DIndexBuffer *) object;

793
    return WINED3D_OK;
794 795
}

796
static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
797

798 799
    IWineD3DDeviceImpl     *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DStateBlockImpl *object;
800
    int i, j;
801
    HRESULT temp_result;
802 803

    D3DCREATEOBJECTINSTANCE(object, StateBlock)
804
    object->blockType     = Type;
805 806 807

    /* Special case - Used during initialization to produce a placeholder stateblock
          so other functions called can update a state block                         */
808
    if (Type == WINED3DSBT_INIT) {
809
        /* Don't bother increasing the reference count otherwise a device will never
810
           be freed due to circular dependencies                                   */
811
        return WINED3D_OK;
812
    }
813 814 815 816
    
    temp_result = allocate_shader_constants(object);
    if (WINED3D_OK != temp_result)
        return temp_result;
817

818
    /* Otherwise, might as well set the whole state block to the appropriate values  */
819 820 821 822
    if (This->stateBlock != NULL)
        stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
    else
        memset(object->streamFreq, 1, sizeof(object->streamFreq));
823

824
    /* Reset the ref and type after kludging it */
825 826 827 828 829 830
    object->wineD3DDevice = This;
    object->ref           = 1;
    object->blockType     = Type;

    TRACE("Updating changed flags appropriate for type %d\n", Type);

831
    if (Type == WINED3DSBT_ALL) {
832

833
        TRACE("ALL => Pretend everything has changed\n");
834 835
        stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
    
836
    } else if (Type == WINED3DSBT_PIXELSTATE) {
837

838
        TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
839
        stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
840

841
        object->changed.pixelShader = TRUE;
842

843
        /* Pixel Shader Constants */
844
        for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
845
            object->changed.pixelShaderConstantsF[i] = TRUE;
846
        for (i = 0; i < MAX_CONST_B; ++i)
847
            object->changed.pixelShaderConstantsB[i] = TRUE;
848
        for (i = 0; i < MAX_CONST_I; ++i)
849
            object->changed.pixelShaderConstantsI[i] = TRUE;
850
        
851 852 853
        for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
            object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
        }
854
        for (j = 0; j < GL_LIMITS(texture_stages); j++) {
855 856 857 858 859 860 861 862 863 864
            for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
                object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
            }
        }
        for (j = 0 ; j < 16; j++) {
            for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {

                object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
            }
        }
865

866
    } else if (Type == WINED3DSBT_VERTEXSTATE) {
867

868
        TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
869
        stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
870

871
        object->changed.vertexShader = TRUE;
872 873

        /* Vertex Shader Constants */
874
        for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
875
            object->changed.vertexShaderConstantsF[i] = TRUE;
876
        for (i = 0; i < MAX_CONST_B; ++i)
877
            object->changed.vertexShaderConstantsB[i] = TRUE;
878
        for (i = 0; i < MAX_CONST_I; ++i)
879
            object->changed.vertexShaderConstantsI[i] = TRUE;
880
 
881 882 883
        for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
            object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
        }
884
        for (j = 0; j < GL_LIMITS(texture_stages); j++) {
885 886 887 888 889 890 891 892 893
            for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
                object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
            }
        }
        for (j = 0 ; j < 16; j++){
            for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
                object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
            }
        }
894 895 896 897 898 899 900 901 902 903 904 905

    /* Duplicate light chain */
    {
        PLIGHTINFOEL *src = NULL;
        PLIGHTINFOEL *dst = NULL;
        PLIGHTINFOEL *newEl = NULL;
        src = This->stateBlock->lights;
        object->lights = NULL;


        while (src) {
            newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
906
            if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
            memcpy(newEl, src, sizeof(PLIGHTINFOEL));
            newEl->prev = dst;
            newEl->changed = TRUE;
            newEl->enabledChanged = TRUE;
            if (dst == NULL) {
                object->lights = newEl;
            } else {
                dst->next = newEl;
            }
            dst = newEl;
            src = src->next;
        }

     }

    } else {
        FIXME("Unrecognized state block type %d\n", Type);
    }

    TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
927
    return WINED3D_OK;
928 929
}

930 931 932 933 934 935 936 937 938 939 940 941

/* ************************************
MSDN:
[in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.

Discard
 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise. 

If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.

******************************** */
 
942
static HRESULT  WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
943 944 945
    IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;    
    IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
    unsigned int pow2Width, pow2Height;
946
    unsigned int Size       = 1;
947
    const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
948
    TRACE("(%p) Create surface\n",This);
949
    
950 951 952 953 954
    /** FIXME: Check ranges on the inputs are valid 
     * MSDN
     *   MultisampleQuality
     *    [in] Quality level. The valid range is between zero and one less than the level
     *    returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType. 
955
     *    Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
956 957 958 959 960 961 962
     *    values of paired render targets, depth stencil surfaces, and the MultiSample type
     *    must all match.
      *******************************/


    /**
    * TODO: Discard MSDN
963
    * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
964 965 966 967 968 969 970
    *
    * If this flag is set, the contents of the depth stencil buffer will be
    * invalid after calling either IDirect3DDevice9::Present or  * IDirect3DDevice9::SetDepthStencilSurface
    * with a different depth surface.
    *
    *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
    ***************************/
971 972

    if(MultisampleQuality < 0) {
973
        FIXME("Invalid multisample level %d\n", MultisampleQuality);
974
        return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
975
    }
976 977

    if(MultisampleQuality > 0) {
978
        FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
979
        MultisampleQuality=0;
980 981
    }

982 983 984 985
    /** FIXME: Check that the format is supported
    *    by the device.
      *******************************/

986
    /* Non-power2 support */
987 988 989 990 991 992 993 994 995
    if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
        pow2Width = Width;
        pow2Height = Height;
    } else {
        /* Find the nearest pow2 match */
        pow2Width = pow2Height = 1;
        while (pow2Width < Width) pow2Width <<= 1;
        while (pow2Height < Height) pow2Height <<= 1;
    }
996

997 998 999 1000
    if (pow2Width > Width || pow2Height > Height) {
         /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
        if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
               || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1001
            FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
1002
                    This, Width, Height);
1003
            return WINED3DERR_NOTAVAILABLE;
1004
        }
1005
    }
1006

1007 1008 1009 1010
    /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
     *  it is based around 4x4 pixel blocks it requires padding, so allocate enough
     *  space!
      *********************************/
1011 1012 1013
    if (WINED3DFMT_UNKNOWN == Format) {
        Size = 0;
    } else if (Format == WINED3DFMT_DXT1) {
1014
        /* DXT1 is half byte per pixel */
1015
       Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1016 1017 1018

    } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
               Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1019
       Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1020
    } else {
1021
       /* The pitch is a multiple of 4 bytes */
1022
       Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1023
       Size *= pow2Height;
1024 1025
    }

1026
    /** Create and initialise the surface resource **/
1027
    D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1028 1029
    /* "Standalone" surface */
    IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1030

1031 1032 1033 1034
    object->currentDesc.Width      = Width;
    object->currentDesc.Height     = Height;
    object->currentDesc.MultiSampleType    = MultiSample;
    object->currentDesc.MultiSampleQuality = MultisampleQuality;
1035

1036
    /* Setup some glformat defaults */
1037 1038 1039
    object->glDescription.glFormat         = tableEntry->glFormat;
    object->glDescription.glFormatInternal = tableEntry->glInternal;
    object->glDescription.glType           = tableEntry->glType;
1040

1041 1042 1043 1044
    object->glDescription.textureName      = 0;
    object->glDescription.level            = Level;
    object->glDescription.target           = GL_TEXTURE_2D;

1045 1046 1047
    /* Internal data */
    object->pow2Width  = pow2Width;
    object->pow2Height = pow2Height;
1048 1049 1050 1051 1052 1053 1054 1055

    /* Flags */
    object->Flags      = 0; /* We start without flags set */
    object->Flags     |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
    object->Flags     |= Discard ? SFLAG_DISCARD : 0;
    object->Flags     |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
    object->Flags     |= Lockable ? SFLAG_LOCKABLE : 0;

1056 1057

    if (WINED3DFMT_UNKNOWN != Format) {
1058
        object->bytesPerPixel = tableEntry->bpp;
1059 1060
        object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
        object->pow2Size *= pow2Height;
1061 1062 1063 1064
    } else {
        object->bytesPerPixel = 0;
        object->pow2Size      = 0;
    }
1065 1066 1067

    /** TODO: change this into a texture transform matrix so that it's processed in hardware **/

1068
    TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1069

1070 1071 1072
    /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
    * this function is too deep to need to care about things like this.
    * Levels need to be checked too, and possibly Type since they all affect what can be done.
1073 1074
    * ****************************************/
    switch(Pool) {
1075
    case WINED3DPOOL_SCRATCH:
1076
        if(!Lockable)
1077
            FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1078 1079 1080
                which are mutually exclusive, setting lockable to true\n");
                Lockable = TRUE;
    break;
1081
    case WINED3DPOOL_SYSTEMMEM:
1082
        if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1083
                                    this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1084
    case WINED3DPOOL_MANAGED:
1085 1086 1087
        if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
                                                Usage of DYNAMIC which are mutually exclusive, not doing \
                                                anything just telling you.\n");
1088
    break;
1089
    case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1090
        if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1091
           && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1092
            WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1093
    break;
1094
    default:
1095 1096 1097
        FIXME("(%p) Unknown pool %d\n", This, Pool);
    break;
    };
1098

1099
    if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1100 1101
        FIXME("Trying to create a render target that isn't in the default pool\n");
    }
1102

1103
    /* mark the texture as dirty so that it gets loaded first time around*/
1104
    IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1105 1106
    TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
           This, Width, Height, Format, debug_d3dformat(Format),
1107
           (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

    /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
    if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
        This->ddraw_primary = (IWineD3DSurface *) object;

    /* Look at the implementation and set the correct Vtable */
    switch(Impl) {
        case SURFACE_OPENGL:
            /* Nothing to do, it's set already */
            break;

        case SURFACE_GDI:
            object->lpVtbl = &IWineGDISurface_Vtbl;
            break;

        default:
            /* To be sure to catch this */
            ERR("Unknown requested surface implementation %d!\n", Impl);
            IWineD3DSurface_Release((IWineD3DSurface *) object);
            return WINED3DERR_INVALIDCALL;
    }

    /* Call the private setup routine */
    return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1132 1133 1134

}

1135
static HRESULT  WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1136
                                                 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1137 1138 1139 1140
                                                 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
                                                 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1141
    IWineD3DTextureImpl *object;
1142 1143 1144 1145
    unsigned int i;
    UINT tmpW;
    UINT tmpH;
    HRESULT hr;
1146 1147
    unsigned int pow2Width;
    unsigned int pow2Height;
1148

1149

1150
    TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1151 1152
    TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
            Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1153

1154 1155 1156
    /* TODO: It should only be possible to create textures for formats 
             that are reported as supported */
    if (WINED3DFMT_UNKNOWN >= Format) {
1157
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1158
        return WINED3DERR_INVALIDCALL;
1159 1160
    }

1161
    D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1162
    D3DINITIALIZEBASETEXTURE(object->baseTexture);    
1163 1164
    object->width  = Width;
    object->height = Height;
1165 1166

    /** Non-power2 support **/
1167 1168 1169 1170 1171 1172 1173 1174 1175
    if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
        pow2Width = Width;
        pow2Height = Height;
    } else {
        /* Find the nearest pow2 match */
        pow2Width = pow2Height = 1;
        while (pow2Width < Width) pow2Width <<= 1;
        while (pow2Height < Height) pow2Height <<= 1;
    }
1176 1177 1178 1179 1180

    /** FIXME: add support for real non-power-two if it's provided by the video card **/
    /* Precalculated scaling for 'faked' non power of two texture coords */
    object->pow2scalingFactorX  =  (((float)Width)  / ((float)pow2Width));
    object->pow2scalingFactorY  =  (((float)Height) / ((float)pow2Height));
1181
    TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1182

1183 1184
    /* Calculate levels for mip mapping */
    if (Levels == 0) {
1185
        TRACE("calculating levels %d\n", object->baseTexture.levels);
1186 1187 1188
        object->baseTexture.levels++;
        tmpW = Width;
        tmpH = Height;
1189
        while (tmpW > 1 || tmpH > 1) {
1190 1191
            tmpW = max(1, tmpW >> 1);
            tmpH = max(1, tmpH >> 1);
1192 1193 1194 1195
            object->baseTexture.levels++;
        }
        TRACE("Calculated levels = %d\n", object->baseTexture.levels);
    }
1196

1197 1198 1199
    /* Generate all the surfaces */
    tmpW = Width;
    tmpH = Height;
1200
    for (i = 0; i < object->baseTexture.levels; i++)
1201
    {
1202
        /* use the callback to create the texture surface */
1203
        hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1204
        if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1205
            FIXME("Failed to create surface  %p\n", object);
1206
            /* clean up */
1207 1208
            object->surfaces[i] = NULL;
            IWineD3DTexture_Release((IWineD3DTexture *)object);
1209

1210 1211
            *ppTexture = NULL;
            return hr;
1212
        }
1213

H. Verbeet's avatar
H. Verbeet committed
1214
        IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1215 1216 1217 1218
        TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
        /* calculate the next mipmap level */
        tmpW = max(1, tmpW >> 1);
        tmpH = max(1, tmpH >> 1);
1219
    }
1220

1221
    TRACE("(%p) : Created  texture %p\n", This, object);
1222
    return WINED3D_OK;
1223 1224
}

1225
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1226 1227
                                                      UINT Width, UINT Height, UINT Depth,
                                                      UINT Levels, DWORD Usage,
1228
                                                      WINED3DFORMAT Format, WINED3DPOOL Pool,
1229 1230
                                                      IWineD3DVolumeTexture **ppVolumeTexture,
                                                      HANDLE *pSharedHandle, IUnknown *parent,
1231 1232 1233 1234 1235 1236 1237 1238 1239
                                                      D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {

    IWineD3DDeviceImpl        *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DVolumeTextureImpl *object;
    unsigned int               i;
    UINT                       tmpW;
    UINT                       tmpH;
    UINT                       tmpD;

1240 1241 1242
    /* TODO: It should only be possible to create textures for formats 
             that are reported as supported */
    if (WINED3DFMT_UNKNOWN >= Format) {
1243
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1244
        return WINED3DERR_INVALIDCALL;
1245 1246
    }

1247
    D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1248
    D3DINITIALIZEBASETEXTURE(object->baseTexture);
1249

1250
    TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
          Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));

    object->width  = Width;
    object->height = Height;
    object->depth  = Depth;

    /* Calculate levels for mip mapping */
    if (Levels == 0) {
        object->baseTexture.levels++;
        tmpW = Width;
        tmpH = Height;
        tmpD = Depth;
1263
        while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1264 1265 1266
            tmpW = max(1, tmpW >> 1);
            tmpH = max(1, tmpH >> 1);
            tmpD = max(1, tmpD >> 1);
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
            object->baseTexture.levels++;
        }
        TRACE("Calculated levels = %d\n", object->baseTexture.levels);
    }

    /* Generate all the surfaces */
    tmpW = Width;
    tmpH = Height;
    tmpD = Depth;

1277
    for (i = 0; i < object->baseTexture.levels; i++)
1278
    {
1279
        /* Create the volume */
1280
        D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1281
                           (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1282

1283
        /* Set its container to this object */
H. Verbeet's avatar
H. Verbeet committed
1284
        IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1285

1286
        /* calcualte the next mipmap level */
1287 1288 1289
        tmpW = max(1, tmpW >> 1);
        tmpH = max(1, tmpH >> 1);
        tmpD = max(1, tmpD >> 1);
1290 1291 1292 1293
    }

    *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
    TRACE("(%p) : Created volume texture %p\n", This, object);
1294
    return WINED3D_OK;
1295 1296
}

1297
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1298 1299
                                               UINT Width, UINT Height, UINT Depth,
                                               DWORD Usage,
1300
                                               WINED3DFORMAT Format, WINED3DPOOL Pool,
1301 1302 1303 1304
                                               IWineD3DVolume** ppVolume,
                                               HANDLE* pSharedHandle, IUnknown *parent) {

    IWineD3DDeviceImpl        *This = (IWineD3DDeviceImpl *)iface;
1305
    IWineD3DVolumeImpl        *object; /** NOTE: impl ref allowed since this is a create function **/
1306
    const PixelFormatDesc *formatDesc  = getFormatDescEntry(Format);
1307

1308
    D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1309

1310
    TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1311 1312
          Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));

1313 1314 1315
    object->currentDesc.Width   = Width;
    object->currentDesc.Height  = Height;
    object->currentDesc.Depth   = Depth;
1316
    object->bytesPerPixel       = formatDesc->bpp;
1317 1318 1319 1320

    /** Note: Volume textures cannot be dxtn, hence no need to check here **/
    object->lockable            = TRUE;
    object->locked              = FALSE;
1321
    memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1322 1323 1324
    object->dirty               = TRUE;

    return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1325 1326
}

1327
static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1328
                                                    UINT Levels, DWORD Usage,
1329
                                                    WINED3DFORMAT Format, WINED3DPOOL Pool,
1330 1331
                                                    IWineD3DCubeTexture **ppCubeTexture,
                                                    HANDLE *pSharedHandle, IUnknown *parent,
1332 1333
                                                    D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {

1334 1335
    IWineD3DDeviceImpl      *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1336
    unsigned int             i, j;
1337 1338 1339 1340
    UINT                     tmpW;
    HRESULT                  hr;
    unsigned int pow2EdgeLength  = EdgeLength;

1341 1342 1343
    /* TODO: It should only be possible to create textures for formats 
             that are reported as supported */
    if (WINED3DFMT_UNKNOWN >= Format) {
1344
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1345
        return WINED3DERR_INVALIDCALL;
1346 1347
    }

1348
    D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1349
    D3DINITIALIZEBASETEXTURE(object->baseTexture);
1350

1351
    TRACE("(%p) Create Cube Texture\n", This);
1352 1353 1354 1355 1356 1357 1358

    /** Non-power2 support **/

    /* Find the nearest pow2 match */
    pow2EdgeLength = 1;
    while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;

1359
    object->edgeLength           = EdgeLength;
1360 1361 1362 1363 1364 1365 1366 1367 1368
    /* TODO: support for native non-power 2 */
    /* Precalculated scaling for 'faked' non power of two texture coords */
    object->pow2scalingFactor    = ((float)EdgeLength) / ((float)pow2EdgeLength);

    /* Calculate levels for mip mapping */
    if (Levels == 0) {
        object->baseTexture.levels++;
        tmpW = EdgeLength;
        while (tmpW > 1) {
1369
            tmpW = max(1, tmpW >> 1);
1370 1371 1372 1373
            object->baseTexture.levels++;
        }
        TRACE("Calculated levels = %d\n", object->baseTexture.levels);
    }
1374 1375 1376 1377 1378 1379 1380

    /* Generate all the surfaces */
    tmpW = EdgeLength;
    for (i = 0; i < object->baseTexture.levels; i++) {

        /* Create the 6 faces */
        for (j = 0; j < 6; j++) {
1381

1382
            hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1383
                                   i /* Level */, &object->surfaces[j][i],pSharedHandle);
1384

1385
            if(hr!= WINED3D_OK) {
1386 1387
                /* clean up */
                int k;
1388
                int l;
1389
                for (l = 0; l < j; l++) {
1390 1391
                    IWineD3DSurface_Release(object->surfaces[j][i]);
                }
1392 1393
                for (k = 0; k < i; k++) {
                    for (l = 0; l < 6; l++) {
1394
                    IWineD3DSurface_Release(object->surfaces[l][j]);
1395 1396
                    }
                }
1397

1398 1399 1400 1401
                FIXME("(%p) Failed to create surface\n",object);
                HeapFree(GetProcessHeap(),0,object);
                *ppCubeTexture = NULL;
                return hr;
1402
            }
H. Verbeet's avatar
H. Verbeet committed
1403
            IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1404
            TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1405
        }
1406
        tmpW = max(1, tmpW >> 1);
1407 1408 1409 1410
    }

    TRACE("(%p) : Created Cube Texture %p\n", This, object);
    *ppCubeTexture = (IWineD3DCubeTexture *) object;
1411
    return WINED3D_OK;
1412 1413
}

1414
static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1415
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1416 1417
    IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */

1418
    if (NULL == ppQuery) {
1419
        /* Just a check to see if we support this type of query */
1420
        HRESULT hr = WINED3DERR_NOTAVAILABLE;
1421
        switch(Type) {
1422 1423
        case WINED3DQUERYTYPE_OCCLUSION:
            TRACE("(%p) occlusion query\n", This);
1424
            if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1425
                hr = WINED3D_OK;
1426 1427 1428
            else
                WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
            break;
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
        case WINED3DQUERYTYPE_VCACHE:
        case WINED3DQUERYTYPE_RESOURCEMANAGER:
        case WINED3DQUERYTYPE_VERTEXSTATS:
        case WINED3DQUERYTYPE_EVENT:
        case WINED3DQUERYTYPE_TIMESTAMP:
        case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
        case WINED3DQUERYTYPE_TIMESTAMPFREQ:
        case WINED3DQUERYTYPE_PIPELINETIMINGS:
        case WINED3DQUERYTYPE_INTERFACETIMINGS:
        case WINED3DQUERYTYPE_VERTEXTIMINGS:
        case WINED3DQUERYTYPE_PIXELTIMINGS:
        case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
        case WINED3DQUERYTYPE_CACHEUTILIZATION:
1442
        default:
1443
            FIXME("(%p) Unhandled query type %d\n", This, Type);
1444 1445 1446 1447 1448 1449
        }
        return hr;
    }

    D3DCREATEOBJECTINSTANCE(object, Query)
    object->type         = Type;
1450 1451
    /* allocated the 'extended' data based on the type of query requested */
    switch(Type){
1452
    case WINED3DQUERYTYPE_OCCLUSION:
1453
        if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1454 1455
            TRACE("(%p) Allocating data for an occlusion query\n", This);
            object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1456
            GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1457 1458
            break;
        }
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
    case WINED3DQUERYTYPE_VCACHE:
    case WINED3DQUERYTYPE_RESOURCEMANAGER:
    case WINED3DQUERYTYPE_VERTEXSTATS:
    case WINED3DQUERYTYPE_EVENT:
    case WINED3DQUERYTYPE_TIMESTAMP:
    case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
    case WINED3DQUERYTYPE_TIMESTAMPFREQ:
    case WINED3DQUERYTYPE_PIPELINETIMINGS:
    case WINED3DQUERYTYPE_INTERFACETIMINGS:
    case WINED3DQUERYTYPE_VERTEXTIMINGS:
    case WINED3DQUERYTYPE_PIXELTIMINGS:
    case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
    case WINED3DQUERYTYPE_CACHEUTILIZATION:
1472 1473 1474 1475
    default:
        object->extendedData = 0;
        FIXME("(%p) Unhandled query type %d\n",This , Type);
    }
1476
    TRACE("(%p) : Created Query %p\n", This, object);
1477
    return WINED3D_OK;
1478 1479 1480
}

/* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1481
static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS*  pPresentationParameters,                                                                   IWineD3DSwapChain** ppSwapChain,
1482 1483
                                                            IUnknown* parent,
                                                            D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1484
                                                            D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1485
    IWineD3DDeviceImpl      *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
1486 1487 1488 1489 1490 1491 1492

    HDC                     hDc;
    IWineD3DSwapChainImpl  *object; /** NOTE: impl ref allowed since this is a create function **/
    int                     num;
    XVisualInfo             template;
    GLXContext              oldContext;
    Drawable                oldDrawable;
1493
    HRESULT                 hr = WINED3D_OK;
Oliver Stieber's avatar
Oliver Stieber committed
1494 1495 1496 1497 1498

    TRACE("(%p) : Created Aditional Swap Chain\n", This);

   /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
   * does a device hold a reference to a swap chain giving them a lifetime of the device
1499
   * or does the swap chain notify the device of its destruction.
Oliver Stieber's avatar
Oliver Stieber committed
1500 1501
    *******************************/

1502
    /* Check the params */
1503
    if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1504 1505
        ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
        return WINED3DERR_INVALIDCALL;
1506 1507
    } else if (*pPresentationParameters->BackBufferCount > 1) {
        FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1508 1509
    }

Oliver Stieber's avatar
Oliver Stieber committed
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
    D3DCREATEOBJECTINSTANCE(object, SwapChain)

    /*********************
    * Lookup the window Handle and the relating X window handle
    ********************/

    /* Setup hwnd we are using, plus which display this equates to */
    object->win_handle = *(pPresentationParameters->hDeviceWindow);
    if (!object->win_handle) {
        object->win_handle = This->createParms.hFocusWindow;
    }

1522 1523 1524
    object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
    if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
        ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1525
        return WINED3DERR_NOTAVAILABLE;
1526
    }
Oliver Stieber's avatar
Oliver Stieber committed
1527 1528 1529
    hDc                = GetDC(object->win_handle);
    object->display    = get_display(hDc);
    ReleaseDC(object->win_handle, hDc);
1530
    TRACE("Using a display of %p %p\n", object->display, hDc);
Oliver Stieber's avatar
Oliver Stieber committed
1531 1532 1533

    if (NULL == object->display || NULL == hDc) {
        WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1534
        return WINED3DERR_NOTAVAILABLE;
Oliver Stieber's avatar
Oliver Stieber committed
1535 1536 1537 1538
    }

    if (object->win == 0) {
        WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1539
        return WINED3DERR_NOTAVAILABLE;
Oliver Stieber's avatar
Oliver Stieber committed
1540
    }
1541 1542 1543 1544

    object->orig_width = GetSystemMetrics(SM_CXSCREEN);
    object->orig_height = GetSystemMetrics(SM_CYSCREEN);

Oliver Stieber's avatar
Oliver Stieber committed
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
    /**
    * Create an opengl context for the display visual
    *  NOTE: the visual is chosen as the window is created and the glcontext cannot
    *     use different properties after that point in time. FIXME: How to handle when requested format
    *     doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
    *     it chooses is identical to the one already being used!
     **********************************/

    /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
    ENTER_GL();

    /* Create a new context for this swapchain */
    template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
    /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
    (or the best possible if none is requested) */
    TRACE("Found x visual ID  : %ld\n", template.visualid);

    object->visInfo   = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
    if (NULL == object->visInfo) {
        ERR("cannot really get XVisual\n");
        LEAVE_GL();
1566
        return WINED3DERR_NOTAVAILABLE;
Oliver Stieber's avatar
Oliver Stieber committed
1567 1568 1569 1570 1571 1572
    } else {
        int n, value;
        /* Write out some debug info about the visual/s */
        TRACE("Using x visual ID  : %ld\n", template.visualid);
        TRACE("        visual info: %p\n", object->visInfo);
        TRACE("        num items  : %d\n", num);
1573
        for (n = 0;n < num; n++) {
Oliver Stieber's avatar
Oliver Stieber committed
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
            TRACE("=====item=====: %d\n", n + 1);
            TRACE("   visualid      : %ld\n", object->visInfo[n].visualid);
            TRACE("   screen        : %d\n",  object->visInfo[n].screen);
            TRACE("   depth         : %u\n",  object->visInfo[n].depth);
            TRACE("   class         : %d\n",  object->visInfo[n].class);
            TRACE("   red_mask      : %ld\n", object->visInfo[n].red_mask);
            TRACE("   green_mask    : %ld\n", object->visInfo[n].green_mask);
            TRACE("   blue_mask     : %ld\n", object->visInfo[n].blue_mask);
            TRACE("   colormap_size : %d\n",  object->visInfo[n].colormap_size);
            TRACE("   bits_per_rgb  : %d\n",  object->visInfo[n].bits_per_rgb);
            /* log some extra glx info */
            glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
            TRACE("   gl_aux_buffers  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
            TRACE("   gl_buffer_size  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
            TRACE("   gl_red_size  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
            TRACE("   gl_green_size  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
            TRACE("   gl_blue_size  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
            TRACE("   gl_alpha_size  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
            TRACE("   gl_depth_size  : %d\n",  value);
            glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
            TRACE("   gl_stencil_size : %d\n",  value);
        }
1602
        /* Now choose a similar visual ID*/
Oliver Stieber's avatar
Oliver Stieber committed
1603 1604 1605 1606 1607 1608 1609 1610
    }
#ifdef USE_CONTEXT_MANAGER

    /** TODO: use a context mamager **/
#endif

    {
        IWineD3DSwapChain *implSwapChain;
1611
        if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1612
            /* The first time around we create the context that is shared with all other swapchains and render targets */
Oliver Stieber's avatar
Oliver Stieber committed
1613
            object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1614
            TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
Oliver Stieber's avatar
Oliver Stieber committed
1615 1616 1617 1618 1619 1620
        } else {

            TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
            /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
            /* and create a new context with the implicit swapchains context as the shared context */
            object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1621
            IWineD3DSwapChain_Release(implSwapChain);
Oliver Stieber's avatar
Oliver Stieber committed
1622 1623 1624 1625 1626 1627 1628 1629
        }
    }

    /* Cleanup */
    XFree(object->visInfo);
    object->visInfo = NULL;

    LEAVE_GL();
1630 1631 1632 1633

    if (!object->glCtx) {
        ERR("Failed to create GLX context\n");
        return WINED3DERR_NOTAVAILABLE;
Oliver Stieber's avatar
Oliver Stieber committed
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
    } else {
        TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
                object->win_handle, object->glCtx, object->win, object->visInfo);
    }

   /*********************
   * Windowed / Fullscreen
   *******************/

   /**
1644
   * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1645
   * so we should really check to see if there is a fullscreen swapchain already
1646
   * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
Oliver Stieber's avatar
Oliver Stieber committed
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
    **************************************/

   if (!*(pPresentationParameters->Windowed)) {

        DEVMODEW devmode;
        HDC      hdc;
        int      bpp = 0;

        /* Get info on the current display setup */
        hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
        bpp = GetDeviceCaps(hdc, BITSPIXEL);
        DeleteDC(hdc);

        /* Change the display settings */
        memset(&devmode, 0, sizeof(DEVMODEW));
        devmode.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
        devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
        devmode.dmPelsWidth  = *(pPresentationParameters->BackBufferWidth);
        devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
        MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
        ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);

        /* Make popup window */
        SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
        SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
                     *(pPresentationParameters->BackBufferWidth),
                     *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);

1675 1676 1677 1678
        /* For GetDisplayMode */
        This->ddraw_width = devmode.dmPelsWidth;
        This->ddraw_height = devmode.dmPelsHeight;
        This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
Oliver Stieber's avatar
Oliver Stieber committed
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
    }


    /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
     *  then the corresponding dimension of the client area of the hDeviceWindow
     *  (or the focus window, if hDeviceWindow is NULL) is taken.
      **********************/

    if (*(pPresentationParameters->Windowed) &&
        ((*(pPresentationParameters->BackBufferWidth)  == 0) ||
         (*(pPresentationParameters->BackBufferHeight) == 0))) {

        RECT Rect;
        GetClientRect(object->win_handle, &Rect);

        if (*(pPresentationParameters->BackBufferWidth) == 0) {
           *(pPresentationParameters->BackBufferWidth) = Rect.right;
           TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
        }
        if (*(pPresentationParameters->BackBufferHeight) == 0) {
           *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
           TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
        }
    }

   /*********************
   * finish off parameter initialization
   *******************/

    /* Put the correct figures in the presentation parameters */
1709
    TRACE("Copying across presentation parameters\n");
Oliver Stieber's avatar
Oliver Stieber committed
1710 1711 1712 1713 1714
    object->presentParms.BackBufferWidth                = *(pPresentationParameters->BackBufferWidth);
    object->presentParms.BackBufferHeight               = *(pPresentationParameters->BackBufferHeight);
    object->presentParms.BackBufferFormat               = *(pPresentationParameters->BackBufferFormat);
    object->presentParms.BackBufferCount                = *(pPresentationParameters->BackBufferCount);
    object->presentParms.MultiSampleType                = *(pPresentationParameters->MultiSampleType);
1715
    object->presentParms.MultiSampleQuality             = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
Oliver Stieber's avatar
Oliver Stieber committed
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
    object->presentParms.SwapEffect                     = *(pPresentationParameters->SwapEffect);
    object->presentParms.hDeviceWindow                  = *(pPresentationParameters->hDeviceWindow);
    object->presentParms.Windowed                       = *(pPresentationParameters->Windowed);
    object->presentParms.EnableAutoDepthStencil         = *(pPresentationParameters->EnableAutoDepthStencil);
    object->presentParms.AutoDepthStencilFormat         = *(pPresentationParameters->AutoDepthStencilFormat);
    object->presentParms.Flags                          = *(pPresentationParameters->Flags);
    object->presentParms.FullScreen_RefreshRateInHz     = *(pPresentationParameters->FullScreen_RefreshRateInHz);
    object->presentParms.PresentationInterval           = *(pPresentationParameters->PresentationInterval);


   /*********************
   * Create the back, front and stencil buffers
   *******************/
1729

Oliver Stieber's avatar
Oliver Stieber committed
1730 1731
    TRACE("calling rendertarget CB\n");
    hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1732
                             parent,
Oliver Stieber's avatar
Oliver Stieber committed
1733 1734 1735 1736 1737 1738 1739 1740 1741
                             object->presentParms.BackBufferWidth,
                             object->presentParms.BackBufferHeight,
                             object->presentParms.BackBufferFormat,
                             object->presentParms.MultiSampleType,
                             object->presentParms.MultiSampleQuality,
                             TRUE /* Lockable */,
                             &object->frontBuffer,
                             NULL /* pShared (always null)*/);
    if (object->frontBuffer != NULL)
H. Verbeet's avatar
H. Verbeet committed
1742
        IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1743

1744
    if(object->presentParms.BackBufferCount > 0) {
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
        int i;

        object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
        if(!object->backBuffer) {
            ERR("Out of memory\n");

            if (object->frontBuffer) {
                IUnknown *bufferParent;
                IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
                IUnknown_Release(bufferParent); /* once for the get parent */
                if (IUnknown_Release(bufferParent) > 0) {
                    FIXME("(%p) Something's still holding the front buffer\n",This);
                }
            }
            HeapFree(GetProcessHeap(), 0, object);
            return E_OUTOFMEMORY;
        }

        for(i = 0; i < object->presentParms.BackBufferCount; i++) {
            TRACE("calling rendertarget CB\n");
            hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1766
                                    parent,
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
                                    object->presentParms.BackBufferWidth,
                                    object->presentParms.BackBufferHeight,
                                    object->presentParms.BackBufferFormat,
                                    object->presentParms.MultiSampleType,
                                    object->presentParms.MultiSampleQuality,
                                    TRUE /* Lockable */,
                                    &object->backBuffer[i],
                                    NULL /* pShared (always null)*/);
            if(hr == WINED3D_OK && object->backBuffer[i]) {
                IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
            } else {
                break;
            }
        }
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796
    } else {
        object->backBuffer = NULL;
    }

    if (object->backBuffer != NULL) {
        ENTER_GL();
        glDrawBuffer(GL_BACK);
        checkGLcall("glDrawBuffer(GL_BACK)");
        LEAVE_GL();
    } else {
        /* Single buffering - draw to front buffer */
        ENTER_GL();
        glDrawBuffer(GL_FRONT);
        checkGLcall("glDrawBuffer(GL_FRONT)");
        LEAVE_GL();
    }
Oliver Stieber's avatar
Oliver Stieber committed
1797 1798

    /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1799
    if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
1800 1801 1802
        TRACE("Creating depth stencil buffer\n");
        if (This->depthStencilBuffer == NULL ) {
            hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1803
                                    parent,
Oliver Stieber's avatar
Oliver Stieber committed
1804 1805 1806 1807 1808 1809 1810 1811 1812
                                    object->presentParms.BackBufferWidth,
                                    object->presentParms.BackBufferHeight,
                                    object->presentParms.AutoDepthStencilFormat,
                                    object->presentParms.MultiSampleType,
                                    object->presentParms.MultiSampleQuality,
                                    FALSE /* FIXME: Discard */,
                                    &This->depthStencilBuffer,
                                    NULL /* pShared (always null)*/  );
            if (This->depthStencilBuffer != NULL)
1813
                IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
Oliver Stieber's avatar
Oliver Stieber committed
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
        }

        /** TODO: A check on width, height and multisample types
        *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
         ****************************/
        object->wantsDepthStencilBuffer = TRUE;
    } else {
        object->wantsDepthStencilBuffer = FALSE;
    }

1824
    TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
Oliver Stieber's avatar
Oliver Stieber committed
1825 1826 1827 1828 1829 1830 1831 1832


   /*********************
   * init the default renderTarget management
   *******************/
    object->drawable     = object->win;
    object->render_ctx   = object->glCtx;

1833
    if (hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
1834 1835 1836 1837 1838
        /*********************
         * Setup some defaults and clear down the buffers
         *******************/
        ENTER_GL();
        /** save current context and drawable **/
1839 1840
        oldContext  = glXGetCurrentContext();
        oldDrawable = glXGetCurrentDrawable();
Oliver Stieber's avatar
Oliver Stieber committed
1841 1842 1843 1844 1845 1846 1847 1848 1849

        TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
        if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
            ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
        }
        checkGLcall("glXMakeCurrent");

        TRACE("Setting up the screen\n");
        /* Clear the screen */
1850
        glClearColor(1.0, 0.0, 0.0, 0.0);
Oliver Stieber's avatar
Oliver Stieber committed
1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
        checkGLcall("glClearColor");
        glClearIndex(0);
        glClearDepth(1);
        glClearStencil(0xffff);

        checkGLcall("glClear");

        glColor3f(1.0, 1.0, 1.0);
        checkGLcall("glColor3f");

        glEnable(GL_LIGHTING);
        checkGLcall("glEnable");

        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
        checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");

        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
        checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");

        glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
        checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");

1873
        /* switch back to the original context (if there was one)*/
1874
        if (This->swapchains) {
Oliver Stieber's avatar
Oliver Stieber committed
1875 1876 1877 1878
            /** TODO: restore the context and drawable **/
            glXMakeCurrent(object->display, oldDrawable, oldContext);
        }

1879
        /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1880 1881 1882 1883
        glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
        checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
        glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
        checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1884

Oliver Stieber's avatar
Oliver Stieber committed
1885 1886 1887 1888 1889 1890
        LEAVE_GL();

        TRACE("Set swapchain to %p\n", object);
    } else { /* something went wrong so clean up */
        IUnknown* bufferParent;
        if (object->frontBuffer) {
1891

Oliver Stieber's avatar
Oliver Stieber committed
1892 1893
            IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
            IUnknown_Release(bufferParent); /* once for the get parent */
1894
            if (IUnknown_Release(bufferParent) > 0) {
Oliver Stieber's avatar
Oliver Stieber committed
1895 1896 1897 1898
                FIXME("(%p) Something's still holding the front buffer\n",This);
            }
        }
        if (object->backBuffer) {
1899 1900 1901 1902 1903 1904 1905 1906 1907
            int i;
            for(i = 0; i < object->presentParms.BackBufferCount; i++) {
                if(object->backBuffer[i]) {
                    IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
                    IUnknown_Release(bufferParent); /* once for the get parent */
                    if (IUnknown_Release(bufferParent) > 0) {
                        FIXME("(%p) Something's still holding the back buffer\n",This);
                    }
                }
Oliver Stieber's avatar
Oliver Stieber committed
1908
            }
1909 1910
            HeapFree(GetProcessHeap(), 0, object->backBuffer);
            object->backBuffer = NULL;
Oliver Stieber's avatar
Oliver Stieber committed
1911 1912 1913 1914 1915
        }
        /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
        /* Clean up the context */
        /* check that we are the current context first (we shouldn't be though!) */
        if (object->glCtx != 0) {
1916
            if(glXGetCurrentContext() == object->glCtx) {
Oliver Stieber's avatar
Oliver Stieber committed
1917 1918 1919 1920 1921 1922 1923
                glXMakeCurrent(object->display, None, NULL);
            }
            glXDestroyContext(object->display, object->glCtx);
        }
        HeapFree(GetProcessHeap(), 0, object);

    }
1924

Oliver Stieber's avatar
Oliver Stieber committed
1925
    return hr;
1926 1927
}

1928
/** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1929
static UINT     WINAPI  IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1930
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1931
    TRACE("(%p)\n", This);
Oliver Stieber's avatar
Oliver Stieber committed
1932

1933
    return This->NumberOfSwapChains;
1934 1935
}

1936
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1937
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1938
    TRACE("(%p) : swapchain %d\n", This, iSwapChain);
Oliver Stieber's avatar
Oliver Stieber committed
1939

1940 1941
    if(iSwapChain < This->NumberOfSwapChains) {
        *pSwapChain = This->swapchains[iSwapChain];
1942
        IWineD3DSwapChain_AddRef(*pSwapChain);
1943 1944 1945 1946 1947 1948
        TRACE("(%p) returning %p\n", This, *pSwapChain);
        return WINED3D_OK;
    } else {
        TRACE("Swapchain out of range\n");
        *pSwapChain = NULL;
        return WINED3DERR_INVALIDCALL;
1949
    }
1950 1951 1952 1953 1954
}

/*****
 * Vertex Declaration
 *****/
1955
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1956 1957
    IWineD3DDeviceImpl            *This   = (IWineD3DDeviceImpl *)iface;
    IWineD3DVertexDeclarationImpl *object = NULL;
1958
    HRESULT hr = WINED3D_OK;
1959
    TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1960 1961 1962
    D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
    object->allFVF = 0;

1963
    hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1964 1965 1966 1967 1968

    return hr;
}

/* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1969
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1970 1971
    IWineD3DDeviceImpl       *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DVertexShaderImpl *object;  /* NOTE: impl usage is ok, this is a create */
1972
    HRESULT hr = WINED3D_OK;
1973
    D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1974
    object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1975

1976
    TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1977 1978 1979 1980 1981 1982

    /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
    /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
    if (pDeclaration != NULL) {
        IWineD3DVertexDeclaration *vertexDeclaration;
        hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1983
        if (WINED3D_OK == hr) {
1984 1985 1986
            TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
            object->vertexDeclaration = vertexDeclaration;
        } else {
1987
            FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1988
            IWineD3DVertexShader_Release(*ppVertexShader);
1989
            return WINED3DERR_INVALIDCALL;
1990 1991 1992
        }
    }

1993 1994
    hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);

1995 1996
    if (WINED3D_OK != hr) {
        FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1997
        IWineD3DVertexShader_Release(*ppVertexShader);
1998
        return WINED3DERR_INVALIDCALL;
1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
    }

#if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
    if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
        /* Foo */
    } else {
        /* Bar */
    }

#endif

2010
    return WINED3D_OK;
2011 2012
}

2013
static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2014
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2015
    IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2016
    HRESULT hr = WINED3D_OK;
2017

2018
    D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2019
    object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2020
    hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2021
    if (WINED3D_OK == hr) {
2022 2023 2024 2025
        TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
    } else {
        WARN("(%p) : Failed to create pixel shader\n", This);
    }
2026

2027
    return hr;
2028 2029
}

2030
static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2031 2032
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DPaletteImpl *object;
2033
    HRESULT hr;
2034
    TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2035 2036 2037 2038 2039

    /* Create the new object */
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
    if(!object) {
        ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2040
        return E_OUTOFMEMORY;
2041 2042 2043 2044
    }

    object->lpVtbl = &IWineD3DPalette_Vtbl;
    object->ref = 1;
2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
    object->Flags = Flags;
    object->parent = Parent;
    object->wineD3DDevice = This;
    object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
	
    object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));

    if(!object->hpal) {
        HeapFree( GetProcessHeap(), 0, object);
        return E_OUTOFMEMORY;
    }

    hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
    if(FAILED(hr)) {
        IWineD3DPalette_Release((IWineD3DPalette *) object);
        return hr;
    }
2062 2063 2064

    *Palette = (IWineD3DPalette *) object;

2065
    return WINED3D_OK;
2066 2067
}

2068
static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2069 2070
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSwapChainImpl *swapchain;
2071
    DWORD state;
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084

    TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
    if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;

    /* TODO: Test if OpenGL is compiled in and loaded */

    /* Setup the implicit swapchain */
    TRACE("Creating implicit swapchain\n");
    if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
        WARN("Failed to create implicit swapchain\n");
        return WINED3DERR_INVALIDCALL;
    }

2085 2086 2087 2088 2089 2090 2091 2092 2093
    This->NumberOfSwapChains = 1;
    This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
    if(!This->swapchains) {
        ERR("Out of memory!\n");
        IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
        return E_OUTOFMEMORY;
    }
    This->swapchains[0] = (IWineD3DSwapChain *) swapchain;

2094
    if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2095
        TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2096
        This->renderTarget = swapchain->backBuffer[0];
2097 2098 2099 2100 2101 2102 2103 2104
    }
    else {
        TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
        This->renderTarget = swapchain->frontBuffer;
    }
    IWineD3DSurface_AddRef(This->renderTarget);
    /* Depth Stencil support */
    This->stencilBufferTarget = This->depthStencilBuffer;
2105 2106 2107
    if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
        set_depth_stencil_fbo(iface, This->depthStencilBuffer);
    }
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
    if (NULL != This->stencilBufferTarget) {
        IWineD3DSurface_AddRef(This->stencilBufferTarget);
    }

    /* Set up some starting GL setup */
    ENTER_GL();
    /*
    * Initialize openGL extension related variables
    *  with Default values
    */

H. Verbeet's avatar
H. Verbeet committed
2119
    ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2120 2121 2122 2123 2124 2125 2126
    /* Setup all the devices defaults */
    IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
#if 0
    IWineD3DImpl_CheckGraphicsMemory();
#endif
    LEAVE_GL();

2127 2128 2129
    /* Initialize our list of GLSL programs */
    list_init(&This->glsl_shader_progs);

2130
    { /* Set a default viewport */
2131
        WINED3DVIEWPORT vp;
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149
        vp.X      = 0;
        vp.Y      = 0;
        vp.Width  = *(pPresentationParameters->BackBufferWidth);
        vp.Height = *(pPresentationParameters->BackBufferHeight);
        vp.MinZ   = 0.0f;
        vp.MaxZ   = 1.0f;
        IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
    }

    /* Initialize the current view state */
    This->modelview_valid = 1;
    This->proj_valid = 0;
    This->view_ident = 1;
    This->last_was_rhw = 0;
    glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
    TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);

    /* Clear the screen */
2150
    IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2151

2152 2153 2154 2155 2156 2157 2158 2159 2160
    /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
     * This might create a problem in 2 situations:
     * ->The D3D default value is 0, but the opengl default value is something else
     * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
     */
    for(state = 0; state <= STATE_HIGHEST; state++) {
        IWineD3DDeviceImpl_MarkStateDirty(This, state);
    }

2161 2162
    This->d3d_initialized = TRUE;
    return WINED3D_OK;
2163 2164
}

2165
static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2166
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2167
    int sampler;
2168
    uint i;
2169 2170 2171 2172
    TRACE("(%p)\n", This);

    if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;

2173 2174 2175 2176 2177 2178 2179 2180
    /* Delete the mouse cursor texture */
    if(This->cursorTexture) {
        ENTER_GL();
        glDeleteTextures(1, &This->cursorTexture);
        LEAVE_GL();
        This->cursorTexture = 0;
    }

2181 2182
    for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
        IWineD3DDevice_SetTexture(iface, sampler, NULL);
2183 2184
    }

2185
    /* Release the buffers (with sanity checks)*/
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199
    TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
    if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
        if(This->depthStencilBuffer != This->stencilBufferTarget)
            FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
    }
    This->stencilBufferTarget = NULL;

    TRACE("Releasing the render target at %p\n", This->renderTarget);
    if(IWineD3DSurface_Release(This->renderTarget) >0){
          /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
    }
    TRACE("Setting rendertarget to NULL\n");
    This->renderTarget = NULL;

2200
    if (This->depthStencilBuffer) {
2201
        if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2202
            FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2203 2204
        }
        This->depthStencilBuffer = NULL;
2205 2206
    }

2207 2208
    for(i=0; i < This->NumberOfSwapChains; i++) {
        TRACE("Releasing the implicit swapchain %d\n", i);
2209
        if (D3DCB_DestroySwapChain(This->swapchains[i])  > 0) {
2210 2211 2212
            FIXME("(%p) Something's still holding the implicit swapchain\n", This);
        }
    }
2213 2214

    HeapFree(GetProcessHeap(), 0, This->swapchains);
2215
    This->swapchains = NULL;
2216
    This->NumberOfSwapChains = 0;
2217 2218 2219

    This->d3d_initialized = FALSE;
    return WINED3D_OK;
2220 2221
}

2222 2223 2224 2225 2226 2227
static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");

    /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
     * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2228 2229
     * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
     * separately.
2230 2231 2232 2233
     */
    This->ddraw_fullscreen = fullscreen;
}

2234
static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2235 2236 2237 2238
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    DEVMODEW DevModeW;
    int i;
2239
    const PixelFormatDesc *formatDesc  = getFormatDescEntry(pixelformat);
2240

2241
    TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2242 2243 2244 2245 2246

    for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
        /* Ignore some modes if a description was passed */
        if ( (Width > 0)  && (Width != DevModeW.dmPelsWidth)) continue;
        if ( (Height > 0)  && (Height != DevModeW.dmPelsHeight)) continue;
2247
        if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2248

2249
        TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2250 2251 2252 2253 2254 2255

        if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
            return D3D_OK;
    }

    return D3D_OK;
2256 2257
}

2258
static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2259 2260 2261
    DEVMODEW devmode;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    LONG ret;
2262
    const PixelFormatDesc *formatDesc  = getFormatDescEntry(pMode->Format);
2263
    RECT clip_rc;
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273

    TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));

    /* Resize the screen even without a window:
     * The app could have unset it with SetCooperativeLevel, but not called
     * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
     * but we don't have any hwnd
     */

    devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2274
    devmode.dmBitsPerPel = formatDesc->bpp * 8;
2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
    if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
    devmode.dmPelsWidth  = pMode->Width;
    devmode.dmPelsHeight = pMode->Height;

    devmode.dmDisplayFrequency = pMode->RefreshRate;
    if (pMode->RefreshRate != 0)  {
        devmode.dmFields |= DM_DISPLAYFREQUENCY;
    }

    /* Only change the mode if necessary */
    if( (This->ddraw_width == pMode->Width) &&
        (This->ddraw_height == pMode->Height) &&
        (This->ddraw_format == pMode->Format) &&
        (pMode->RefreshRate == 0) ) {
        return D3D_OK;
    }

    ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
    if (ret != DISP_CHANGE_SUCCESSFUL) {
        if(devmode.dmDisplayFrequency != 0) {
            WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
            devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
            devmode.dmDisplayFrequency = 0;
            ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
        }
        if(ret != DISP_CHANGE_SUCCESSFUL) {
            return DDERR_INVALIDMODE;
        }
    }

    /* Store the new values */
    This->ddraw_width = pMode->Width;
    This->ddraw_height = pMode->Height;
    This->ddraw_format = pMode->Format;

    /* Only do this with a window of course */
    if(This->ddraw_window)
      MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);

2314 2315 2316 2317
    /* And finally clip mouse to our screen */
    SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
    ClipCursor(&clip_rc);

2318
    return WINED3D_OK;
2319 2320
}

2321
static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2322 2323 2324
   IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
   *ppD3D= This->wineD3D;
   TRACE("(%p) : wineD3D returning %p\n", This,  *ppD3D);
2325
   IWineD3D_AddRef(*ppD3D);
2326
   return WINED3D_OK;
2327
}
2328

2329
static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2330 2331
    /** NOTE: There's a probably  a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
    * into the video ram as possible and seeing how many fit
2332 2333
    * you can also get the correct initial value from nvidia and ATI's driver via X
    * texture memory is video memory + AGP memory
2334
    *******************/
2335
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2336 2337
    static BOOL showfixmes = TRUE;
    if (showfixmes) {
2338 2339 2340
        FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
         (wined3d_settings.emulated_textureram/(1024*1024)),
         ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2341 2342
         showfixmes = FALSE;
    }
2343 2344 2345 2346 2347
    TRACE("(%p) : simulating %dMB, returning %dMB left\n",  This,
         (wined3d_settings.emulated_textureram/(1024*1024)),
         ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
    /* return simulated texture memory left */
    return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2348 2349 2350
}


2351

2352 2353 2354
/*****
 * Get / Set FVF
 *****/
2355
static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2356
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2357
    HRESULT hr = WINED3D_OK;
2358

2359
    /* Update the current state block */
2360 2361 2362 2363
    This->updateStateBlock->fvf              = fvf;
    This->updateStateBlock->changed.fvf      = TRUE;
    This->updateStateBlock->set.fvf          = TRUE;

2364
    TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2365
    return hr;
2366
}
2367 2368


2369
static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2370
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2371
    TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2372
    *pfvf = This->stateBlock->fvf;
2373
    return WINED3D_OK;
2374
}
2375

2376 2377 2378
/*****
 * Get / Set Stream Source
 *****/
2379
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2380
        IWineD3DDeviceImpl       *This = (IWineD3DDeviceImpl *)iface;
2381 2382
    IWineD3DVertexBuffer     *oldSrc;

2383 2384 2385 2386 2387 2388 2389 2390 2391
    /**TODO: instance and index data, see
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
    and
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
     **************/

    /* D3d9 only, but shouldn't  hurt d3d8 */
    UINT streamFlags;

2392
    streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2393
    if (streamFlags) {
2394
        if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2395 2396
           FIXME("stream index data not supported\n");
        }
2397
        if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2398 2399 2400 2401
           FIXME("stream instance data not supported\n");
        }
    }

2402
    StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2403 2404 2405

    if (StreamNumber >= MAX_STREAMS) {
        WARN("Stream out of range %d\n", StreamNumber);
2406
        return WINED3DERR_INVALIDCALL;
2407 2408
    }

2409
    oldSrc = This->stateBlock->streamSource[StreamNumber];
2410 2411
    TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);

2412 2413 2414 2415 2416
    This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
    This->updateStateBlock->set.streamSource[StreamNumber]     = TRUE;
    This->updateStateBlock->streamStride[StreamNumber]         = Stride;
    This->updateStateBlock->streamSource[StreamNumber]         = pStreamData;
    This->updateStateBlock->streamOffset[StreamNumber]         = OffsetInBytes;
2417
    This->updateStateBlock->streamFlags[StreamNumber]          = streamFlags;
2418 2419 2420 2421

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2422
        return WINED3D_OK;
2423 2424
    }

2425 2426 2427 2428
    /* Same stream object: no action */
    if (oldSrc == pStreamData)
        return WINED3D_OK;

2429 2430 2431 2432
    /* Need to do a getParent and pass the reffs up */
    /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
    which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
    so for now, just count internally   */
2433
    if (pStreamData != NULL) {
2434 2435 2436 2437 2438 2439
        IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
        if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
            WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
        }
        vbImpl->stream = StreamNumber;
        vbImpl->Flags |= VBFLAG_STREAM;
2440
        IWineD3DVertexBuffer_AddRef(pStreamData);
2441 2442
    }
    if (oldSrc != NULL) {
2443
        ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2444
        IWineD3DVertexBuffer_Release(oldSrc);
2445
    }
2446

2447
    return WINED3D_OK;
2448 2449
}

2450
static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2451
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2452 2453 2454 2455
    UINT streamFlags;

    TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
           This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2456

2457

2458
    streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2459
    if (streamFlags) {
2460
        if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2461 2462
           FIXME("stream index data not supported\n");
        }
2463
        if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2464 2465 2466 2467
            FIXME("stream instance data not supported\n");
        }
    }

2468
    StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2469 2470 2471

    if (StreamNumber >= MAX_STREAMS) {
        WARN("Stream out of range %d\n", StreamNumber);
2472
        return WINED3DERR_INVALIDCALL;
2473
    }
2474 2475
    *pStream = This->stateBlock->streamSource[StreamNumber];
    *pStride = This->stateBlock->streamStride[StreamNumber];
2476 2477 2478
    if (pOffset) {
        *pOffset = This->stateBlock->streamOffset[StreamNumber];
    }
2479 2480

     if (*pStream == NULL) {
2481 2482
        FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
        return  WINED3DERR_INVALIDCALL;
2483 2484
    }

2485
    IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2486
    return WINED3D_OK;
2487 2488
}

2489 2490 2491 2492 2493 2494
/*Should be quite easy, just an extension of vertexdata
ref...
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp

The divider is a bit odd though

2495
VertexOffset = StartVertex / Divider * StreamStride +
2496 2497 2498
               VertexIndex / Divider * StreamStride + StreamOffset

*/
2499
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT Divider) {
2500
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2501

2502
    TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2503
    This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA  | WINED3DSTREAMSOURCE_INDEXEDDATA );
2504 2505 2506 2507 2508 2509 2510 2511 2512

    This->updateStateBlock->changed.streamFreq[StreamNumber]  = TRUE;
    This->updateStateBlock->set.streamFreq[StreamNumber]      = TRUE;
    This->updateStateBlock->streamFreq[StreamNumber]          = Divider & 0x7FFFFF;

    if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
        FIXME("Stream indexing not fully supported\n");
    }

2513
    return WINED3D_OK;
2514
}
2515

2516
static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT* Divider) {
2517
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518

2519 2520 2521 2522 2523
    TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
    *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];

    TRACE("(%p) : returning %d\n", This, *Divider);

2524
    return WINED3D_OK;
2525 2526
}

2527
/*****
2528
 * Get / Set & Multiply Transform
2529
 *****/
2530
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2531 2532 2533
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    /* Most of this routine, comments included copied from ddraw tree initially: */
2534
    TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2535 2536 2537 2538 2539 2540

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
        This->updateStateBlock->changed.transform[d3dts] = TRUE;
        This->updateStateBlock->set.transform[d3dts]     = TRUE;
2541
        memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2542
        return WINED3D_OK;
2543 2544 2545 2546 2547 2548 2549 2550 2551 2552
    }

    /*
     * If the new matrix is the same as the current one,
     * we cut off any further processing. this seems to be a reasonable
     * optimization because as was noticed, some apps (warcraft3 for example)
     * tend towards setting the same matrix repeatedly for some reason.
     *
     * From here on we assume that the new matrix is different, wherever it matters.
     */
2553
    if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2554
        TRACE("The app is setting the same matrix over again\n");
2555
        return WINED3D_OK;
2556 2557 2558 2559 2560 2561 2562 2563 2564
    } else {
        conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
    }

    /*
       ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
       where ViewMat = Camera space, WorldMat = world space.

       In OpenGL, camera and world space is combined into GL_MODELVIEW
2565
       matrix.  The Projection matrix stay projection matrix.
2566 2567 2568
     */

    /* Capture the times we can just ignore the change for now */
2569
    if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2570
        This->modelview_valid = FALSE;
2571
        return WINED3D_OK;
2572

2573
    } else if (d3dts == WINED3DTS_PROJECTION) {
2574
        This->proj_valid = FALSE;
2575
        return WINED3D_OK;
2576

2577
    } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2578 2579
        /* Indexed Vertex Blending Matrices 256 -> 511  */
        /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2580
        FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2581
        return WINED3D_OK;
2582 2583
    }

2584 2585 2586
    /* Now we really are going to have to change a matrix */
    ENTER_GL();

2587
    if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2588
        /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2589
    } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2590 2591
        unsigned int k;

2592
        /* If we are changing the View matrix, reset the light and clipping planes to the new view
2593
         * NOTE: We have to reset the positions even if the light/plane is not currently
2594
         *       enabled, since the call to enable it will not reset the position.
2595 2596
         * NOTE2: Apparently texture transforms do NOT need reapplying
         */
2597

Adam D. Moss's avatar
Adam D. Moss committed
2598
        PLIGHTINFOEL *lightChain = NULL;
2599
        This->modelview_valid = FALSE;
2600
        This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2601

2602 2603 2604
        glMatrixMode(GL_MODELVIEW);
        checkGLcall("glMatrixMode(GL_MODELVIEW)");
        glPushMatrix();
2605
        glLoadMatrixf((const float *)lpmatrix);
2606 2607 2608
        checkGLcall("glLoadMatrixf(...)");

        /* Reset lights */
2609
        lightChain = This->stateBlock->lights;
2610 2611 2612 2613 2614 2615 2616
        while (lightChain && lightChain->glIndex != -1) {
            glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
            checkGLcall("glLightfv posn");
            glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
            checkGLcall("glLightfv dirn");
            lightChain = lightChain->next;
        }
2617

2618 2619
        /* Reset Clipping Planes if clipping is enabled */
        for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2620
            glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2621 2622 2623 2624 2625 2626 2627 2628 2629 2630
            checkGLcall("glClipPlane");
        }
        glPopMatrix();

    } else { /* What was requested!?? */
        WARN("invalid matrix specified: %i\n", d3dts);
    }

    /* Release lock, all done */
    LEAVE_GL();
2631
    return WINED3D_OK;
2632 2633

}
2634
static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2635
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2636
    TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2637
    memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2638
    return WINED3D_OK;
2639 2640
}

2641 2642 2643
static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
    WINED3DMATRIX *mat = NULL;
    WINED3DMATRIX temp;
2644

2645 2646
    /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
     * below means it will be recorded in a state block change, but it
2647
     * works regardless where it is recorded.
2648 2649
     * If this is found to be wrong, change to StateBlock.
     */
2650
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2651
    TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2652 2653 2654 2655 2656 2657 2658 2659

    if (State < HIGHEST_TRANSFORMSTATE)
    {
        mat = &This->updateStateBlock->transforms[State];
    } else {
        FIXME("Unhandled transform state!!\n");
    }

2660
    multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2661 2662

    /* Apply change via set transform - will reapply to eg. lights this way */
2663
    return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2664 2665 2666 2667 2668 2669
}

/*****
 * Get / Set Light
 *****/
/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2670
   you can reference any indexes you want as long as that number max are enabled at any
2671 2672 2673
   one point in time! Therefore since the indexes can be anything, we need a linked list of them.
   However, this causes stateblock problems. When capturing the state block, I duplicate the list,
   but when recording, just build a chain pretty much of commands to be replayed.                  */
2674

2675
static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2676 2677 2678 2679
    float rho;
    PLIGHTINFOEL *object, *temp;

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680
    TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2681 2682 2683 2684 2685

    /* If recording state block, just add to end of lights chain */
    if (This->isRecordingState) {
        object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
        if (NULL == object) {
2686
            return WINED3DERR_OUTOFVIDEOMEMORY;
2687
        }
2688
        memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
        object->OriginalIndex = Index;
        object->glIndex = -1;
        object->changed = TRUE;

        /* Add to the END of the chain of lights changes to be replayed */
        if (This->updateStateBlock->lights == NULL) {
            This->updateStateBlock->lights = object;
        } else {
            temp = This->updateStateBlock->lights;
            while (temp->next != NULL) temp=temp->next;
            temp->next = object;
        }
        TRACE("Recording... not performing anything more\n");
2702
        return WINED3D_OK;
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714
    }

    /* Ok, not recording any longer so do real work */
    object = This->stateBlock->lights;
    while (object != NULL && object->OriginalIndex != Index) object = object->next;

    /* If we didn't find it in the list of lights, time to add it */
    if (object == NULL) {
        PLIGHTINFOEL *insertAt,*prevPos;

        object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
        if (NULL == object) {
2715
            return WINED3DERR_OUTOFVIDEOMEMORY;
2716 2717 2718 2719
        }
        object->OriginalIndex = Index;
        object->glIndex = -1;

2720
        /* Add it to the front of list with the idea that lights will be changed as needed
2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745
           BUT after any lights currently assigned GL indexes                             */
        insertAt = This->stateBlock->lights;
        prevPos  = NULL;
        while (insertAt != NULL && insertAt->glIndex != -1) {
            prevPos  = insertAt;
            insertAt = insertAt->next;
        }

        if (insertAt == NULL && prevPos == NULL) { /* Start of list */
            This->stateBlock->lights = object;
        } else if (insertAt == NULL) { /* End of list */
            prevPos->next = object;
            object->prev = prevPos;
        } else { /* Middle of chain */
            if (prevPos == NULL) {
                This->stateBlock->lights = object;
            } else {
                prevPos->next = object;
            }
            object->prev = prevPos;
            object->next = insertAt;
            insertAt->prev = object;
        }
    }

2746
    /* Initialize the object */
2747
    TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2748 2749 2750 2751 2752 2753 2754 2755
          pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
          pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
          pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
    TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
          pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
    TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);

    /* Save away the information */
2756
    memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2757 2758

    switch (pLight->Type) {
2759
    case WINED3DLIGHT_POINT:
2760 2761 2762 2763 2764 2765 2766 2767 2768
        /* Position */
        object->lightPosn[0] = pLight->Position.x;
        object->lightPosn[1] = pLight->Position.y;
        object->lightPosn[2] = pLight->Position.z;
        object->lightPosn[3] = 1.0f;
        object->cutoff = 180.0f;
        /* FIXME: Range */
        break;

2769
    case WINED3DLIGHT_DIRECTIONAL:
2770 2771 2772 2773 2774 2775 2776 2777 2778
        /* Direction */
        object->lightPosn[0] = -pLight->Direction.x;
        object->lightPosn[1] = -pLight->Direction.y;
        object->lightPosn[2] = -pLight->Direction.z;
        object->lightPosn[3] = 0.0;
        object->exponent     = 0.0f;
        object->cutoff       = 180.0f;
        break;

2779
    case WINED3DLIGHT_SPOT:
2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805
        /* Position */
        object->lightPosn[0] = pLight->Position.x;
        object->lightPosn[1] = pLight->Position.y;
        object->lightPosn[2] = pLight->Position.z;
        object->lightPosn[3] = 1.0;

        /* Direction */
        object->lightDirn[0] = pLight->Direction.x;
        object->lightDirn[1] = pLight->Direction.y;
        object->lightDirn[2] = pLight->Direction.z;
        object->lightDirn[3] = 1.0;

        /*
         * opengl-ish and d3d-ish spot lights use too different models for the
         * light "intensity" as a function of the angle towards the main light direction,
         * so we only can approximate very roughly.
         * however spot lights are rather rarely used in games (if ever used at all).
         * furthermore if still used, probably nobody pays attention to such details.
         */
        if (pLight->Falloff == 0) {
            rho = 6.28f;
        } else {
            rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
        }
        if (rho < 0.0001) rho = 0.0001f;
        object->exponent = -0.3/log(cos(rho/2));
2806 2807 2808
	if (object->exponent > 128.0) {
		object->exponent = 128.0;
	}
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821
        object->cutoff = pLight->Phi*90/M_PI;

        /* FIXME: Range */
        break;

    default:
        FIXME("Unrecognized light type %d\n", pLight->Type);
    }

    /* Update the live definitions if the light is currently assigned a glIndex */
    if (object->glIndex != -1) {
        setup_light(iface, object->glIndex, object);
    }
2822
    return WINED3D_OK;
2823 2824
}

2825
static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2826
    PLIGHTINFOEL *lightInfo = NULL;
2827
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828
    TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2829

2830 2831 2832 2833 2834 2835
    /* Locate the light in the live lights */
    lightInfo = This->stateBlock->lights;
    while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;

    if (lightInfo == NULL) {
        TRACE("Light information requested but light not defined\n");
2836
        return WINED3DERR_INVALIDCALL;
2837 2838
    }

2839
    memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2840
    return WINED3D_OK;
2841 2842 2843
}

/*****
2844
 * Get / Set Light Enable
2845 2846
 *   (Note for consistency, renamed d3dx function by adding the 'set' prefix)
 *****/
2847
static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2848 2849
    PLIGHTINFOEL *lightInfo = NULL;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850
    TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2851

2852 2853 2854 2855
    /* Tests show true = 128...not clear why */

    Enable = Enable? 128: 0;

2856 2857 2858 2859
    /* If recording state block, just add to end of lights chain with changedEnable set to true */
    if (This->isRecordingState) {
        lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
        if (NULL == lightInfo) {
2860
            return WINED3DERR_OUTOFVIDEOMEMORY;
2861 2862 2863 2864
        }
        lightInfo->OriginalIndex = Index;
        lightInfo->glIndex = -1;
        lightInfo->enabledChanged = TRUE;
2865
        lightInfo->lightEnabled = Enable;
2866 2867 2868 2869 2870 2871 2872 2873 2874 2875

        /* Add to the END of the chain of lights changes to be replayed */
        if (This->updateStateBlock->lights == NULL) {
            This->updateStateBlock->lights = lightInfo;
        } else {
            PLIGHTINFOEL *temp = This->updateStateBlock->lights;
            while (temp->next != NULL) temp=temp->next;
            temp->next = lightInfo;
        }
        TRACE("Recording... not performing anything more\n");
2876
        return WINED3D_OK;
2877 2878 2879 2880 2881 2882 2883 2884
    }

    /* Not recording... So, locate the light in the live lights */
    lightInfo = This->stateBlock->lights;
    while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;

    /* Special case - enabling an undefined light creates one with a strict set of parms! */
    if (lightInfo == NULL) {
2885

2886
        TRACE("Light enabled requested but light not defined, so defining one!\n");
2887
        IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2888 2889 2890 2891 2892 2893

        /* Search for it again! Should be fairly quick as near head of list */
        lightInfo = This->stateBlock->lights;
        while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
        if (lightInfo == NULL) {
            FIXME("Adding default lights has failed dismally\n");
2894
            return WINED3DERR_INVALIDCALL;
2895 2896 2897 2898
        }
    }

    /* OK, we now have a light... */
2899
    if (!Enable) {
2900 2901 2902

        /* If we are disabling it, check it was enabled, and
           still only do something if it has assigned a glIndex (which it should have!)   */
2903
        if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2904
            TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2905 2906 2907 2908 2909 2910 2911
            ENTER_GL();
            glDisable(GL_LIGHT0 + lightInfo->glIndex);
            checkGLcall("glDisable GL_LIGHT0+Index");
            LEAVE_GL();
        } else {
            TRACE("Nothing to do as light was not enabled\n");
        }
2912
        lightInfo->lightEnabled = Enable;
2913 2914
    } else {

2915
        /* We are enabling it. If it is enabled, it's really simple */
2916
        if (lightInfo->lightEnabled) {
2917 2918 2919
            /* nop */
            TRACE("Nothing to do as light was enabled\n");

2920
        /* If it already has a glIndex, it's still simple */
2921
        } else if (lightInfo->glIndex != -1) {
2922
            TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2923
            lightInfo->lightEnabled = Enable;
2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940
            ENTER_GL();
            glEnable(GL_LIGHT0 + lightInfo->glIndex);
            checkGLcall("glEnable GL_LIGHT0+Index already setup");
            LEAVE_GL();

        /* Otherwise got to find space - lights are ordered gl indexes first */
        } else {
            PLIGHTINFOEL *bsf  = NULL;
            PLIGHTINFOEL *pos  = This->stateBlock->lights;
            PLIGHTINFOEL *prev = NULL;
            int           Index= 0;
            int           glIndex = -1;

            /* Try to minimize changes as much as possible */
            while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {

                /* Try to remember which index can be replaced if necessary */
2941
                if (bsf==NULL && !pos->lightEnabled) {
2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954
                    /* Found a light we can replace, save as best replacement */
                    bsf = pos;
                }

                /* Step to next space */
                prev = pos;
                pos = pos->next;
                Index ++;
            }

            /* If we have too many active lights, fail the call */
            if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
                FIXME("Program requests too many concurrent lights\n");
2955
                return WINED3DERR_INVALIDCALL;
2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993

            /* If we have allocated all lights, but not all are enabled,
               reuse one which is not enabled                           */
            } else if (Index == This->maxConcurrentLights) {
                /* use bsf - Simply swap the new light and the BSF one */
                PLIGHTINFOEL *bsfNext = bsf->next;
                PLIGHTINFOEL *bsfPrev = bsf->prev;

                /* Sort out ends */
                if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
                if (bsf->prev != NULL) {
                    bsf->prev->next = lightInfo;
                } else {
                    This->stateBlock->lights = lightInfo;
                }

                /* If not side by side, lots of chains to update */
                if (bsf->next != lightInfo) {
                    lightInfo->prev->next = bsf;
                    bsf->next->prev = lightInfo;
                    bsf->next       = lightInfo->next;
                    bsf->prev       = lightInfo->prev;
                    lightInfo->next = bsfNext;
                    lightInfo->prev = bsfPrev;

                } else {
                    /* Simple swaps */
                    bsf->prev = lightInfo;
                    bsf->next = lightInfo->next;
                    lightInfo->next = bsf;
                    lightInfo->prev = bsfPrev;
                }


                /* Update states */
                glIndex = bsf->glIndex;
                bsf->glIndex = -1;
                lightInfo->glIndex = glIndex;
2994
                lightInfo->lightEnabled = Enable;
2995 2996

                /* Finally set up the light in gl itself */
2997
                TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2998 2999 3000 3001 3002 3003 3004 3005 3006 3007
                ENTER_GL();
                setup_light(iface, glIndex, lightInfo);
                glEnable(GL_LIGHT0 + glIndex);
                checkGLcall("glEnable GL_LIGHT0 new setup");
                LEAVE_GL();

            /* If we reached the end of the allocated lights, with space in the
               gl lights, setup a new light                                     */
            } else if (pos->glIndex == -1) {

3008
                /* We reached the end of the allocated gl lights, so already
3009 3010 3011
                    know the index of the next one!                          */
                glIndex = Index;
                lightInfo->glIndex = glIndex;
3012
                lightInfo->lightEnabled = Enable;
3013

3014
                /* In an ideal world, it's already in the right place */
3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037
                if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
                   /* No need to move it */
                } else {
                    /* Remove this light from the list */
                    lightInfo->prev->next = lightInfo->next;
                    if (lightInfo->next != NULL) {
                        lightInfo->next->prev = lightInfo->prev;
                    }

                    /* Add in at appropriate place (inbetween prev and pos) */
                    lightInfo->prev = prev;
                    lightInfo->next = pos;
                    if (prev == NULL) {
                        This->stateBlock->lights = lightInfo;
                    } else {
                        prev->next = lightInfo;
                    }
                    if (pos != NULL) {
                        pos->prev = lightInfo;
                    }
                }

                /* Finally set up the light in gl itself */
3038
                TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3039 3040 3041 3042 3043
                ENTER_GL();
                setup_light(iface, glIndex, lightInfo);
                glEnable(GL_LIGHT0 + glIndex);
                checkGLcall("glEnable GL_LIGHT0 new setup");
                LEAVE_GL();
3044

3045 3046 3047
            }
        }
    }
3048
    return WINED3D_OK;
3049 3050
}

3051
static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3052 3053

    PLIGHTINFOEL *lightInfo = NULL;
3054
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055
    TRACE("(%p) : for idx(%d)\n", This, Index);
3056

3057 3058 3059 3060 3061 3062
    /* Locate the light in the live lights */
    lightInfo = This->stateBlock->lights;
    while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;

    if (lightInfo == NULL) {
        TRACE("Light enabled state requested but light not defined\n");
3063
        return WINED3DERR_INVALIDCALL;
3064 3065
    }
    *pEnable = lightInfo->lightEnabled;
3066
    return WINED3D_OK;
3067 3068 3069 3070 3071
}

/*****
 * Get / Set Clip Planes
 *****/
3072
static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3073
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074
    TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3075 3076 3077 3078

    /* Validate Index */
    if (Index >= GL_LIMITS(clipplanes)) {
        TRACE("Application has requested clipplane this device doesn't support\n");
3079
        return WINED3DERR_INVALIDCALL;
3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091
    }

    This->updateStateBlock->changed.clipplane[Index] = TRUE;
    This->updateStateBlock->set.clipplane[Index] = TRUE;
    This->updateStateBlock->clipplane[Index][0] = pPlane[0];
    This->updateStateBlock->clipplane[Index][1] = pPlane[1];
    This->updateStateBlock->clipplane[Index][2] = pPlane[2];
    This->updateStateBlock->clipplane[Index][3] = pPlane[3];

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3092
        return WINED3D_OK;
3093 3094 3095 3096 3097 3098 3099 3100 3101
    }

    /* Apply it */

    ENTER_GL();

    /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
3102
    glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3103

3104 3105
    TRACE("Clipplane [%f,%f,%f,%f]\n",
          This->updateStateBlock->clipplane[Index][0],
3106
          This->updateStateBlock->clipplane[Index][1],
3107
          This->updateStateBlock->clipplane[Index][2],
3108
          This->updateStateBlock->clipplane[Index][3]);
3109 3110 3111 3112 3113 3114
    glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
    checkGLcall("glClipPlane");

    glPopMatrix();
    LEAVE_GL();

3115
    return WINED3D_OK;
3116 3117
}

3118
static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3119
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120
    TRACE("(%p) : for idx %d\n", This, Index);
3121 3122 3123 3124

    /* Validate Index */
    if (Index >= GL_LIMITS(clipplanes)) {
        TRACE("Application has requested clipplane this device doesn't support\n");
3125
        return WINED3DERR_INVALIDCALL;
3126 3127 3128 3129 3130 3131
    }

    pPlane[0] = This->stateBlock->clipplane[Index][0];
    pPlane[1] = This->stateBlock->clipplane[Index][1];
    pPlane[2] = This->stateBlock->clipplane[Index][2];
    pPlane[3] = This->stateBlock->clipplane[Index][3];
3132
    return WINED3D_OK;
3133 3134 3135 3136 3137 3138
}

/*****
 * Get / Set Clip Plane Status
 *   WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
 *****/
3139
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3140 3141 3142
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    FIXME("(%p) : stub\n", This);
    if (NULL == pClipStatus) {
3143
      return WINED3DERR_INVALIDCALL;
3144 3145 3146
    }
    This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
    This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3147
    return WINED3D_OK;
3148 3149
}

3150
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3151
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152
    FIXME("(%p) : stub\n", This);
3153
    if (NULL == pClipStatus) {
3154
      return WINED3DERR_INVALIDCALL;
3155 3156 3157
    }
    pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
    pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3158
    return WINED3D_OK;
3159 3160 3161 3162 3163
}

/*****
 * Get / Set Material
 *****/
3164
static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3165 3166 3167 3168 3169 3170 3171 3172 3173
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    This->updateStateBlock->changed.material = TRUE;
    This->updateStateBlock->set.material = TRUE;
    memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3174
        return WINED3D_OK;
3175 3176 3177
    }

    ENTER_GL();
3178 3179 3180 3181 3182 3183 3184 3185
    TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
        pMaterial->Diffuse.b, pMaterial->Diffuse.a);
    TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
        pMaterial->Ambient.b, pMaterial->Ambient.a);
    TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
        pMaterial->Specular.b, pMaterial->Specular.a);
    TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
        pMaterial->Emissive.b, pMaterial->Emissive.a);
3186 3187 3188
    TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);

    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3189
    checkGLcall("glMaterialfv(GL_AMBIENT)");
3190
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3191
    checkGLcall("glMaterialfv(GL_DIFFUSE)");
3192 3193

    /* Only change material color if specular is enabled, otherwise it is set to black */
3194
    if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3195
       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3196
       checkGLcall("glMaterialfv(GL_SPECULAR");
3197 3198 3199
    } else {
       float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3200
       checkGLcall("glMaterialfv(GL_SPECULAR");
3201 3202
    }
    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3203
    checkGLcall("glMaterialfv(GL_EMISSION)");
3204
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3205
    checkGLcall("glMaterialf(GL_SHININESS");
3206 3207

    LEAVE_GL();
3208
    return WINED3D_OK;
3209 3210
}

3211
static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3212 3213
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3214 3215 3216 3217 3218 3219 3220 3221
    TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
        pMaterial->Diffuse.b, pMaterial->Diffuse.a);
    TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
        pMaterial->Ambient.b, pMaterial->Ambient.a);
    TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
        pMaterial->Specular.b, pMaterial->Specular.a);
    TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
        pMaterial->Emissive.b, pMaterial->Emissive.a);
3222
    TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3223

3224
    return WINED3D_OK;
3225 3226
}

3227 3228 3229
/*****
 * Get / Set Indices
 *****/
3230
static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
                                             UINT BaseVertexIndex) {
    IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DIndexBuffer *oldIdxs;

    TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
    oldIdxs = This->updateStateBlock->pIndexData;

    This->updateStateBlock->changed.indices = TRUE;
    This->updateStateBlock->set.indices = TRUE;
    This->updateStateBlock->pIndexData = pIndexData;
    This->updateStateBlock->baseVertexIndex = BaseVertexIndex;

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3246
        return WINED3D_OK;
3247 3248
    }

3249 3250
    if (NULL != pIndexData) {
        IWineD3DIndexBuffer_AddRef(pIndexData);
3251
    }
3252 3253
    if (NULL != oldIdxs) {
        IWineD3DIndexBuffer_Release(oldIdxs);
3254
    }
3255
    return WINED3D_OK;
3256 3257
}

3258
static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3259 3260 3261
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    *ppIndexData = This->stateBlock->pIndexData;
3262

3263
    /* up ref count on ppindexdata */
3264
    if (*ppIndexData) {
3265
        IWineD3DIndexBuffer_AddRef(*ppIndexData);
3266 3267 3268 3269 3270
        *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
        TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
    }else{
        TRACE("(%p) No index data set\n", This);
    }
3271
    TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3272

3273
    return WINED3D_OK;
3274 3275 3276 3277 3278
}

/*****
 * Get / Set Viewports
 *****/
3279
static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3280 3281 3282 3283 3284 3285 3286 3287 3288 3289
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("(%p)\n", This);
    This->updateStateBlock->changed.viewport = TRUE;
    This->updateStateBlock->set.viewport = TRUE;
    memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3290
        return WINED3D_OK;
3291
    }
3292
    This->viewport_changed = TRUE;
3293 3294 3295

    ENTER_GL();

3296
    TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3297 3298 3299 3300 3301
          pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);

    glDepthRange(pViewport->MinZ, pViewport->MaxZ);
    checkGLcall("glDepthRange");
    /* Note: GL requires lower left, DirectX supplies upper left */
3302
    /* TODO: replace usage of renderTarget with context management */
3303 3304 3305 3306
    glViewport(pViewport->X,
               (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
               pViewport->Width, pViewport->Height);

3307 3308 3309 3310
    checkGLcall("glViewport");

    LEAVE_GL();

3311
    return WINED3D_OK;
3312 3313 3314

}

3315
static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3316 3317 3318
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)\n", This);
    memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3319
    return WINED3D_OK;
3320 3321
}

3322 3323 3324 3325
/*****
 * Get / Set Render States
 * TODO: Verify against dx9 definitions
 *****/
3326
static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3327 3328

    IWineD3DDeviceImpl  *This     = (IWineD3DDeviceImpl *)iface;
3329
    DWORD oldValue = This->stateBlock->renderState[State];
3330

3331
    TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3332

3333 3334 3335 3336 3337 3338 3339
    This->updateStateBlock->changed.renderState[State] = TRUE;
    This->updateStateBlock->set.renderState[State] = TRUE;
    This->updateStateBlock->renderState[State] = Value;

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3340
        return WINED3D_OK;
3341 3342
    }

3343 3344 3345 3346 3347 3348
    /* Compared here and not before the assignment to allow proper stateblock recording */
    if(Value == oldValue) {
        TRACE("Application is setting the old value over, nothing to do\n");
    } else {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
    }
3349

3350
    return WINED3D_OK;
3351 3352
}

3353
static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3354
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3355
    TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3356
    *pValue = This->stateBlock->renderState[State];
3357
    return WINED3D_OK;
3358 3359
}

3360
/*****
3361
 * Get / Set Sampler States
3362 3363 3364
 * TODO: Verify against dx9 definitions
 *****/

3365
static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    /**
    * SetSampler is designed to allow for more than the standard up to 8 textures
    *  and Geforce has stopped supporting more than 6 standard textures in openGL.
    * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
    *
    * http://developer.nvidia.com/object/General_FAQ.html#t6
    *
    * There are two new settings for GForce
    * the sampler one:
    * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
    * and the texture one:
    * GL_MAX_TEXTURE_COORDS_ARB.
    * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
     ******************/
3381
    /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3382
    if(Sampler >  GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3383
         FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3384
            Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3385
        return WINED3DERR_INVALIDCALL;
3386
    }
3387

3388
    TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3389
        debug_d3dsamplerstate(Type), Type, Value);
3390
    This->updateStateBlock->samplerState[Sampler][Type]         = Value;
3391 3392
    This->updateStateBlock->set.samplerState[Sampler][Type]     = Value;
    This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3393 3394 3395 3396

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3397
        return WINED3D_OK;
3398 3399
    }

3400
    return WINED3D_OK;
3401 3402
}

3403
static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3404
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405
    /** TODO: check that sampler is in  range **/
3406
    *Value = This->stateBlock->samplerState[Sampler][Type];
3407
    TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3408

3409
    return WINED3D_OK;
3410 3411
}

3412
static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3413
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 3415
    RECT windowRect;
    UINT winHeight;
3416

3417 3418 3419 3420 3421 3422 3423 3424 3425 3426
    GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
    /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
    * Warning2: Even in windowed mode the coords are relative to the window, not the screen
    */
    winHeight = windowRect.bottom - windowRect.top;
    TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
          pRect->right - pRect->left, pRect->bottom - pRect->top);
    ENTER_GL();
    glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
    checkGLcall("glScissor");
3427
    LEAVE_GL();
3428

3429
    return WINED3D_OK;
3430 3431
}

3432
static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3433 3434 3435 3436 3437 3438
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    GLint scissorBox[4];

    ENTER_GL();
    /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
    glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3439 3440 3441 3442
    pRect->left = scissorBox[0];
    pRect->top = scissorBox[1];
    pRect->right = scissorBox[0] + scissorBox[2];
    pRect->bottom = scissorBox[1] + scissorBox[3];
3443
    TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3444
    LEAVE_GL();
3445
    return WINED3D_OK;
3446 3447
}

3448
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3449
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3450
    IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3451

3452 3453
    TRACE("(%p) : pDecl=%p\n", This, pDecl);

3454 3455 3456 3457 3458 3459 3460 3461
    This->updateStateBlock->vertexDecl = pDecl;
    This->updateStateBlock->changed.vertexDecl = TRUE;
    This->updateStateBlock->set.vertexDecl = TRUE;

    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
    }

3462 3463 3464
    if (NULL != pDecl) {
        IWineD3DVertexDeclaration_AddRef(pDecl);
    }
3465 3466
    if (NULL != oldDecl) {
        IWineD3DVertexDeclaration_Release(oldDecl);
3467
    }
3468
    return WINED3D_OK;
3469 3470
}

3471
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3472 3473 3474
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3475

3476
    *ppDecl = This->stateBlock->vertexDecl;
3477
    if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3478
    return WINED3D_OK;
3479 3480
}

3481
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3482 3483
    IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
    IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3484

3485
    This->updateStateBlock->vertexShader         = pShader;
3486
    This->updateStateBlock->changed.vertexShader = TRUE;
3487
    This->updateStateBlock->set.vertexShader     = TRUE;
3488

3489 3490
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3491 3492
    }

3493 3494 3495 3496 3497 3498 3499
    if (NULL != pShader) {
        IWineD3DVertexShader_AddRef(pShader);
    }
    if (NULL != oldShader) {
        IWineD3DVertexShader_Release(oldShader);
    }

3500
    TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3501 3502 3503
    /**
     * TODO: merge HAL shaders context switching from prototype
     */
3504
    return WINED3D_OK;
3505 3506
}

3507
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3508
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3509 3510

    if (NULL == ppShader) {
3511
        return WINED3DERR_INVALIDCALL;
3512 3513 3514
    }
    *ppShader = This->stateBlock->vertexShader;
    if( NULL != *ppShader)
3515
        IWineD3DVertexShader_AddRef(*ppShader);
3516

3517
    TRACE("(%p) : returning %p\n", This, *ppShader);
3518
    return WINED3D_OK;
3519 3520
}

3521
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3522 3523 3524 3525
    IWineD3DDevice *iface,
    UINT start,
    CONST BOOL *srcData,
    UINT count) {
3526

3527
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3528
    int i, cnt = min(count, MAX_CONST_B - start);
3529

3530 3531
    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);
3532

3533 3534
    if (srcData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;
3535

3536
    memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3537
    for (i = 0; i < cnt; i++)
3538
        TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3539

3540
    for (i = start; i < cnt + start; ++i) {
3541 3542
        This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
        This->updateStateBlock->set.vertexShaderConstantsB[i]     = TRUE;
3543
    }
3544

3545
    return WINED3D_OK;
3546 3547
}

3548
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3549 3550 3551 3552
    IWineD3DDevice *iface,
    UINT start,
    BOOL *dstData,
    UINT count) {
3553

3554
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555
    int cnt = min(count, MAX_CONST_B - start);
3556

3557 3558
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3559

3560
    if (dstData == NULL || cnt < 0)
3561
        return WINED3DERR_INVALIDCALL;
3562

3563
    memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3564
    return WINED3D_OK;
3565 3566
}

3567
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3568 3569 3570 3571
    IWineD3DDevice *iface,
    UINT start,
    CONST int *srcData,
    UINT count) {
3572

3573
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3574
    int i, cnt = min(count, MAX_CONST_I - start);
3575

3576 3577 3578 3579 3580 3581
    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);

    if (srcData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3582
    memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3583
    for (i = 0; i < cnt; i++)
3584
        TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3585
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3586 3587 3588 3589 3590 3591 3592

    for (i = start; i < cnt + start; ++i) {
        This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
        This->updateStateBlock->set.vertexShaderConstantsI[i]     = TRUE;
    }

    return WINED3D_OK;
3593
}
3594

3595
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3596 3597 3598 3599 3600
    IWineD3DDevice *iface,
    UINT start,
    int *dstData,
    UINT count) {

3601
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3602
    int cnt = min(count, MAX_CONST_I - start);
3603 3604 3605 3606

    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);

3607
    if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3608 3609
        return WINED3DERR_INVALIDCALL;

3610
    memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3611
    return WINED3D_OK;
3612
}
3613

3614
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3615 3616 3617 3618
    IWineD3DDevice *iface,
    UINT start,
    CONST float *srcData,
    UINT count) {
3619

3620
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3621
    int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3622 3623 3624

    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);
3625

3626
    if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3627 3628
        return WINED3DERR_INVALIDCALL;

3629
    memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3630
    for (i = 0; i < cnt; i++)
3631
        TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3632
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3633 3634

    for (i = start; i < cnt + start; ++i) {
3635 3636 3637 3638 3639 3640
        if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
            constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
            ptr->idx = i;
            list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
            This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
        }
3641 3642 3643 3644
        This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
    }

    return WINED3D_OK;
3645
}
3646

3647
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3648 3649 3650 3651 3652
    IWineD3DDevice *iface,
    UINT start,
    float *dstData,
    UINT count) {

3653
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3654
    int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3655

3656 3657
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3658

3659 3660 3661
    if (dstData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3662
    memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3663
    return WINED3D_OK;
3664 3665
}

3666
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3667
    IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
3668
    IWineD3DPixelShader *oldShader  = This->updateStateBlock->pixelShader;
3669 3670 3671 3672 3673 3674
    This->updateStateBlock->pixelShader         = pShader;
    This->updateStateBlock->changed.pixelShader = TRUE;
    This->updateStateBlock->set.pixelShader     = TRUE;

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
3675
        TRACE("Recording... not performing anything\n");
3676
    }
3677

3678 3679 3680 3681 3682 3683 3684
    if (NULL != pShader) {
        IWineD3DPixelShader_AddRef(pShader);
    }
    if (NULL != oldShader) {
        IWineD3DPixelShader_Release(oldShader);
    }

3685
    TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3686 3687 3688
    /**
     * TODO: merge HAL shaders context switching from prototype
     */
3689
    return WINED3D_OK;
3690 3691
}

3692
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3693
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3694

3695
    if (NULL == ppShader) {
3696
        WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3697
        return WINED3DERR_INVALIDCALL;
3698 3699
    }

3700
    *ppShader =  This->stateBlock->pixelShader;
3701
    if (NULL != *ppShader) {
3702 3703 3704
        IWineD3DPixelShader_AddRef(*ppShader);
    }
    TRACE("(%p) : returning %p\n", This, *ppShader);
3705
    return WINED3D_OK;
3706 3707
}

3708
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3709 3710 3711 3712
    IWineD3DDevice *iface,
    UINT start,
    CONST BOOL *srcData,
    UINT count) {
3713

3714
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3715
    int i, cnt = min(count, MAX_CONST_B - start);
3716

3717 3718
    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);
3719

3720 3721
    if (srcData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;
3722

3723
    memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3724
    for (i = 0; i < cnt; i++)
3725
        TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3726

3727
    for (i = start; i < cnt + start; ++i) {
3728 3729
        This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
        This->updateStateBlock->set.pixelShaderConstantsB[i]     = TRUE;
3730
    }
3731

3732
    return WINED3D_OK;
3733 3734
}

3735
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3736 3737 3738 3739
    IWineD3DDevice *iface,
    UINT start,
    BOOL *dstData,
    UINT count) {
3740

3741
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3742
    int cnt = min(count, MAX_CONST_B - start);
3743

3744 3745
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3746

3747
    if (dstData == NULL || cnt < 0)
3748
        return WINED3DERR_INVALIDCALL;
3749

3750
    memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3751
    return WINED3D_OK;
3752 3753
}

3754
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3755 3756 3757 3758
    IWineD3DDevice *iface,
    UINT start,
    CONST int *srcData,
    UINT count) {
3759 3760

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761
    int i, cnt = min(count, MAX_CONST_I - start);
3762

3763 3764
    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);
3765

3766 3767 3768
    if (srcData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3769
    memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3770
    for (i = 0; i < cnt; i++)
3771
        TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3772
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3773 3774 3775 3776 3777

    for (i = start; i < cnt + start; ++i) {
        This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
        This->updateStateBlock->set.pixelShaderConstantsI[i]     = TRUE;
    }
3778

3779
    return WINED3D_OK;
3780
}
3781

3782
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3783 3784 3785 3786 3787
    IWineD3DDevice *iface,
    UINT start,
    int *dstData,
    UINT count) {

3788
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3789
    int cnt = min(count, MAX_CONST_I - start);
3790 3791 3792 3793 3794 3795 3796

    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);

    if (dstData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3797
    memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3798
    return WINED3D_OK;
3799 3800
}

3801
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3802 3803 3804 3805 3806
    IWineD3DDevice *iface,
    UINT start,
    CONST float *srcData,
    UINT count) {

3807
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3808
    int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3809 3810 3811 3812 3813 3814 3815

    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);

    if (srcData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3816
    memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3817
    for (i = 0; i < cnt; i++)
3818
        TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3819
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3820 3821

    for (i = start; i < cnt + start; ++i) {
3822 3823 3824 3825 3826 3827
        if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
            constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
            ptr->idx = i;
            list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
            This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
        }
3828 3829 3830 3831
        This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
    }

    return WINED3D_OK;
3832 3833
}

3834
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3835 3836 3837 3838 3839
    IWineD3DDevice *iface,
    UINT start,
    float *dstData,
    UINT count) {

3840
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3841
    int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3842

3843 3844
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3845

3846 3847 3848
    if (dstData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3849
    memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3850
    return WINED3D_OK;
3851 3852
}

3853 3854 3855
#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
static HRESULT
process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3856
    char *dest_ptr, *dest_conv = NULL;
3857 3858
    unsigned int i;
    DWORD DestFVF = dest->fvf;
3859
    WINED3DVIEWPORT vp;
3860
    WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3861 3862 3863
    BOOL doClip;
    int numTextures;

3864
    if (SrcFVF & WINED3DFVF_NORMAL) {
3865 3866 3867
        WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
    }

3868
    if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3869 3870 3871 3872
        ERR("Source has no position mask\n");
        return WINED3DERR_INVALIDCALL;
    }

3873 3874 3875
    /* We might access VBOs from this code, so hold the lock */
    ENTER_GL();

3876
    if (dest->resource.allocatedMemory == NULL) {
3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889
        /* This may happen if we do direct locking into a vbo. Unlikely,
         * but theoretically possible(ddraw processvertices test)
         */
        dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
        if(!dest->resource.allocatedMemory) {
            LEAVE_GL();
            ERR("Out of memory\n");
            return E_OUTOFMEMORY;
        }
        if(dest->vbo) {
            void *src;
            GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
            checkGLcall("glBindBufferARB");
3890
            src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907
            if(src) {
                memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
            }
            GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
            checkGLcall("glUnmapBufferARB");
        }
    }

    /* Get a pointer into the destination vbo(create one if none exists) and
     * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
     */
    if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
        CreateVBO(dest);
    }

    if(dest->vbo) {
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3908
        dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3909 3910 3911 3912
        if(!dest_conv) {
            ERR("glMapBuffer failed\n");
            /* Continue without storing converted vertices */
        }
3913 3914 3915
    }

    /* Should I clip?
3916
     * a) WINED3DRS_CLIPPING is enabled
3917 3918
     * b) WINED3DVOP_CLIP is passed
     */
3919
    if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935
        static BOOL warned = FALSE;
        /*
         * The clipping code is not quite correct. Some things need
         * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
         * so disable clipping for now.
         * (The graphics in Half-Life are broken, and my processvertices
         *  test crashes with IDirect3DDevice3)
        doClip = TRUE;
         */
        doClip = FALSE;
        if(!warned) {
           warned = TRUE;
           FIXME("Clipping is broken and disabled for now\n");
        }
    } else doClip = FALSE;
    dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3936 3937 3938
    if(dest_conv) {
        dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
    }
3939 3940

    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3941
                                 WINED3DTS_VIEW,
3942 3943
                                 &view_mat);
    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3944
                                 WINED3DTS_PROJECTION,
3945 3946
                                 &proj_mat);
    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3947
                                 WINED3DTS_WORLDMATRIX(0),
3948 3949
                                 &world_mat);

3950
    TRACE("View mat:\n");
3951 3952 3953 3954 3955
    TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14); \
    TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24); \
    TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34); \
    TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44); \

3956
    TRACE("Proj mat:\n");
3957 3958 3959 3960 3961
    TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14); \
    TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24); \
    TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34); \
    TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44); \

3962
    TRACE("World mat:\n");
3963 3964 3965 3966 3967 3968 3969
    TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14); \
    TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24); \
    TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34); \
    TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44); \

    /* Get the viewport */
    IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3970
    TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3971 3972 3973 3974 3975
          vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);

    multiply_matrix(&mat,&view_mat,&world_mat);
    multiply_matrix(&mat,&proj_mat,&mat);

3976
    numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3977 3978 3979 3980

    for (i = 0; i < dwCount; i+= 1) {
        unsigned int tex_index;

3981 3982
        if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
             ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014
            /* The position first */
            float *p =
              (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
            float x, y, z, rhw;
            TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);

            /* Multiplication with world, view and projection matrix */
            x =   (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
            y =   (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
            z =   (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
            rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);

            TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);

            /* WARNING: The following things are taken from d3d7 and were not yet checked
             * against d3d8 or d3d9!
             */

            /* Clipping conditions: From
             * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
             *
             * A vertex is clipped if it does not match the following requirements
             * -rhw < x <= rhw
             * -rhw < y <= rhw
             *    0 < z <= rhw
             *    0 < rhw ( Not in d3d7, but tested in d3d7)
             *
             * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
             * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
             *
             */

4015
            if( !doClip ||
4016 4017 4018 4019 4020
                ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
                  (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) && 
                  ( rhw > eps ) ) ) {

                /* "Normal" viewport transformation (not clipped)
4021
                 * 1) The values are divided by rhw
4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061
                 * 2) The y axis is negative, so multiply it with -1
                 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
                 *    -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
                 * 4) Multiply x with Width/2 and add Width/2
                 * 5) The same for the height
                 * 6) Add the viewpoint X and Y to the 2D coordinates and
                 *    The minimum Z value to z
                 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
                 *
                 * Well, basically it's simply a linear transformation into viewport
                 * coordinates
                 */

                x /= rhw;
                y /= rhw;
                z /= rhw;

                y *= -1;

                x *= vp.Width / 2;
                y *= vp.Height / 2;
                z *= vp.MaxZ - vp.MinZ;

                x += vp.Width / 2 + vp.X;
                y += vp.Height / 2 + vp.Y;
                z += vp.MinZ;

                rhw = 1 / rhw;
            } else {
                /* That vertex got clipped
                 * Contrary to OpenGL it is not dropped completely, it just
                 * undergoes a different calculation.
                 */
                TRACE("Vertex got clipped\n");
                x += rhw;
                y += rhw;

                x  /= 2;
                y  /= 2;

4062
                /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077
                 * outside of the main vertex buffer memory. That needs some more
                 * investigation...
                 */
            }

            TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);


            ( (float *) dest_ptr)[0] = x;
            ( (float *) dest_ptr)[1] = y;
            ( (float *) dest_ptr)[2] = z;
            ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */

            dest_ptr += 3 * sizeof(float);

4078
            if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4079 4080
                dest_ptr += sizeof(float);
            }
4081 4082 4083 4084 4085 4086 4087 4088 4089 4090

            if(dest_conv) {
                float w = 1 / rhw;
                ( (float *) dest_conv)[0] = x * w;
                ( (float *) dest_conv)[1] = y * w;
                ( (float *) dest_conv)[2] = z * w;
                ( (float *) dest_conv)[3] = w;

                dest_conv += 3 * sizeof(float);

4091
                if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4092 4093 4094
                    dest_conv += sizeof(float);
                }
            }
4095
        }
4096
        if (DestFVF & WINED3DFVF_PSIZE) {
4097
            dest_ptr += sizeof(DWORD);
4098
            if(dest_conv) dest_conv += sizeof(DWORD);
4099
        }
4100
        if (DestFVF & WINED3DFVF_NORMAL) {
4101 4102 4103 4104 4105
            float *normal =
              (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
            /* AFAIK this should go into the lighting information */
            FIXME("Didn't expect the destination to have a normal\n");
            copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4106 4107 4108
            if(dest_conv) {
                copy_and_next(dest_conv, normal, 3 * sizeof(float));
            }
4109 4110
        }

4111
        if (DestFVF & WINED3DFVF_DIFFUSE) {
4112 4113 4114 4115 4116
            DWORD *color_d = 
              (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
            if(!color_d) {
                static BOOL warned = FALSE;

4117
                if(!warned) {
4118 4119 4120 4121 4122 4123
                    ERR("No diffuse color in source, but destination has one\n");
                    warned = TRUE;
                }

                *( (DWORD *) dest_ptr) = 0xffffffff;
                dest_ptr += sizeof(DWORD);
4124 4125 4126 4127 4128

                if(dest_conv) {
                    *( (DWORD *) dest_conv) = 0xffffffff;
                    dest_conv += sizeof(DWORD);
                }
4129
            }
4130
            else {
4131
                copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4132 4133 4134 4135 4136 4137 4138
                if(dest_conv) {
                    *( (DWORD *) dest_conv)  = (*color_d & 0xff00ff00)      ; /* Alpha + green */
                    *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
                    *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
                    dest_conv += sizeof(DWORD);
                }
            }
4139 4140
        }

4141
        if (DestFVF & WINED3DFVF_SPECULAR) { 
4142 4143 4144 4145 4146 4147
            /* What's the color value in the feedback buffer? */
            DWORD *color_s = 
              (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
            if(!color_s) {
                static BOOL warned = FALSE;

4148
                if(!warned) {
4149 4150 4151 4152 4153 4154
                    ERR("No specular color in source, but destination has one\n");
                    warned = TRUE;
                }

                *( (DWORD *) dest_ptr) = 0xFF000000;
                dest_ptr += sizeof(DWORD);
4155 4156 4157 4158 4159

                if(dest_conv) {
                    *( (DWORD *) dest_conv) = 0xFF000000;
                    dest_conv += sizeof(DWORD);
                }
4160 4161 4162
            }
            else {
                copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4163 4164 4165 4166 4167 4168
                if(dest_conv) {
                    *( (DWORD *) dest_conv)  = (*color_s & 0xff00ff00)      ; /* Alpha + green */
                    *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
                    *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
                    dest_conv += sizeof(DWORD);
                }
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178
            }
        }

        for (tex_index = 0; tex_index < numTextures; tex_index++) {
            float *tex_coord =
              (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) + 
                            i * lpStrideData->u.s.texCoords[tex_index].dwStride);
            if(!tex_coord) {
                ERR("No source texture, but destination requests one\n");
                dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4179
                if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4180 4181 4182
            }
            else {
                copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4183 4184 4185
                if(dest_conv) {
                    copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
                }
4186 4187 4188 4189
            }
        }
    }

4190 4191 4192 4193 4194 4195 4196
    if(dest_conv) {
        GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
        checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
    }

    LEAVE_GL();

4197 4198 4199 4200
    return WINED3D_OK;
}
#undef copy_and_next

4201
static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4202
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4203 4204
    IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
    WineDirect3DVertexStridedData strided;
4205
    TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4206

4207 4208 4209 4210
    if (!SrcImpl) {
        WARN("NULL source vertex buffer\n");
        return WINED3DERR_INVALIDCALL;
    }
4211 4212 4213 4214 4215
    /* We don't need the source vbo because this buffer is only used as
     * a source for ProcessVertices. Avoid wasting resources by converting the
     * buffer and loading the VBO
     */
    if(SrcImpl->vbo) {
4216
        TRACE("Releasing the source vbo, it won't be needed\n");
4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230

        if(!SrcImpl->resource.allocatedMemory) {
            /* Rescue the data from the buffer */
            void *src;
            SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
            if(!SrcImpl->resource.allocatedMemory) {
                ERR("Out of memory\n");
                return E_OUTOFMEMORY;
            }

            ENTER_GL();
            GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
            checkGLcall("glBindBufferARB");

4231
            src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250
            if(src) {
                memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
            }

            GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
            checkGLcall("glUnmapBufferARB");
        } else {
            ENTER_GL();
        }

        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
        checkGLcall("glBindBufferARB");
        GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
        checkGLcall("glDeleteBuffersARB");
        LEAVE_GL();

        SrcImpl->vbo = 0;
    }

4251
    memset(&strided, 0, sizeof(strided));
4252
    primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4253 4254

    return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4255
}
4256 4257

/*****
4258
 * Apply / Get / Set Texture Stage States
4259 4260 4261
 * TODO: Verify against dx9 definitions
 *****/

4262
/* NOTE: It's expected that this function is going to be called lots of times with the same stage active, so make it the callers responsibility to GLACTIVETEXTURE(Stage) for better state management. Set the correct Texture unit active before calling ApplyTextureStageState */
4263
static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
4264 4265
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    DWORD Value = This->updateStateBlock->textureState[Stage][Type];
4266
    /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4267

4268
    TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4269

4270
    /* Check that the stage is within limits  */
4271
    if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
4272
        TRACE("Attempt to access invalid texture rejected\n");
4273
        return;
4274 4275 4276 4277 4278
    }

    ENTER_GL();

    switch (Type) {
4279 4280
    case WINED3DTSS_ALPHAOP               :
    case WINED3DTSS_COLOROP               :
4281 4282
        /* nothing to do as moved to drawprim for now */
        break;
4283
    case WINED3DTSS_ADDRESSW              :
4284 4285
#if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
            if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
4286
                FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
4287

4288 4289 4290 4291 4292 4293 4294
            } else {
                GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
                TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
                glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
                checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
            }
#endif
4295
    case WINED3DTSS_TEXCOORDINDEX         :
4296 4297 4298
        {
            /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */

4299
            /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
4300 4301
                  one flag, you can still specify an index value, which the system uses to
                  determine the texture wrapping mode.
4302
                  eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 );
4303
                  means use the vertex position (camera-space) as the input texture coordinates
4304
                  for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
4305
                  state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
4306
                  to the TEXCOORDINDEX value */
4307 4308 4309

            /**
             * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
4310 4311
             */
            switch (Value & 0xFFFF0000) {
4312
            case WINED3DTSS_TCI_PASSTHRU:
4313 4314 4315 4316 4317 4318 4319
                /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
                glDisable(GL_TEXTURE_GEN_S);
                glDisable(GL_TEXTURE_GEN_T);
                glDisable(GL_TEXTURE_GEN_R);
                glDisable(GL_TEXTURE_GEN_Q);
                checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
                break;
4320

4321
            case WINED3DTSS_TCI_CAMERASPACEPOSITION:
4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
                /* CameraSpacePosition means use the vertex position, transformed to camera space,
                    as the input texture coordinates for this stage's texture transformation. This
                    equates roughly to EYE_LINEAR                                                  */
                {
                    float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
                    float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
                    float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
                    float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
                    TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
    
                    glMatrixMode(GL_MODELVIEW);
                    glPushMatrix();
                    glLoadIdentity();
                    glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
                    glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
                    glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
                    glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
                    glPopMatrix();
    
                    TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
                    glEnable(GL_TEXTURE_GEN_S);
                    checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
                    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
                    checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
                    glEnable(GL_TEXTURE_GEN_T);
                    checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
                    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
                    checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
                    glEnable(GL_TEXTURE_GEN_R);
                    checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
                    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
                    checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
                }
                break;
4356

4357
            case WINED3DTSS_TCI_CAMERASPACENORMAL:
4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387
                {
                    if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
                        float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
                        float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
                        float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
                        float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
                        TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
        
                        glMatrixMode(GL_MODELVIEW);
                        glPushMatrix();
                        glLoadIdentity();
                        glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
                        glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
                        glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
                        glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
                        glPopMatrix();
        
                        glEnable(GL_TEXTURE_GEN_S);
                        checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
                        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
                        checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
                        glEnable(GL_TEXTURE_GEN_T);
                        checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
                        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
                        checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
                        glEnable(GL_TEXTURE_GEN_R);
                        checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
                        glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
                        checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
                    }
4388
                }
4389
                break;
4390

4391
            case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421
                {
                    if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
                    float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
                    float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
                    float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
                    float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
                    TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
    
                    glMatrixMode(GL_MODELVIEW);
                    glPushMatrix();
                    glLoadIdentity();
                    glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
                    glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
                    glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
                    glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
                    glPopMatrix();
    
                    glEnable(GL_TEXTURE_GEN_S);
                    checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
                    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
                    checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
                    glEnable(GL_TEXTURE_GEN_T);
                    checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
                    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
                    checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
                    glEnable(GL_TEXTURE_GEN_R);
                    checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
                    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
                    checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
                    }
4422
                }
4423
                break;
4424 4425 4426 4427

            /* Unhandled types: */
            default:
                /* Todo: */
4428
                /* ? disable GL_TEXTURE_GEN_n ? */
4429 4430 4431
                glDisable(GL_TEXTURE_GEN_S);
                glDisable(GL_TEXTURE_GEN_T);
                glDisable(GL_TEXTURE_GEN_R);
4432
                glDisable(GL_TEXTURE_GEN_Q);
4433
                FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
4434 4435 4436 4437 4438 4439
                break;
            }
        }
        break;

        /* Unhandled */
4440
    case WINED3DTSS_TEXTURETRANSFORMFLAGS :
4441
        set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU);
4442
        break;
4443

4444 4445
    case WINED3DTSS_BUMPENVMAT00          :
    case WINED3DTSS_BUMPENVMAT01          :
4446
        TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
4447
        break;
4448 4449
    case WINED3DTSS_BUMPENVMAT10          :
    case WINED3DTSS_BUMPENVMAT11          :
4450
        TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
4451 4452
        break;

4453
    case WINED3DTSS_BUMPENVLSCALE         :
4454
      TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4455 4456
      break;

4457
    case WINED3DTSS_BUMPENVLOFFSET        :
4458
      TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4459 4460
      break;

4461
    case WINED3DTSS_RESULTARG             :
4462
      TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4463 4464 4465
      break;

    default:
4466 4467
        /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
        TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4468 4469 4470 4471
    }

    LEAVE_GL();

4472 4473 4474
    return;
}

4475 4476 4477 4478
/*****
 * Get / Set Texture Stage States
 * TODO: Verify against dx9 definitions
 *****/
4479
static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4480 4481 4482 4483
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */

4484
    TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4485 4486

    /* Reject invalid texture units */
4487
    if (Stage >= GL_LIMITS(texture_stages)) {
4488
        TRACE("Attempt to access invalid texture rejected\n");
4489
        return WINED3DERR_INVALIDCALL;
4490 4491
    }

4492 4493
    This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
    This->updateStateBlock->set.textureState[Stage][Type]     = TRUE;
4494 4495
    This->updateStateBlock->textureState[Stage][Type]         = Value;

4496
    return WINED3D_OK;
4497 4498
}

4499
static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4500
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4501
    TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4502
    *pValue = This->updateStateBlock->textureState[Stage][Type];
4503
    return WINED3D_OK;
4504 4505
}

4506
/*****
4507
 * Get / Set Texture
4508
 *****/
4509
static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4510 4511 4512 4513 4514

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DBaseTexture   *oldTexture;

    oldTexture = This->updateStateBlock->textures[Stage];
4515
    TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4516

4517 4518 4519
#if 0 /* TODO: check so vertex textures */
    if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
        This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4520
        return WINED3D_OK;
4521 4522 4523
    }
#endif

4524
    /* Reject invalid texture units */
4525
    if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4526
        WARN("Attempt to access invalid texture rejected\n");
4527
        return WINED3DERR_INVALIDCALL;
4528 4529
    }

4530
    if(pTexture != NULL) {
4531 4532 4533
        /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH; 
         */
        if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4534
            WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4535
            return WINED3DERR_INVALIDCALL;
4536 4537 4538
        }
    }

4539
    oldTexture = This->updateStateBlock->textures[Stage];
4540
    TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4541 4542 4543
    TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);

    This->updateStateBlock->set.textures[Stage]     = TRUE;
4544
    This->updateStateBlock->changed.textures[Stage] = TRUE;
4545 4546
    TRACE("(%p) : setting new texture to %p\n", This, pTexture);
    This->updateStateBlock->textures[Stage]         = pTexture;
4547 4548 4549 4550

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
4551
        return WINED3D_OK;
4552 4553
    }

4554 4555
    /** NOTE: MSDN says that setTexture increases the reference count,
    * and the the application nust set the texture back to null (or have a leaky application),
4556
    * This means we should pass the refcount up to the parent
4557
     *******************************/
4558
    if (NULL != This->updateStateBlock->textures[Stage]) {
4559
        IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4560
    }
4561

4562
    if (NULL != oldTexture) {
4563
        IWineD3DBaseTexture_Release(oldTexture);
4564
    }
4565

4566 4567 4568
    /* Color keying is affected by the texture. Temporarily mark the color key state (=alpha test)
     * dirty until textures are integrated with the state management
     */
4569
    if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
4570
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORKEYENABLE));
4571 4572
    }

4573
    return WINED3D_OK;
4574 4575
}

4576
static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4577
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578
    TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4579 4580

    /* Reject invalid texture units */
4581
    if (Stage >= GL_LIMITS(sampler_stages)) {
4582
        TRACE("Attempt to access invalid texture rejected\n");
4583
        return WINED3DERR_INVALIDCALL;
4584
    }
4585
    *ppTexture=This->stateBlock->textures[Stage];
4586 4587
    if (*ppTexture)
        IWineD3DBaseTexture_AddRef(*ppTexture);
4588

4589
    return WINED3D_OK;
4590 4591 4592 4593 4594
}

/*****
 * Get Back Buffer
 *****/
4595
static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4596
                                                IWineD3DSurface **ppBackBuffer) {
4597
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4598 4599 4600
    IWineD3DSwapChain *swapChain;
    HRESULT hr;

4601 4602
    TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);

Oliver Stieber's avatar
Oliver Stieber committed
4603
    hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, &swapChain);
4604
    if (hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
4605
        hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4606
            IWineD3DSwapChain_Release(swapChain);
4607
    } else {
Oliver Stieber's avatar
Oliver Stieber committed
4608
        *ppBackBuffer = NULL;
4609
    }
Oliver Stieber's avatar
Oliver Stieber committed
4610
    return hr;
4611 4612
}

4613
static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4614 4615
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    WARN("(%p) : stub, calling idirect3d for now\n", This);
4616
    return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4617 4618
}

4619
static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4620
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4621 4622
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
4623

4624 4625 4626 4627
    if(iSwapChain > 0) {
        hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, (IWineD3DSwapChain **)&swapChain);
        if (hr == WINED3D_OK) {
            hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4628
            IWineD3DSwapChain_Release(swapChain);
4629 4630 4631
        } else {
            FIXME("(%p) Error getting display mode\n", This);
        }
4632
    } else {
4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644
        /* Don't read the real display mode,
           but return the stored mode instead. X11 can't change the color
           depth, and some apps are pretty angry if they SetDisplayMode from
           24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp

           Also don't relay to the swapchain because with ddraw it's possible
           that there isn't a swapchain at all */
        pMode->Width = This->ddraw_width;
        pMode->Height = This->ddraw_height;
        pMode->Format = This->ddraw_format;
        pMode->RefreshRate = 0;
        hr = WINED3D_OK;
Oliver Stieber's avatar
Oliver Stieber committed
4645
    }
4646

Oliver Stieber's avatar
Oliver Stieber committed
4647
    return hr;
4648
}
4649

4650
static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4651 4652
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)->(%p)\n", This, hWnd);
4653

4654 4655
    This->ddraw_window = hWnd;
    return WINED3D_OK;
4656 4657
}

4658
static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4659 4660
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)->(%p)\n", This, hWnd);
4661

4662 4663
    *hWnd = This->ddraw_window;
    return WINED3D_OK;
4664 4665
}

4666 4667 4668 4669
/*****
 * Stateblock related functions
 *****/

4670
static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4671 4672
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DStateBlockImpl *object;
4673 4674
    HRESULT temp_result;
    
4675
    TRACE("(%p)\n", This);
4676 4677
    
    if (This->isRecordingState) {
4678
        return WINED3DERR_INVALIDCALL;
4679 4680
    }
    
4681
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4682
    if (NULL == object ) {
4683 4684 4685
        FIXME("(%p)Error allocating memory for stateblock\n", This);
        return E_OUTOFMEMORY;
    }
4686
    TRACE("(%p) created object %p\n", This, object);
4687
    object->wineD3DDevice= This;
4688 4689
    /** FIXME: object->parent       = parent; **/
    object->parent       = NULL;
4690
    object->blockType    = WINED3DSBT_ALL;
4691
    object->ref          = 1;
4692
    object->lpVtbl       = &IWineD3DStateBlock_Vtbl;
4693 4694 4695 4696
    
    temp_result = allocate_shader_constants(object);
    if (WINED3D_OK != temp_result)
        return temp_result;
4697

4698 4699 4700
    IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
    This->updateStateBlock = object;
    This->isRecordingState = TRUE;
4701

4702
    TRACE("(%p) recording stateblock %p\n",This , object);
4703
    return WINED3D_OK;
4704 4705
}

4706
static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4707 4708 4709 4710 4711
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    if (!This->isRecordingState) {
        FIXME("(%p) not recording! returning error\n", This);
        *ppStateBlock = NULL;
4712
        return WINED3DERR_INVALIDCALL;
4713 4714 4715 4716
    }

    *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
    This->isRecordingState = FALSE;
4717
    This->updateStateBlock = This->stateBlock;
4718 4719 4720
    IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
    /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
    TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4721
    return WINED3D_OK;
4722 4723
}

4724 4725 4726
/*****
 * Scene related functions
 *****/
4727
static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4728 4729 4730 4731
    /* At the moment we have no need for any functionality at the beginning
       of a scene                                                          */
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p) : stub\n", This);
4732
    return WINED3D_OK;
4733 4734
}

4735
static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4736 4737 4738
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)\n", This);
    ENTER_GL();
4739
    /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4740 4741 4742
    glFlush();
    checkGLcall("glFlush");

4743
    TRACE("End Scene\n");
4744 4745
    /* If we're using FBOs this isn't needed */
    if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
4746

4747 4748
        /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
        IUnknown *targetContainer = NULL;
4749 4750
        if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
            || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
4751
            TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
4752 4753 4754 4755 4756
            /** always dirtify for now. we must find a better way to see that surface have been modified
            (Modifications should will only occur via draw-primitive, but we do need better locking
            switching to render-to-texture should remove the overhead though.
            */
            IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
4757 4758
            IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
            IWineD3DSurface_PreLoad(This->renderTarget);
4759 4760
            IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
            IUnknown_Release(targetContainer);
4761
        }
4762
    }
4763
    This->sceneEnded = TRUE;
4764
    LEAVE_GL();
4765
    return WINED3D_OK;
4766 4767
}

4768
static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4769
                                          CONST RECT* pSourceRect, CONST RECT* pDestRect,
4770
                                          HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4771
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4772 4773 4774
    IWineD3DSwapChain *swapChain = NULL;
    int i;
    int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4775

Oliver Stieber's avatar
Oliver Stieber committed
4776
    TRACE("(%p) Presenting the frame\n", This);
4777

4778
    for(i = 0 ; i < swapchains ; i ++) {
4779

Oliver Stieber's avatar
Oliver Stieber committed
4780 4781 4782
        IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
        TRACE("presentinng chain %d, %p\n", i, swapChain);
        IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4783
        IWineD3DSwapChain_Release(swapChain);
4784 4785
    }

4786
    return WINED3D_OK;
4787 4788
}

4789
static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4790
                                        DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4791 4792
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

4793 4794
    /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
      render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4795 4796 4797 4798 4799 4800 4801
      when the depth-buffer format does not contain stencil buffer information, this method fails. */
    GLbitfield     glMask = 0;
    GLboolean      old_ztest;
    GLfloat        old_z_clear_value;
    GLint          old_stencil_clear_value;
    GLfloat        old_color_clear_value[4];
    unsigned int   i;
4802
    CONST WINED3DRECT* curRect;
4803

4804
    TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
          Count, pRects, Flags, Z, Stencil);

    ENTER_GL();

    glEnable(GL_SCISSOR_TEST);
    checkGLcall("glEnable GL_SCISSOR_TEST");

    if (Count > 0 && pRects) {
        curRect = pRects;
    } else {
        curRect = NULL;
    }

    /* Only set the values up once, as they are not changing */
4819
    if (Flags & WINED3DCLEAR_STENCIL) {
4820 4821 4822 4823 4824 4825 4826
        glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
        glClearStencil(Stencil);
        checkGLcall("glClearStencil");
        glMask = glMask | GL_STENCIL_BUFFER_BIT;
        glStencilMask(0xFFFFFFFF);
    }

4827
    if (Flags & WINED3DCLEAR_ZBUFFER) {
4828
        glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4829
        glDepthMask(GL_TRUE);
4830 4831 4832 4833 4834 4835
        glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
        glClearDepth(Z);
        checkGLcall("glClearDepth");
        glMask = glMask | GL_DEPTH_BUFFER_BIT;
    }

4836
    if (Flags & WINED3DCLEAR_TARGET) {
4837
        TRACE("Clearing screen with glClear to color %x\n", Color);
4838
        glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4839 4840 4841 4842
        glClearColor(D3DCOLOR_R(Color),
                     D3DCOLOR_G(Color),
                     D3DCOLOR_B(Color),
                     D3DCOLOR_A(Color));
4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854
        checkGLcall("glClearColor");

        /* Clear ALL colors! */
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glMask = glMask | GL_COLOR_BUFFER_BIT;
    }

    /* Now process each rect in turn */
    for (i = 0; i < Count || i == 0; i++) {

        if (curRect) {
            /* Note gl uses lower left, width/height */
4855
            TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4856
                  curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4857
                  curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
4858
                  curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4859
            glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
4860 4861 4862
                      curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
            checkGLcall("glScissor");
        } else {
4863
            glScissor(This->stateBlock->viewport.X,
4864 4865
                      (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - 
                      (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4866
                      This->stateBlock->viewport.Width,
4867 4868 4869 4870 4871 4872 4873 4874 4875
                      This->stateBlock->viewport.Height);
            checkGLcall("glScissor");
        }

        /* Clear the selected rectangle (or full screen) */
        glClear(glMask);
        checkGLcall("glClear");

        /* Step to the next rectangle */
4876
        if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4877 4878 4879
    }

    /* Restore the old values (why..?) */
4880
    if (Flags & WINED3DCLEAR_STENCIL) {
4881
        glClearStencil(old_stencil_clear_value);
4882
        glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4883
    }
4884
    if (Flags & WINED3DCLEAR_ZBUFFER) {
4885 4886 4887
        glDepthMask(old_ztest);
        glClearDepth(old_z_clear_value);
    }
4888
    if (Flags & WINED3DCLEAR_TARGET) {
4889
        glClearColor(old_color_clear_value[0],
4890
                     old_color_clear_value[1],
4891
                     old_color_clear_value[2],
4892
                     old_color_clear_value[3]);
4893 4894 4895 4896
        glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
                    This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
                    This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE  ? GL_TRUE : GL_FALSE,
                    This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4897 4898 4899 4900 4901 4902
    }

    glDisable(GL_SCISSOR_TEST);
    checkGLcall("glDisable");
    LEAVE_GL();

4903
    return WINED3D_OK;
4904 4905
}

4906 4907 4908
/*****
 * Drawing functions
 *****/
4909
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4910 4911 4912 4913 4914
                                                UINT PrimitiveCount) {

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    This->stateBlock->streamIsUP = FALSE;

4915 4916
    TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
                               debug_d3dprimitivetype(PrimitiveType),
4917
                               StartVertex, PrimitiveCount);
4918
    drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4919
                  0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
4920

4921

4922
    return WINED3D_OK;
4923 4924 4925
}

/* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4926
static HRESULT  WINAPI  IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4927
                                                           WINED3DPRIMITIVETYPE PrimitiveType,
4928
                                                           INT baseVIndex, UINT minIndex,
4929
                                                           UINT NumVertices, UINT startIndex, UINT primCount) {
4930 4931 4932 4933

    IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;
    UINT                 idxStride = 2;
    IWineD3DIndexBuffer *pIB;
4934
    WINED3DINDEXBUFFER_DESC  IdxBufDsc;
4935

4936 4937 4938
    pIB = This->stateBlock->pIndexData;
    This->stateBlock->streamIsUP = FALSE;

4939
    TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
4940 4941 4942 4943
          PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
          minIndex, NumVertices, startIndex, baseVIndex, primCount);

    IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4944
    if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4945 4946 4947 4948 4949
        idxStride = 2;
    } else {
        idxStride = 4;
    }

4950
    drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
4951
                   idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
4952

4953
    return WINED3D_OK;
4954 4955
}

4956
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4957 4958 4959 4960
                                                    UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
                                                    UINT VertexStreamZeroStride) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

4961 4962
    TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
             debug_d3dprimitivetype(PrimitiveType),
4963 4964
             PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);

4965
    /* release the stream source */
4966
    if (This->stateBlock->streamSource[0] != NULL) {
4967
        IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4968
    }
4969

4970
    /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4971 4972
    This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
    This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4973
    This->stateBlock->streamIsUP = TRUE;
4974 4975

    drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0  /* NumVertices */,
4976
                  0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
4977 4978

    /* MSDN specifies stream zero settings must be set to NULL */
4979 4980
    This->stateBlock->streamStride[0] = 0;
    This->stateBlock->streamSource[0] = NULL;
4981 4982

    /*stream zero settings set to null at end, as per the msdn */
4983
    return WINED3D_OK;
4984 4985
}

4986
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4987 4988 4989
                                                             UINT MinVertexIndex, UINT NumVertices,
                                                             UINT PrimitiveCount, CONST void* pIndexData,
                                                             WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4990 4991 4992 4993
                                                             UINT VertexStreamZeroStride) {
    int                 idxStride;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

4994
    TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4995
             This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4996
             MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4997 4998
             IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);

4999
    if (IndexDataFormat == WINED3DFMT_INDEX16) {
5000 5001 5002 5003 5004
        idxStride = 2;
    } else {
        idxStride = 4;
    }

5005
    /* release the stream and index data */
5006
    if (This->stateBlock->streamSource[0] != NULL) {
5007
        IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5008 5009
    }
    if (This->stateBlock->pIndexData) {
5010
        IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
5011 5012
    }

5013
    /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5014
    This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5015
    This->stateBlock->streamIsUP = TRUE;
5016
    This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5017

5018
    drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
5019

5020
    /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5021 5022
    This->stateBlock->streamSource[0] = NULL;
    This->stateBlock->streamStride[0] = 0;
5023
    This->stateBlock->pIndexData = NULL;
5024

5025
    return WINED3D_OK;
5026 5027
}

5028
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5029 5030 5031 5032

    drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
    return WINED3D_OK;
}
5033
 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5034
static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture,  IWineD3DBaseTexture *pDestinationTexture){
5035
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5036
    HRESULT hr = WINED3D_OK;
5037 5038
    WINED3DRESOURCETYPE sourceType;
    WINED3DRESOURCETYPE destinationType;
5039
    int i ,levels;
5040

5041
    /* TODO: think about moving the code into IWineD3DBaseTexture  */
5042

5043
    TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5044

5045
    /* verify that the source and destination textures aren't NULL */
5046
    if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5047
        WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5048
             This, pSourceTexture, pDestinationTexture);
5049
        hr = WINED3DERR_INVALIDCALL;
5050
    }
5051

5052
    if (pSourceTexture == pDestinationTexture) {
5053
        WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5054
             This, pSourceTexture, pDestinationTexture);
5055
        hr = WINED3DERR_INVALIDCALL;
5056
    }
5057 5058 5059
    /* Verify that the source and destination textures are the same type */
    sourceType      = IWineD3DBaseTexture_GetType(pSourceTexture);
    destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5060

5061
    if (sourceType != destinationType) {
5062
        WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5063
             This);
5064
        hr = WINED3DERR_INVALIDCALL;
5065
    }
5066

5067 5068
    /* check that both textures have the identical numbers of levels  */
    if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture)  != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5069 5070
        WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
        hr = WINED3DERR_INVALIDCALL;
5071
    }
5072

5073
    if (WINED3D_OK == hr) {
5074 5075 5076 5077 5078 5079 5080 5081

        /* Make sure that the destination texture is loaded */
        IWineD3DBaseTexture_PreLoad(pDestinationTexture);

        /* Update every surface level of the texture */
        levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);

        switch (sourceType) {
5082
        case WINED3DRTYPE_TEXTURE:
5083 5084 5085 5086 5087 5088 5089 5090 5091 5092
            {
                IWineD3DSurface *srcSurface;
                IWineD3DSurface *destSurface;

                for (i = 0 ; i < levels ; ++i) {
                    IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture,      i, &srcSurface);
                    IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
                    hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
                    IWineD3DSurface_Release(srcSurface);
                    IWineD3DSurface_Release(destSurface);
5093
                    if (WINED3D_OK != hr) {
5094 5095 5096 5097 5098 5099
                        WARN("(%p) : Call to update surface failed\n", This);
                        return hr;
                    }
                }
            }
            break;
5100
        case WINED3DRTYPE_CUBETEXTURE:
5101 5102 5103
            {
                IWineD3DSurface *srcSurface;
                IWineD3DSurface *destSurface;
5104
                WINED3DCUBEMAP_FACES faceType;
5105 5106 5107

                for (i = 0 ; i < levels ; ++i) {
                    /* Update each cube face */
5108
                    for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5109
                        hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture,      faceType, i, &srcSurface);
5110
                        if (WINED3D_OK != hr) {
5111 5112 5113 5114 5115
                            FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
                        } else {
                            TRACE("Got srcSurface %p\n", srcSurface);
                        }
                        hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5116
                        if (WINED3D_OK != hr) {
5117 5118 5119 5120 5121 5122 5123
                            FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
                        } else {
                            TRACE("Got desrSurface %p\n", destSurface);
                        }
                        hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
                        IWineD3DSurface_Release(srcSurface);
                        IWineD3DSurface_Release(destSurface);
5124
                        if (WINED3D_OK != hr) {
5125 5126 5127 5128 5129 5130 5131 5132
                            WARN("(%p) : Call to update surface failed\n", This);
                            return hr;
                        }
                    }
                }
            }
            break;
#if 0 /* TODO: Add support for volume textures */
5133
        case WINED3DRTYPE_VOLUMETEXTURE:
5134 5135 5136 5137 5138 5139 5140 5141 5142 5143
            {
                IWineD3DVolume  srcVolume  = NULL;
                IWineD3DSurface destVolume = NULL;

                for (i = 0 ; i < levels ; ++i) {
                    IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture,      i, &srcVolume);
                    IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
                    hr =  IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
                    IWineD3DVolume_Release(srcSurface);
                    IWineD3DVolume_Release(destSurface);
5144
                    if (WINED3D_OK != hr) {
5145 5146 5147 5148 5149 5150
                        WARN("(%p) : Call to update volume failed\n", This);
                        return hr;
                    }
                }
            }
            break;
5151
#endif
5152 5153
        default:
            FIXME("(%p) : Unsupported source and destination type\n", This);
5154
            hr = WINED3DERR_INVALIDCALL;
5155
        }
5156 5157
    }

5158
    return hr;
5159
}
5160

5161
static HRESULT  WINAPI  IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5162
                                                CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5163
                                                CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
5164
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5165

5166
    TRACE("(%p) : stub\n", This);
5167
    return WINED3D_OK;
5168
}
5169
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5170
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183
    /** TODO: remove remove casts to IWineD3DSurfaceImpl *
    *  NOTE It may be best to move the code into surface to occomplish this
    ****************************************/

    WINED3DSURFACE_DESC surfaceDesc;
    unsigned int surfaceWidth, surfaceHeight;
    glDescriptor *targetGlDescription  = NULL;
    glDescriptor *surfaceGlDescription = NULL;
    IWineD3DSwapChainImpl *container = NULL;
    
    IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
    IWineD3DSurface_GetGlDesc(pSurface,      &surfaceGlDescription);
    memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5184

5185 5186 5187
    surfaceDesc.Width  = &surfaceWidth;
    surfaceDesc.Height = &surfaceHeight;
    IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5188
   /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5189

5190
    /* Ok, I may need to setup some kind of active swapchain reference on the device */
5191 5192 5193 5194
    IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
    ENTER_GL();
    /* TODO: opengl Context switching for swapchains etc... */
    if (NULL != container  || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
5195
        if (NULL != container  && (pRenderTarget == container->backBuffer[0])) {
5196 5197 5198 5199 5200 5201 5202 5203 5204
            glReadBuffer(GL_BACK);
            vcheckGLcall("glReadBuffer(GL_BACK)");
        } else if ((NULL != container  && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
            glReadBuffer(GL_FRONT);
            vcheckGLcall("glReadBuffer(GL_FRONT)");
        } else if (pRenderTarget == This->depthStencilBuffer) {
            FIXME("Reading of depthstencil not yet supported\n");
        }

5205 5206
        glReadPixels(0,
                    0,
5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219
                    surfaceWidth,
                    surfaceHeight,
                    surfaceGlDescription->glFormat,
                    surfaceGlDescription->glType,
                    (void *)IWineD3DSurface_GetData(pSurface));
        vcheckGLcall("glReadPixels(...)");
        if(NULL != container ){
            IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
        }
    } else {
        IWineD3DBaseTexture *container;
        GLenum textureDimensions = GL_TEXTURE_2D;

5220
        if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242
            textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
            IWineD3DBaseTexture_Release(container);
        }
        /* TODO: 2D -> Cube surface coppies etc.. */
        if (surfaceGlDescription->target != textureDimensions) {
            FIXME("(%p) : Texture dimension mismatch\n", This);
        }
        glEnable(textureDimensions);
        vcheckGLcall("glEnable(GL_TEXTURE_...)");
        /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
        glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
        vcheckGLcall("glBindTexture");
        glGetTexImage(surfaceGlDescription->target,
                        surfaceGlDescription->level,
                        surfaceGlDescription->glFormat,
                        surfaceGlDescription->glType,
                        (void *)IWineD3DSurface_GetData(pSurface));
        glDisable(textureDimensions);
        vcheckGLcall("glDisable(GL_TEXTURE_...)");

    }
    LEAVE_GL();
5243
    return WINED3D_OK;
5244
}
5245

5246
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
Oliver Stieber's avatar
Oliver Stieber committed
5247 5248 5249
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
    hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, (IWineD3DSwapChain **)&swapChain);
5250
    if(hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
5251
        hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5252
                IWineD3DSwapChain_Release(swapChain);
Oliver Stieber's avatar
Oliver Stieber committed
5253 5254
    }
    return hr;
5255 5256
}

5257
static HRESULT  WINAPI  IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5258 5259 5260
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    /* return a sensible default */
    *pNumPasses = 1;
5261
    /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5262
    FIXME("(%p) : stub\n", This);
5263
    return WINED3D_OK;
5264
}
5265

5266
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5267
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5268 5269 5270 5271
    int j;
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
    if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
        WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5272
        return WINED3DERR_INVALIDCALL;
5273 5274 5275 5276 5277 5278 5279 5280
    }
    for (j = 0; j < 256; ++j) {
        This->palettes[PaletteNumber][j].peRed   = pEntries[j].peRed;
        This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
        This->palettes[PaletteNumber][j].peBlue  = pEntries[j].peBlue;
        This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
    }
    TRACE("(%p) : returning\n", This);
5281
    return WINED3D_OK;
5282
}
5283

5284
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5285
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5286 5287 5288 5289
    int j;
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
    if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
        WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5290
        return WINED3DERR_INVALIDCALL;
5291 5292 5293 5294 5295 5296 5297 5298
    }
    for (j = 0; j < 256; ++j) {
        pEntries[j].peRed   = This->palettes[PaletteNumber][j].peRed;
        pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
        pEntries[j].peBlue  = This->palettes[PaletteNumber][j].peBlue;
        pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
    }
    TRACE("(%p) : returning\n", This);
5299
    return WINED3D_OK;
5300
}
5301

5302
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5303
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5304 5305 5306
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
    if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
        WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5307
        return WINED3DERR_INVALIDCALL;
5308 5309 5310 5311
    }
    /*TODO: stateblocks */
    This->currentPalette = PaletteNumber;
    TRACE("(%p) : returning\n", This);
5312
    return WINED3D_OK;
5313
}
5314

5315
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5316
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 5318
    if (PaletteNumber == NULL) {
        WARN("(%p) : returning Invalid Call\n", This);
5319
        return WINED3DERR_INVALIDCALL;
5320 5321 5322 5323
    }
    /*TODO: stateblocks */
    *PaletteNumber = This->currentPalette;
    TRACE("(%p) : returning  %u\n", This, *PaletteNumber);
5324
    return WINED3D_OK;
5325
}
5326

5327
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5328
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 5330 5331 5332 5333 5334
    static BOOL showFixmes = TRUE;
    if (showFixmes) {
        FIXME("(%p) : stub\n", This);
        showFixmes = FALSE;
    }

5335
    This->softwareVertexProcessing = bSoftware;
5336
    return WINED3D_OK;
5337 5338 5339
}


5340
static BOOL     WINAPI  IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5341
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5342 5343 5344 5345 5346
    static BOOL showFixmes = TRUE;
    if (showFixmes) {
        FIXME("(%p) : stub\n", This);
        showFixmes = FALSE;
    }
5347
    return This->softwareVertexProcessing;
5348 5349 5350
}


5351
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5352
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5353 5354
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
5355

5356 5357 5358
    TRACE("(%p) :  SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);

    hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, (IWineD3DSwapChain **)&swapChain);
5359
    if(hr == WINED3D_OK){
5360
        hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5361
        IWineD3DSwapChain_Release(swapChain);
5362
    }else{
5363
        FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5364 5365
    }
    return hr;
5366 5367 5368
}


5369
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5370 5371
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    static BOOL showfixmes = TRUE;
5372 5373
    if(nSegments != 0.0f) {
        if( showfixmes) {
5374 5375 5376
            FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
            showfixmes = FALSE;
        }
5377
    }
5378
    return WINED3D_OK;
5379
}
5380

5381
static float    WINAPI  IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5382
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5383
    static BOOL showfixmes = TRUE;
5384
    if( showfixmes) {
5385 5386 5387 5388 5389
        FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
        showfixmes = FALSE;
    }
    return 0.0f;
}
5390

5391
static HRESULT  WINAPI  IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5392 5393 5394 5395 5396
    IWineD3DDeviceImpl  *This         = (IWineD3DDeviceImpl *) iface;
    /** TODO: remove casts to IWineD3DSurfaceImpl
     *       NOTE: move code to surface to accomplish this
      ****************************************/
    IWineD3DSurfaceImpl *pSrcSurface  = (IWineD3DSurfaceImpl *)pSourceSurface;
Mike McCormack's avatar
Mike McCormack committed
5397
    int srcWidth, srcHeight;
5398
    unsigned int  srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5399
    WINED3DFORMAT destFormat, srcFormat;
5400
    UINT          destSize;
5401
    int destLeft, destTop;
5402
    WINED3DPOOL       srcPool, destPool;
5403 5404 5405 5406 5407 5408 5409 5410
    int offset    = 0;
    int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
    glDescriptor *glDescription = NULL;
    GLenum textureDimensions = GL_TEXTURE_2D;
    IWineD3DBaseTexture *baseTexture;

    WINED3DSURFACE_DESC  winedesc;

5411
    TRACE("(%p) : Source (%p)  Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427
    memset(&winedesc, 0, sizeof(winedesc));
    winedesc.Width  = &srcSurfaceWidth;
    winedesc.Height = &srcSurfaceHeight;
    winedesc.Pool   = &srcPool;
    winedesc.Format = &srcFormat;

    IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);

    winedesc.Width  = &destSurfaceWidth;
    winedesc.Height = &destSurfaceHeight;
    winedesc.Pool   = &destPool;
    winedesc.Format = &destFormat;
    winedesc.Size   = &destSize;

    IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);

5428
    if(srcPool != WINED3DPOOL_SYSTEMMEM  || destPool != WINED3DPOOL_DEFAULT){
5429 5430
        WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
        return WINED3DERR_INVALIDCALL;
5431
    }
5432 5433 5434 5435 5436 5437 5438 5439 5440

    if (destFormat == WINED3DFMT_UNKNOWN) {
        TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
        IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);

        /* Get the update surface description */
        IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
    }

5441
    /* Make sure the surface is loaded and up to date */
5442 5443 5444
    IWineD3DSurface_PreLoad(pDestinationSurface);

    IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5445

5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480
    ENTER_GL();

    /* this needs to be done in lines if the sourceRect != the sourceWidth */
    srcWidth   = pSourceRect ? pSourceRect->right - pSourceRect->left   : srcSurfaceWidth;
    srcHeight  = pSourceRect ? pSourceRect->top   - pSourceRect->bottom : srcSurfaceHeight;
    destLeft   = pDestPoint  ? pDestPoint->x : 0;
    destTop    = pDestPoint  ? pDestPoint->y : 0;


    /* This function doesn't support compressed textures
    the pitch is just bytesPerPixel * width */
    if(srcWidth != srcSurfaceWidth  || (pSourceRect != NULL && pSourceRect->left != 0) ){
        rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
        offset   += pSourceRect->left * pSrcSurface->bytesPerPixel;
        /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
    }
    /* TODO DXT formats */

    if(pSourceRect != NULL && pSourceRect->top != 0){
       offset +=  pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
    }
    TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
    ,This
    ,glDescription->level
    ,destLeft
    ,destTop
    ,srcWidth
    ,srcHeight
    ,glDescription->glFormat
    ,glDescription->glType
    ,IWineD3DSurface_GetData(pSourceSurface)
    );

    /* Sanity check */
    if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5481 5482 5483

        /* need to lock the surface to get the data */
        FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5484
    }
5485

5486 5487 5488 5489
    /* TODO: Cube and volume support */
    if(rowoffset != 0){
        /* not a whole row so we have to do it a line at a time */
        int j;
5490

5491
        /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5492
        const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503

        for(j = destTop ; j < (srcHeight + destTop) ; j++){

                glTexSubImage2D(glDescription->target
                    ,glDescription->level
                    ,destLeft
                    ,j
                    ,srcWidth
                    ,1
                    ,glDescription->glFormat
                    ,glDescription->glType
5504
                    ,data /* could be quicker using */
5505 5506 5507 5508 5509 5510 5511
                );
            data += rowoffset;
        }

    } else { /* Full width, so just write out the whole texture */

        if (WINED3DFMT_DXT1 == destFormat ||
5512
            WINED3DFMT_DXT2 == destFormat ||
5513
            WINED3DFMT_DXT3 == destFormat ||
5514
            WINED3DFMT_DXT4 == destFormat ||
5515 5516 5517
            WINED3DFMT_DXT5 == destFormat) {
            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
                if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5518
                    /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537
                    FIXME("Updating part of a compressed texture is not supported at the moment\n");
                } if (destFormat != srcFormat) {
                    FIXME("Updating mixed format compressed texture is not curretly support\n");
                } else {
                    GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
                                                        glDescription->level,
                                                        glDescription->glFormatInternal,
                                                        srcWidth,
                                                        srcHeight,
                                                        0,
                                                        destSize,
                                                        IWineD3DSurface_GetData(pSourceSurface));
                }
            } else {
                FIXME("Attempting to update a DXT compressed texture without hardware support\n");
            }


        } else {
5538
            if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5539

5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555
                /* some applications cannot handle odd pitches returned by soft non-power2, so we have
                to repack the data from pow2Width/Height to expected Width,Height, this makes the
                data returned by GetData non-power2 width/height with hardware non-power2
                pow2Width/height are set to surface width height, repacking isn't needed so it
                doesn't matter which function gets called. */
                glTexSubImage2D(glDescription->target
                        ,glDescription->level
                        ,destLeft
                        ,destTop
                        ,srcWidth
                        ,srcHeight
                        ,glDescription->glFormat
                        ,glDescription->glType
                        ,IWineD3DSurface_GetData(pSourceSurface)
                    );
            } else {
5556

5557 5558
                /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
                glTexSubImage2D(glDescription->target
5559 5560 5561
                    ,glDescription->level
                    ,destLeft
                    ,destTop
5562 5563
                    ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
                    ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5564 5565 5566 5567
                    ,glDescription->glFormat
                    ,glDescription->glType
                    ,IWineD3DSurface_GetData(pSourceSurface)
                );
5568
            }
5569 5570 5571 5572

        }
     }
    checkGLcall("glTexSubImage2D");
5573
    ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5574

5575 5576 5577
    /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
     * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
     * surface bigger than it needs to be hmm.. */
5578
    if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5579 5580 5581 5582 5583 5584 5585
        textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
        IWineD3DBaseTexture_Release(baseTexture);
    }

    glDisable(textureDimensions); /* This needs to be managed better.... */
    LEAVE_GL();

5586
    return WINED3D_OK;
5587 5588
}

5589 5590 5591 5592 5593 5594 5595 5596
/* Implementation details at http://developer.nvidia.com/attach/6494
and
http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
hmm.. no longer supported use
OpenGL evaluators or  tessellate surfaces within your application.
*/

/* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5597
static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5598
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5599
    TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5600
    FIXME("(%p) : Stub\n", This);
5601
    return WINED3D_OK;
5602 5603 5604

}

5605
/* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5606
static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5607
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5608
    TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5609
    FIXME("(%p) : Stub\n", This);
5610
    return WINED3D_OK;
5611
}
5612

5613
static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5614 5615 5616
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p) Handle(%d)\n", This, Handle);
    FIXME("(%p) : Stub\n", This);
5617
    return WINED3D_OK;
5618
}
5619

5620
static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5621 5622 5623
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
    DDBLTFX BltFx;
5624
    TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5625

5626 5627
    if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
        FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5628
        return WINED3DERR_INVALIDCALL;
5629
    }
5630

5631 5632 5633 5634 5635
    /* Just forward this to the DirectDraw blitting engine */
    memset(&BltFx, 0, sizeof(BltFx));
    BltFx.dwSize = sizeof(BltFx);
    BltFx.u5.dwFillColor = color;
    return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5636 5637
}

5638
/* rendertarget and deptth stencil functions */
5639
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5640
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641

5642 5643
    /* FIXME: Implelent RenderTargetIndex >0 */
    if(RenderTargetIndex > 0)
5644
        FIXME("(%p) : RenderTargetIndex %d >0 not currently supported\n", This, RenderTargetIndex);
5645

5646
    *ppRenderTarget = This->renderTarget;
5647
    TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5648 5649 5650
    /* Note inc ref on returned surface */
    if(*ppRenderTarget != NULL)
        IWineD3DSurface_AddRef(*ppRenderTarget);
5651
    return WINED3D_OK;
5652
}
5653

5654
static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
    IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
    IWineD3DSwapChainImpl *Swapchain;
    HRESULT hr;

    TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);

    hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
    if(hr != WINED3D_OK) {
        ERR("Can't get the swapchain\n");
        return hr;
    }

5669 5670 5671
    /* Make sure to release the swapchain */
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);

5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691
    if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
        ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
        return WINED3DERR_INVALIDCALL;
    }
    else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
        ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
        return WINED3DERR_INVALIDCALL;
    }

    if(Swapchain->frontBuffer != Front) {
        TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);

        if(Swapchain->frontBuffer)
            IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
        Swapchain->frontBuffer = Front;

        if(Swapchain->frontBuffer) {
            IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
        }
    }
5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702

    if(Back && !Swapchain->backBuffer) {
        /* We need memory for the back buffer array - only one back buffer this way */
        Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
        if(!Swapchain->backBuffer) {
            ERR("Out of memory\n");
            return E_OUTOFMEMORY;
        }
    }

    if(Swapchain->backBuffer[0] != Back) {
5703 5704
        TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
        ENTER_GL();
5705
        if(!Swapchain->backBuffer[0]) {
5706 5707 5708 5709 5710
            /* GL was told to draw to the front buffer at creation,
             * undo that
             */
            glDrawBuffer(GL_BACK);
            checkGLcall("glDrawBuffer(GL_BACK)");
5711 5712
            /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
            Swapchain->presentParms.BackBufferCount = 1;
5713 5714 5715 5716
        } else if (!Back) {
            /* That makes problems - disable for now */
            /* glDrawBuffer(GL_FRONT); */
            checkGLcall("glDrawBuffer(GL_FRONT)");
5717 5718
            /* We have lost our back buffer, set this to 0 to avoid confusing other code */
            Swapchain->presentParms.BackBufferCount = 0;
5719 5720 5721
        }
        LEAVE_GL();

5722 5723 5724
        if(Swapchain->backBuffer[0])
            IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
        Swapchain->backBuffer[0] = Back;
5725

5726 5727 5728 5729
        if(Swapchain->backBuffer[0]) {
            IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
        } else {
            HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5730 5731 5732 5733 5734
        }

    }

    return WINED3D_OK;
5735 5736
}

5737
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5738
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739
    *ppZStencilSurface = This->depthStencilBuffer;
5740
    TRACE("(%p) : zStencilSurface  returning %p\n", This,  *ppZStencilSurface);
5741

5742 5743 5744 5745
    if(*ppZStencilSurface != NULL) {
        /* Note inc ref on returned surface */
        IWineD3DSurface_AddRef(*ppZStencilSurface);
    }
5746
    return WINED3D_OK;
5747 5748
}

5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764
static void bind_fbo(IWineD3DDevice *iface) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    if (!This->fbo) {
        GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
        checkGLcall("glGenFramebuffersEXT()");
    }
    GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
    checkGLcall("glBindFramebuffer()");
}

/* TODO: Handle stencil attachments */
static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;

5765 5766
    This->depth_copy_state = WINED3D_DCS_NO_COPY;

5767 5768 5769
    bind_fbo(iface);

    if (depth_stencil_impl) {
5770 5771
        GLenum texttarget, target;

5772
        IWineD3DSurface_PreLoad(depth_stencil);
5773 5774
        texttarget = depth_stencil_impl->glDescription.target;
        target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5775

5776 5777 5778 5779
        glBindTexture(target, depth_stencil_impl->glDescription.textureName);
        glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5780
        glBindTexture(target, 0);
5781

5782
        GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799
        checkGLcall("glFramebufferTexture2DEXT()");
    } else {
        GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
        checkGLcall("glFramebufferTexture2DEXT()");
    }

    if (!This->render_offscreen) {
        GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
        checkGLcall("glBindFramebuffer()");
    }
}

static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;

    if (This->render_offscreen) {
5800 5801
        GLenum texttarget, target;

5802 5803 5804
        bind_fbo(iface);

        IWineD3DSurface_PreLoad(render_target);
5805 5806
        texttarget = rtimpl->glDescription.target;
        target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5807

5808 5809 5810
        glBindTexture(target, rtimpl->glDescription.textureName);
        glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5811
        glBindTexture(target, 0);
5812

5813
        GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texttarget, rtimpl->glDescription.textureName, 0));
5814 5815 5816 5817 5818 5819 5820
        checkGLcall("glFramebufferTexture2DEXT()");
    } else {
        GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
        checkGLcall("glBindFramebuffer()");
    }
}

5821
/* internal static helper functions */
5822
static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5823 5824
                                                IWineD3DSurface *RenderSurface);

5825
static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5826
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5827
    HRESULT  hr = WINED3D_OK;
5828
    WINED3DVIEWPORT viewport;
5829

5830
    TRACE("(%p) Swapping rendertarget\n",This);
5831
    if (RenderTargetIndex > 0) {
5832
        FIXME("(%p) Render targets other than the first are not supported\n",This);
5833
        RenderTargetIndex = 0;
5834 5835 5836
    }

    /* MSDN says that null disables the render target
5837
    but a device must always be associated with a render target
5838 5839 5840 5841 5842 5843 5844
    nope MSDN says that we return invalid call to a null rendertarget with an index of 0

    see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
    for more details
    */
    if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
        FIXME("Trying to set render target 0 to NULL\n");
5845
        return WINED3DERR_INVALIDCALL;
5846
    }
5847
    /* TODO: replace Impl* usage with interface usage */
5848 5849
    if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
        FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5850
        return WINED3DERR_INVALIDCALL;
5851 5852 5853 5854 5855 5856 5857 5858 5859
    }
    /** TODO: check that the depth stencil format matches the render target, this is only done in debug
     *        builds, but I think wine counts as a 'debug' build for now.
      ******************************/
    /* If we are trying to set what we already have, don't bother */
    if (pRenderTarget == This->renderTarget) {
        TRACE("Trying to do a NOP SetRenderTarget operation\n");
    } else {
        /* Otherwise, set the render target up */
5860

5861
        if (!This->sceneEnded) {
5862 5863
            IWineD3DDevice_EndScene(iface);
        }
5864 5865 5866
        TRACE("clearing renderer\n");
        /* IWineD3DDeviceImpl_CleanRender(iface); */
        /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5867
        depending on the renter target implementation being used.
5868
        A shared context implementation will share all buffers between all rendertargets (including swapchains),
5869
        implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5870 5871
        stencil buffer and incure an extra memory overhead */
        hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5872 5873 5874
        if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
            set_render_target_fbo(iface, pRenderTarget);
        }
5875 5876 5877 5878
    }

    if (SUCCEEDED(hr)) {
        /* Finally, reset the viewport as the MSDN states. */
5879
        /* TODO: Replace impl usage */
5880 5881 5882 5883 5884 5885 5886
        viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
        viewport.Width  = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
        viewport.X      = 0;
        viewport.Y      = 0;
        viewport.MaxZ   = 1.0f;
        viewport.MinZ   = 0.0f;
        IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5887
    } else {
5888 5889
        FIXME("Unknown error setting the render target\n");
    }
5890
    This->sceneEnded = FALSE;
5891
    return hr;
5892 5893
}

5894
static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5895
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896
    HRESULT  hr = WINED3D_OK;
5897 5898 5899 5900
    IWineD3DSurface *tmp;

    TRACE("(%p) Swapping z-buffer\n",This);

5901
    if (pNewZStencil == This->stencilBufferTarget) {
5902
        TRACE("Trying to do a NOP SetRenderTarget operation\n");
5903
    } else {
5904
        /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5905
        * depending on the renter target implementation being used.
5906
        * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5907
        * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5908 5909 5910 5911 5912 5913 5914 5915 5916
        * stencil buffer and incure an extra memory overhead
         ******************************************************/


        tmp = This->stencilBufferTarget;
        This->stencilBufferTarget = pNewZStencil;
        /* should we be calling the parent or the wined3d surface? */
        if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
        if (NULL != tmp) IWineD3DSurface_Release(tmp);
5917
        hr = WINED3D_OK;
5918 5919 5920
        /** TODO: glEnable/glDisable on depth/stencil    depending on
         *   pNewZStencil is NULL and the depth/stencil is enabled in d3d
          **********************************************************/
5921 5922 5923
        if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
            set_depth_stencil_fbo(iface, pNewZStencil);
        }
5924 5925 5926 5927 5928 5929
    }

    return hr;
}


5930
#ifdef GL_VERSION_1_3
5931 5932 5933 5934 5935
/* Internal functions not in DirectX */
 /** TODO: move this off to the opengl context manager
 *(the swapchain doesn't need to know anything about offscreen rendering!)
  ****************************************************/

5936
static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5937 5938 5939 5940 5941 5942
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("(%p), %p\n", This, swapchain);

    if (swapchain->win != swapchain->drawable) {
5943
        /* Set everything back the way it ws */
5944
        swapchain->render_ctx = swapchain->glCtx;
5945
        swapchain->drawable   = swapchain->win;
5946
    }
5947
    return WINED3D_OK;
5948
}
5949

5950
/* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5951
static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5952 5953
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    int i;
Mike McCormack's avatar
Mike McCormack committed
5954 5955
    unsigned int width;
    unsigned int height;
5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969
    WINED3DFORMAT format;
    WINED3DSURFACE_DESC surfaceDesc;
    memset(&surfaceDesc, 0, sizeof(surfaceDesc));
    surfaceDesc.Width  = &width;
    surfaceDesc.Height = &height;
    surfaceDesc.Format = &format;
    IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
    *context = NULL;
    /* I need a get width/height function (and should do something with the format) */
    for (i = 0; i < CONTEXT_CACHE; ++i) {
        /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
        ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
        the pSurface can be set to 0 allowing it to be reused from cache **/
        if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5970
          && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007
            *context = &This->contextCache[i];
            break;
        }
        if (This->contextCache[i].Width == 0) {
            This->contextCache[i].pSurface = pSurface;
            This->contextCache[i].Width    = width;
            This->contextCache[i].Height   = height;
            *context = &This->contextCache[i];
            break;
        }
    }
    if (i == CONTEXT_CACHE) {
        int minUsage = 0x7FFFFFFF; /* MAX_INT */
        glContext *dropContext = 0;
        for (i = 0; i < CONTEXT_CACHE; i++) {
            if (This->contextCache[i].usedcount < minUsage) {
                dropContext = &This->contextCache[i];
                minUsage = This->contextCache[i].usedcount;
            }
        }
        /* clean up the context (this doesn't work for ATI at the moment */
#if 0
        glXDestroyContext(swapchain->display, dropContext->context);
        glXDestroyPbuffer(swapchain->display, dropContext->drawable);
#endif
        FIXME("Leak\n");
        dropContext->Width = 0;
        dropContext->pSurface = pSurface;
        *context = dropContext;
    } else {
        if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
          for (i = 0; i < CONTEXT_CACHE; i++) {
             This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
          }
        }
    }
    if (*context != NULL)
6008
        return WINED3D_OK;
6009 6010
    else
        return E_OUTOFMEMORY;
6011
}
6012
#endif
6013

6014 6015 6016 6017 6018
/* Reapply the device stateblock */
static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {

    BOOL oldRecording;  
    IWineD3DStateBlockImpl *oldUpdateStateBlock;
6019
    DWORD i;
6020 6021 6022 6023 6024 6025 6026 6027 6028 6029

    /* Disable recording */
    oldUpdateStateBlock = This->updateStateBlock;
    oldRecording= This->isRecordingState;
    This->isRecordingState = FALSE;
    This->updateStateBlock = This->stateBlock;

    /* Reapply the state block */ 
    IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);

6030 6031 6032 6033 6034 6035 6036
    /* Temporaryily mark all render states dirty to force reapplication
     * until the context management for is integrated with the state management
     */
    for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
    }

6037 6038 6039 6040 6041
    /* Restore recording */
    This->isRecordingState = oldRecording;
    This->updateStateBlock = oldUpdateStateBlock;
}

6042 6043 6044 6045 6046 6047
/* Set offscreen rendering. When rendering offscreen the surface will be
 * rendered upside down to compensate for the fact that D3D texture coordinates
 * are flipped compared to GL texture coordinates. The cullmode is affected by
 * this, so it must be updated. To update the cullmode stateblock recording has
 * to be temporarily disabled. The new state management code will hopefully
 * make this unnecessary */
6048 6049
static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {

6050 6051
    BOOL oldRecording;
    IWineD3DStateBlockImpl *oldUpdateStateBlock;
6052

6053 6054 6055
    /* Nothing to update, return. */
    if (This->render_offscreen == isTexture) return;

6056 6057 6058 6059 6060 6061
    /* Disable recording */
    oldUpdateStateBlock = This->updateStateBlock;
    oldRecording= This->isRecordingState;
    This->isRecordingState = FALSE;
    This->updateStateBlock = This->stateBlock;

6062
    This->render_offscreen = isTexture;
6063 6064 6065
    if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
        This->depth_copy_state = WINED3D_DCS_COPY;
    }
6066 6067
    This->last_was_rhw = FALSE;
    This->proj_valid = FALSE;
6068
    IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081

    /* Restore recording */
    This->isRecordingState = oldRecording;
    This->updateStateBlock = oldUpdateStateBlock;
}

/* Returns an array of compatible FBconfig(s).
 * The array must be freed with XFree. Requires ENTER_GL() */

static GLXFBConfig* device_find_fbconfigs(
    IWineD3DDeviceImpl* This,
    IWineD3DSwapChainImpl* implicitSwapchainImpl,
    IWineD3DSurface* RenderSurface) {
6082 6083 6084 6085 6086

    GLXFBConfig* cfgs = NULL;
    int nCfgs = 0;
    int attribs[256];
    int nAttribs = 0;
6087 6088

    IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
6089 6090
    WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
    WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
6091 6092

    /**TODO:
6093
        if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off, 
6094 6095 6096 6097 6098 6099 6100 6101 6102 6103
        it StencilSurface != NULL && zBufferTarget == NULL switch it on
    */

#define PUSH1(att)        attribs[nAttribs++] = (att);
#define PUSH2(att,value)  attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);

    /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/

    PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
    PUSH2(GLX_X_RENDERABLE,  TRUE);
6104
    PUSH2(GLX_DOUBLEBUFFER,  TRUE);
6105 6106 6107 6108
    TRACE("calling makeglcfg\n");
    D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
    PUSH1(None);
    TRACE("calling chooseFGConfig\n");
6109 6110 6111 6112 6113
    cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
                             DefaultScreen(implicitSwapchainImpl->display),
                             attribs, &nCfgs);
    if (cfgs == NULL) {
        /* OK we didn't find the exact config, so use any reasonable match */
6114 6115 6116 6117 6118 6119 6120 6121
        /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
           why we failed. */
        static BOOL show_message = TRUE;
        if (show_message) {
            ERR("Failed to find exact match, finding alternative but you may "
                "suffer performance issues, try changing xfree's depth to match the requested depth\n");
            show_message = FALSE;
        }
6122 6123
        nAttribs = 0;
        PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
6124
        /* PUSH2(GLX_X_RENDERABLE,  TRUE); */
6125 6126 6127 6128 6129
        PUSH2(GLX_RENDER_TYPE,   GLX_RGBA_BIT);
        PUSH2(GLX_DOUBLEBUFFER, FALSE);
        TRACE("calling makeglcfg\n");
        D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
        PUSH1(None);
6130 6131 6132 6133 6134 6135 6136 6137 6138 6139
        cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
                                 DefaultScreen(implicitSwapchainImpl->display),
                                 attribs, &nCfgs);
    }
                                                                                                                                                                      
    if (cfgs == NULL) {
        ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
            BackBufferFormat, debug_d3dformat(BackBufferFormat),
            StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
    } else {
6140 6141 6142 6143 6144 6145 6146
#ifdef EXTRA_TRACES
        int i;
        for (i = 0; i < nCfgs; ++i) {
            TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
            debug_d3dformat(BackBufferFormat), StencilBufferFormat,
            debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
        }
6147 6148 6149 6150 6151 6152 6153 6154
        if (NULL != This->renderTarget) {
            glFlush();
            vcheckGLcall("glFlush");
            /** This is only useful if the old render target was a swapchain,
            * we need to supercede this with a function that displays
            * the current buffer on the screen. This is easy to do in glx1.3 but
            * we need to do copy-write pixels in glx 1.2.
            ************************************************/
6155 6156
            glXSwapBuffers(implicitSwapChainImpl->display,
                           implicitSwapChainImpl->drawable);
6157 6158 6159
            printf("Hit Enter to get next frame ...\n");
            getchar();
        }
6160 6161
#endif
    }
6162 6163 6164 6165 6166
#undef PUSH1
#undef PUSH2

   return cfgs;
}
6167

6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207
/** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
* the functionality needs splitting up so that we don't do more than we should do.
* this only seems to impact performance a little.
 ******************************/
static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
                                               IWineD3DSurface *RenderSurface) {

    /**
    * Currently only active for GLX >= 1.3
    * for others versions we'll have to use GLXPixmaps
    *
    * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
    * as they implement GLX 1.3 but only define GLX_VERSION_1_2
    * so only check OpenGL version
    * ..........................
    * I don't believe that it is a problem with NVidia headers,
    * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
    * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
    * ATI Note:
    * Your application will report GLX version 1.2 on glXQueryVersion.
    * However, it is safe to call the GLX 1.3 functions as described below.
    */
#if defined(GL_VERSION_1_3)

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    GLXFBConfig* cfgs = NULL;
    IWineD3DSwapChain     *currentSwapchain;
    IWineD3DSwapChainImpl *currentSwapchainImpl;
    IWineD3DSwapChain     *implicitSwapchain;
    IWineD3DSwapChainImpl *implicitSwapchainImpl;
    IWineD3DSwapChain     *renderSurfaceSwapchain;
    IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;

    /* Obtain a reference to the device implicit swapchain,
     * the swapchain of the current render target,
     * and the swapchain of the new render target.
     * Fallback to device implicit swapchain if the current render target doesn't have one */
    IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
    IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
    IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
6208
    if (currentSwapchain == NULL)
6209
        IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6210 6211 6212 6213 6214 6215

    currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
    implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
    renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;

    ENTER_GL();
6216 6217 6218

    /**
    * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6219
    *  renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6220
     **********************************************************************/
6221 6222
    if (renderSurfaceSwapchain != NULL) {

6223
        /* We also need to make sure that the lights &co are also in the context of the swapchains */
6224
        /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6225
        TRACE("making swapchain active\n");
6226
        if (RenderSurface != This->renderTarget) {
6227 6228 6229
            BOOL backbuf = FALSE;
            int i;

6230 6231
            for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
                if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6232 6233 6234 6235 6236 6237
                    backbuf = TRUE;
                    break;
                }
            }

            if (backbuf) {
6238 6239 6240 6241
            } else {
                /* This could be flagged so that some operations work directly with the front buffer */
                FIXME("Attempting to set the  renderTarget to the frontBuffer\n");
            }
6242 6243 6244 6245
            if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
                               renderSurfaceSwapchainImpl->win,
                               renderSurfaceSwapchainImpl->glCtx) == False) {

6246
                TRACE("Error in setting current context: context %p drawable %ld !\n",
6247
                       implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6248
            }
6249 6250 6251 6252
            checkGLcall("glXMakeContextCurrent");

            /* Clean up the old context */
            IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6253

6254 6255 6256
            /* Reapply the stateblock, and set the device not to render to texture */
            device_reapply_stateblock(This);
            device_render_to_texture(This, FALSE);
6257 6258
        }

6259 6260
    /* Offscreen rendering: PBuffers (currently disabled).
     * Also note that this path is never reached if FBOs are supported */
6261
    } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6262
               (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6263 6264

        /** ********************************************************************
6265 6266 6267 6268
        * This is a quickly hacked out implementation of offscreen textures.
        * It will work in most cases but there may be problems if the client
        * modifies the texture directly, or expects the contents of the rendertarget
        * to be persistent.
6269
        *
6270
        * There are some real speed vs compatibility issues here:
6271 6272 6273 6274 6275 6276
        *    we should really use a new context for every texture, but that eats ram.
        *    we should also be restoring the texture to the pbuffer but that eats CPU
        *    we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
        *    but if this means reusing the display backbuffer then we need to make sure that
        *    states are correctly preserved.
        * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6277
        * and gain a good performance increase at the cost of compatibility.
6278
        * I would suggest that, when this is the case, a user configurable flag be made
6279
        * available, allowing the user to choose the best emulated experience for them.
6280 6281 6282
         *********************************************************************/

        XVisualInfo *visinfo;
6283
        glContext   *newContext;
6284

6285
        /* Here were using a shared context model */
6286
        if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6287 6288
            FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
        }
6289

6290 6291 6292
        /* If the context doesn't exist then create a new one */
        /* TODO: This should really be part of findGlContext */
        if (NULL == newContext->context) {
6293

6294 6295 6296
            int attribs[256];
            int nAttribs = 0;

6297
            TRACE("making new buffer\n");
6298 6299 6300 6301 6302
            attribs[nAttribs++] = GLX_PBUFFER_WIDTH; 
            attribs[nAttribs++] = newContext->Width;
            attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
            attribs[nAttribs++] = newContext->Height;
            attribs[nAttribs++] = None;
6303

6304
            newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6305 6306

            /** ****************************************
6307
            *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6308 6309 6310 6311 6312
            *they note:
            *   In future releases, we may provide the calls glXCreateNewContext,
            *   glXQueryDrawable and glXMakeContextCurrent.
            *    so until then we have to use glXGetVisualFromFBConfig &co..
            ********************************************/
6313

6314
            visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6315 6316
            if (!visinfo) {
                ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6317
            } else {
6318 6319 6320 6321
                newContext->context = glXCreateContext(
                    implicitSwapchainImpl->display, visinfo,
                    implicitSwapchainImpl->glCtx, GL_TRUE);

6322
                XFree(visinfo);
6323
            }
6324 6325 6326 6327
        }
        if (NULL == newContext || NULL == newContext->context) {
            ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
        } else {
6328
            /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6329 6330 6331 6332 6333
            if (glXMakeCurrent(implicitSwapchainImpl->display,
                newContext->drawable, newContext->context) == False) {

                TRACE("Error in setting current context: context %p drawable %ld\n",
                    newContext->context, newContext->drawable);
6334
            }
6335
            checkGLcall("glXMakeContextCurrent");
6336

6337
            /* Clean up the old context */
6338
            IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6339

6340 6341 6342
            /* Reapply stateblock, and set device to render to a texture */
            device_reapply_stateblock(This);
            device_render_to_texture(This, TRUE);
6343

6344 6345 6346 6347
            /* Set the current context of the swapchain to the new context */
            implicitSwapchainImpl->drawable   = newContext->drawable;
            implicitSwapchainImpl->render_ctx = newContext->context;
        }
6348
    } else {
6349
        /* Same context, but update render_offscreen and cull mode */
6350
        device_render_to_texture(This, TRUE);
6351 6352
    }

6353
    /* Replace the render target */
6354 6355 6356 6357 6358
    if (This->renderTarget != RenderSurface) {
        IWineD3DSurface_Release(This->renderTarget);
        This->renderTarget = RenderSurface;
        IWineD3DSurface_AddRef(RenderSurface);
    }
6359

6360
    if (cfgs != NULL)                   XFree(cfgs);
6361
    if (implicitSwapchain != NULL)       IWineD3DSwapChain_Release(implicitSwapchain);
6362 6363
    if (currentSwapchain != NULL)       IWineD3DSwapChain_Release(currentSwapchain);
    if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6364 6365
    LEAVE_GL();
#endif
6366
    return WINED3D_OK;
6367 6368
}

6369
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6370
                                                        UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6371
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6372
    /* TODO: the use of Impl is deprecated. */
6373 6374 6375 6376
    IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;

    TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);

6377
    /* some basic validation checks */
6378 6379 6380 6381 6382 6383 6384
    if(This->cursorTexture) {
        ENTER_GL();
        glDeleteTextures(1, &This->cursorTexture);
        LEAVE_GL();
        This->cursorTexture = 0;
    }

6385 6386 6387 6388 6389 6390 6391 6392 6393 6394
    if(pCursorBitmap) {
        /* MSDN: Cursor must be A8R8G8B8 */
        if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
            ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
            return WINED3DERR_INVALIDCALL;
        }

        /* MSDN: Cursor must be smaller than the display mode */
        if(pSur->currentDesc.Width > This->ddraw_width ||
           pSur->currentDesc.Height > This->ddraw_height) {
6395
            ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
6396 6397 6398 6399 6400 6401 6402 6403
            return WINED3DERR_INVALIDCALL;
        }

        /* TODO: MSDN: Cursor sizes must be a power of 2 */
        /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
         * Texture and Blitting code to draw the cursor
         */
        pSur->Flags |= SFLAG_FORCELOAD;
6404 6405 6406 6407 6408 6409 6410 6411 6412
        IWineD3DSurface_PreLoad(pCursorBitmap);
        pSur->Flags &= ~SFLAG_FORCELOAD;
        /* Do not store the surface's pointer because the application may release
         * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
         * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
         */
        This->cursorTexture = pSur->glDescription.textureName;
        This->cursorWidth = pSur->currentDesc.Width;
        This->cursorHeight = pSur->currentDesc.Height;
6413
        pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6414
    }
6415

6416 6417
    This->xHotSpot = XHotSpot;
    This->yHotSpot = YHotSpot;
6418
    return WINED3D_OK;
6419 6420
}

6421
static void     WINAPI  IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6422 6423
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6424

6425 6426
    This->xScreenSpace = XScreenSpace;
    This->yScreenSpace = YScreenSpace;
6427

6428 6429 6430 6431
    return;

}

6432
static BOOL     WINAPI  IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6433
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6434
    BOOL oldVisible = This->bCursorVisible;
6435
    TRACE("(%p) : visible(%d)\n", This, bShow);
6436

6437 6438
    if(This->cursorTexture)
        This->bCursorVisible = bShow;
6439

6440
    return oldVisible;
6441 6442
}

6443
static HRESULT  WINAPI  IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6444
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6445
    TRACE("(%p) : state (%u)\n", This, This->state);
6446 6447
    /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
    switch (This->state) {
6448 6449 6450
    case WINED3D_OK:
        return WINED3D_OK;
    case WINED3DERR_DEVICELOST:
6451 6452 6453
        {
            ResourceList *resourceList  = This->resources;
            while (NULL != resourceList) {
6454
                if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6455
                return WINED3DERR_DEVICENOTRESET;
6456 6457
                resourceList = resourceList->next;
            }
6458
            return WINED3DERR_DEVICELOST;
6459
        }
6460 6461
    case WINED3DERR_DRIVERINTERNALERROR:
        return WINED3DERR_DRIVERINTERNALERROR;
6462 6463 6464
    }

    /* Unknown state */
6465
    return WINED3DERR_DRIVERINTERNALERROR;
6466 6467 6468
}


6469
static HRESULT  WINAPI  IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6470 6471 6472 6473 6474 6475
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    /** FIXME: Resource tracking needs to be done,
    * The closes we can do to this is set the priorities of all managed textures low
    * and then reset them.
     ***********************************************************/
    FIXME("(%p) : stub\n", This);
6476
    return WINED3D_OK;
6477 6478
}

6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516
void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
    /* Reallocate proper memory for the front and back buffer and adjust their sizes */
    if(surface->Flags & SFLAG_DIBSECTION) {
        /* Release the DC */
        SelectObject(surface->hDC, surface->dib.holdbitmap);
        DeleteDC(surface->hDC);
        /* Release the DIB section */
        DeleteObject(surface->dib.DIBsection);
        surface->dib.bitmap_data = NULL;
        surface->resource.allocatedMemory = NULL;
        surface->Flags &= ~SFLAG_DIBSECTION;
    }
    surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
    surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
    if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
        surface->pow2Width = *pPresentationParameters->BackBufferWidth;
        surface->pow2Height = *pPresentationParameters->BackBufferHeight;
    } else {
        surface->pow2Width = surface->pow2Height = 1;
        while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
        while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
    }
    if(surface->glDescription.textureName) {
        ENTER_GL();
        glDeleteTextures(1, &surface->glDescription.textureName);
        LEAVE_GL();
        surface->glDescription.textureName = 0;
    }
    if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
       surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
        surface->Flags |= SFLAG_NONPOW2;
    } else  {
        surface->Flags &= ~SFLAG_NONPOW2;
    }
    HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
    surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
}

6517
static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6518
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624
    IWineD3DSwapChainImpl *swapchain;
    HRESULT hr;
    BOOL DisplayModeChanged = FALSE;
    WINED3DDISPLAYMODE mode;
    TRACE("(%p)\n", This);

    hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
    if(FAILED(hr)) {
        ERR("Failed to get the first implicit swapchain\n");
        return hr;
    }

    /* Is it necessary to recreate the gl context? Actually every setting can be changed
     * on an existing gl context, so there's no real need for recreation.
     *
     * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
     *
     * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
     */
    TRACE("New params:\n");
    TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
    TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
    TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
    TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
    TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
    TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
    TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
    TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
    TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
    TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
    TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
    TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
    TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);

    /* No special treatment of these parameters. Just store them */
    swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
    swapchain->presentParms.Flags = *pPresentationParameters->Flags;
    swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
    swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;

    /* What to do about these? */
    if(*pPresentationParameters->BackBufferCount != 0 &&
        *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
        ERR("Cannot change the back buffer count yet\n");
    }
    if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
        *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
        ERR("Cannot change the back buffer format yet\n");
    }
    if(*pPresentationParameters->hDeviceWindow != NULL &&
        *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
        ERR("Cannot change the device window yet\n");
    }
    if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
        ERR("What do do about a changed auto depth stencil parameter?\n");
    }

    if(*pPresentationParameters->Windowed) {
        mode.Width = swapchain->orig_width;
        mode.Height = swapchain->orig_height;
        mode.RefreshRate = 0;
        mode.Format = swapchain->presentParms.BackBufferFormat;
    } else {
        mode.Width = *pPresentationParameters->BackBufferWidth;
        mode.Height = *pPresentationParameters->BackBufferHeight;
        mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
        mode.Format = swapchain->presentParms.BackBufferFormat;
    }

    /* Should Width == 800 && Height == 0 set 800x600? */
    if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
       (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
        *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
    {
        WINED3DVIEWPORT vp;
        int i;

        vp.X = 0;
        vp.Y = 0;
        vp.Width = *pPresentationParameters->BackBufferWidth;
        vp.Height = *pPresentationParameters->BackBufferHeight;
        vp.MinZ = 0;
        vp.MaxZ = 1;

        if(!*pPresentationParameters->Windowed) {
            DisplayModeChanged = TRUE;
        }
        swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
        swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;

        updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
        for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
            updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
        }

        /* Now set the new viewport */
        IWineD3DDevice_SetViewport(iface, &vp);
    }

    if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
       (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
        DisplayModeChanged) {
        IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
    }

    IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6625
    return WINED3D_OK;
6626 6627
}

6628
static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6629 6630
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    /** FIXME: always true at the moment **/
6631
    if(!bEnableDialogs) {
6632 6633
        FIXME("(%p) Dialogs cannot be disabled yet\n", This);
    }
6634
    return WINED3D_OK;
6635 6636 6637
}


6638
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6639
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6640
    TRACE("(%p) : pParameters %p\n", This, pParameters);
6641

6642
    *pParameters = This->createParms;
6643
    return WINED3D_OK;
6644 6645
}

6646
static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
Oliver Stieber's avatar
Oliver Stieber committed
6647
    IWineD3DSwapChain *swapchain;
6648
    HRESULT hrc = WINED3D_OK;
Oliver Stieber's avatar
Oliver Stieber committed
6649 6650 6651

    TRACE("Relaying  to swapchain\n");

6652
    if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6653
        IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6654
        IWineD3DSwapChain_Release(swapchain);
Oliver Stieber's avatar
Oliver Stieber committed
6655
    }
6656 6657 6658
    return;
}

6659
static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
Oliver Stieber's avatar
Oliver Stieber committed
6660
    IWineD3DSwapChain *swapchain;
6661
    HRESULT hrc = WINED3D_OK;
6662

Oliver Stieber's avatar
Oliver Stieber committed
6663 6664
    TRACE("Relaying  to swapchain\n");

6665
    if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
6666
        hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6667
        IWineD3DSwapChain_Release(swapchain);
Oliver Stieber's avatar
Oliver Stieber committed
6668
    }
6669
    return;
6670 6671
}

6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745

/** ********************************************************
*   Notification functions
** ********************************************************/
/** This function must be called in the release of a resource when ref == 0,
* the contents of resource must still be correct,
* any handels to other resource held by the caller must be closed
* (e.g. a texture should release all held surfaces because telling the device that it's been released.)
 *****************************************************/
static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    ResourceList* resourceList;

    TRACE("(%p) : resource %p\n", This, resource);
#if 0
    EnterCriticalSection(&resourceStoreCriticalSection);
#endif
    /* add a new texture to the frot of the linked list */
    resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
    resourceList->resource = resource;

    /* Get the old head */
    resourceList->next = This->resources;

    This->resources = resourceList;
    TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);

#if 0
    LeaveCriticalSection(&resourceStoreCriticalSection);
#endif
    return;
}

static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    ResourceList* resourceList = NULL;
    ResourceList* previousResourceList = NULL;
    
    TRACE("(%p) : resource %p\n", This, resource);

#if 0
    EnterCriticalSection(&resourceStoreCriticalSection);
#endif
    resourceList = This->resources;

    while (resourceList != NULL) {
        if(resourceList->resource == resource) break;
        previousResourceList = resourceList;
        resourceList = resourceList->next;
    }

    if (resourceList == NULL) {
        FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
#if 0
        LeaveCriticalSection(&resourceStoreCriticalSection);
#endif
        return;
    } else {
            TRACE("Found resource  %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
    }
    /* make sure we don't leave a hole in the list */
    if (previousResourceList != NULL) {
        previousResourceList->next = resourceList->next;
    } else {
        This->resources = resourceList->next;
    }

#if 0
    LeaveCriticalSection(&resourceStoreCriticalSection);
#endif
    return;
}


6746
static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6747 6748 6749 6750 6751
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    int counter;

    TRACE("(%p) : resource %p\n", This, resource);
    switch(IWineD3DResource_GetType(resource)){
6752
        case WINED3DRTYPE_SURFACE:
6753 6754
        /* TODO: check front and back buffers, rendertargets etc..  possibly swapchains? */
        break;
6755 6756 6757
        case WINED3DRTYPE_TEXTURE:
        case WINED3DRTYPE_CUBETEXTURE:
        case WINED3DRTYPE_VOLUMETEXTURE:
6758
                for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6759
                    if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6760
                        WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6761 6762 6763 6764
                        This->stateBlock->textures[counter] = NULL;
                    }
                    if (This->updateStateBlock != This->stateBlock ){
                        if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6765
                            WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6766 6767 6768 6769 6770
                            This->updateStateBlock->textures[counter] = NULL;
                        }
                    }
                }
        break;
6771
        case WINED3DRTYPE_VOLUME:
6772 6773
        /* TODO: nothing really? */
        break;
6774
        case WINED3DRTYPE_VERTEXBUFFER:
6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785
        /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
        {
            int streamNumber;
            TRACE("Cleaning up stream pointers\n");

            for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
                /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
                FINDOUT: should changes.streamSource[StreamNumber] be set ?
                */
                if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
                    if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6786
                        FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6787 6788 6789 6790
                        This->updateStateBlock->streamSource[streamNumber] = 0;
                        /* Set changed flag? */
                    }
                }
6791
                if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6792
                    if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6793
                        TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805
                        This->stateBlock->streamSource[streamNumber] = 0;
                    }
                }
#if 0   /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
                 else { /* This shouldn't happen */
                    FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
                }
#endif

            }
        }
        break;
6806
        case WINED3DRTYPE_INDEXBUFFER:
6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820
        /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
        if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
            if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
                This->updateStateBlock->pIndexData =  NULL;
            }
        }
        if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
            if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
                This->stateBlock->pIndexData =  NULL;
            }
        }

        break;
        default:
6821
        FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832
        break;
    }


    /* Remove the resoruce from the resourceStore */
    IWineD3DDeviceImpl_RemoveResource(iface, resource);

    TRACE("Resource released\n");

}

6833 6834 6835 6836
/**********************************************************
 * IWineD3DDevice VTbl follows
 **********************************************************/

6837
const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6838
{
6839
    /*** IUnknown methods ***/
6840 6841
    IWineD3DDeviceImpl_QueryInterface,
    IWineD3DDeviceImpl_AddRef,
6842
    IWineD3DDeviceImpl_Release,
6843
    /*** IWineD3DDevice methods ***/
6844
    IWineD3DDeviceImpl_GetParent,
6845
    /*** Creation methods**/
6846
    IWineD3DDeviceImpl_CreateVertexBuffer,
6847
    IWineD3DDeviceImpl_CreateIndexBuffer,
6848
    IWineD3DDeviceImpl_CreateStateBlock,
6849
    IWineD3DDeviceImpl_CreateSurface,
6850 6851 6852 6853
    IWineD3DDeviceImpl_CreateTexture,
    IWineD3DDeviceImpl_CreateVolumeTexture,
    IWineD3DDeviceImpl_CreateVolume,
    IWineD3DDeviceImpl_CreateCubeTexture,
6854 6855 6856 6857 6858
    IWineD3DDeviceImpl_CreateQuery,
    IWineD3DDeviceImpl_CreateAdditionalSwapChain,
    IWineD3DDeviceImpl_CreateVertexDeclaration,
    IWineD3DDeviceImpl_CreateVertexShader,
    IWineD3DDeviceImpl_CreatePixelShader,
6859
    IWineD3DDeviceImpl_CreatePalette,
6860
    /*** Odd functions **/
6861 6862
    IWineD3DDeviceImpl_Init3D,
    IWineD3DDeviceImpl_Uninit3D,
6863
    IWineD3DDeviceImpl_SetFullscreen,
6864
    IWineD3DDeviceImpl_EnumDisplayModes,
6865
    IWineD3DDeviceImpl_EvictManagedResources,
6866 6867 6868 6869 6870 6871
    IWineD3DDeviceImpl_GetAvailableTextureMem,
    IWineD3DDeviceImpl_GetBackBuffer,
    IWineD3DDeviceImpl_GetCreationParameters,
    IWineD3DDeviceImpl_GetDeviceCaps,
    IWineD3DDeviceImpl_GetDirect3D,
    IWineD3DDeviceImpl_GetDisplayMode,
6872
    IWineD3DDeviceImpl_SetDisplayMode,
6873 6874
    IWineD3DDeviceImpl_GetHWND,
    IWineD3DDeviceImpl_SetHWND,
6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892
    IWineD3DDeviceImpl_GetNumberOfSwapChains,
    IWineD3DDeviceImpl_GetRasterStatus,
    IWineD3DDeviceImpl_GetSwapChain,
    IWineD3DDeviceImpl_Reset,
    IWineD3DDeviceImpl_SetDialogBoxMode,
    IWineD3DDeviceImpl_SetCursorProperties,
    IWineD3DDeviceImpl_SetCursorPosition,
    IWineD3DDeviceImpl_ShowCursor,
    IWineD3DDeviceImpl_TestCooperativeLevel,
    /*** Getters and setters **/
    IWineD3DDeviceImpl_SetClipPlane,
    IWineD3DDeviceImpl_GetClipPlane,
    IWineD3DDeviceImpl_SetClipStatus,
    IWineD3DDeviceImpl_GetClipStatus,
    IWineD3DDeviceImpl_SetCurrentTexturePalette,
    IWineD3DDeviceImpl_GetCurrentTexturePalette,
    IWineD3DDeviceImpl_SetDepthStencilSurface,
    IWineD3DDeviceImpl_GetDepthStencilSurface,
6893
    IWineD3DDeviceImpl_SetFVF,
6894
    IWineD3DDeviceImpl_GetFVF,
6895
    IWineD3DDeviceImpl_SetGammaRamp,
6896
    IWineD3DDeviceImpl_GetGammaRamp,
6897
    IWineD3DDeviceImpl_SetIndices,
6898
    IWineD3DDeviceImpl_GetIndices,
6899 6900 6901 6902 6903 6904
    IWineD3DDeviceImpl_SetLight,
    IWineD3DDeviceImpl_GetLight,
    IWineD3DDeviceImpl_SetLightEnable,
    IWineD3DDeviceImpl_GetLightEnable,
    IWineD3DDeviceImpl_SetMaterial,
    IWineD3DDeviceImpl_GetMaterial,
6905
    IWineD3DDeviceImpl_SetNPatchMode,
6906
    IWineD3DDeviceImpl_GetNPatchMode,
6907 6908 6909 6910 6911 6912 6913 6914 6915 6916
    IWineD3DDeviceImpl_SetPaletteEntries,
    IWineD3DDeviceImpl_GetPaletteEntries,
    IWineD3DDeviceImpl_SetPixelShader,
    IWineD3DDeviceImpl_GetPixelShader,
    IWineD3DDeviceImpl_SetPixelShaderConstantB,
    IWineD3DDeviceImpl_GetPixelShaderConstantB,
    IWineD3DDeviceImpl_SetPixelShaderConstantI,
    IWineD3DDeviceImpl_GetPixelShaderConstantI,
    IWineD3DDeviceImpl_SetPixelShaderConstantF,
    IWineD3DDeviceImpl_GetPixelShaderConstantF,
6917 6918
    IWineD3DDeviceImpl_SetRenderState,
    IWineD3DDeviceImpl_GetRenderState,
6919 6920
    IWineD3DDeviceImpl_SetRenderTarget,
    IWineD3DDeviceImpl_GetRenderTarget,
6921
    IWineD3DDeviceImpl_SetFrontBackBuffers,
6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932
    IWineD3DDeviceImpl_SetSamplerState,
    IWineD3DDeviceImpl_GetSamplerState,
    IWineD3DDeviceImpl_SetScissorRect,
    IWineD3DDeviceImpl_GetScissorRect,
    IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
    IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
    IWineD3DDeviceImpl_SetStreamSource,
    IWineD3DDeviceImpl_GetStreamSource,
    IWineD3DDeviceImpl_SetStreamSourceFreq,
    IWineD3DDeviceImpl_GetStreamSourceFreq,
    IWineD3DDeviceImpl_SetTexture,
6933
    IWineD3DDeviceImpl_GetTexture,
6934 6935
    IWineD3DDeviceImpl_SetTextureStageState,
    IWineD3DDeviceImpl_GetTextureStageState,
6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956
    IWineD3DDeviceImpl_SetTransform,
    IWineD3DDeviceImpl_GetTransform,
    IWineD3DDeviceImpl_SetVertexDeclaration,
    IWineD3DDeviceImpl_GetVertexDeclaration,
    IWineD3DDeviceImpl_SetVertexShader,
    IWineD3DDeviceImpl_GetVertexShader,
    IWineD3DDeviceImpl_SetVertexShaderConstantB,
    IWineD3DDeviceImpl_GetVertexShaderConstantB,
    IWineD3DDeviceImpl_SetVertexShaderConstantI,
    IWineD3DDeviceImpl_GetVertexShaderConstantI,
    IWineD3DDeviceImpl_SetVertexShaderConstantF,
    IWineD3DDeviceImpl_GetVertexShaderConstantF,
    IWineD3DDeviceImpl_SetViewport,
    IWineD3DDeviceImpl_GetViewport,
    IWineD3DDeviceImpl_MultiplyTransform,
    IWineD3DDeviceImpl_ValidateDevice,
    IWineD3DDeviceImpl_ProcessVertices,
    /*** State block ***/
    IWineD3DDeviceImpl_BeginStateBlock,
    IWineD3DDeviceImpl_EndStateBlock,
    /*** Scene management ***/
6957
    IWineD3DDeviceImpl_BeginScene,
6958 6959 6960
    IWineD3DDeviceImpl_EndScene,
    IWineD3DDeviceImpl_Present,
    IWineD3DDeviceImpl_Clear,
6961
    /*** Drawing ***/
6962 6963 6964
    IWineD3DDeviceImpl_DrawPrimitive,
    IWineD3DDeviceImpl_DrawIndexedPrimitive,
    IWineD3DDeviceImpl_DrawPrimitiveUP,
6965
    IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6966
    IWineD3DDeviceImpl_DrawPrimitiveStrided,
6967 6968 6969 6970 6971 6972 6973 6974 6975 6976
    IWineD3DDeviceImpl_DrawRectPatch,
    IWineD3DDeviceImpl_DrawTriPatch,
    IWineD3DDeviceImpl_DeletePatch,
    IWineD3DDeviceImpl_ColorFill,
    IWineD3DDeviceImpl_UpdateTexture,
    IWineD3DDeviceImpl_UpdateSurface,
    IWineD3DDeviceImpl_StretchRect,
    IWineD3DDeviceImpl_GetRenderTargetData,
    IWineD3DDeviceImpl_GetFrontBufferData,
    /*** Internal use IWineD3DDevice methods ***/
6977 6978 6979
    IWineD3DDeviceImpl_SetupTextureStates,
    /*** object tracking ***/
    IWineD3DDeviceImpl_ResourceReleased
6980
};
6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098


const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
    WINED3DRS_ALPHABLENDENABLE   ,
    WINED3DRS_ALPHAFUNC          ,
    WINED3DRS_ALPHAREF           ,
    WINED3DRS_ALPHATESTENABLE    ,
    WINED3DRS_BLENDOP            ,
    WINED3DRS_COLORWRITEENABLE   ,
    WINED3DRS_DESTBLEND          ,
    WINED3DRS_DITHERENABLE       ,
    WINED3DRS_FILLMODE           ,
    WINED3DRS_FOGDENSITY         ,
    WINED3DRS_FOGEND             ,
    WINED3DRS_FOGSTART           ,
    WINED3DRS_LASTPIXEL          ,
    WINED3DRS_SHADEMODE          ,
    WINED3DRS_SRCBLEND           ,
    WINED3DRS_STENCILENABLE      ,
    WINED3DRS_STENCILFAIL        ,
    WINED3DRS_STENCILFUNC        ,
    WINED3DRS_STENCILMASK        ,
    WINED3DRS_STENCILPASS        ,
    WINED3DRS_STENCILREF         ,
    WINED3DRS_STENCILWRITEMASK   ,
    WINED3DRS_STENCILZFAIL       ,
    WINED3DRS_TEXTUREFACTOR      ,
    WINED3DRS_WRAP0              ,
    WINED3DRS_WRAP1              ,
    WINED3DRS_WRAP2              ,
    WINED3DRS_WRAP3              ,
    WINED3DRS_WRAP4              ,
    WINED3DRS_WRAP5              ,
    WINED3DRS_WRAP6              ,
    WINED3DRS_WRAP7              ,
    WINED3DRS_ZENABLE            ,
    WINED3DRS_ZFUNC              ,
    WINED3DRS_ZWRITEENABLE
};

const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
    WINED3DTSS_ADDRESSW              ,
    WINED3DTSS_ALPHAARG0             ,
    WINED3DTSS_ALPHAARG1             ,
    WINED3DTSS_ALPHAARG2             ,
    WINED3DTSS_ALPHAOP               ,
    WINED3DTSS_BUMPENVLOFFSET        ,
    WINED3DTSS_BUMPENVLSCALE         ,
    WINED3DTSS_BUMPENVMAT00          ,
    WINED3DTSS_BUMPENVMAT01          ,
    WINED3DTSS_BUMPENVMAT10          ,
    WINED3DTSS_BUMPENVMAT11          ,
    WINED3DTSS_COLORARG0             ,
    WINED3DTSS_COLORARG1             ,
    WINED3DTSS_COLORARG2             ,
    WINED3DTSS_COLOROP               ,
    WINED3DTSS_RESULTARG             ,
    WINED3DTSS_TEXCOORDINDEX         ,
    WINED3DTSS_TEXTURETRANSFORMFLAGS
};

const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
    WINED3DSAMP_ADDRESSU         ,
    WINED3DSAMP_ADDRESSV         ,
    WINED3DSAMP_ADDRESSW         ,
    WINED3DSAMP_BORDERCOLOR      ,
    WINED3DSAMP_MAGFILTER        ,
    WINED3DSAMP_MINFILTER        ,
    WINED3DSAMP_MIPFILTER        ,
    WINED3DSAMP_MIPMAPLODBIAS    ,
    WINED3DSAMP_MAXMIPLEVEL      ,
    WINED3DSAMP_MAXANISOTROPY    ,
    WINED3DSAMP_SRGBTEXTURE      ,
    WINED3DSAMP_ELEMENTINDEX
};

const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
    WINED3DRS_AMBIENT                       ,
    WINED3DRS_AMBIENTMATERIALSOURCE         ,
    WINED3DRS_CLIPPING                      ,
    WINED3DRS_CLIPPLANEENABLE               ,
    WINED3DRS_COLORVERTEX                   ,
    WINED3DRS_DIFFUSEMATERIALSOURCE         ,
    WINED3DRS_EMISSIVEMATERIALSOURCE        ,
    WINED3DRS_FOGDENSITY                    ,
    WINED3DRS_FOGEND                        ,
    WINED3DRS_FOGSTART                      ,
    WINED3DRS_FOGTABLEMODE                  ,
    WINED3DRS_FOGVERTEXMODE                 ,
    WINED3DRS_INDEXEDVERTEXBLENDENABLE      ,
    WINED3DRS_LIGHTING                      ,
    WINED3DRS_LOCALVIEWER                   ,
    WINED3DRS_MULTISAMPLEANTIALIAS          ,
    WINED3DRS_MULTISAMPLEMASK               ,
    WINED3DRS_NORMALIZENORMALS              ,
    WINED3DRS_PATCHEDGESTYLE                ,
    WINED3DRS_POINTSCALE_A                  ,
    WINED3DRS_POINTSCALE_B                  ,
    WINED3DRS_POINTSCALE_C                  ,
    WINED3DRS_POINTSCALEENABLE              ,
    WINED3DRS_POINTSIZE                     ,
    WINED3DRS_POINTSIZE_MAX                 ,
    WINED3DRS_POINTSIZE_MIN                 ,
    WINED3DRS_POINTSPRITEENABLE             ,
    WINED3DRS_RANGEFOGENABLE                ,
    WINED3DRS_SPECULARMATERIALSOURCE        ,
    WINED3DRS_TWEENFACTOR                   ,
    WINED3DRS_VERTEXBLEND
};

const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
    WINED3DTSS_TEXCOORDINDEX         ,
    WINED3DTSS_TEXTURETRANSFORMFLAGS
};

const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
    WINED3DSAMP_DMAPOFFSET
};
7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111

void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
    DWORD rep = StateTable[state].representative;
    DWORD idx;
    BYTE shift;

    if(!rep || isStateDirty(This, rep)) return;

    This->dirtyArray[This->numDirtyEntries++] = rep;
    idx = rep >> 5;
    shift = rep & 0x1f;
    This->isStateDirty[idx] |= (1 << shift);
}