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