vertexdeclaration.c 12 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * IDirect3DVertexDeclaration9 implementation
 *
 * Copyright 2002-2003 Raphael Junqueira
 *                     Jason Edmeades
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23 24
 */

#include "config.h"
#include "d3d9_private.h"

25
WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
26

27 28 29 30 31 32
typedef struct _D3DDECLTYPE_INFO {
    D3DDECLTYPE d3dType;
    int         size;
    int         typesize;
} D3DDECLTYPE_INFO;

33
static D3DDECLTYPE_INFO const d3d_dtype_lookup[D3DDECLTYPE_UNUSED] = {
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
   {D3DDECLTYPE_FLOAT1,    1, sizeof(float)},
   {D3DDECLTYPE_FLOAT2,    2, sizeof(float)},
   {D3DDECLTYPE_FLOAT3,    3, sizeof(float)},
   {D3DDECLTYPE_FLOAT4,    4, sizeof(float)},
   {D3DDECLTYPE_D3DCOLOR,  4, sizeof(BYTE)},
   {D3DDECLTYPE_UBYTE4,    4, sizeof(BYTE)},
   {D3DDECLTYPE_SHORT2,    2, sizeof(short int)},
   {D3DDECLTYPE_SHORT4,    4, sizeof(short int)},
   {D3DDECLTYPE_UBYTE4N,   4, sizeof(BYTE)},
   {D3DDECLTYPE_SHORT2N,   2, sizeof(short int)},
   {D3DDECLTYPE_SHORT4N,   4, sizeof(short int)},
   {D3DDECLTYPE_USHORT2N,  2, sizeof(short int)},
   {D3DDECLTYPE_USHORT4N,  4, sizeof(short int)},
   {D3DDECLTYPE_UDEC3,     3, sizeof(short int)},
   {D3DDECLTYPE_DEC3N,     3, sizeof(short int)},
   {D3DDECLTYPE_FLOAT16_2, 2, sizeof(short int)},
   {D3DDECLTYPE_FLOAT16_4, 4, sizeof(short int)}};

#define D3D_DECL_SIZE(type)          d3d_dtype_lookup[type].size
#define D3D_DECL_TYPESIZE(type)      d3d_dtype_lookup[type].typesize

