- use Interlocked* functions in AddRef and Release.
[wine] / dlls / ddraw / d3dvertexbuffer.c
1 /* Direct3D Viewport
2  * Copyright (c) 2002 Lionel ULMER
3  *
4  * This file contains the implementation of Direct3DVertexBuffer COM object
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "objbase.h"
28 #include "wingdi.h"
29 #include "ddraw.h"
30 #include "d3d.h"
31 #include "wine/debug.h"
32
33 #include "d3d_private.h"
34 #include "mesa_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
37 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
38
39 HRESULT WINAPI
40 Main_IDirect3DVertexBufferImpl_7_1T_QueryInterface(LPDIRECT3DVERTEXBUFFER7 iface,
41                                                    REFIID riid,
42                                                    LPVOID* obp)
43 {
44     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
45     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_guid(riid), obp);
46
47     /* By default, set the object pointer to NULL */
48     *obp = NULL;
49       
50     if ( IsEqualGUID( &IID_IUnknown,  riid ) ) {
51         IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This,IDirect3DVertexBuffer7));
52         *obp = iface;
53         TRACE("  Creating IUnknown interface at %p.\n", *obp);
54         return S_OK;
55     }
56     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer, riid ) ) {
57         IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This,IDirect3DVertexBuffer7));
58         *obp = ICOM_INTERFACE(This, IDirect3DVertexBuffer);
59         TRACE("  Creating IDirect3DVertexBuffer interface %p\n", *obp);
60         return S_OK;
61     }
62     if ( IsEqualGUID( &IID_IDirect3DVertexBuffer7, riid ) ) {
63         IDirect3DVertexBuffer7_AddRef(ICOM_INTERFACE(This,IDirect3DVertexBuffer7));
64         *obp = ICOM_INTERFACE(This, IDirect3DVertexBuffer7);
65         TRACE("  Creating IDirect3DVertexBuffer7 interface %p\n", *obp);
66         return S_OK;
67     }
68     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
69     return OLE_E_ENUM_NOMORE;
70 }
71
72 ULONG WINAPI
73 Main_IDirect3DVertexBufferImpl_7_1T_AddRef(LPDIRECT3DVERTEXBUFFER7 iface)
74 {
75     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
76     ULONG ref = InterlockedIncrement(&This->ref);
77
78     TRACE("(%p/%p)->() incrementing from %lu.\n", This, iface, ref - 1);
79
80     return ref;
81 }
82
83 ULONG WINAPI
84 Main_IDirect3DVertexBufferImpl_7_1T_Release(LPDIRECT3DVERTEXBUFFER7 iface)
85 {
86     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
87     ULONG ref = InterlockedDecrement(&This->ref);
88
89     TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, ref + 1);
90
91     if (ref == 0) {
92         HeapFree(GetProcessHeap(), 0, This->vertices);
93         HeapFree(GetProcessHeap(), 0, This);
94         return 0;
95     }
96     return ref;
97 }
98
99 HRESULT WINAPI
100 Main_IDirect3DVertexBufferImpl_7_1T_Lock(LPDIRECT3DVERTEXBUFFER7 iface,
101                                          DWORD dwFlags,
102                                          LPVOID* lplpData,
103                                          LPDWORD lpdwSize)
104 {
105     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
106     TRACE("(%p/%p)->(%08lx,%p,%p)\n", This, iface, dwFlags, lplpData, lpdwSize);
107
108     if (TRACE_ON(ddraw)) {
109         TRACE(" lock flags : ");
110         DDRAW_dump_lockflag(dwFlags);
111     }
112     
113     if (This->processed) {
114         WARN(" application does a Lock on a vertex buffer resulting from a ProcessVertices call. Expect problems !\n");
115     }
116
117     if (This->desc.dwCaps & D3DVBCAPS_OPTIMIZED) return D3DERR_VERTEXBUFFEROPTIMIZED;
118
119     if (lpdwSize != NULL) *lpdwSize = This->vertex_buffer_size;
120     *lplpData = This->vertices;
121     
122     return DD_OK;
123 }
124
125 HRESULT WINAPI
126 Main_IDirect3DVertexBufferImpl_7_1T_Unlock(LPDIRECT3DVERTEXBUFFER7 iface)
127 {
128     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
129     TRACE("(%p/%p)->()\n", This, iface);
130     /* Nothing to do here for now. Maybe some optimizations if ever we want to do some :-) */
131     return DD_OK;
132 }
133
134 HRESULT WINAPI
135 Main_IDirect3DVertexBufferImpl_7_1T_ProcessVertices(LPDIRECT3DVERTEXBUFFER7 iface,
136                                                     DWORD dwVertexOp,
137                                                     DWORD dwDestIndex,
138                                                     DWORD dwCount,
139                                                     LPDIRECT3DVERTEXBUFFER7 lpSrcBuffer,
140                                                     DWORD dwSrcIndex,
141                                                     LPDIRECT3DDEVICE7 lpD3DDevice,
142                                                     DWORD dwFlags)
143 {
144     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
145     FIXME("(%p/%p)->(%08lx,%08lx,%08lx,%p,%08lx,%p,%08lx): stub!\n", This, iface, dwVertexOp, dwDestIndex, dwCount, lpSrcBuffer, dwSrcIndex, lpD3DDevice, dwFlags);    
146     return DD_OK;
147 }
148
149 HRESULT WINAPI
150 Main_IDirect3DVertexBufferImpl_7_1T_GetVertexBufferDesc(LPDIRECT3DVERTEXBUFFER7 iface,
151                                                         LPD3DVERTEXBUFFERDESC lpD3DVertexBufferDesc)
152 {
153     DWORD size;
154     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
155     
156     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DVertexBufferDesc);
157     
158     size = lpD3DVertexBufferDesc->dwSize;
159     memset(lpD3DVertexBufferDesc, 0, size);
160     memcpy(lpD3DVertexBufferDesc, &This->desc, 
161            (size < This->desc.dwSize) ? size : This->desc.dwSize);
162     
163     return DD_OK;
164 }
165
166 HRESULT WINAPI
167 Main_IDirect3DVertexBufferImpl_7_1T_Optimize(LPDIRECT3DVERTEXBUFFER7 iface,
168                                              LPDIRECT3DDEVICE7 lpD3DDevice,
169                                              DWORD dwFlags)
170 {
171     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
172     FIXME("(%p/%p)->(%p,%08lx): stub!\n", This, iface, lpD3DDevice, dwFlags);
173
174     This->desc.dwCaps |= D3DVBCAPS_OPTIMIZED;
175
176     return DD_OK;
177 }
178
179 HRESULT WINAPI
180 Main_IDirect3DVertexBufferImpl_7_ProcessVerticesStrided(LPDIRECT3DVERTEXBUFFER7 iface,
181                                                         DWORD dwVertexOp,
182                                                         DWORD dwDestIndex,
183                                                         DWORD dwCount,
184                                                         LPD3DDRAWPRIMITIVESTRIDEDDATA lpStrideData,
185                                                         DWORD dwVertexTypeDesc,
186                                                         LPDIRECT3DDEVICE7 lpD3DDevice,
187                                                         DWORD dwFlags)
188 {
189     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
190     FIXME("(%p/%p)->(%08lx,%08lx,%08lx,%p,%08lx,%p,%08lx): stub!\n", This, iface, dwVertexOp, dwDestIndex, dwCount, lpStrideData, dwVertexTypeDesc, lpD3DDevice, dwFlags);
191     return DD_OK;
192 }
193
194 HRESULT WINAPI
195 Thunk_IDirect3DVertexBufferImpl_1_ProcessVertices(LPDIRECT3DVERTEXBUFFER iface,
196                                                   DWORD dwVertexOp,
197                                                   DWORD dwDestIndex,
198                                                   DWORD dwCount,
199                                                   LPDIRECT3DVERTEXBUFFER lpSrcBuffer,
200                                                   DWORD dwSrcIndex,
201                                                   LPDIRECT3DDEVICE3 lpD3DDevice,
202                                                   DWORD dwFlags)
203 {
204     TRACE("(%p)->(%08lx,%08lx,%08lx,%p,%08lx,%p,%08lx) thunking to IDirect3DVertexBuffer7 interface.\n", iface,
205           dwVertexOp, dwDestIndex, dwCount, lpSrcBuffer, dwSrcIndex, lpD3DDevice, dwFlags);
206     return IDirect3DVertexBuffer7_ProcessVertices(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface),
207                                                   dwVertexOp,
208                                                   dwDestIndex,
209                                                   dwCount,
210                                                   COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, lpSrcBuffer),
211                                                   dwSrcIndex,
212                                                   COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice3, IDirect3DDevice7, lpD3DDevice),
213                                                   dwFlags);
214 }
215
216 HRESULT WINAPI
217 Thunk_IDirect3DVertexBufferImpl_1_Optimize(LPDIRECT3DVERTEXBUFFER iface,
218                                            LPDIRECT3DDEVICE3 lpD3DDevice,
219                                            DWORD dwFlags)
220 {
221     TRACE("(%p)->(%p,%08lx) thunking to IDirect3DVertexBuffer7 interface.\n", iface, lpD3DDevice, dwFlags);
222     return IDirect3DVertexBuffer7_Optimize(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface),
223                                            COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice3, IDirect3DDevice7, lpD3DDevice),
224                                            dwFlags);
225 }
226
227 HRESULT WINAPI
228 Thunk_IDirect3DVertexBufferImpl_1_QueryInterface(LPDIRECT3DVERTEXBUFFER iface,
229                                                  REFIID riid,
230                                                  LPVOID* obp)
231 {
232     TRACE("(%p)->(%s,%p) thunking to IDirect3DVertexBuffer7 interface.\n", iface, debugstr_guid(riid), obp);
233     return IDirect3DVertexBuffer7_QueryInterface(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface),
234                                                  riid,
235                                                  obp);
236 }
237
238 ULONG WINAPI
239 Thunk_IDirect3DVertexBufferImpl_1_AddRef(LPDIRECT3DVERTEXBUFFER iface)
240 {
241     TRACE("(%p)->() thunking to IDirect3DVertexBuffer7 interface.\n", iface);
242     return IDirect3DVertexBuffer7_AddRef(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface));
243 }
244
245 ULONG WINAPI
246 Thunk_IDirect3DVertexBufferImpl_1_Release(LPDIRECT3DVERTEXBUFFER iface)
247 {
248     TRACE("(%p)->() thunking to IDirect3DVertexBuffer7 interface.\n", iface);
249     return IDirect3DVertexBuffer7_Release(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface));
250 }
251
252 HRESULT WINAPI
253 Thunk_IDirect3DVertexBufferImpl_1_Lock(LPDIRECT3DVERTEXBUFFER iface,
254                                        DWORD dwFlags,
255                                        LPVOID* lplpData,
256                                        LPDWORD lpdwSize)
257 {
258     TRACE("(%p)->(%08lx,%p,%p) thunking to IDirect3DVertexBuffer7 interface.\n", iface, dwFlags, lplpData, lpdwSize);
259     return IDirect3DVertexBuffer7_Lock(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface),
260                                        dwFlags,
261                                        lplpData,
262                                        lpdwSize);
263 }
264
265 HRESULT WINAPI
266 Thunk_IDirect3DVertexBufferImpl_1_Unlock(LPDIRECT3DVERTEXBUFFER iface)
267 {
268     TRACE("(%p)->() thunking to IDirect3DVertexBuffer7 interface.\n", iface);
269     return IDirect3DVertexBuffer7_Unlock(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface));
270 }
271
272 HRESULT WINAPI
273 Thunk_IDirect3DVertexBufferImpl_1_GetVertexBufferDesc(LPDIRECT3DVERTEXBUFFER iface,
274                                                       LPD3DVERTEXBUFFERDESC lpD3DVertexBufferDesc)
275 {
276     TRACE("(%p)->(%p) thunking to IDirect3DVertexBuffer7 interface.\n", iface, lpD3DVertexBufferDesc);
277     return IDirect3DVertexBuffer7_GetVertexBufferDesc(COM_INTERFACE_CAST(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer, IDirect3DVertexBuffer7, iface),
278                                                       lpD3DVertexBufferDesc);
279 }
280
281 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
282
283 static HRESULT
284 process_vertices_strided(IDirect3DVertexBufferImpl *This,
285                          DWORD dwVertexOp,
286                          DWORD dwDestIndex,
287                          DWORD dwCount,
288                          LPD3DDRAWPRIMITIVESTRIDEDDATA lpStrideData,
289                          DWORD dwVertexTypeDesc,
290                          IDirect3DDeviceImpl *device_impl,
291                          DWORD dwFlags)
292 {
293     IDirect3DVertexBufferGLImpl *glThis = (IDirect3DVertexBufferGLImpl *) This;
294     DWORD size = get_flexible_vertex_size(dwVertexTypeDesc);
295     char *dest_ptr;
296     unsigned int i;
297
298     This->processed = TRUE;
299
300     /* For the moment, the trick is to save the transform and lighting state at process
301        time to restore them at drawing time.
302        
303        The BIG problem with this method is nothing prevents D3D to do dirty tricks like
304        processing two different sets of vertices with two different rendering parameters
305        and then to display them using the same DrawPrimitive call.
306
307        It would be nice to check for such code here (but well, even this is not trivial
308        to do).
309
310        This is exactly what the TWIST.EXE demo does but using the same kind of ugly stuff
311        in the D3DExecuteBuffer code. I really wonder why Microsoft went back in time when
312        implementing this mostly useless (IMHO) API.
313     */
314     glThis->dwVertexTypeDesc = dwVertexTypeDesc;
315
316     if (dwVertexTypeDesc & D3DFVF_NORMAL) {
317         WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
318     }
319
320     if (glThis->vertices == NULL) {
321         glThis->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * This->desc.dwNumVertices);
322     }
323     dest_ptr = ((char *) glThis->vertices) + dwDestIndex * size;
324     
325     memcpy(&(glThis->world_mat), device_impl->world_mat, sizeof(D3DMATRIX));
326     memcpy(&(glThis->view_mat), device_impl->view_mat, sizeof(D3DMATRIX));
327     memcpy(&(glThis->proj_mat), device_impl->proj_mat, sizeof(D3DMATRIX));
328
329     for (i = 0; i < dwCount; i++) {
330         unsigned int tex_index;
331
332         if ((dwVertexTypeDesc & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
333             D3DVALUE *position =
334               (D3DVALUE *) (((char *) lpStrideData->position.lpvData) + i * lpStrideData->position.dwStride);
335             copy_and_next(dest_ptr, position, 3 * sizeof(D3DVALUE));
336         } else if ((dwVertexTypeDesc & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
337             D3DVALUE *position =
338               (D3DVALUE *) (((char *) lpStrideData->position.lpvData) + i * lpStrideData->position.dwStride);
339             copy_and_next(dest_ptr, position, 4 * sizeof(D3DVALUE));
340         }
341         if (dwVertexTypeDesc & D3DFVF_RESERVED1) {
342             dest_ptr += sizeof(DWORD);
343         }
344         if (dwVertexTypeDesc & D3DFVF_NORMAL) { 
345             D3DVALUE *normal = 
346               (D3DVALUE *) (((char *) lpStrideData->normal.lpvData) + i * lpStrideData->normal.dwStride);           
347             copy_and_next(dest_ptr, normal, 3 * sizeof(D3DVALUE));
348         }
349         if (dwVertexTypeDesc & D3DFVF_DIFFUSE) {
350             DWORD *color_d = 
351               (DWORD *) (((char *) lpStrideData->diffuse.lpvData) + i * lpStrideData->diffuse.dwStride);
352             copy_and_next(dest_ptr, color_d, sizeof(DWORD));
353         }
354         if (dwVertexTypeDesc & D3DFVF_SPECULAR) { 
355             DWORD *color_s = 
356               (DWORD *) (((char *) lpStrideData->specular.lpvData) + i * lpStrideData->specular.dwStride);
357             copy_and_next(dest_ptr, color_s, sizeof(DWORD));
358         }
359         for (tex_index = 0; tex_index < ((dwVertexTypeDesc & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
360             D3DVALUE *tex_coord =
361               (D3DVALUE *) (((char *) lpStrideData->textureCoords[tex_index].lpvData) + 
362                             i * lpStrideData->textureCoords[tex_index].dwStride);
363             copy_and_next(dest_ptr, tex_coord, 2 * sizeof(D3DVALUE));
364         }
365
366         if (TRACE_ON(ddraw_geom)) {
367             if ((dwVertexTypeDesc & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
368                 D3DVALUE *position =
369                   (D3DVALUE *) (((char *) lpStrideData->position.lpvData) + i * lpStrideData->position.dwStride);
370                 TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
371             } else if ((dwVertexTypeDesc & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
372                 D3DVALUE *position =
373                   (D3DVALUE *) (((char *) lpStrideData->position.lpvData) + i * lpStrideData->position.dwStride);
374                 TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
375             }
376             if (dwVertexTypeDesc & D3DFVF_NORMAL) { 
377                 D3DVALUE *normal = 
378                   (D3DVALUE *) (((char *) lpStrideData->normal.lpvData) + i * lpStrideData->normal.dwStride);       
379                 TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
380             }
381             if (dwVertexTypeDesc & D3DFVF_DIFFUSE) {
382                 DWORD *color_d = 
383                   (DWORD *) (((char *) lpStrideData->diffuse.lpvData) + i * lpStrideData->diffuse.dwStride);
384                 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
385                                    (*color_d >> 16) & 0xFF,
386                                    (*color_d >>  8) & 0xFF,
387                                    (*color_d >>  0) & 0xFF,
388                                    (*color_d >> 24) & 0xFF);
389             }
390             if (dwVertexTypeDesc & D3DFVF_SPECULAR) { 
391                 DWORD *color_s = 
392                   (DWORD *) (((char *) lpStrideData->specular.lpvData) + i * lpStrideData->specular.dwStride);
393                 TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
394                                    (*color_s >> 16) & 0xFF,
395                                    (*color_s >>  8) & 0xFF,
396                                    (*color_s >>  0) & 0xFF,
397                                    (*color_s >> 24) & 0xFF);
398             }
399             for (tex_index = 0; tex_index < ((dwVertexTypeDesc & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
400                 D3DVALUE *tex_coord =
401                   (D3DVALUE *) (((char *) lpStrideData->textureCoords[tex_index].lpvData) + 
402                                 i * lpStrideData->textureCoords[tex_index].dwStride);
403                 TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
404             }
405             TRACE_(ddraw_geom)("\n");
406         }
407     }
408
409     return DD_OK;
410 }
411
412 #undef copy_and_next
413
414 HRESULT WINAPI
415 GL_IDirect3DVertexBufferImpl_7_1T_ProcessVertices(LPDIRECT3DVERTEXBUFFER7 iface,
416                                                   DWORD dwVertexOp,
417                                                   DWORD dwDestIndex,
418                                                   DWORD dwCount,
419                                                   LPDIRECT3DVERTEXBUFFER7 lpSrcBuffer,
420                                                   DWORD dwSrcIndex,
421                                                   LPDIRECT3DDEVICE7 lpD3DDevice,
422                                                   DWORD dwFlags)
423 {
424     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
425     IDirect3DVertexBufferImpl *src_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpSrcBuffer);
426     IDirect3DDeviceImpl *device_impl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, lpD3DDevice);
427     D3DDRAWPRIMITIVESTRIDEDDATA strided;
428     DWORD size;
429
430     TRACE("(%p/%p)->(%08lx,%08lx,%08lx,%p,%08lx,%p,%08lx)\n", This, iface, dwVertexOp, dwDestIndex, dwCount, lpSrcBuffer, dwSrcIndex, lpD3DDevice, dwFlags);    
431
432     if (TRACE_ON(ddraw)) {
433         TRACE(" - vertex operations : "); dump_D3DVOP(dwVertexOp);
434         TRACE(" - flags             : "); dump_D3DPV(dwFlags);
435     }
436
437     if ((dwVertexOp & D3DVOP_TRANSFORM) == 0) return DDERR_INVALIDPARAMS;
438
439     size = get_flexible_vertex_size(src_impl->desc.dwFVF);
440     convert_FVF_to_strided_data(src_impl->desc.dwFVF, ((char *) src_impl->vertices) + dwSrcIndex * size, &strided, 0);
441
442     return process_vertices_strided(This, dwVertexOp, dwDestIndex, dwCount, &strided, src_impl->desc.dwFVF, device_impl, dwFlags);
443 }
444
445 HRESULT WINAPI
446 GL_IDirect3DVertexBufferImpl_7_ProcessVerticesStrided(LPDIRECT3DVERTEXBUFFER7 iface,
447                                                       DWORD dwVertexOp,
448                                                       DWORD dwDestIndex,
449                                                       DWORD dwCount,
450                                                       LPD3DDRAWPRIMITIVESTRIDEDDATA lpStrideData,
451                                                       DWORD dwVertexTypeDesc,
452                                                       LPDIRECT3DDEVICE7 lpD3DDevice,
453                                                       DWORD dwFlags)
454 {
455     ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface);
456     IDirect3DDeviceImpl *device_impl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, lpD3DDevice);
457
458     TRACE("(%p/%p)->(%08lx,%08lx,%08lx,%p,%08lx,%p,%08lx)\n", This, iface, dwVertexOp, dwDestIndex, dwCount, lpStrideData, dwVertexTypeDesc, lpD3DDevice, dwFlags);
459     if (TRACE_ON(ddraw)) {
460         TRACE(" - vertex operations : "); dump_D3DVOP(dwVertexOp);
461         TRACE(" - flags             : "); dump_D3DPV(dwFlags);
462         TRACE(" - vertex format     : "); dump_flexible_vertex(dwVertexTypeDesc);
463     }
464
465     if ((dwVertexOp & D3DVOP_TRANSFORM) == 0) return DDERR_INVALIDPARAMS;
466
467     return process_vertices_strided(This, dwVertexOp, dwDestIndex, dwCount, lpStrideData, dwVertexTypeDesc, device_impl, dwFlags);
468 }
469
470
471
472 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
473 # define XCAST(fun)     (typeof(VTABLE_IDirect3DVertexBuffer7.fun))
474 #else
475 # define XCAST(fun)     (void*)
476 #endif
477
478 IDirect3DVertexBuffer7Vtbl VTABLE_IDirect3DVertexBuffer7 =
479 {
480     XCAST(QueryInterface) Main_IDirect3DVertexBufferImpl_7_1T_QueryInterface,
481     XCAST(AddRef) Main_IDirect3DVertexBufferImpl_7_1T_AddRef,
482     XCAST(Release) Main_IDirect3DVertexBufferImpl_7_1T_Release,
483     XCAST(Lock) Main_IDirect3DVertexBufferImpl_7_1T_Lock,
484     XCAST(Unlock) Main_IDirect3DVertexBufferImpl_7_1T_Unlock,
485     XCAST(ProcessVertices) GL_IDirect3DVertexBufferImpl_7_1T_ProcessVertices,
486     XCAST(GetVertexBufferDesc) Main_IDirect3DVertexBufferImpl_7_1T_GetVertexBufferDesc,
487     XCAST(Optimize) Main_IDirect3DVertexBufferImpl_7_1T_Optimize,
488     XCAST(ProcessVerticesStrided) GL_IDirect3DVertexBufferImpl_7_ProcessVerticesStrided
489 };
490
491 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
492 #undef XCAST
493 #endif
494
495
496 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
497 # define XCAST(fun)     (typeof(VTABLE_IDirect3DVertexBuffer.fun))
498 #else
499 # define XCAST(fun)     (void*)
500 #endif
501
502 IDirect3DVertexBufferVtbl VTABLE_IDirect3DVertexBuffer =
503 {
504     XCAST(QueryInterface) Thunk_IDirect3DVertexBufferImpl_1_QueryInterface,
505     XCAST(AddRef) Thunk_IDirect3DVertexBufferImpl_1_AddRef,
506     XCAST(Release) Thunk_IDirect3DVertexBufferImpl_1_Release,
507     XCAST(Lock) Thunk_IDirect3DVertexBufferImpl_1_Lock,
508     XCAST(Unlock) Thunk_IDirect3DVertexBufferImpl_1_Unlock,
509     XCAST(ProcessVertices) Thunk_IDirect3DVertexBufferImpl_1_ProcessVertices,
510     XCAST(GetVertexBufferDesc) Thunk_IDirect3DVertexBufferImpl_1_GetVertexBufferDesc,
511     XCAST(Optimize) Thunk_IDirect3DVertexBufferImpl_1_Optimize
512 };
513
514 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
515 #undef XCAST
516 #endif
517
518 HRESULT d3dvertexbuffer_create(IDirect3DVertexBufferImpl **obj, IDirectDrawImpl *d3d, LPD3DVERTEXBUFFERDESC lpD3DVertBufDesc, DWORD dwFlags)
519 {
520     IDirect3DVertexBufferImpl *object;
521     static const flag_info flags[] = {
522         FE(D3DVBCAPS_DONOTCLIP),
523         FE(D3DVBCAPS_OPTIMIZED),
524         FE(D3DVBCAPS_SYSTEMMEMORY),
525         FE(D3DVBCAPS_WRITEONLY)
526     };
527
528     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVertexBufferGLImpl));
529     if (object == NULL) return DDERR_OUTOFMEMORY;
530
531     object->ref = 1;
532     object->d3d = d3d;
533     object->desc = *lpD3DVertBufDesc;
534     object->vertex_buffer_size = get_flexible_vertex_size(lpD3DVertBufDesc->dwFVF) * lpD3DVertBufDesc->dwNumVertices;
535     object->vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->vertex_buffer_size);
536     
537     ICOM_INIT_INTERFACE(object, IDirect3DVertexBuffer,  VTABLE_IDirect3DVertexBuffer);
538     ICOM_INIT_INTERFACE(object, IDirect3DVertexBuffer7, VTABLE_IDirect3DVertexBuffer7);
539
540     *obj = object;
541
542     if (TRACE_ON(ddraw)) {
543         TRACE(" creating implementation at %p with description : \n", *obj);
544         TRACE("  flags        : "); DDRAW_dump_flags_(lpD3DVertBufDesc->dwCaps, flags, sizeof(flags)/sizeof(flags[0]), TRUE);
545         TRACE("  vertex type  : "); dump_flexible_vertex(lpD3DVertBufDesc->dwFVF);
546         TRACE("  num vertices : %ld\n", lpD3DVertBufDesc->dwNumVertices);
547     }
548     
549     
550     return D3D_OK;
551 }