ddraw: Do not let the a surface dimension fall to 0.
[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 #include "wine/debug.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #define COBJMACROS
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winnls.h"
36 #include "winerror.h"
37 #include "wingdi.h"
38 #include "wine/exception.h"
39 #include "excpt.h"
40
41 #include "ddraw.h"
42 #include "d3d.h"
43
44 #include "ddraw_private.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
47 WINE_DECLARE_DEBUG_CHANNEL(ddraw_thunk);
48
49
50 /*****************************************************************************
51  * IUnknown Methods
52  *****************************************************************************/
53
54 /*****************************************************************************
55  * IDirect3DVertexBuffer7::QueryInterface
56  *
57  * The QueryInterface Method for Vertex Buffers
58  * For a link to QueryInterface rules, see IDirectDraw7::QueryInterface
59  *
60  * Params
61  *  riid: Queryied Interface id
62  *  obj: Address to return the interface pointer
63  *
64  * Returns:
65  *  S_OK on success
66  *  E_NOINTERFACE if the interface wasn't found
67  *
68  *****************************************************************************/
69 static HRESULT WINAPI
70 IDirect3DVertexBufferImpl_QueryInterface(IDirect3DVertexBuffer7 *iface,
71                                          REFIID riid,
72                                          void  **obj)
73 {
74     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
75     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), obj);
76
77     /* By default, set the object pointer to NULL */
78     *obj = NULL;
79
80     if ( IsEqualGUID( &IID_IUnknown,  riid ) )
81     {
82         IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This,IDirect3DVertexBuffer7));
83         *obj = iface;
84         TRACE("  Creating IUnknown interface at %p.\n", *obj);
85         return S_OK;
86     }
87     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer, riid ) )
88     {
89         IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This,IDirect3DVertexBuffer7));
90         *obj = ICOM_INTERFACE(This, IDirect3DVertexBuffer);
91         TRACE("  Creating IDirect3DVertexBuffer interface %p\n", *obj);
92         return S_OK;
93     }
94     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer7, riid ) )
95     {
96         IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This,IDirect3DVertexBuffer7));
97         *obj = ICOM_INTERFACE(This, IDirect3DVertexBuffer7);
98         TRACE("  Creating IDirect3DVertexBuffer7 interface %p\n", *obj);
99         return S_OK;
100     }
101     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
102     return E_NOINTERFACE;
103 }
104
105 static HRESULT WINAPI
106 Thunk_IDirect3DVertexBufferImpl_1_QueryInterface(IDirect3DVertexBuffer *iface,
107                                                  REFIID riid,
108                                                  void **obj)
109 {
110     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
111     TRACE_(ddraw_thunk)("(%p)->(%s,%p) thunking to IDirect3DVertexBuffer7 interface.\n", This, debugstr_guid(riid), obj);
112
113     return IDirect3DVertexBuffer7_QueryInterface(ICOM_INTERFACE(This, IDirect3DVertexBuffer7),
114                                                  riid,
115                                                  obj);
116 }
117
118 /*****************************************************************************
119  * IDirect3DVertexBuffer7::AddRef
120  *
121  * AddRef for Vertex Buffers
122  *
123  * Returns:
124  *  The new refcount
125  *
126  *****************************************************************************/
127 static ULONG WINAPI
128 IDirect3DVertexBufferImpl_AddRef(IDirect3DVertexBuffer7 *iface)
129 {
130     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
131     ULONG ref = InterlockedIncrement(&This->ref);
132
133     TRACE("(%p/%p)->() incrementing from %u.\n", This, iface, ref - 1);
134
135     return ref;
136 }
137
138 static ULONG WINAPI
139 Thunk_IDirect3DVertexBufferImpl_1_AddRef(IDirect3DVertexBuffer *iface)
140 {
141     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
142     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DVertexBuffer7 interface.\n", This);
143
144     return IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This, IDirect3DVertexBuffer7));
145 }
146
147
148 /*****************************************************************************
149  * IDirect3DVertexBuffer7::Release
150  *
151  * Release for Vertex Buffers
152  *
153  * Returns:
154  *  The new refcount
155  *
156  *****************************************************************************/
157 static ULONG WINAPI
158 IDirect3DVertexBufferImpl_Release(IDirect3DVertexBuffer7 *iface)
159 {
160     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
161     ULONG ref = InterlockedDecrement(&This->ref);
162
163     TRACE("(%p)->() decrementing from %u.\n", This, ref + 1);
164
165     if (ref == 0)
166     {
167         IWineD3DVertexBuffer_Release(This->wineD3DVertexBuffer);
168         HeapFree(GetProcessHeap(), 0, This);
169         return 0;
170     }
171     return ref;
172 }
173
174 static ULONG WINAPI
175 Thunk_IDirect3DVertexBufferImpl_1_Release(IDirect3DVertexBuffer *iface)
176 {
177     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
178     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DVertexBuffer7 interface.\n", This);
179
180     return IDirect3DVertexBuffer7_Release(ICOM_INTERFACE(This, IDirect3DVertexBuffer7));
181 }
182
183 /*****************************************************************************
184  * IDirect3DVertexBuffer Methods
185  *****************************************************************************/
186
187 /*****************************************************************************
188  * IDirect3DVertexBuffer7::Lock
189  *
190  * Locks the vertex buffer and returns a pointer to the vertex data
191  * Locking vertex buffers is similar to locking surfaces, because Windows
192  * uses surfaces to store vertex data internally (According to the DX sdk)
193  *
194  * Params:
195  *  Flags: Locking flags. Relevant here are DDLOCK_READONLY, DDLOCK_WRITEONLY,
196  *         DDLOCK_DISCARDCONTENTS and DDLOCK_NOOVERWRITE.
197  *  Data:  Returns a pointer to the vertex data
198  *  Size:  Returns the size of the buffer if not NULL
199  *
200  * Returns:
201  *  D3D_OK on success
202  *  DDERR_INVALIDPARAMS if Data is NULL
203  *  D3DERR_VERTEXBUFFEROPTIMIZED if called on an optimized buffer(WineD3D)
204  *
205  *****************************************************************************/
206 static HRESULT WINAPI
207 IDirect3DVertexBufferImpl_Lock(IDirect3DVertexBuffer7 *iface,
208                                DWORD Flags,
209                                void **Data,
210                                DWORD *Size)
211 {
212     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
213     WINED3DVERTEXBUFFER_DESC Desc;
214     HRESULT hr;
215     TRACE("(%p)->(%08x,%p,%p)\n", This, Flags, Data, Size);
216
217     if(Size)
218     {
219         /* Get the size, for returning it, and for locking */
220         hr = IWineD3DVertexBuffer_GetDesc(This->wineD3DVertexBuffer,
221                                           &Desc);
222         if(hr != D3D_OK)
223         {
224             ERR("(%p) IWineD3DVertexBuffer::GetDesc failed with hr=%08x\n", This, hr);
225             return hr;
226         }
227         *Size = Desc.Size;
228     }
229
230     return IWineD3DVertexBuffer_Lock(This->wineD3DVertexBuffer,
231                                      0 /* OffsetToLock */,
232                                      0 /* SizeToLock, 0 == Full lock */,
233                                      (BYTE **) Data,
234                                      Flags);
235 }
236
237 static HRESULT WINAPI
238 Thunk_IDirect3DVertexBufferImpl_1_Lock(IDirect3DVertexBuffer *iface,
239                                        DWORD Flags,
240                                        void **Data,
241                                        DWORD *Size)
242 {
243     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
244     TRACE_(ddraw_thunk)("(%p)->(%08x,%p,%p) thunking to IDirect3DVertexBuffer7 interface.\n", This, Flags, Data, Size);
245
246     return IDirect3DVertexBuffer7_Lock(ICOM_INTERFACE(This, IDirect3DVertexBuffer7),
247                                        Flags,
248                                        Data,
249                                        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
262 IDirect3DVertexBufferImpl_Unlock(IDirect3DVertexBuffer7 *iface)
263 {
264     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
265     TRACE("(%p)->()\n", This);
266
267     /* This is easy :) */
268     return IWineD3DVertexBuffer_Unlock(This->wineD3DVertexBuffer);
269 }
270
271 static HRESULT WINAPI
272 Thunk_IDirect3DVertexBufferImpl_1_Unlock(IDirect3DVertexBuffer *iface)
273 {
274     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
275     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DVertexBuffer7 interface.\n", This);
276
277     return IDirect3DVertexBuffer7_Unlock(ICOM_INTERFACE(This, IDirect3DVertexBuffer7));
278 }
279
280
281 /*****************************************************************************
282  * IDirect3DVertexBuffer7::ProcessVertices
283  *
284  * Processes untransformed Vertices into a transformed or optimized vertex
285  * buffer. It can also perform other operations, such as lighting or clipping
286  *
287  * Params
288  *  VertexOp: Operation(s) to perform: D3DVOP_CLIP, _EXTENTS, _LIGHT, _TRANSFORM
289  *  DestIndex: Index in the destination buffer(This), where the vertices are
290  *             placed
291  *  Count: Number of Vertices in the Source buffer to process
292  *  SrcBuffer: Source vertex buffer
293  *  SrcIndex: Index of the first vertex in the src buffer to process
294  *  D3DDevice: Device to use for transformation
295  *  Flags: 0 for default, D3DPV_DONOTCOPYDATA to prevent copying
296  *         unchaned vertices
297  *
298  * Returns:
299  *  D3D_OK on success
300  *  DDERR_INVALIDPARAMS If D3DVOP_TRANSFORM wasn't passed
301  *
302  *****************************************************************************/
303 static HRESULT WINAPI
304 IDirect3DVertexBufferImpl_ProcessVertices(IDirect3DVertexBuffer7 *iface,
305                                           DWORD VertexOp,
306                                           DWORD DestIndex,
307                                           DWORD Count,
308                                           IDirect3DVertexBuffer7 *SrcBuffer,
309                                           DWORD SrcIndex,
310                                           IDirect3DDevice7 *D3DDevice,
311                                           DWORD Flags)
312 {
313     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
314     IDirect3DVertexBufferImpl *Src = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, SrcBuffer);
315     IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, D3DDevice);
316     BOOL oldClip, doClip;
317     HRESULT hr;
318
319     TRACE("(%p)->(%08x,%d,%d,%p,%d,%p,%08x)\n", This, VertexOp, DestIndex, Count, Src, SrcIndex, D3D, Flags);
320
321     /* Vertex operations:
322      * D3DVOP_CLIP: Clips vertices outside the viewing frustrum. Needs clipping information
323      * in the vertex buffer (Buffer may not be created with D3DVBCAPS_DONOTCLIP)
324      * D3DVOP_EXTENTS: Causes the screen extents to be updated when rendering the vertices
325      * D3DVOP_LIGHT: Lights the vertices
326      * D3DVOP_TRANSFORM: Transform the vertices. This flag is necessary
327      *
328      * WineD3D only transforms and clips the vertices by now, so EXTENTS and LIGHT
329      * are not implemented. Clipping is disabled ATM, because of unsure conditions.
330      */
331     if( !(VertexOp & D3DVOP_TRANSFORM) ) return DDERR_INVALIDPARAMS;
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     IWineD3DDevice_GetRenderState(D3D->wineD3DDevice,
339                                   WINED3DRS_CLIPPING,
340                                   (DWORD *) &oldClip);
341     if(doClip != oldClip)
342     {
343         IWineD3DDevice_SetRenderState(D3D->wineD3DDevice,
344                                       WINED3DRS_CLIPPING,
345                                       doClip);
346     }
347
348
349     hr = IWineD3DDevice_ProcessVertices(D3D->wineD3DDevice,
350                                         SrcIndex,
351                                         DestIndex,
352                                         Count,
353                                         This->wineD3DVertexBuffer,
354                                         Src->wineD3DVertexBuffer,
355                                         Flags);
356
357     /* Restore the states if needed */
358     if(doClip != oldClip)
359         IWineD3DDevice_SetRenderState(D3D->wineD3DDevice,
360                                       WINED3DRS_CLIPPING,
361                                       oldClip);
362     return hr;
363 }
364
365 static HRESULT WINAPI
366 Thunk_IDirect3DVertexBufferImpl_1_ProcessVertices(IDirect3DVertexBuffer *iface,
367                                                   DWORD VertexOp,
368                                                   DWORD DestIndex,
369                                                   DWORD Count,
370                                                   IDirect3DVertexBuffer *SrcBuffer,
371                                                   DWORD SrcIndex,
372                                                   IDirect3DDevice3 *D3DDevice,
373                                                   DWORD Flags)
374 {
375     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
376     IDirect3DVertexBufferImpl *Src = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, SrcBuffer);
377     IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice3, D3DDevice);
378
379     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%08x,%p,%08x,%p,%08x) thunking to IDirect3DVertexBuffer7 interface.\n", This, VertexOp, DestIndex, Count, Src, SrcIndex, D3D, Flags);
380
381     return IDirect3DVertexBuffer7_ProcessVertices(ICOM_INTERFACE(This, IDirect3DVertexBuffer7),
382                                                   VertexOp,
383                                                   DestIndex,
384                                                   Count,
385                                                   ICOM_INTERFACE(Src, IDirect3DVertexBuffer7),
386                                                   SrcIndex,
387                                                   ICOM_INTERFACE(D3D, IDirect3DDevice7),
388                                                   Flags);
389 }
390
391 /*****************************************************************************
392  * IDirect3DVertexBuffer7::GetVertexBufferDesc
393  *
394  * Returns the description of a vertex buffer
395  *
396  * Params:
397  *  Desc: Address to write the description to
398  *
399  * Returns
400  *  DDERR_INVALIDPARAMS if Desc is NULL
401  *  D3D_OK on success
402  *
403  *****************************************************************************/
404 static HRESULT WINAPI
405 IDirect3DVertexBufferImpl_GetVertexBufferDesc(IDirect3DVertexBuffer7 *iface,
406                                               D3DVERTEXBUFFERDESC *Desc)
407 {
408     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
409     WINED3DVERTEXBUFFER_DESC WDesc;
410     HRESULT hr;
411     DWORD size;
412     TRACE("(%p)->(%p)\n", This, Desc);
413
414     if(!Desc) return DDERR_INVALIDPARAMS;
415
416     hr = IWineD3DVertexBuffer_GetDesc(This->wineD3DVertexBuffer,
417                                       &WDesc);
418     if(hr != D3D_OK)
419     {
420         ERR("(%p) IWineD3DVertexBuffer::GetDesc failed with hr=%08x\n", This, hr);
421         return hr;
422     }
423
424     /* Clear the return value of garbage */
425     size = Desc->dwSize;
426     memset(Desc, 0, size);
427
428     /* Now fill the Desc structure */
429     Desc->dwSize = size;
430     Desc->dwCaps = This->Caps;
431     Desc->dwFVF = WDesc.FVF;
432     Desc->dwNumVertices = WDesc.Size / get_flexible_vertex_size(WDesc.FVF);
433
434     return D3D_OK;
435 }
436
437 static HRESULT WINAPI
438 Thunk_IDirect3DVertexBufferImpl_1_GetVertexBufferDesc(IDirect3DVertexBuffer *iface,
439                                                       D3DVERTEXBUFFERDESC *Desc)
440 {
441     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
442     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DVertexBuffer7 interface.\n", This, Desc);
443
444     return IDirect3DVertexBuffer7_GetVertexBufferDesc(ICOM_INTERFACE(This, IDirect3DVertexBuffer7),
445                                                       Desc);
446 }
447
448
449 /*****************************************************************************
450  * IDirect3DVertexBuffer7::Optimize
451  *
452  * Converts an unoptimized vertex buffer into an optimized buffer
453  *
454  * Params:
455  *  D3DDevice: Device for which this buffer is optimized
456  *  Flags: Not used, should be set to 0
457  *
458  * Returns
459  *  D3D_OK, because it's a stub
460  *
461  *****************************************************************************/
462 static HRESULT WINAPI
463 IDirect3DVertexBufferImpl_Optimize(IDirect3DVertexBuffer7 *iface,
464                                    IDirect3DDevice7 *D3DDevice,
465                                    DWORD Flags)
466 {
467     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
468     IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, D3DDevice);
469     FIXME("(%p)->(%p,%08x): stub!\n", This, D3D, Flags);
470
471     /* We could forward this call to WineD3D and take advantage
472      * of it once we use OpenGL vertex buffers
473      */
474     This->Caps |= D3DVBCAPS_OPTIMIZED;
475
476     return DD_OK;
477 }
478
479 static HRESULT WINAPI
480 Thunk_IDirect3DVertexBufferImpl_1_Optimize(IDirect3DVertexBuffer *iface,
481                                            IDirect3DDevice3 *D3DDevice,
482                                            DWORD Flags)
483 {
484     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, iface);
485     IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice3, D3DDevice);
486     TRACE_(ddraw_thunk)("(%p)->(%p,%08x) thunking to IDirect3DVertexBuffer7 interface.\n", This, D3D, Flags);
487
488     return IDirect3DVertexBuffer7_Optimize(ICOM_INTERFACE(This, IDirect3DVertexBuffer7),
489                                            ICOM_INTERFACE(D3D, IDirect3DDevice7),
490                                            Flags);
491 }
492
493 /*****************************************************************************
494  * IDirect3DVertexBuffer7::ProcessVerticesStrided
495  *
496  * This method processes untransformed strided vertices into a processed
497  * or optimized vertex buffer.
498  *
499  * For more details on the parameters, see
500  * IDirect3DVertexBuffer7::ProcessVertices
501  *
502  * Params:
503  *  VertexOp: Operations to perform
504  *  DestIndex: Destination index to write the vertices to
505  *  Count: Number of input vertices
506  *  StrideData: Array containing the input vertices
507  *  VertexTypeDesc: Vertex Description or source index?????????
508  *  D3DDevice: IDirect3DDevice7 to use for processing
509  *  Flags: Can be D3DPV_DONOTCOPYDATA to avoid copying unmodified vertices
510  *
511  * Returns
512  *  D3D_OK on success, or DDERR_*
513  *
514  *****************************************************************************/
515 static HRESULT WINAPI
516 IDirect3DVertexBufferImpl_ProcessVerticesStrided(IDirect3DVertexBuffer7 *iface,
517                                                  DWORD VertexOp,
518                                                  DWORD DestIndex,
519                                                  DWORD Count,
520                                                  D3DDRAWPRIMITIVESTRIDEDDATA *StrideData,
521                                                  DWORD VertexTypeDesc,
522                                                  IDirect3DDevice7 *D3DDevice,
523                                                  DWORD Flags)
524 {
525     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
526     IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, D3DDevice);
527     FIXME("(%p)->(%08x,%08x,%08x,%p,%08x,%p,%08x): stub!\n", This, VertexOp, DestIndex, Count, StrideData, VertexTypeDesc, D3D, Flags);
528     return DD_OK;
529 }
530
531 /*****************************************************************************
532  * The VTables
533  *****************************************************************************/
534
535 const IDirect3DVertexBuffer7Vtbl IDirect3DVertexBuffer7_Vtbl =
536 {
537     /*** IUnknown Methods ***/
538     IDirect3DVertexBufferImpl_QueryInterface,
539     IDirect3DVertexBufferImpl_AddRef,
540     IDirect3DVertexBufferImpl_Release,
541     /*** IDirect3DVertexBuffer Methods ***/
542     IDirect3DVertexBufferImpl_Lock,
543     IDirect3DVertexBufferImpl_Unlock,
544     IDirect3DVertexBufferImpl_ProcessVertices,
545     IDirect3DVertexBufferImpl_GetVertexBufferDesc,
546     IDirect3DVertexBufferImpl_Optimize,
547     /*** IDirect3DVertexBuffer7 Methods ***/
548     IDirect3DVertexBufferImpl_ProcessVerticesStrided
549 };
550
551 const IDirect3DVertexBufferVtbl IDirect3DVertexBuffer1_Vtbl =
552 {
553     /*** IUnknown Methods ***/
554     Thunk_IDirect3DVertexBufferImpl_1_QueryInterface,
555     Thunk_IDirect3DVertexBufferImpl_1_AddRef,
556     Thunk_IDirect3DVertexBufferImpl_1_Release,
557     /*** IDirect3DVertexBuffer Methods ***/
558     Thunk_IDirect3DVertexBufferImpl_1_Lock,
559     Thunk_IDirect3DVertexBufferImpl_1_Unlock,
560     Thunk_IDirect3DVertexBufferImpl_1_ProcessVertices,
561     Thunk_IDirect3DVertexBufferImpl_1_GetVertexBufferDesc,
562     Thunk_IDirect3DVertexBufferImpl_1_Optimize
563 };