HRESULT vdecl_convert_fvf(
    DWORD fvf,
    D3DVERTEXELEMENT9** ppVertexElements) {

    unsigned int idx, idx2;
    unsigned int offset;
    BOOL has_pos = (fvf & D3DFVF_POSITION_MASK) != 0;
    BOOL has_blend = (fvf & D3DFVF_XYZB5) > D3DFVF_XYZRHW;
    BOOL has_blend_idx = has_blend &&
       (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB5) ||
        (fvf & D3DFVF_LASTBETA_D3DCOLOR) ||
        (fvf & D3DFVF_LASTBETA_UBYTE4));
    BOOL has_normal = (fvf & D3DFVF_NORMAL) != 0;
    BOOL has_psize = (fvf & D3DFVF_PSIZE) != 0;
    BOOL has_diffuse = (fvf & D3DFVF_DIFFUSE) != 0;
    BOOL has_specular = (fvf & D3DFVF_SPECULAR) !=0;

    DWORD num_textures = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
    DWORD texcoords = (fvf & 0x00FF0000) >> 16;

    D3DVERTEXELEMENT9 end_element = D3DDECL_END();
    D3DVERTEXELEMENT9 *elements = NULL;

    unsigned int size;
    DWORD num_blends = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
    if (has_blend_idx) num_blends--;

    /* Compute declaration size */
    size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
           has_psize + has_diffuse + has_specular + num_textures + 1;

    /* convert the declaration */
    elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(D3DVERTEXELEMENT9));
    if (!elements) 
        return D3DERR_OUTOFVIDEOMEMORY;

    memcpy(&elements[size-1], &end_element, sizeof(D3DVERTEXELEMENT9));
    idx = 0;
    if (has_pos) {
        if (!has_blend && (fvf & D3DFVF_XYZRHW)) {
            elements[idx].Type = D3DDECLTYPE_FLOAT4;
            elements[idx].Usage = D3DDECLUSAGE_POSITIONT;
        }
        else {
            elements[idx].Type = D3DDECLTYPE_FLOAT3;
            elements[idx].Usage = D3DDECLUSAGE_POSITION;
        }
        elements[idx].UsageIndex = 0;
        idx++;
    }
    if (has_blend && (num_blends > 0)) {
        if (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB2) && (fvf & D3DFVF_LASTBETA_D3DCOLOR))
            elements[idx].Type = D3DDECLTYPE_D3DCOLOR;
        else
            elements[idx].Type = D3DDECLTYPE_FLOAT1 + num_blends - 1;
        elements[idx].Usage = D3DDECLUSAGE_BLENDWEIGHT;
        elements[idx].UsageIndex = 0;
        idx++;
    }
    if (has_blend_idx) {
        if (fvf & D3DFVF_LASTBETA_UBYTE4 ||
            (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB2) && (fvf & D3DFVF_LASTBETA_D3DCOLOR)))
            elements[idx].Type = D3DDECLTYPE_UBYTE4;
        else if (fvf & D3DFVF_LASTBETA_D3DCOLOR)
            elements[idx].Type = D3DDECLTYPE_D3DCOLOR;
        else
            elements[idx].Type = D3DDECLTYPE_FLOAT1;
        elements[idx].Usage = D3DDECLUSAGE_BLENDINDICES;
        elements[idx].UsageIndex = 0;
        idx++;
    }
    if (has_normal) {
        elements[idx].Type = D3DDECLTYPE_FLOAT3;
        elements[idx].Usage = D3DDECLUSAGE_NORMAL;
        elements[idx].UsageIndex = 0;
        idx++;
    }
    if (has_psize) {
        elements[idx].Type = D3DDECLTYPE_FLOAT1;
        elements[idx].Usage = D3DDECLUSAGE_PSIZE;
        elements[idx].UsageIndex = 0;
        idx++;
    }
    if (has_diffuse) {
        elements[idx].Type = D3DDECLTYPE_D3DCOLOR;
        elements[idx].Usage = D3DDECLUSAGE_COLOR;
        elements[idx].UsageIndex = 0;
        idx++;
    }
    if (has_specular) {
        elements[idx].Type = D3DDECLTYPE_D3DCOLOR;
        elements[idx].Usage = D3DDECLUSAGE_COLOR;
        elements[idx].UsageIndex = 1;
        idx++;
    }
    for (idx2 = 0; idx2 < num_textures; idx2++) {
        unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
        switch (numcoords) {
            case D3DFVF_TEXTUREFORMAT1:
                elements[idx].Type = D3DDECLTYPE_FLOAT1;
                break;
            case D3DFVF_TEXTUREFORMAT2:
                elements[idx].Type = D3DDECLTYPE_FLOAT2;
                break;
            case D3DFVF_TEXTUREFORMAT3:
                elements[idx].Type = D3DDECLTYPE_FLOAT3;
                break;
            case D3DFVF_TEXTUREFORMAT4:
                elements[idx].Type = D3DDECLTYPE_FLOAT4;
                break;
        }
        elements[idx].Usage = D3DDECLUSAGE_TEXCOORD;
        elements[idx].UsageIndex = idx2;
        idx++;
    }

    /* Now compute offsets, and initialize the rest of the fields */
    for (idx = 0, offset = 0; idx < size-1; idx++) {
        elements[idx].Stream = 0;
        elements[idx].Method = D3DDECLMETHOD_DEFAULT;
        elements[idx].Offset = offset;
        offset += D3D_DECL_SIZE(elements[idx].Type) * D3D_DECL_TYPESIZE(elements[idx].Type);
    }

    *ppVertexElements = elements;
    return D3D_OK;
}

