/*
 * Direct3D9 palettes
 * Copyright (c) 2003, TransGaming Technologies Inc.
 */

#include "config.h"

#include "winbase.h"
#include "d3d9.h"
#include "wine/debug.h"

#include "d3d9_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(ddraw);

#define PALETTESIZE (sizeof(PALETTEENTRY)*256)

static DWORD stamp;

static HRESULT WINAPI AllocPalette(IDirect3DDevice9Impl *This, DWORD dwIndex)
{
  D3D9Palette *pal;
  LPPALETTEENTRY entries;

  if (This->palette[dwIndex]) return D3D_OK;

  pal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3D9Palette));
  pal->local.lpGbl = &pal->global;
  pal->local.lpDD_lcl = &This->local;
  pal->global.lpDD_lcl = &This->local;
  pal->inter.lpLcl = &pal->local;
  pal->global.dwProcessId = GetCurrentProcessId();
  pal->global.dwFlags = DDPCAPS_8BIT | DDPCAPS_ALPHA;
  pal->global.dwContentsStamp = InterlockedExchangeAdd(&stamp, 1);

  /* FIXME: call HAL */

  entries = HeapAlloc(GetProcessHeap(), 0, PALETTESIZE);
  memset(entries, 0xff, PALETTESIZE);
  pal->global.lpColorTable = entries;

  This->palette[dwIndex] = pal;
  return D3D_OK;
}

static HRESULT WINAPI FreePalette(IDirect3DDevice9Impl *This, DWORD dwIndex)
{
  D3D9Palette *pal;

  pal = This->palette[dwIndex];
  if (!pal) return D3D_OK;

  /* FIXME: call HAL */
  
  HeapFree(GetProcessHeap(), 0, pal->global.lpColorTable);
  HeapFree(GetProcessHeap(), 0, pal);
  return D3D_OK;
}

static HRESULT WINAPI CheckExpandPalettes(IDirect3DDevice9Impl *This, DWORD dwIndex)
{
  if (dwIndex >= This->numpalettes) {
    DWORD newpalettes = dwIndex+1;
    D3D9Palette **newpalette;
    newpalette = HeapReAlloc(GetProcessHeap(),0,This->palette,sizeof(D3D9Palette*)*newpalettes);
    if (!newpalette) {
      ERR("out of memory\n");
      return DDERR_OUTOFMEMORY;
    }
    memset(newpalette+This->numpalettes, 0, sizeof(D3D9Palette*)*(newpalettes-This->numpalettes));
    This->palette = newpalette;
    This->numpalettes = newpalettes;
  }
  if (!This->palette[dwIndex])
    return AllocPalette(This, dwIndex);
  return D3D_OK;
}

HRESULT WINAPI Direct3DDevice9_SetPaletteEntries(LPDIRECT3DDEVICE9 iface,
						 UINT PaletteNumber,
						 CONST PALETTEENTRY* pEntries)
{
  ICOM_THIS(IDirect3DDevice9Impl, iface);
  D3D9Palette *pal;
  D3DHAL_DP2COMMAND cmd = { D3DDP2OP_UPDATEPALETTE, 0 };
  D3DHAL_DP2UPDATEPALETTE data;
  HRESULT hr;

  TRACE("(%p)->(%d,%p)\n", iface, PaletteNumber, pEntries);
  hr = CheckExpandPalettes(This, PaletteNumber);
  if (FAILED(hr)) return hr;

  pal = This->palette[PaletteNumber];
  memcpy(pal->global.lpColorTable, pEntries, PALETTESIZE);
  pal->global.dwContentsStamp = InterlockedExchangeAdd(&stamp, 1);

  data.dwPaletteHandle = (DWORD)&pal->global;
  data.wStartIndex = 0;
  data.wNumEntries = 256;
  hr = This->emit_dp2(This->ip_ctx, &cmd, &data, sizeof(data), NULL, 0);

  return hr;
}

HRESULT WINAPI Direct3DDevice9_GetPaletteEntries(LPDIRECT3DDEVICE9 iface,
						 UINT PaletteNumber,
						 PALETTEENTRY* pEntries)
{
  ICOM_THIS(IDirect3DDevice9Impl, iface);
  HRESULT hr;

  TRACE("(%p)->(%d,%p)\n", iface, PaletteNumber, pEntries);
  hr = CheckExpandPalettes(This, PaletteNumber);
  if (FAILED(hr)) return hr;

  memcpy(pEntries, This->palette[PaletteNumber]->global.lpColorTable, PALETTESIZE);

  return D3D_OK;
}

HRESULT WINAPI Direct3DDevice9_SetCurrentTexturePalette(LPDIRECT3DDEVICE9 iface,
							UINT PaletteNumber)
{
  ICOM_THIS(IDirect3DDevice9Impl, iface);
  D3D9Palette *pal;
  D3DHAL_DP2COMMAND cmd = { D3DDP2OP_SETPALETTE, 0 };
  D3DHAL_DP2SETPALETTE data;
  HRESULT hr;

  TRACE("(%p)->(%d)\n", iface, PaletteNumber);
  hr = CheckExpandPalettes(This, PaletteNumber);
  if (FAILED(hr)) return hr;

  This->curpalette = PaletteNumber;
  pal = This->palette[PaletteNumber];
  data.dwPaletteHandle = (DWORD)&pal->global;
  data.dwPaletteFlags = pal->global.dwFlags;
  data.dwSurfaceHandle = 0; /* all surfaces */
  hr = This->emit_dp2(This->ip_ctx, &cmd, &data, sizeof(data), NULL, 0);

  return hr;
}

HRESULT WINAPI Direct3DDevice9_GetCurrentTexturePalette(LPDIRECT3DDEVICE9 iface,
							UINT* pPaletteNumber)
{
  ICOM_THIS(IDirect3DDevice9Impl, iface);
  TRACE("(%p)->(%p)\n", iface, pPaletteNumber);
  *pPaletteNumber = This->curpalette;
  return D3D_OK;
}

HRESULT WINAPI Direct3DDevice9_DestroyPalettes(LPDIRECT3DDEVICE9 iface)
{
  ICOM_THIS(IDirect3DDevice9Impl, iface);
  unsigned u;
  for (u=0; u<This->numpalettes; u++)
    FreePalette(This, u);
  HeapFree(GetProcessHeap(), 0, This->palette);
  This->palette = NULL;
  This->numpalettes = 0;
  return D3D_OK;
}
