/* Copyright 2001 TransGaming Technologies Inc. */

#ifndef DDRAW_D3DDEVICE_MAIN_H_INCLUDED
#define DDRAW_D3DDEVICE_MAIN_H_INCLUDED

#define D3DFVF_TEXCOUNT(x) (((x) & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT)
#define D3DFVF_TEXCOORDSIZE(fvf,idx) ( ((((fvf)>>((idx)*2 + 16)) + 1) & 0x0003) + 1 )

static inline DWORD WINE_UNUSED D3D_FVF2Stride(DWORD d3dvtVertexType, LPVOID lpvVertices, LPD3DDRAWPRIMITIVESTRIDEDDATA sd)
{
  static const DWORD position_sizes[] = { 0, 3, 4, 4, 5, 6, 7, 8 };

  LPBYTE ptr = (LPBYTE)lpvVertices;
  DWORD stride;
  int i;
  int tex_count = D3DFVF_TEXCOUNT(d3dvtVertexType);

  memset(sd, 0, sizeof(*sd));
  sd->position.lpvData = ptr;
  stride = position_sizes[(d3dvtVertexType & D3DFVF_POSITION_MASK) / 2]
    * sizeof(D3DVALUE);
  if (d3dvtVertexType & D3DFVF_RESERVED1) {
    /* just compatibility with D3DLVERTEX */
    stride += sizeof(DWORD);
  }
  if (d3dvtVertexType & D3DFVF_NORMAL) {
    sd->normal.lpvData = ptr + stride;
    stride += 3*sizeof(float);
  }
  if (d3dvtVertexType & D3DFVF_DIFFUSE) {
    sd->diffuse.lpvData = ptr + stride;
    stride += sizeof(D3DCOLOR);
  }
  if (d3dvtVertexType & D3DFVF_SPECULAR) {
    sd->specular.lpvData = ptr + stride;
    stride += sizeof(D3DCOLOR);
  }

  if (d3dvtVertexType & D3DFVF_TEXCOUNT_MASK)
  {
    int num_coords;
    for (i = 0; i < tex_count; i++) {
      num_coords = D3DFVF_TEXCOORDSIZE(d3dvtVertexType,i);
      sd->textureCoords[i].lpvData = ptr + stride;
      stride += num_coords * sizeof(float);
    }
    /* initialize unused pointers/strides */
    for (i = tex_count; i < D3DDP_MAXTEXCOORD; i++) {
      sd->textureCoords[i].lpvData = NULL;
      sd->textureCoords[i].dwStride = 0;
    }
  }

  sd->position.dwStride = stride;
  sd->normal.dwStride = stride;
  sd->diffuse.dwStride = stride;
  sd->specular.dwStride = stride;
  for (i = 0; i < tex_count; i++)
      sd->textureCoords[i].dwStride = stride;

  return stride;
}

static inline DWORD WINE_UNUSED D3D_FVF2Size(DWORD d3dvtVertexType)
{
  D3DDRAWPRIMITIVESTRIDEDDATA sd;
  return D3D_FVF2Stride(d3dvtVertexType, NULL, &sd);
}


/* Non-interface functions */
HRESULT
Main_Direct3DDevice_Construct(IDirect3DDeviceImpl* This,
			      IDirectDrawImpl* pDD,
			      IDirectDrawSurfaceImpl* pDDS);
void Main_Direct3DDevice_ForceDestroy(IDirect3DDeviceImpl* This);

void Main_Direct3DDevice_final_release(IDirect3DDeviceImpl* This);
void Main_Direct3DDevice_post_init(IDirect3DDeviceImpl* This);
void Main_Direct3DDevice_setup_render_target(IDirect3DDeviceImpl *This);

HRESULT Main_Direct3DDevice_late_allocate_surface(IDirect3DDeviceImpl* This,
						  IDirectDrawSurfaceImpl* pDDS);
void WINAPI Main_Direct3DDevice_demolish_texture(LPVOID ctx, DWORD dwTexture);

void Main_Direct3DDevice_req_load_texture(IDirectDrawSurfaceImpl* texture,
					  IDirectDrawSurfaceImpl* source);
void Main_Direct3DDevice_req_invalidate_texture(IDirectDrawSurfaceImpl* texture,
						LPCRECT pRect);
void Main_Direct3DDevice_req_demolish_texture(IDirectDrawSurfaceImpl* texture);

/* IDirect3DDevice7 (partial) implementation */
ULONG WINAPI
Main_Direct3DDevice_AddRef(LPDIRECT3DDEVICE7 iface);
ULONG WINAPI
Main_Direct3DDevice_Release(LPDIRECT3DDEVICE7 iface);
HRESULT WINAPI
Main_Direct3DDevice_QueryInterface(LPDIRECT3DDEVICE7 iface, REFIID riid,
				   LPVOID* ppObj);
