/*		Direct3DVertexBuffer implementation
 *
 * Copyright 2001 TransGaming Technologies Inc.
 */

#include "config.h"
#include "winerror.h"

#include <assert.h>
#include <stdlib.h>

#include "wine/debug.h"
#include "ddraw_private.h"
#include "dsurface/main.h"
#include "d3ddevice/main.h"
#include "dsurface/vbuffer.h"

WINE_DEFAULT_DEBUG_CHANNEL(ddraw);

static void D3D_SD2VBD( LPDDSURFACEDESC2 sdesc, LPD3DVERTEXBUFFERDESC vbdesc)
{
    memset(vbdesc, 0, sizeof(D3DVERTEXBUFFERDESC));
    vbdesc->dwFVF = sdesc->u4.dwFVF;
    vbdesc->dwNumVertices = sdesc->u1.dwLinearSize / D3D_FVF2Size(vbdesc->dwFVF);
    vbdesc->dwCaps = sdesc->ddsCaps.dwCaps & ~DDSCAPS_EXECUTEBUFFER;
    TRACE("FVF=%lx, NumVertices=%ld, size=%ld, caps=%lx\n", vbdesc->dwFVF,
          vbdesc->dwNumVertices, sdesc->u1.dwLinearSize, vbdesc->dwCaps);
}

#define CONVERT(pd3dvb) COM_INTERFACE_CAST(IDirectDrawSurfaceImpl,	\
					   IDirect3DVertexBuffer7,	\
					   IDirectDrawSurface7,		\
					   (pd3dvb))

static HRESULT WINAPI
Direct3DVertexBuffer7_QueryInterface(LPDIRECT3DVERTEXBUFFER7 iface, REFIID riid,
				     LPVOID *ppObj)
{
    return IDirectDrawSurface7_QueryInterface(CONVERT(iface), riid, ppObj);
}

static ULONG WINAPI
Direct3DVertexBuffer7_AddRef(LPDIRECT3DVERTEXBUFFER7 iface)
{
    return IDirectDrawSurface7_AddRef(CONVERT(iface));
}

static ULONG WINAPI
Direct3DVertexBuffer7_Release(LPDIRECT3DVERTEXBUFFER7 iface)
{
    return IDirectDrawSurface7_Release(CONVERT(iface));
}

static HRESULT WINAPI
Direct3DVertexBuffer7_Lock(LPDIRECT3DVERTEXBUFFER7 iface, DWORD dwFlags,
			   LPVOID* ppData, LPDWORD pdwSize)
{
    ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DVertexBuffer7, iface);
    TRACE("(%p)->(0x%lx,%p,%p)\n", iface, dwFlags, ppData, pdwSize);

    *ppData = (LPVOID)This->t.gbl.fpVidMem;

    if (pdwSize != NULL)
	*pdwSize = This->t.gbl.u4.dwLinearSize;

    This->lock_update(This, NULL, dwFlags);

    return D3D_OK;
}

static HRESULT WINAPI
Direct3DVertexBuffer7_Unlock(LPDIRECT3DVERTEXBUFFER7 iface)
{
    ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DVertexBuffer7, iface);
    TRACE("(%p)\n", iface);

    This->unlock_update(This, NULL);

    return D3D_OK;
}

static HRESULT WINAPI
Direct3DVertexBuffer7_GetVertexBufferDesc( LPDIRECT3DVERTEXBUFFER7 iface,
		                                           LPD3DVERTEXBUFFERDESC lpD3DVertexBufferDesc )
{
    ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DVertexBuffer7, iface);
    TRACE("(%p)->(%p)\n", iface, lpD3DVertexBufferDesc);

    D3D_SD2VBD(&This->surface_desc, lpD3DVertexBufferDesc);

    return D3D_OK;
}

#undef CONVERT

ICOM_VTABLE(IDirect3DVertexBuffer7) DDRAW_ID3DVB7_VTable =
{
    Direct3DVertexBuffer7_QueryInterface,
    Direct3DVertexBuffer7_AddRef,
    Direct3DVertexBuffer7_Release,
    Direct3DVertexBuffer7_Lock,
    Direct3DVertexBuffer7_Unlock,
    (void*)0xdead4003, /* ProcessVertices */
    Direct3DVertexBuffer7_GetVertexBufferDesc,
    (void*)0xdead4005, /* Optimize */
    (void*)0xdead4006  /* ProcessVerticesStrided */
};

#define CONVERT(pd3dvb) COM_INTERFACE_CAST(IDirectDrawSurfaceImpl,	\
					   IDirect3DVertexBuffer,	\
					   IDirectDrawSurface7,		\
					   (pd3dvb))
#define CONVERT7(pd3dvb) COM_INTERFACE_CAST(IDirectDrawSurfaceImpl,	\
					    IDirect3DVertexBuffer,	\
					    IDirect3DVertexBuffer7,	\
					    (pd3dvb))

static HRESULT WINAPI
Direct3DVertexBuffer_QueryInterface(LPDIRECT3DVERTEXBUFFER iface, REFIID riid,
				    LPVOID *ppObj)
{
    return IDirectDrawSurface7_QueryInterface(CONVERT(iface), riid, ppObj);
}

static ULONG WINAPI
Direct3DVertexBuffer_AddRef(LPDIRECT3DVERTEXBUFFER iface)
{
    return IDirectDrawSurface7_AddRef(CONVERT(iface));
}

static ULONG WINAPI
Direct3DVertexBuffer_Release(LPDIRECT3DVERTEXBUFFER iface)
{
    return IDirectDrawSurface7_Release(CONVERT(iface));
}

static HRESULT WINAPI
Direct3DVertexBuffer_Lock(LPDIRECT3DVERTEXBUFFER iface, DWORD dwFlags,
			  LPVOID* ppData, LPDWORD pdwSize)
{
    return IDirect3DVertexBuffer7_Lock(CONVERT7(iface), dwFlags, ppData, pdwSize);
}

static HRESULT WINAPI
Direct3DVertexBuffer_Unlock(LPDIRECT3DVERTEXBUFFER iface)
{
    return IDirect3DVertexBuffer7_Unlock(CONVERT7(iface));
}

#undef CONVERT7
#undef CONVERT

ICOM_VTABLE(IDirect3DVertexBuffer) DDRAW_ID3DVB_VTable =
{
    Direct3DVertexBuffer_QueryInterface,
    Direct3DVertexBuffer_AddRef,
    Direct3DVertexBuffer_Release,
    Direct3DVertexBuffer_Lock,
    Direct3DVertexBuffer_Unlock,
    (void*)0xdead5003, /* ProcessVertices */
    (void*)0xdead5004, /* GetVertexBufferDesc */
    (void*)0xdead5005  /* Optimize */
};