183
/* IDirect3DVertexDeclaration9 IUnknown parts follow: */
184
static HRESULT WINAPI IDirect3DVertexDeclaration9Impl_QueryInterface(LPDIRECT3DVERTEXDECLARATION9 iface, REFIID riid, LPVOID* ppobj) {
185
    IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
186 187 188

    if (IsEqualGUID(riid, &IID_IUnknown)
        || IsEqualGUID(riid, &IID_IDirect3DVertexDeclaration9)) {
189
        IUnknown_AddRef(iface);
190
        *ppobj = This;
H. Verbeet's avatar
H. Verbeet committed
191
        return S_OK;
192 193 194
    }

    WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
H. Verbeet's avatar
H. Verbeet committed
195
    *ppobj = NULL;
196 197 198
    return E_NOINTERFACE;
}

199
static ULONG WINAPI IDirect3DVertexDeclaration9Impl_AddRef(LPDIRECT3DVERTEXDECLARATION9 iface) {
200
    IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
201 202
    ULONG ref = InterlockedIncrement(&This->ref);

203
    TRACE("(%p) : AddRef from %d\n", This, ref - 1);
204 205

    return ref;
206 207
}

208
static ULONG WINAPI IDirect3DVertexDeclaration9Impl_Release(LPDIRECT3DVERTEXDECLARATION9 iface) {
209
    IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
210 211
    ULONG ref = InterlockedDecrement(&This->ref);

212
    TRACE("(%p) : ReleaseRef to %d\n", This, ref);
213

214
    if (ref == 0) {
215
        IWineD3DVertexDeclaration_Release(This->wineD3DVertexDeclaration);
216
        IUnknown_Release(This->parentDevice);
217 218 219 220 221 222
        HeapFree(GetProcessHeap(), 0, This);
    }
    return ref;
}

/* IDirect3DVertexDeclaration9 Interface follow: */
223
static HRESULT WINAPI IDirect3DVertexDeclaration9Impl_GetDevice(LPDIRECT3DVERTEXDECLARATION9 iface, IDirect3DDevice9** ppDevice) {
224
    IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
225
    IWineD3DDevice *myDevice = NULL;
226 227 228 229 230 231 232 233 234 235
    HRESULT hr = D3D_OK;

    TRACE("(%p) : Relay\n", iface);

    hr = IWineD3DVertexDeclaration_GetDevice(This->wineD3DVertexDeclaration, &myDevice);
    if (hr == D3D_OK && myDevice != NULL) {
        hr = IWineD3DDevice_GetParent(myDevice, (IUnknown **)ppDevice);
        IWineD3DDevice_Release(myDevice);
    }
    return hr;
236 237
}

238
static HRESULT WINAPI IDirect3DVertexDeclaration9Impl_GetDeclaration(LPDIRECT3DVERTEXDECLARATION9 iface, D3DVERTEXELEMENT9* pDecl, UINT* pNumElements) {
239
    IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
240 241 242 243
    DWORD NumElements;
    HRESULT hr;
    TRACE("(%p) : Relay\n", iface);
    hr = IWineD3DVertexDeclaration_GetDeclaration(This->wineD3DVertexDeclaration, pDecl, &NumElements);
244

245 246 247
    *pNumElements = NumElements;
    return hr;
}
248

249
static const IDirect3DVertexDeclaration9Vtbl Direct3DVertexDeclaration9_Vtbl =
250
{
251
    /* IUnknown */
252 253 254
    IDirect3DVertexDeclaration9Impl_QueryInterface,
    IDirect3DVertexDeclaration9Impl_AddRef,
    IDirect3DVertexDeclaration9Impl_Release,
255
    /* IDirect3DVertexDeclaration9 */
256 257 258 259 260 261 262
    IDirect3DVertexDeclaration9Impl_GetDevice,
    IDirect3DVertexDeclaration9Impl_GetDeclaration
};