HRESULT WINAPI
Main_Direct3DDevice_GetCaps(LPDIRECT3DDEVICE7 iface, LPD3DDEVICEDESC7 lpCaps);
HRESULT WINAPI
Main_Direct3DDevice_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
				       LPD3DENUMPIXELFORMATSCALLBACK lpCB,
				       LPVOID lpContext);
HRESULT WINAPI
Main_Direct3DDevice_BeginScene(LPDIRECT3DDEVICE7 iface);
HRESULT WINAPI
Main_Direct3DDevice_EndScene(LPDIRECT3DDEVICE7 iface);
HRESULT WINAPI
Main_Direct3DDevice_SetRenderTarget(LPDIRECT3DDEVICE7 iface,
				    LPDIRECTDRAWSURFACE7 lpDDS,
				    DWORD dwFlags);
HRESULT WINAPI
Main_Direct3DDevice_GetRenderTarget(LPDIRECT3DDEVICE7 iface,
				    LPDIRECTDRAWSURFACE7* lplpDDS);
HRESULT WINAPI
Main_Direct3DDevice_Clear(LPDIRECT3DDEVICE7 iface, DWORD dwCount,
			  LPD3DRECT lpRects, DWORD dwFlags,
			  D3DCOLOR dwColor, D3DVALUE dvZ,
			  DWORD dwStencil);
HRESULT WINAPI
Main_Direct3DDevice_SetTransform(LPDIRECT3DDEVICE7 iface,
				 D3DTRANSFORMSTATETYPE dtstType,
				 LPD3DMATRIX lpD3DMatrix);
HRESULT WINAPI
Main_Direct3DDevice_GetTransform(LPDIRECT3DDEVICE7 iface,
				 D3DTRANSFORMSTATETYPE dtstType,
				 LPD3DMATRIX lpD3DMatrix);
HRESULT WINAPI
Main_Direct3DDevice_SetViewport(LPDIRECT3DDEVICE7 iface,
				LPD3DVIEWPORT7 lpData);
HRESULT WINAPI
Main_Direct3DDevice_GetViewport(LPDIRECT3DDEVICE7 iface,
				LPD3DVIEWPORT7 lpData);
HRESULT WINAPI
Main_Direct3DDevice_SetMaterial(LPDIRECT3DDEVICE7 iface,
				LPD3DMATERIAL7 lpMat);
HRESULT WINAPI
Main_Direct3DDevice_GetMaterial(LPDIRECT3DDEVICE7 iface,
				LPD3DMATERIAL7 lpMat);
HRESULT WINAPI
Main_Direct3DDevice_SetLight(LPDIRECT3DDEVICE7 iface,
			     DWORD dwIndex,
			     LPD3DLIGHT7 lpLight);
HRESULT WINAPI
Main_Direct3DDevice_GetLight(LPDIRECT3DDEVICE7 iface,
			     DWORD dwIndex,
			     LPD3DLIGHT7 lpLight);
HRESULT WINAPI
Main_Direct3DDevice_SetRenderState(LPDIRECT3DDEVICE7 iface,
				   D3DRENDERSTATETYPE d3dType,
				   DWORD dwState);
HRESULT WINAPI
Main_Direct3DDevice_GetRenderState(LPDIRECT3DDEVICE7 iface,
				   D3DRENDERSTATETYPE d3dType,
				   LPDWORD lpdwState);
HRESULT WINAPI
Main_Direct3DDevice_BeginStateBlock(LPDIRECT3DDEVICE7 iface);
HRESULT WINAPI
Main_Direct3DDevice_EndStateBlock(LPDIRECT3DDEVICE7 iface,
				  LPDWORD lpdwBlock);
HRESULT WINAPI
Main_Direct3DDevice_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
				  D3DPRIMITIVETYPE d3dptPrimType,
				  DWORD d3dvtVertexType,
				  LPVOID lpvVertices,
				  DWORD dwVertexCount,
				  DWORD dwFlags);
HRESULT WINAPI
Main_Direct3DDevice_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
					 D3DPRIMITIVETYPE d3dptPrimType,
					 DWORD d3dvtVertexType,
					 LPVOID lpvVertices,
					 DWORD dwVertexCount,
					 LPWORD dwIndices,
					 DWORD dwIndexCount,
					 DWORD dwFlags);
HRESULT WINAPI
Main_Direct3DDevice_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
					 D3DPRIMITIVETYPE d3dptPrimType,
					 DWORD d3dvtVertexType,
					 LPD3DDRAWPRIMITIVESTRIDEDDATA lpData,
					 DWORD dwVertexCount,
					 DWORD dwFlags);
