ddraw: Avoid LPD3DINSTRUCTION.
[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 struct d3d_vertex_buffer *impl_from_IDirect3DVertexBuffer(IDirect3DVertexBuffer *iface)
30 {
31     return CONTAINING_RECORD(iface, struct d3d_vertex_buffer, IDirect3DVertexBuffer_iface);
32 }
33
34 static inline struct d3d_vertex_buffer *impl_from_IDirect3DVertexBuffer7(IDirect3DVertexBuffer7 *iface)
35 {
36     return CONTAINING_RECORD(iface, struct d3d_vertex_buffer, 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 d3d_vertex_buffer7_QueryInterface(IDirect3DVertexBuffer7 *iface, REFIID riid, void  **obj)
59 {
60     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
61
62     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
63
64     /* By default, set the object pointer to NULL */
65     *obj = NULL;
66
67     if ( IsEqualGUID( &IID_IUnknown,  riid ) )
68     {
69         IDirect3DVertexBuffer7_AddRef(iface);
70         *obj = iface;
71         TRACE("  Creating IUnknown interface at %p.\n", *obj);
72         return S_OK;
73     }
74     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer, riid ) )
75     {
76         IDirect3DVertexBuffer7_AddRef(iface);
77         *obj = &buffer->IDirect3DVertexBuffer_iface;
78         TRACE("  Creating IDirect3DVertexBuffer interface %p\n", *obj);
79         return S_OK;
80     }
81     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer7, riid ) )
82     {
83         IDirect3DVertexBuffer7_AddRef(iface);
84         *obj = iface;
85         TRACE("  Creating IDirect3DVertexBuffer7 interface %p\n", *obj);
86         return S_OK;
87     }
88
89     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
90
91     return E_NOINTERFACE;
92 }
93
94 static HRESULT WINAPI d3d_vertex_buffer1_QueryInterface(IDirect3DVertexBuffer *iface, REFIID riid, void **obj)
95 {
96     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
97
98     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
99
100     return d3d_vertex_buffer7_QueryInterface(&buffer->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 d3d_vertex_buffer7_AddRef(IDirect3DVertexBuffer7 *iface)
113 {
114     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
115     ULONG ref = InterlockedIncrement(&buffer->ref);
116
117     TRACE("%p increasing refcount to %u.\n", buffer, ref);
118
119     return ref;
120 }
121
122 static ULONG WINAPI d3d_vertex_buffer1_AddRef(IDirect3DVertexBuffer *iface)
123 {
124     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
125
126     TRACE("iface %p.\n", iface);
127
128     return d3d_vertex_buffer7_AddRef(&buffer->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 d3d_vertex_buffer7_Release(IDirect3DVertexBuffer7 *iface)
142 {
143     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
144     ULONG ref = InterlockedDecrement(&buffer->ref);
145
146     TRACE("%p decreasing refcount to %u.\n", buffer, 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(buffer->ddraw->wined3d_device,
159                 0, &curVB, &offset, &stride);
160         if (curVB == buffer->wineD3DVertexBuffer)
161             wined3d_device_set_stream_source(buffer->ddraw->wined3d_device, 0, NULL, 0, 0);
162         if (curVB)
163             wined3d_buffer_decref(curVB); /* For the GetStreamSource */
164
165         wined3d_vertex_declaration_decref(buffer->wineD3DVertexDeclaration);
166         wined3d_buffer_decref(buffer->wineD3DVertexBuffer);
167         wined3d_mutex_unlock();
168
169         HeapFree(GetProcessHeap(), 0, buffer);
170     }
171
172     return ref;
173 }
174
175 static ULONG WINAPI d3d_vertex_buffer1_Release(IDirect3DVertexBuffer *iface)
176 {
177     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
178
179     TRACE("iface %p.\n", iface);
180
181     return d3d_vertex_buffer7_Release(&buffer->IDirect3DVertexBuffer7_iface);
182 }
183
184 /*****************************************************************************
185  * IDirect3DVertexBuffer Methods
186  *****************************************************************************/
187
188 static HRESULT d3d_vertex_buffer_create_wined3d_buffer(struct d3d_vertex_buffer *buffer, BOOL dynamic,
189         struct wined3d_buffer **wined3d_buffer)
190 {
191     DWORD usage = WINED3DUSAGE_STATICDECL;
192     enum wined3d_pool pool;
193
194     if (buffer->Caps & D3DVBCAPS_SYSTEMMEMORY)
195         pool = WINED3D_POOL_SYSTEM_MEM;
196     else
197         pool = WINED3D_POOL_DEFAULT;
198
199     if (buffer->Caps & D3DVBCAPS_WRITEONLY)
200         usage |= WINED3DUSAGE_WRITEONLY;
201     if (dynamic)
202         usage |= WINED3DUSAGE_DYNAMIC;
203
204     return wined3d_buffer_create_vb(buffer->ddraw->wined3d_device,
205         buffer->size, usage, pool, buffer, &ddraw_null_wined3d_parent_ops,
206         wined3d_buffer);
207 }
208
209 /*****************************************************************************
210  * IDirect3DVertexBuffer7::Lock
211  *
212  * Locks the vertex buffer and returns a pointer to the vertex data
213  * Locking vertex buffers is similar to locking surfaces, because Windows
214  * uses surfaces to store vertex data internally (According to the DX sdk)
215  *
216  * Params:
217  *  Flags: Locking flags. Relevant here are DDLOCK_READONLY, DDLOCK_WRITEONLY,
218  *         DDLOCK_DISCARDCONTENTS and DDLOCK_NOOVERWRITE.
219  *  Data:  Returns a pointer to the vertex data
220  *  Size:  Returns the size of the buffer if not NULL
221  *
222  * Returns:
223  *  D3D_OK on success
224  *  DDERR_INVALIDPARAMS if Data is NULL
225  *  D3DERR_VERTEXBUFFEROPTIMIZED if called on an optimized buffer(WineD3D)
226  *
227  *****************************************************************************/
228 static HRESULT WINAPI d3d_vertex_buffer7_Lock(IDirect3DVertexBuffer7 *iface,
229         DWORD flags, void **data, DWORD *data_size)
230 {
231     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
232     struct wined3d_resource_desc wined3d_desc;
233     struct wined3d_resource *wined3d_resource;
234     HRESULT hr;
235     DWORD wined3d_flags = 0;
236
237     TRACE("iface %p, flags %#x, data %p, data_size %p.\n", iface, flags, data, data_size);
238
239     /* Writeonly: Pointless. Event: Unsupported by native according to the sdk
240      * nosyslock: Not applicable
241      */
242     if (!(flags & DDLOCK_WAIT))
243         wined3d_flags |= WINED3D_MAP_DONOTWAIT;
244     if (flags & DDLOCK_READONLY)
245         wined3d_flags |= WINED3D_MAP_READONLY;
246     if (flags & DDLOCK_NOOVERWRITE)
247         wined3d_flags |= WINED3D_MAP_NOOVERWRITE;
248     if (flags & DDLOCK_DISCARDCONTENTS && buffer->read_since_last_map)
249     {
250         wined3d_flags |= WINED3D_MAP_DISCARD;
251
252         if (!buffer->dynamic)
253         {
254             struct wined3d_buffer *new_buffer;
255             wined3d_mutex_lock();
256             hr = d3d_vertex_buffer_create_wined3d_buffer(buffer, TRUE, &new_buffer);
257             if (SUCCEEDED(hr))
258             {
259                 buffer->dynamic = TRUE;
260                 wined3d_buffer_decref(buffer->wineD3DVertexBuffer);
261                 buffer->wineD3DVertexBuffer = new_buffer;
262             }
263             else
264             {
265                 WARN("Failed to create a dynamic buffer\n");
266             }
267             wined3d_mutex_unlock();
268         }
269     }
270
271     wined3d_mutex_lock();
272     if (data_size)
273     {
274         /* Get the size, for returning it, and for locking */
275         wined3d_resource = wined3d_buffer_get_resource(buffer->wineD3DVertexBuffer);
276         wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
277         *data_size = wined3d_desc.size;
278     }
279
280     hr = wined3d_buffer_map(buffer->wineD3DVertexBuffer, 0, 0, (BYTE **)data, wined3d_flags);
281
282     if (SUCCEEDED(hr))
283         buffer->read_since_last_map = FALSE;
284
285     wined3d_mutex_unlock();
286
287     return hr;
288 }
289
290 static HRESULT WINAPI d3d_vertex_buffer1_Lock(IDirect3DVertexBuffer *iface,
291         DWORD flags, void **data, DWORD *data_size)
292 {
293     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
294
295     TRACE("iface %p, flags %#x, data %p, data_size %p.\n", iface, flags, data, data_size);
296
297     return d3d_vertex_buffer7_Lock(&buffer->IDirect3DVertexBuffer7_iface, flags, data, data_size);
298 }
299
300 /*****************************************************************************
301  * IDirect3DVertexBuffer7::Unlock
302  *
303  * Unlocks a vertex Buffer
304  *
305  * Returns:
306  *  D3D_OK on success
307  *
308  *****************************************************************************/
309 static HRESULT WINAPI d3d_vertex_buffer7_Unlock(IDirect3DVertexBuffer7 *iface)
310 {
311     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
312
313     TRACE("iface %p.\n", iface);
314
315     wined3d_mutex_lock();
316     wined3d_buffer_unmap(buffer->wineD3DVertexBuffer);
317     wined3d_mutex_unlock();
318
319     return D3D_OK;
320 }
321
322 static HRESULT WINAPI d3d_vertex_buffer1_Unlock(IDirect3DVertexBuffer *iface)
323 {
324     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
325
326     TRACE("iface %p.\n", iface);
327
328     return d3d_vertex_buffer7_Unlock(&buffer->IDirect3DVertexBuffer7_iface);
329 }
330
331
332 /*****************************************************************************
333  * IDirect3DVertexBuffer7::ProcessVertices
334  *
335  * Processes untransformed Vertices into a transformed or optimized vertex
336  * buffer. It can also perform other operations, such as lighting or clipping
337  *
338  * Params
339  *  VertexOp: Operation(s) to perform: D3DVOP_CLIP, _EXTENTS, _LIGHT, _TRANSFORM
340  *  DestIndex: Index in the destination buffer(This), where the vertices are
341  *             placed
342  *  Count: Number of Vertices in the Source buffer to process
343  *  SrcBuffer: Source vertex buffer
344  *  SrcIndex: Index of the first vertex in the src buffer to process
345  *  D3DDevice: Device to use for transformation
346  *  Flags: 0 for default, D3DPV_DONOTCOPYDATA to prevent copying
347  *         unchaned vertices
348  *
349  * Returns:
350  *  D3D_OK on success
351  *  DDERR_INVALIDPARAMS If D3DVOP_TRANSFORM wasn't passed
352  *
353  *****************************************************************************/
354 static HRESULT WINAPI d3d_vertex_buffer7_ProcessVertices(IDirect3DVertexBuffer7 *iface,
355         DWORD vertex_op, DWORD dst_idx, DWORD count, IDirect3DVertexBuffer7 *src_buffer,
356         DWORD src_idx, IDirect3DDevice7 *device, DWORD flags)
357 {
358     struct d3d_vertex_buffer *dst_buffer_impl = impl_from_IDirect3DVertexBuffer7(iface);
359     struct d3d_vertex_buffer *src_buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer7(src_buffer);
360     struct d3d_device *device_impl = unsafe_impl_from_IDirect3DDevice7(device);
361     BOOL oldClip, doClip;
362     HRESULT hr;
363
364     TRACE("iface %p, vertex_op %#x, dst_idx %u, count %u, src_buffer %p, src_idx %u, device %p, flags %#x.\n",
365             iface, vertex_op, dst_idx, count, src_buffer, src_idx, device, flags);
366
367     /* Vertex operations:
368      * D3DVOP_CLIP: Clips vertices outside the viewing frustrum. Needs clipping information
369      * in the vertex buffer (Buffer may not be created with D3DVBCAPS_DONOTCLIP)
370      * D3DVOP_EXTENTS: Causes the screen extents to be updated when rendering the vertices
371      * D3DVOP_LIGHT: Lights the vertices
372      * D3DVOP_TRANSFORM: Transform the vertices. This flag is necessary
373      *
374      * WineD3D only transforms and clips the vertices by now, so EXTENTS and LIGHT
375      * are not implemented. Clipping is disabled ATM, because of unsure conditions.
376      */
377     if (!(vertex_op & D3DVOP_TRANSFORM))
378         return DDERR_INVALIDPARAMS;
379
380     wined3d_mutex_lock();
381
382     /* WineD3D doesn't know d3d7 vertex operation, it uses
383      * render states instead. Set the render states according to
384      * the vertex ops
385      */
386     doClip = !!(vertex_op & D3DVOP_CLIP);
387     oldClip = wined3d_device_get_render_state(device_impl->wined3d_device, WINED3D_RS_CLIPPING);
388     if (doClip != oldClip)
389         wined3d_device_set_render_state(device_impl->wined3d_device, WINED3D_RS_CLIPPING, doClip);
390
391     wined3d_device_set_stream_source(device_impl->wined3d_device,
392             0, src_buffer_impl->wineD3DVertexBuffer, 0, get_flexible_vertex_size(src_buffer_impl->fvf));
393     wined3d_device_set_vertex_declaration(device_impl->wined3d_device, src_buffer_impl->wineD3DVertexDeclaration);
394     hr = wined3d_device_process_vertices(device_impl->wined3d_device, src_idx, dst_idx,
395             count, dst_buffer_impl->wineD3DVertexBuffer, NULL, flags, dst_buffer_impl->fvf);
396
397     /* Restore the states if needed */
398     if (doClip != oldClip)
399         wined3d_device_set_render_state(device_impl->wined3d_device, WINED3D_RS_CLIPPING, oldClip);
400
401     wined3d_mutex_unlock();
402
403     return hr;
404 }
405
406 static HRESULT WINAPI d3d_vertex_buffer1_ProcessVertices(IDirect3DVertexBuffer *iface,
407         DWORD vertex_op, DWORD dst_idx, DWORD count, IDirect3DVertexBuffer *src_buffer,
408         DWORD src_idx, IDirect3DDevice3 *device, DWORD flags)
409 {
410     struct d3d_vertex_buffer *dst_buffer_impl = impl_from_IDirect3DVertexBuffer(iface);
411     struct d3d_vertex_buffer *src_buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer(src_buffer);
412     struct d3d_device *device_impl = unsafe_impl_from_IDirect3DDevice3(device);
413
414     TRACE("iface %p, vertex_op %#x, dst_idx %u, count %u, src_buffer %p, src_idx %u, device %p, flags %#x.\n",
415             iface, vertex_op, dst_idx, count, src_buffer, src_idx, device, flags);
416
417     return d3d_vertex_buffer7_ProcessVertices(&dst_buffer_impl->IDirect3DVertexBuffer7_iface, vertex_op,
418             dst_idx, count, &src_buffer_impl->IDirect3DVertexBuffer7_iface, src_idx,
419             device_impl ? &device_impl->IDirect3DDevice7_iface : NULL, flags);
420 }
421
422 /*****************************************************************************
423  * IDirect3DVertexBuffer7::GetVertexBufferDesc
424  *
425  * Returns the description of a vertex buffer
426  *
427  * Params:
428  *  Desc: Address to write the description to
429  *
430  * Returns
431  *  DDERR_INVALIDPARAMS if Desc is NULL
432  *  D3D_OK on success
433  *
434  *****************************************************************************/
435 static HRESULT WINAPI d3d_vertex_buffer7_GetVertexBufferDesc(IDirect3DVertexBuffer7 *iface, D3DVERTEXBUFFERDESC *desc)
436 {
437     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
438     struct wined3d_resource_desc wined3d_desc;
439     struct wined3d_resource *wined3d_resource;
440
441     TRACE("iface %p, desc %p.\n", iface, desc);
442
443     if (!desc) return DDERR_INVALIDPARAMS;
444
445     wined3d_mutex_lock();
446     wined3d_resource = wined3d_buffer_get_resource(buffer->wineD3DVertexBuffer);
447     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
448     wined3d_mutex_unlock();
449
450     /* Now fill the desc structure */
451     desc->dwCaps = buffer->Caps;
452     desc->dwFVF = buffer->fvf;
453     desc->dwNumVertices = wined3d_desc.size / get_flexible_vertex_size(buffer->fvf);
454
455     return D3D_OK;
456 }
457
458 static HRESULT WINAPI d3d_vertex_buffer1_GetVertexBufferDesc(IDirect3DVertexBuffer *iface, D3DVERTEXBUFFERDESC *desc)
459 {
460     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
461
462     TRACE("iface %p, desc %p.\n", iface, desc);
463
464     return d3d_vertex_buffer7_GetVertexBufferDesc(&buffer->IDirect3DVertexBuffer7_iface, desc);
465 }
466
467
468 /*****************************************************************************
469  * IDirect3DVertexBuffer7::Optimize
470  *
471  * Converts an unoptimized vertex buffer into an optimized buffer
472  *
473  * Params:
474  *  D3DDevice: Device for which this buffer is optimized
475  *  Flags: Not used, should be set to 0
476  *
477  * Returns
478  *  D3D_OK, because it's a stub
479  *
480  *****************************************************************************/
481 static HRESULT WINAPI d3d_vertex_buffer7_Optimize(IDirect3DVertexBuffer7 *iface,
482         IDirect3DDevice7 *device, DWORD flags)
483 {
484     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
485     static BOOL hide = FALSE;
486
487     TRACE("iface %p, device %p, flags %#x.\n", iface, device, flags);
488
489     if (!hide)
490     {
491         FIXME("iface %p, device %p, flags %#x stub!\n", iface, device, flags);
492         hide = TRUE;
493     }
494
495     /* We could forward this call to WineD3D and take advantage
496      * of it once we use OpenGL vertex buffers
497      */
498     wined3d_mutex_lock();
499     buffer->Caps |= D3DVBCAPS_OPTIMIZED;
500     wined3d_mutex_unlock();
501
502     return DD_OK;
503 }
504
505 static HRESULT WINAPI d3d_vertex_buffer1_Optimize(IDirect3DVertexBuffer *iface,
506         IDirect3DDevice3 *device, DWORD flags)
507 {
508     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
509     struct d3d_device *device_impl = unsafe_impl_from_IDirect3DDevice3(device);
510
511     TRACE("iface %p, device %p, flags %#x.\n", iface, device, flags);
512
513     return d3d_vertex_buffer7_Optimize(&buffer->IDirect3DVertexBuffer7_iface,
514             device_impl ? &device_impl->IDirect3DDevice7_iface : NULL, flags);
515 }
516
517 /*****************************************************************************
518  * IDirect3DVertexBuffer7::ProcessVerticesStrided
519  *
520  * This method processes untransformed strided vertices into a processed
521  * or optimized vertex buffer.
522  *
523  * For more details on the parameters, see
524  * IDirect3DVertexBuffer7::ProcessVertices
525  *
526  * Params:
527  *  VertexOp: Operations to perform
528  *  DestIndex: Destination index to write the vertices to
529  *  Count: Number of input vertices
530  *  StrideData: Array containing the input vertices
531  *  VertexTypeDesc: Vertex Description or source index?????????
532  *  D3DDevice: IDirect3DDevice7 to use for processing
533  *  Flags: Can be D3DPV_DONOTCOPYDATA to avoid copying unmodified vertices
534  *
535  * Returns
536  *  D3D_OK on success, or DDERR_*
537  *
538  *****************************************************************************/
539 static HRESULT WINAPI d3d_vertex_buffer7_ProcessVerticesStrided(IDirect3DVertexBuffer7 *iface,
540         DWORD vertex_op, DWORD dst_idx, DWORD count, D3DDRAWPRIMITIVESTRIDEDDATA *data,
541         DWORD fvf, IDirect3DDevice7 *device, DWORD flags)
542 {
543     FIXME("iface %p, vertex_op %#x, dst_idx %u, count %u, data %p, fvf %#x, device %p, flags %#x stub!\n",
544             iface, vertex_op, dst_idx, count, data, fvf, device, flags);
545
546     return DD_OK;
547 }
548
549 /*****************************************************************************
550  * The VTables
551  *****************************************************************************/
552
553 static const struct IDirect3DVertexBuffer7Vtbl d3d_vertex_buffer7_vtbl =
554 {
555     d3d_vertex_buffer7_QueryInterface,
556     d3d_vertex_buffer7_AddRef,
557     d3d_vertex_buffer7_Release,
558     d3d_vertex_buffer7_Lock,
559     d3d_vertex_buffer7_Unlock,
560     d3d_vertex_buffer7_ProcessVertices,
561     d3d_vertex_buffer7_GetVertexBufferDesc,
562     d3d_vertex_buffer7_Optimize,
563     d3d_vertex_buffer7_ProcessVerticesStrided,
564 };
565
566 static const struct IDirect3DVertexBufferVtbl d3d_vertex_buffer1_vtbl =
567 {
568     d3d_vertex_buffer1_QueryInterface,
569     d3d_vertex_buffer1_AddRef,
570     d3d_vertex_buffer1_Release,
571     d3d_vertex_buffer1_Lock,
572     d3d_vertex_buffer1_Unlock,
573     d3d_vertex_buffer1_ProcessVertices,
574     d3d_vertex_buffer1_GetVertexBufferDesc,
575     d3d_vertex_buffer1_Optimize,
576 };
577
578 HRESULT d3d_vertex_buffer_create(struct d3d_vertex_buffer **vertex_buf,
579         struct ddraw *ddraw, D3DVERTEXBUFFERDESC *desc)
580 {
581     struct d3d_vertex_buffer *buffer;
582     HRESULT hr = D3D_OK;
583
584     TRACE("Vertex buffer description:\n");
585     TRACE("    dwSize %u\n", desc->dwSize);
586     TRACE("    dwCaps %#x\n", desc->dwCaps);
587     TRACE("    FVF %#x\n", desc->dwFVF);
588     TRACE("    dwNumVertices %u\n", desc->dwNumVertices);
589
590     buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*buffer));
591     if (!buffer)
592         return DDERR_OUTOFMEMORY;
593
594     buffer->IDirect3DVertexBuffer7_iface.lpVtbl = &d3d_vertex_buffer7_vtbl;
595     buffer->IDirect3DVertexBuffer_iface.lpVtbl = &d3d_vertex_buffer1_vtbl;
596     buffer->ref = 1;
597
598     buffer->ddraw = ddraw;
599     buffer->Caps = desc->dwCaps;
600     buffer->fvf = desc->dwFVF;
601     buffer->size = get_flexible_vertex_size(desc->dwFVF) * desc->dwNumVertices;
602
603     wined3d_mutex_lock();
604
605     hr = d3d_vertex_buffer_create_wined3d_buffer(buffer, FALSE, &buffer->wineD3DVertexBuffer);
606     if (FAILED(hr))
607     {
608         WARN("Failed to create wined3d vertex buffer, hr %#x.\n", hr);
609         if (hr == WINED3DERR_INVALIDCALL)
610             hr = DDERR_INVALIDPARAMS;
611         goto end;
612     }
613
614     buffer->wineD3DVertexDeclaration = ddraw_find_decl(ddraw, desc->dwFVF);
615     if (!buffer->wineD3DVertexDeclaration)
616     {
617         ERR("Failed to find vertex declaration for fvf %#x.\n", desc->dwFVF);
618         wined3d_buffer_decref(buffer->wineD3DVertexBuffer);
619         hr = DDERR_INVALIDPARAMS;
620         goto end;
621     }
622     wined3d_vertex_declaration_incref(buffer->wineD3DVertexDeclaration);
623
624 end:
625     wined3d_mutex_unlock();
626     if (hr == D3D_OK)
627         *vertex_buf = buffer;
628     else
629         HeapFree(GetProcessHeap(), 0, buffer);
630
631     return hr;
632 }
633
634 struct d3d_vertex_buffer *unsafe_impl_from_IDirect3DVertexBuffer(IDirect3DVertexBuffer *iface)
635 {
636     if (!iface)
637         return NULL;
638     assert(iface->lpVtbl == &d3d_vertex_buffer1_vtbl);
639
640     return impl_from_IDirect3DVertexBuffer(iface);
641 }
642
643 struct d3d_vertex_buffer *unsafe_impl_from_IDirect3DVertexBuffer7(IDirect3DVertexBuffer7 *iface)
644 {
645     if (!iface)
646         return NULL;
647     assert(iface->lpVtbl == &d3d_vertex_buffer7_vtbl);
648
649     return impl_from_IDirect3DVertexBuffer7(iface);
650 }