/* IDirect3DDevice9 IDirect3DVertexDeclaration9 Methods follow: */
HRESULT  WINAPI  IDirect3DDevice9Impl_CreateVertexDeclaration(LPDIRECT3DDEVICE9 iface, CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) {
263
    
264
    IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface;
265 266
    IDirect3DVertexDeclaration9Impl *object = NULL;
    HRESULT hr = D3D_OK;
267 268

    TRACE("(%p) : Relay\n", iface);
269
    if (NULL == ppDecl) {
270
        WARN("(%p) : Caller passed NULL As ppDecl, returning D3DERR_INVALIDCALL\n",This);
271
        return D3DERR_INVALIDCALL;
272 273 274 275
    }
    /* Allocate the storage for the device */
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVertexDeclaration9Impl));
    if (NULL == object) {
276 277
        FIXME("Allocation of memory failed, returning D3DERR_OUTOFVIDEOMEMORY\n");
        return D3DERR_OUTOFVIDEOMEMORY;
278 279 280 281
    }

    object->lpVtbl = &Direct3DVertexDeclaration9_Vtbl;
    object->ref = 1;
282
    hr = IWineD3DDevice_CreateVertexDeclaration(This->WineD3DDevice, pVertexElements, &object->wineD3DVertexDeclaration, (IUnknown *)object);
283 284

    if (FAILED(hr)) {
285 286 287 288

        /* free up object */
        FIXME("(%p) call to IWineD3DDevice_CreateVertexDeclaration failed\n", This);
        HeapFree(GetProcessHeap(), 0, object);
289
    } else {
290 291
        IUnknown_AddRef(iface);
        object->parentDevice = iface;
292
        *ppDecl = (LPDIRECT3DVERTEXDECLARATION9) object;
293
         TRACE("(%p) : Created vertex declaration %p\n", This, object);
294 295
    }
    return hr;
296 297 298
}

HRESULT  WINAPI  IDirect3DDevice9Impl_SetVertexDeclaration(LPDIRECT3DDEVICE9 iface, IDirect3DVertexDeclaration9* pDecl) {
299
    IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface;
300
    IDirect3DVertexDeclaration9Impl *pDeclImpl = (IDirect3DVertexDeclaration9Impl *)pDecl;
301 302 303 304 305 306
    HRESULT hr = D3D_OK;

    TRACE("(%p) : Relay\n", iface);

    hr = IWineD3DDevice_SetVertexDeclaration(This->WineD3DDevice, pDeclImpl == NULL ? NULL : pDeclImpl->wineD3DVertexDeclaration);

307
    return hr;
308 309 310
}

HRESULT  WINAPI  IDirect3DDevice9Impl_GetVertexDeclaration(LPDIRECT3DDEVICE9 iface, IDirect3DVertexDeclaration9** ppDecl) {
311 312
    IDirect3DDevice9Impl* This = (IDirect3DDevice9Impl*) iface;
    IWineD3DVertexDeclaration* pTest = NULL;
313 314 315
    HRESULT hr = D3D_OK;

    TRACE("(%p) : Relay+\n", iface);
316 317 318 319

    if (NULL == ppDecl) {
      return D3DERR_INVALIDCALL;
    }
320

321 322
    *ppDecl = NULL;
    hr = IWineD3DDevice_GetVertexDeclaration(This->WineD3DDevice, &pTest);
323
    if (hr == D3D_OK && NULL != pTest) {
324 325
        IWineD3DVertexDeclaration_GetParent(pTest, (IUnknown **)ppDecl);
        IWineD3DVertexDeclaration_Release(pTest);
326 327
    } else {
        *ppDecl = NULL;
328
    }
329
    TRACE("(%p) : returning %p\n", This, *ppDecl);
330
    return hr;
331
}