HRESULT WINAPI
Main_Direct3DDevice_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
						D3DPRIMITIVETYPE d3dptPrimType,
						DWORD d3dvtVertexType,
						LPD3DDRAWPRIMITIVESTRIDEDDATA lpData,
						DWORD dwVertexCount,
						LPWORD dwIndices,
						DWORD dwIndexCount,
						DWORD dwFlags);
HRESULT WINAPI
Main_Direct3DDevice_SetClipStatus(LPDIRECT3DDEVICE7 iface,
				  LPD3DCLIPSTATUS lpD3DClipStatus);
HRESULT WINAPI
Main_Direct3DDevice_GetClipStatus(LPDIRECT3DDEVICE7 iface,
				  LPD3DCLIPSTATUS lpD3DClipStatus);

HRESULT WINAPI
Main_Direct3DDevice_ComputeSphereVisibility(LPDIRECT3DDEVICE7 iface, LPD3DVECTOR lpCenters,
              LPD3DVALUE  lpRadius, DWORD dwSpheres, DWORD dwFlags,LPDWORD lpdwReturnValues);
              
HRESULT WINAPI             
Main_Direct3DDevice_GetTexture(LPDIRECT3DDEVICE7 iface,
			       DWORD dwStage,
			       LPDIRECTDRAWSURFACE7* lplpTexture);
HRESULT WINAPI
Main_Direct3DDevice_SetTexture(LPDIRECT3DDEVICE7 iface,
			       DWORD dwStage,
			       LPDIRECTDRAWSURFACE7 lpTexture);
HRESULT WINAPI
Main_Direct3DDevice_GetTextureStageState(LPDIRECT3DDEVICE7 iface,
					 DWORD dwStage,
					 D3DTEXTURESTAGESTATETYPE d3dType,
					 LPDWORD lpdwState);
HRESULT WINAPI
Main_Direct3DDevice_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
					 DWORD dwStage,
					 D3DTEXTURESTAGESTATETYPE d3dType,
					 DWORD dwState);
HRESULT WINAPI
Main_Direct3DDevice_ValidateDevice(LPDIRECT3DDEVICE7 iface, LPDWORD lpdwPasses);
HRESULT WINAPI
Main_Direct3DDevice_ApplyStateBlock(LPDIRECT3DDEVICE7 iface,
				    DWORD dwBlock);
HRESULT WINAPI
Main_Direct3DDevice_CaptureStateBlock(LPDIRECT3DDEVICE7 iface,
				      DWORD dwBlock);
HRESULT WINAPI
Main_Direct3DDevice_DeleteStateBlock(LPDIRECT3DDEVICE7 iface,
				     DWORD dwBlock);
HRESULT WINAPI
Main_Direct3DDevice_Load(LPDIRECT3DDEVICE7 iface, LPDIRECTDRAWSURFACE7 lpDestTex,
			 LPPOINT lpDestPoint, LPDIRECTDRAWSURFACE7 lpSrcTex,
			 LPRECT lprcSrcRect, DWORD dwFlags);
HRESULT WINAPI
Main_Direct3DDevice_LightEnable(LPDIRECT3DDEVICE7 iface,
				DWORD dwIndex, BOOL bEnable);
HRESULT WINAPI
Main_Direct3DDevice_GetLightEnable(LPDIRECT3DDEVICE7 iface,
				   DWORD dwIndex, LPBOOL lpbEnable);
HRESULT WINAPI
Main_Direct3DDevice_GetInfo(LPDIRECT3DDEVICE7 iface, DWORD DevInfoID,
			    LPVOID pDevInfoStruct, DWORD DevInfoStructSize);

/* light.c */
HRESULT
Direct3DLight_Construct(IDirect3DLightImpl* This,
			IDirectDrawImpl* pDD);
HRESULT
Direct3DLight_Create(IDirectDrawImpl *pDD,
		     LPDIRECT3DLIGHT *ppd3dl);
void Direct3DLight_ForceDestroy(IDirect3DLightImpl* This);

/* material.c */
HRESULT
Direct3DMaterial3_Construct(IDirect3DMaterialImpl* This,
			    IDirectDrawImpl* pDD);
HRESULT
Direct3DMaterial3_Create(IDirectDrawImpl *pDD,
			 LPDIRECT3DMATERIAL3 *ppd3dm);
void Direct3DMaterial_ForceDestroy(IDirect3DMaterialImpl* This);

/* viewport.c */
HRESULT
Direct3DViewport3_Construct(IDirect3DViewportImpl* This,
			    IDirectDrawImpl* pDD);
HRESULT
Direct3DViewport3_Create(IDirectDrawImpl *pDD,
			 LPDIRECT3DVIEWPORT3 *ppd3dv);
void Direct3DViewport_ForceDestroy(IDirect3DViewportImpl* This);

#endif
