wined3d: Get rid of the WINED3DRENDERSTATETYPE typedef.
[wine] / dlls / ddraw / vertexbuffer.c
1 /* Direct3D Vertex Buffer
2  * Copyright (c) 2002 Lionel ULMER
3  * Copyright (c) 2006 Stefan DÖSINGER
4  *
5  * This file contains the implementation of Direct3DVertexBuffer COM object
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * 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 #include "config.h"
23 #include "wine/port.h"
24
25 #include "ddraw_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
28
29 static inline IDirect3DVertexBufferImpl *impl_from_IDirect3DVertexBuffer(IDirect3DVertexBuffer *iface)
30 {
31     return CONTAINING_RECORD(iface, IDirect3DVertexBufferImpl, IDirect3DVertexBuffer_iface);
32 }
33
34 static inline IDirect3DVertexBufferImpl *impl_from_IDirect3DVertexBuffer7(IDirect3DVertexBuffer7 *iface)
35 {
36     return CONTAINING_RECORD(iface, IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7_iface);
37 }
38
39 /*****************************************************************************
40  * IUnknown Methods
41  *****************************************************************************/
42
43 /*****************************************************************************
44  * IDirect3DVertexBuffer7::QueryInterface
45  *
46  * The QueryInterface Method for Vertex Buffers
47  * For a link to QueryInterface rules, see IDirectDraw7::QueryInterface
48  *
49  * Params
50  *  riid: Queried Interface id
51  *  obj: Address to return the interface pointer
52  *
53  * Returns:
54  *  S_OK on success
55  *  E_NOINTERFACE if the interface wasn't found
56  *
57  *****************************************************************************/
58 static HRESULT WINAPI IDirect3DVertexBufferImpl_QueryInterface(IDirect3DVertexBuffer7 *iface,
59         REFIID riid, void  **obj)
60 {
61     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
62
63     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
64
65     /* By default, set the object pointer to NULL */
66     *obj = NULL;
67
68     if ( IsEqualGUID( &IID_IUnknown,  riid ) )
69     {
70         IUnknown_AddRef(iface);
71         *obj = iface;
72         TRACE("  Creating IUnknown interface at %p.\n", *obj);
73         return S_OK;
74     }
75     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer, riid ) )
76     {
77         IUnknown_AddRef(iface);
78         *obj = &This->IDirect3DVertexBuffer_iface;
79         TRACE("  Creating IDirect3DVertexBuffer interface %p\n", *obj);
80         return S_OK;
81     }
82     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer7, riid ) )
83     {
84         IUnknown_AddRef(iface);
85         *obj = iface;
86         TRACE("  Creating IDirect3DVertexBuffer7 interface %p\n", *obj);
87         return S_OK;
88     }
89     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
90     return E_NOINTERFACE;
91 }
92
93 static HRESULT WINAPI IDirect3DVertexBufferImpl_1_QueryInterface(IDirect3DVertexBuffer *iface,
94         REFIID riid, void **obj)
95 {
96     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
97
98     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
99
100     return IDirect3DVertexBuffer7_QueryInterface(&This->IDirect3DVertexBuffer7_iface, riid, obj);
101 }
102
103 /*****************************************************************************
104  * IDirect3DVertexBuffer7::AddRef
105  *
106  * AddRef for Vertex Buffers
107  *
108  * Returns:
109  *  The new refcount
110  *
111  *****************************************************************************/
112 static ULONG WINAPI IDirect3DVertexBufferImpl_AddRef(IDirect3DVertexBuffer7 *iface)
113 {
114     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
115     ULONG ref = InterlockedIncrement(&This->ref);
116
117     TRACE("%p increasing refcount to %u.\n", This, ref);
118
119     return ref;
120 }
121
122 static ULONG WINAPI IDirect3DVertexBufferImpl_1_AddRef(IDirect3DVertexBuffer *iface)
123 {
124     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
125
126     TRACE("iface %p.\n", iface);
127
128     return IDirect3DVertexBuffer7_AddRef(&This->IDirect3DVertexBuffer7_iface);
129 }
130
131
132 /*****************************************************************************
133  * IDirect3DVertexBuffer7::Release
134  *
135  * Release for Vertex Buffers
136  *
137  * Returns:
138  *  The new refcount
139  *
140  *****************************************************************************/
141 static ULONG WINAPI IDirect3DVertexBufferImpl_Release(IDirect3DVertexBuffer7 *iface)
142 {
143     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
144     ULONG ref = InterlockedDecrement(&This->ref);
145
146     TRACE("%p decreasing refcount to %u.\n", This, ref);
147
148     if (ref == 0)
149     {
150         struct wined3d_buffer *curVB = NULL;
151         UINT offset, stride;
152
153         /* D3D7 Vertex buffers don't stay bound in the device, they are passed
154          * as a parameter to drawPrimitiveVB. DrawPrimitiveVB sets them as the
155          * stream source in wined3d, and they should get unset there before
156          * they are destroyed. */
157         wined3d_mutex_lock();
158         wined3d_device_get_stream_source(This->ddraw->wined3d_device,
159                 0, &curVB, &offset, &stride);
160         if (curVB == This->wineD3DVertexBuffer)
161             wined3d_device_set_stream_source(This->ddraw->wined3d_device, 0, NULL, 0, 0);
162         if (curVB)
163             wined3d_buffer_decref(curVB); /* For the GetStreamSource */
164
165         wined3d_vertex_declaration_decref(This->wineD3DVertexDeclaration);
166         wined3d_buffer_decref(This->wineD3DVertexBuffer);
167         wined3d_mutex_unlock();
168
169         HeapFree(GetProcessHeap(), 0, This);
170
171         return 0;
172     }
173     return ref;
174 }
175
176 static ULONG WINAPI IDirect3DVertexBufferImpl_1_Release(IDirect3DVertexBuffer *iface)
177 {
178     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
179
180     TRACE("iface %p.\n", iface);
181
182     return IDirect3DVertexBuffer7_Release(&This->IDirect3DVertexBuffer7_iface);
183 }
184
185 /*****************************************************************************
186  * IDirect3DVertexBuffer Methods
187  *****************************************************************************/
188
189 /*****************************************************************************
190  * IDirect3DVertexBuffer7::Lock
191  *
192  * Locks the vertex buffer and returns a pointer to the vertex data
193  * Locking vertex buffers is similar to locking surfaces, because Windows
194  * uses surfaces to store vertex data internally (According to the DX sdk)
195  *
196  * Params:
197  *  Flags: Locking flags. Relevant here are DDLOCK_READONLY, DDLOCK_WRITEONLY,
198  *         DDLOCK_DISCARDCONTENTS and DDLOCK_NOOVERWRITE.
199  *  Data:  Returns a pointer to the vertex data
200  *  Size:  Returns the size of the buffer if not NULL
201  *
202  * Returns:
203  *  D3D_OK on success
204  *  DDERR_INVALIDPARAMS if Data is NULL
205  *  D3DERR_VERTEXBUFFEROPTIMIZED if called on an optimized buffer(WineD3D)
206  *
207  *****************************************************************************/
208 static HRESULT WINAPI IDirect3DVertexBufferImpl_Lock(IDirect3DVertexBuffer7 *iface, DWORD Flags,
209         void **Data, DWORD *Size)
210 {
211     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
212     struct wined3d_resource_desc wined3d_desc;
213     struct wined3d_resource *wined3d_resource;
214     HRESULT hr;
215     DWORD wined3d_flags = 0;
216
217     TRACE("iface %p, flags %#x, data %p, data_size %p.\n", iface, Flags, Data, Size);
218
219     /* Writeonly: Pointless. Event: Unsupported by native according to the sdk
220      * nosyslock: Not applicable
221      */
222     if(!(Flags & DDLOCK_WAIT))          wined3d_flags |= WINED3DLOCK_DONOTWAIT;
223     if(Flags & DDLOCK_READONLY)         wined3d_flags |= WINED3DLOCK_READONLY;
224     if(Flags & DDLOCK_NOOVERWRITE)      wined3d_flags |= WINED3DLOCK_NOOVERWRITE;
225     if(Flags & DDLOCK_DISCARDCONTENTS)  wined3d_flags |= WINED3DLOCK_DISCARD;
226
227     wined3d_mutex_lock();
228     if(Size)
229     {
230         /* Get the size, for returning it, and for locking */
231         wined3d_resource = wined3d_buffer_get_resource(This->wineD3DVertexBuffer);
232         wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
233         *Size = wined3d_desc.size;
234     }
235
236     hr = wined3d_buffer_map(This->wineD3DVertexBuffer, 0, 0, (BYTE **)Data, wined3d_flags);
237     wined3d_mutex_unlock();
238
239     return hr;
240 }
241
242 static HRESULT WINAPI IDirect3DVertexBufferImpl_1_Lock(IDirect3DVertexBuffer *iface, DWORD Flags,
243         void **Data, DWORD *Size)
244 {
245     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
246
247     TRACE("iface %p, flags %#x, data %p, data_size %p.\n", iface, Flags, Data, Size);
248
249     return IDirect3DVertexBuffer7_Lock(&This->IDirect3DVertexBuffer7_iface, Flags, Data, Size);
250 }
251
252 /*****************************************************************************
253  * IDirect3DVertexBuffer7::Unlock
254  *
255  * Unlocks a vertex Buffer
256  *
257  * Returns:
258  *  D3D_OK on success
259  *
260  *****************************************************************************/
261 static HRESULT WINAPI IDirect3DVertexBufferImpl_Unlock(IDirect3DVertexBuffer7 *iface)
262 {
263     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
264
265     TRACE("iface %p.\n", iface);
266
267     wined3d_mutex_lock();
268     wined3d_buffer_unmap(This->wineD3DVertexBuffer);
269     wined3d_mutex_unlock();
270
271     return D3D_OK;
272 }
273
274 static HRESULT WINAPI IDirect3DVertexBufferImpl_1_Unlock(IDirect3DVertexBuffer *iface)
275 {
276     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
277
278     TRACE("iface %p.\n", iface);
279
280     return IDirect3DVertexBuffer7_Unlock(&This->IDirect3DVertexBuffer7_iface);
281 }
282
283
284 /*****************************************************************************
285  * IDirect3DVertexBuffer7::ProcessVertices
286  *
287  * Processes untransformed Vertices into a transformed or optimized vertex
288  * buffer. It can also perform other operations, such as lighting or clipping
289  *
290  * Params
291  *  VertexOp: Operation(s) to perform: D3DVOP_CLIP, _EXTENTS, _LIGHT, _TRANSFORM
292  *  DestIndex: Index in the destination buffer(This), where the vertices are
293  *             placed
294  *  Count: Number of Vertices in the Source buffer to process
295  *  SrcBuffer: Source vertex buffer
296  *  SrcIndex: Index of the first vertex in the src buffer to process
297  *  D3DDevice: Device to use for transformation
298  *  Flags: 0 for default, D3DPV_DONOTCOPYDATA to prevent copying
299  *         unchaned vertices
300  *
301  * Returns:
302  *  D3D_OK on success
303  *  DDERR_INVALIDPARAMS If D3DVOP_TRANSFORM wasn't passed
304  *
305  *****************************************************************************/
306 static HRESULT WINAPI IDirect3DVertexBufferImpl_ProcessVertices(IDirect3DVertexBuffer7 *iface,
307         DWORD VertexOp, DWORD DestIndex, DWORD Count, IDirect3DVertexBuffer7 *SrcBuffer,
308         DWORD SrcIndex, IDirect3DDevice7 *device, DWORD Flags)
309 {
310     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
311     IDirect3DVertexBufferImpl *Src = unsafe_impl_from_IDirect3DVertexBuffer7(SrcBuffer);
312     IDirect3DDeviceImpl *device_impl = unsafe_impl_from_IDirect3DDevice7(device);
313     BOOL oldClip, doClip;
314     HRESULT hr;
315
316     TRACE("iface %p, vertex_op %#x, dst_idx %u, count %u, src_buffer %p, src_idx %u, device %p, flags %#x.\n",
317             iface, VertexOp, DestIndex, Count, SrcBuffer, SrcIndex, device, Flags);
318
319     /* Vertex operations:
320      * D3DVOP_CLIP: Clips vertices outside the viewing frustrum. Needs clipping information
321      * in the vertex buffer (Buffer may not be created with D3DVBCAPS_DONOTCLIP)
322      * D3DVOP_EXTENTS: Causes the screen extents to be updated when rendering the vertices
323      * D3DVOP_LIGHT: Lights the vertices
324      * D3DVOP_TRANSFORM: Transform the vertices. This flag is necessary
325      *
326      * WineD3D only transforms and clips the vertices by now, so EXTENTS and LIGHT
327      * are not implemented. Clipping is disabled ATM, because of unsure conditions.
328      */
329     if( !(VertexOp & D3DVOP_TRANSFORM) ) return DDERR_INVALIDPARAMS;
330
331     wined3d_mutex_lock();
332
333     /* WineD3D doesn't know d3d7 vertex operation, it uses
334      * render states instead. Set the render states according to
335      * the vertex ops
336      */
337     doClip = VertexOp & D3DVOP_CLIP ? TRUE : FALSE;
338     wined3d_device_get_render_state(device_impl->wined3d_device, WINED3D_RS_CLIPPING, (DWORD *)&oldClip);
339     if (doClip != oldClip)
340         wined3d_device_set_render_state(device_impl->wined3d_device, WINED3D_RS_CLIPPING, doClip);
341
342     wined3d_device_set_stream_source(device_impl->wined3d_device,
343             0, Src->wineD3DVertexBuffer, 0, get_flexible_vertex_size(Src->fvf));
344     wined3d_device_set_vertex_declaration(device_impl->wined3d_device, Src->wineD3DVertexDeclaration);
345     hr = wined3d_device_process_vertices(device_impl->wined3d_device, SrcIndex, DestIndex,
346             Count, This->wineD3DVertexBuffer, NULL, Flags, This->fvf);
347
348     /* Restore the states if needed */
349     if (doClip != oldClip)
350         wined3d_device_set_render_state(device_impl->wined3d_device, WINED3D_RS_CLIPPING, oldClip);
351
352     wined3d_mutex_unlock();
353
354     return hr;
355 }
356
357 static HRESULT WINAPI IDirect3DVertexBufferImpl_1_ProcessVertices(IDirect3DVertexBuffer *iface,
358         DWORD VertexOp, DWORD DestIndex, DWORD Count, IDirect3DVertexBuffer *SrcBuffer,
359         DWORD SrcIndex, IDirect3DDevice3 *device, DWORD Flags)
360 {
361     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
362     IDirect3DVertexBufferImpl *Src = unsafe_impl_from_IDirect3DVertexBuffer(SrcBuffer);
363     IDirect3DDeviceImpl *device_impl = unsafe_impl_from_IDirect3DDevice3(device);
364
365     TRACE("iface %p, vertex_op %#x, dst_idx %u, count %u, src_buffer %p, src_idx %u, device %p, flags %#x.\n",
366             iface, VertexOp, DestIndex, Count, SrcBuffer, SrcIndex, device, Flags);
367
368     return IDirect3DVertexBuffer7_ProcessVertices(&This->IDirect3DVertexBuffer7_iface, VertexOp,
369             DestIndex, Count, &Src->IDirect3DVertexBuffer7_iface, SrcIndex,
370             device_impl ? &device_impl->IDirect3DDevice7_iface : NULL, Flags);
371 }
372
373 /*****************************************************************************
374  * IDirect3DVertexBuffer7::GetVertexBufferDesc
375  *
376  * Returns the description of a vertex buffer
377  *
378  * Params:
379  *  Desc: Address to write the description to
380  *
381  * Returns
382  *  DDERR_INVALIDPARAMS if Desc is NULL
383  *  D3D_OK on success
384  *
385  *****************************************************************************/
386 static HRESULT WINAPI IDirect3DVertexBufferImpl_GetVertexBufferDesc(IDirect3DVertexBuffer7 *iface,
387         D3DVERTEXBUFFERDESC *Desc)
388 {
389     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
390     struct wined3d_resource_desc wined3d_desc;
391     struct wined3d_resource *wined3d_resource;
392
393     TRACE("iface %p, desc %p.\n", iface, Desc);
394
395     if(!Desc) return DDERR_INVALIDPARAMS;
396
397     wined3d_mutex_lock();
398     wined3d_resource = wined3d_buffer_get_resource(This->wineD3DVertexBuffer);
399     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
400     wined3d_mutex_unlock();
401
402     /* Now fill the Desc structure */
403     Desc->dwCaps = This->Caps;
404     Desc->dwFVF = This->fvf;
405     Desc->dwNumVertices = wined3d_desc.size / get_flexible_vertex_size(This->fvf);
406
407     return D3D_OK;
408 }
409
410 static HRESULT WINAPI IDirect3DVertexBufferImpl_1_GetVertexBufferDesc(IDirect3DVertexBuffer *iface,
411         D3DVERTEXBUFFERDESC *Desc)
412 {
413     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
414
415     TRACE("iface %p, desc %p.\n", iface, Desc);
416
417     return IDirect3DVertexBuffer7_GetVertexBufferDesc(&This->IDirect3DVertexBuffer7_iface, Desc);
418 }
419
420
421 /*****************************************************************************
422  * IDirect3DVertexBuffer7::Optimize
423  *
424  * Converts an unoptimized vertex buffer into an optimized buffer
425  *
426  * Params:
427  *  D3DDevice: Device for which this buffer is optimized
428  *  Flags: Not used, should be set to 0
429  *
430  * Returns
431  *  D3D_OK, because it's a stub
432  *
433  *****************************************************************************/
434 static HRESULT WINAPI IDirect3DVertexBufferImpl_Optimize(IDirect3DVertexBuffer7 *iface,
435         IDirect3DDevice7 *D3DDevice, DWORD Flags)
436 {
437     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer7(iface);
438     static BOOL hide = FALSE;
439
440     TRACE("iface %p, device %p, flags %#x.\n", iface, D3DDevice, Flags);
441
442     if (!hide)
443     {
444         FIXME("iface %p, device %p, flags %#x stub!\n", iface, D3DDevice, Flags);
445         hide = TRUE;
446     }
447
448     /* We could forward this call to WineD3D and take advantage
449      * of it once we use OpenGL vertex buffers
450      */
451     wined3d_mutex_lock();
452     This->Caps |= D3DVBCAPS_OPTIMIZED;
453     wined3d_mutex_unlock();
454
455     return DD_OK;
456 }
457
458 static HRESULT WINAPI IDirect3DVertexBufferImpl_1_Optimize(IDirect3DVertexBuffer *iface,
459         IDirect3DDevice3 *device, DWORD Flags)
460 {
461     IDirect3DVertexBufferImpl *This = impl_from_IDirect3DVertexBuffer(iface);
462     IDirect3DDeviceImpl *device_impl = unsafe_impl_from_IDirect3DDevice3(device);
463
464     TRACE("iface %p, device %p, flags %#x.\n", iface, device, Flags);
465
466     return IDirect3DVertexBuffer7_Optimize(&This->IDirect3DVertexBuffer7_iface,
467             device_impl ? &device_impl->IDirect3DDevice7_iface : NULL, Flags);
468 }
469
470 /*****************************************************************************
471  * IDirect3DVertexBuffer7::ProcessVerticesStrided
472  *
473  * This method processes untransformed strided vertices into a processed
474  * or optimized vertex buffer.
475  *
476  * For more details on the parameters, see
477  * IDirect3DVertexBuffer7::ProcessVertices
478  *
479  * Params:
480  *  VertexOp: Operations to perform
481  *  DestIndex: Destination index to write the vertices to
482  *  Count: Number of input vertices
483  *  StrideData: Array containing the input vertices
484  *  VertexTypeDesc: Vertex Description or source index?????????
485  *  D3DDevice: IDirect3DDevice7 to use for processing
486  *  Flags: Can be D3DPV_DONOTCOPYDATA to avoid copying unmodified vertices
487  *
488  * Returns
489  *  D3D_OK on success, or DDERR_*
490  *
491  *****************************************************************************/
492 static HRESULT WINAPI
493 IDirect3DVertexBufferImpl_ProcessVerticesStrided(IDirect3DVertexBuffer7 *iface,
494                                                  DWORD VertexOp,
495                                                  DWORD DestIndex,
496                                                  DWORD Count,
497                                                  D3DDRAWPRIMITIVESTRIDEDDATA *StrideData,
498                                                  DWORD VertexTypeDesc,
499                                                  IDirect3DDevice7 *D3DDevice,
500                                                  DWORD Flags)
501 {
502     FIXME("iface %p, vertex_op %#x, dst_idx %u, count %u, data %p, vertex_type %#x, device %p, flags %#x stub!\n",
503             iface, VertexOp, DestIndex, Count, StrideData, VertexTypeDesc, D3DDevice, Flags);
504
505     return DD_OK;
506 }
507
508 /*****************************************************************************
509  * The VTables
510  *****************************************************************************/
511
512 static const struct IDirect3DVertexBuffer7Vtbl d3d_vertex_buffer7_vtbl =
513 {
514     /*** IUnknown Methods ***/
515     IDirect3DVertexBufferImpl_QueryInterface,
516     IDirect3DVertexBufferImpl_AddRef,
517     IDirect3DVertexBufferImpl_Release,
518     /*** IDirect3DVertexBuffer Methods ***/
519     IDirect3DVertexBufferImpl_Lock,
520     IDirect3DVertexBufferImpl_Unlock,
521     IDirect3DVertexBufferImpl_ProcessVertices,
522     IDirect3DVertexBufferImpl_GetVertexBufferDesc,
523     IDirect3DVertexBufferImpl_Optimize,
524     /*** IDirect3DVertexBuffer7 Methods ***/
525     IDirect3DVertexBufferImpl_ProcessVerticesStrided
526 };
527
528 static const struct IDirect3DVertexBufferVtbl d3d_vertex_buffer1_vtbl =
529 {
530     /*** IUnknown Methods ***/
531     IDirect3DVertexBufferImpl_1_QueryInterface,
532     IDirect3DVertexBufferImpl_1_AddRef,
533     IDirect3DVertexBufferImpl_1_Release,
534     /*** IDirect3DVertexBuffer Methods ***/
535     IDirect3DVertexBufferImpl_1_Lock,
536     IDirect3DVertexBufferImpl_1_Unlock,
537     IDirect3DVertexBufferImpl_1_ProcessVertices,
538     IDirect3DVertexBufferImpl_1_GetVertexBufferDesc,
539     IDirect3DVertexBufferImpl_1_Optimize
540 };
541
542 HRESULT d3d_vertex_buffer_create(IDirect3DVertexBufferImpl **vertex_buf, IDirectDrawImpl *ddraw,
543         D3DVERTEXBUFFERDESC *desc)
544 {
545     IDirect3DVertexBufferImpl *buffer;
546     DWORD usage;
547     HRESULT hr = D3D_OK;
548
549     TRACE("Vertex buffer description:\n");
550     TRACE("    dwSize %u\n", desc->dwSize);
551     TRACE("    dwCaps %#x\n", desc->dwCaps);
552     TRACE("    FVF %#x\n", desc->dwFVF);
553     TRACE("    dwNumVertices %u\n", desc->dwNumVertices);
554
555     buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buffer));
556     if (!buffer)
557         return DDERR_OUTOFMEMORY;
558
559     buffer->IDirect3DVertexBuffer7_iface.lpVtbl = &d3d_vertex_buffer7_vtbl;
560     buffer->IDirect3DVertexBuffer_iface.lpVtbl = &d3d_vertex_buffer1_vtbl;
561     buffer->ref = 1;
562
563     buffer->ddraw = ddraw;
564     buffer->Caps = desc->dwCaps;
565     buffer->fvf = desc->dwFVF;
566
567     usage = desc->dwCaps & D3DVBCAPS_WRITEONLY ? WINED3DUSAGE_WRITEONLY : 0;
568     usage |= WINED3DUSAGE_STATICDECL;
569
570     wined3d_mutex_lock();
571
572     hr = wined3d_buffer_create_vb(ddraw->wined3d_device,
573             get_flexible_vertex_size(desc->dwFVF) * desc->dwNumVertices,
574             usage, desc->dwCaps & D3DVBCAPS_SYSTEMMEMORY ? WINED3DPOOL_SYSTEMMEM : WINED3DPOOL_DEFAULT,
575             buffer, &ddraw_null_wined3d_parent_ops, &buffer->wineD3DVertexBuffer);
576     if (FAILED(hr))
577     {
578         WARN("Failed to create wined3d vertex buffer, hr %#x.\n", hr);
579         if (hr == WINED3DERR_INVALIDCALL)
580             hr = DDERR_INVALIDPARAMS;
581         goto end;
582     }
583
584     buffer->wineD3DVertexDeclaration = ddraw_find_decl(ddraw, desc->dwFVF);
585     if (!buffer->wineD3DVertexDeclaration)
586     {
587         ERR("Failed to find vertex declaration for fvf %#x.\n", desc->dwFVF);
588         wined3d_buffer_decref(buffer->wineD3DVertexBuffer);
589         hr = DDERR_INVALIDPARAMS;
590         goto end;
591     }
592     wined3d_vertex_declaration_incref(buffer->wineD3DVertexDeclaration);
593
594 end:
595     wined3d_mutex_unlock();
596     if (hr == D3D_OK)
597         *vertex_buf = buffer;
598     else
599         HeapFree(GetProcessHeap(), 0, buffer);
600
601     return hr;
602 }
603
604 IDirect3DVertexBufferImpl *unsafe_impl_from_IDirect3DVertexBuffer(IDirect3DVertexBuffer *iface)
605 {
606     if (!iface)
607         return NULL;
608     assert(iface->lpVtbl == &d3d_vertex_buffer1_vtbl);
609
610     return impl_from_IDirect3DVertexBuffer(iface);
611 }
612
613 IDirect3DVertexBufferImpl *unsafe_impl_from_IDirect3DVertexBuffer7(IDirect3DVertexBuffer7 *iface)
614 {
615     if (!iface)
616         return NULL;
617     assert(iface->lpVtbl == &d3d_vertex_buffer7_vtbl);
618
619     return impl_from_IDirect3DVertexBuffer7(iface);
620 }