#include "SM_Engine3DPCH.h"


#define VERTEXSTREAMSIZE  65000
#define INDEXSTREAMSIZE   65000
namespace ResourceManager 
{


struct RenderTargetDepth
{
  IDirect3DSurface8* m_pZStencilSurface;      
  IDirect3DSurface8* m_pBackBuffer;
  IDirect3DTexture8* m_pAsTexture;
  int                m_iDepthID;
  int                m_iRenderTargetID;
};


MBStaticList<RenderTargetDepth> g_slRTDStack;


int m_iPosNormalDiffuseTex1Stream=-1;
int m_iIndexStream=-1;

#define SCRATCHTEXTURES 2
int m_iScratchTextures[SCRATCHTEXTURES] = { -1, -1 };

#define SCRATCHDEPTH 1
int m_iDepthTextures[SCRATCHDEPTH] = { -1 };



struct ResourceTexture
{
  ResourceTexture()
  {
    pCubeTexture = 0;
    pTexture     = 0;
    pSurface     = 0;
  }

  IDirect3DCubeTexture8* pCubeTexture;
  IDirect3DTexture8*     pTexture;
  IDirect3DSurface8*     pSurface;
};

struct ResourceVB
{
  IDirect3DVertexBuffer8* pVertexBuffer;
  unsigned                uLength;
  unsigned                uOffset;
};

struct ResourceIB
{
  IDirect3DIndexBuffer8* pIndexBuffer;
  unsigned                uLength;
  unsigned                uOffset;
};

MBStaticList<ResourceTexture> g_slTextureList;
MBStaticList<ResourceVB>      g_slVBList;
MBStaticList<ResourceIB>      g_slIBList;

unsigned				      m_iMaxWidth;
unsigned				      m_iMaxHeight;


MSurface* LockD3DTexture(MSurface* pSurface, IDirect3DSurface8* pD3DSurface)
{
  D3DSURFACE_DESC Desc;
  D3DLOCKED_RECT  Locked;

  if (FAILED(pD3DSurface->GetDesc(&Desc)))
  {
    return (0);
  }


  if (FAILED(pD3DSurface->LockRect(&Locked, NULL, 0)))
  {
    return (0);
  }
     
  MPixelFormatDescriptor PixelFormat;
  switch (Desc.Format)
  {
  case D3DFMT_R8G8B8:
    PixelFormat=CommonPixelDescriptors[E__RGB24__888];
    break;
  case D3DFMT_A8R8G8B8:
    PixelFormat=CommonPixelDescriptors[E_ARGB32_8888];
    break;
  case D3DFMT_X8R8G8B8:
    PixelFormat=CommonPixelDescriptors[E__RGB32__888];
    break;
  case D3DFMT_R5G6B5:
    PixelFormat=CommonPixelDescriptors[E__RGB16__565];
    break;
  case D3DFMT_X1R5G5B5:
    PixelFormat=CommonPixelDescriptors[E__RGB16__555];
    break;
  case D3DFMT_A1R5G5B5:
    PixelFormat=CommonPixelDescriptors[E_ARGB16__1555];
    break;    
  case D3DFMT_A4R4G4B4:
    PixelFormat=CommonPixelDescriptors[E_ARGB16__444];
    break;    
  default:
    assert(!"Not supported yet");
    return (0);
  }

  MSurfaceDescriptor sd;
  sd.m_pfPixelFormat=PixelFormat;
  sd.m_uiByteStride =Locked.Pitch;
  sd.m_uiWidth      =Desc.Width;
  sd.m_uiHeight     =Desc.Height;


  if (pSurface->Init(sd, Locked.pBits, 0)!=0)
  {
    pD3DSurface->UnlockRect();
    return (0);
  }

  return (pSurface);
}

MSurface* UnlockD3DTexture(MSurface* pSurface, IDirect3DSurface8* pD3DSurface)
{
  pD3DSurface->UnlockRect();
  return (pSurface);
}

void GetCurrentRenderTarget(IDirect3DSurface8** ppDepthStencil, IDirect3DSurface8** ppBackBuffer, 
                          IDirect3DTexture8** ppTexture, int* piDepthID, int* piRenderTarget)
{

  assert(g_slRTDStack.GetNumberElements());

  RenderTargetDepth* pRT;
  g_slRTDStack.Get(g_slRTDStack.Last(), pRT);

  if (ppDepthStencil)
  {
    *ppDepthStencil=pRT->m_pZStencilSurface;
  }

  if (ppBackBuffer)
  {
    *ppBackBuffer=pRT->m_pBackBuffer;
  }

  if (ppTexture)
  {
    *ppTexture=pRT->m_pAsTexture;
  }

  if (piDepthID)
  {
    *piDepthID=pRT->m_iDepthID;
  }

  if (piRenderTarget)
  {
    *piRenderTarget=pRT->m_iRenderTargetID;
  }

}

int ResetRenderTargetStack()
{
  while (g_slRTDStack.GetNumberElements() > 1)
  {
    RestoreRenderTarget();
  }
  
  return 0;
}

int SetRenderTarget(int iRenderTarget, int iDepthBuffer)
{
  //SM_Main::OutputDebug("set render target\n");

  RenderTargetDepth rtd;
  SM_D3d::Device()->GetDepthStencilSurface(&rtd.m_pZStencilSurface);  
  SM_D3d::Device()->GetRenderTarget(&rtd.m_pBackBuffer);
  rtd.m_pAsTexture=ResourceManager::GetTextureFromID(iRenderTarget);
  rtd.m_iRenderTargetID=iRenderTarget;
  rtd.m_iDepthID       =iDepthBuffer;
  
  g_slRTDStack.InsertTail(rtd);
  
  if (iRenderTarget==-1)
  {
    SM_Main::OutputConsole("Render/Depth aux buffers weren't initialized");
    return (-1);
  }

  assert(iRenderTarget!=-1);
  
  IDirect3DSurface8* pTextureSurface;      
  ResourceManager::GetTextureFromID(iRenderTarget)->GetSurfaceLevel(0, &pTextureSurface);
  if (FAILED(SM_D3d::Device()->SetRenderTarget(
        pTextureSurface, 
        iDepthBuffer!=-1?ResourceManager::GetSurfaceFromID(iDepthBuffer):0)))
  {
    assert("Render target failed");
    return -1;
  }
  pTextureSurface->Release();

  Coordinates::UpdatePhysicalSize();
  return 0;
}

int RestoreRenderTarget()
{
  //SM_Main::OutputDebug("Restoring render target\n");

  RenderTargetDepth rtd;
  g_slRTDStack.Get(g_slRTDStack.Last(), rtd);
  
  SM_D3d::Device()->SetRenderTarget(rtd.m_pBackBuffer, rtd.m_pZStencilSurface);  

  rtd.m_pBackBuffer->Release();
  if (rtd.m_pZStencilSurface) rtd.m_pZStencilSurface->Release();

  g_slRTDStack.Delete(g_slRTDStack.Last());
  
  Coordinates::UpdatePhysicalSize();
  return 0;
}


int Init()
{
  g_slTextureList.Init();
  g_slIBList.Init();
  g_slVBList.Init();

  D3DCAPS8 Caps;
  if (FAILED(SM_D3d::Device()->GetDeviceCaps(&Caps)))
  {
    return -1;
  }

  m_iMaxWidth =Caps.MaxTextureWidth;
  m_iMaxHeight=Caps.MaxTextureHeight;


  assert(m_iPosNormalDiffuseTex1Stream==-1);
  m_iPosNormalDiffuseTex1Stream = CreateDynamicVertexBuffer (VERTEXSTREAMSIZE*sizeof(FVF_PosNormalDiffuseTex1), FVF_POSNORMALDIFFUSETEX1);

  assert(m_iIndexStream==-1);
  m_iIndexStream= CreateDynamicIndexBuffer (INDEXSTREAMSIZE*sizeof(unsigned short), D3DFMT_INDEX16);

  g_slRTDStack.Init();

  RenderTargetDepth rtd;
  SM_D3d::Device()->GetDepthStencilSurface(&rtd.m_pZStencilSurface);  
  SM_D3d::Device()->GetRenderTarget(&rtd.m_pBackBuffer);
  rtd.m_pAsTexture     =0;
  rtd.m_iDepthID       =-1;
  rtd.m_iRenderTargetID=-1;

  g_slRTDStack.InsertTail(rtd);
  

  GetScratchRenderTexture(0);
  GetScratchRenderTexture(1);
  GetScratchDepthTexture(0);  

  return (0);
}

int Shutdown()
{
  if (m_iIndexStream!=-1)
  {
    ReleaseIndexBuffer(m_iIndexStream);
    m_iIndexStream=-1;
  }

  if (m_iPosNormalDiffuseTex1Stream!=-1)
  {
    ReleaseVertexBuffer(m_iPosNormalDiffuseTex1Stream);
    m_iPosNormalDiffuseTex1Stream=-1;
  }

  int i;
  for (i = 0 ; i < SCRATCHTEXTURES ; i++)
  {
    if (m_iScratchTextures[i] != -1)
    {
      ReleaseTexture(m_iScratchTextures[i]);
      m_iScratchTextures[i] = -1;
    }
  }

  for (i = 0 ; i < SCRATCHDEPTH ; i++)
  {
    if (m_iDepthTextures[i] != -1)
    {
      ReleaseTexture(m_iDepthTextures[i]);
      m_iDepthTextures[i] = -1;
    }
  }

  if (g_slRTDStack.GetNumberElements())
  {
    assert(g_slRTDStack.GetNumberElements()==1);
    RenderTargetDepth* rtd;
    g_slRTDStack.Get(g_slRTDStack.First(), rtd);
    rtd->m_pBackBuffer->Release();
    if (rtd->m_pZStencilSurface) rtd->m_pZStencilSurface->Release();    
  }

  
  g_slRTDStack.Shutdown();  
  
  
  assert(g_slTextureList.GetNumberElements()==0);
  g_slTextureList.Shutdown();

  assert(g_slVBList.GetNumberElements()==0);
  g_slVBList.Shutdown();

  assert(g_slIBList.GetNumberElements()==0);
  g_slIBList.Shutdown();

    
  return (0);
}

int CreateDepthTexture(unsigned uWidth, unsigned uHeight, D3DFORMAT Format)
{
  ResourceTexture rTexture;
  IDirect3DSurface8* pVideoTexture =0;

  D3DFORMAT ZFormat;

  if (SM_D3d::GetCurrentMode()->bStencil)
  {
    if (SUCCEEDED(SM_D3d::D3D()->CheckDeviceFormat(
      SM_D3d::GetCurrentMode()->uDevice,
      D3DDEVTYPE_HAL,
      SM_D3d::GetCurrentMode()->d3dFormat,
      D3DUSAGE_DEPTHSTENCIL ,
      D3DRTYPE_SURFACE,
      D3DFMT_D24S8)) &&
    
      SUCCEEDED(SM_D3d::D3D()->CheckDepthStencilMatch(
                  SM_D3d::GetCurrentMode()->uDevice,
                  D3DDEVTYPE_HAL,
                  SM_D3d::GetCurrentMode()->d3dFormat,
                  Format,
                  D3DFMT_D24S8)))
    {
      ZFormat=D3DFMT_D24S8;
    }
    else
    {
      return false;
    }
  }
  else
  if (SUCCEEDED(SM_D3d::D3D()->CheckDeviceFormat(
      SM_D3d::GetCurrentMode()->uDevice,
      D3DDEVTYPE_HAL,
      SM_D3d::GetCurrentMode()->d3dFormat,
      D3DUSAGE_DEPTHSTENCIL ,
      D3DRTYPE_SURFACE,
      D3DFMT_D16_LOCKABLE)) &&
    
      SUCCEEDED(SM_D3d::D3D()->CheckDepthStencilMatch(
                  SM_D3d::GetCurrentMode()->uDevice,
                  D3DDEVTYPE_HAL,
                  SM_D3d::GetCurrentMode()->d3dFormat,
                  Format,
                  D3DFMT_D16_LOCKABLE)))
  {
    ZFormat=D3DFMT_D16_LOCKABLE;
  }
  else       
  if (SUCCEEDED(SM_D3d::D3D()->CheckDeviceFormat(
      SM_D3d::GetCurrentMode()->uDevice,
      D3DDEVTYPE_HAL,
      SM_D3d::GetCurrentMode()->d3dFormat,
      D3DUSAGE_DEPTHSTENCIL ,
      D3DRTYPE_SURFACE,
      D3DFMT_D16)) &&
    
      SUCCEEDED(SM_D3d::D3D()->CheckDepthStencilMatch(
                  SM_D3d::GetCurrentMode()->uDevice,
                  D3DDEVTYPE_HAL,
                  SM_D3d::GetCurrentMode()->d3dFormat,
                  Format,
                  D3DFMT_D16)))
  {
    ZFormat=D3DFMT_D16;
  }
  else
  if (SUCCEEDED(SM_D3d::D3D()->CheckDeviceFormat(
      SM_D3d::GetCurrentMode()->uDevice,
      D3DDEVTYPE_HAL,
      SM_D3d::GetCurrentMode()->d3dFormat,
      D3DUSAGE_DEPTHSTENCIL ,
      D3DRTYPE_SURFACE,
      D3DFMT_D32)) &&
    
      SUCCEEDED(SM_D3d::D3D()->CheckDepthStencilMatch(
                  SM_D3d::GetCurrentMode()->uDevice,
                  D3DDEVTYPE_HAL,
                  SM_D3d::GetCurrentMode()->d3dFormat,
                  Format,
                  D3DFMT_D32)))
  {
    ZFormat=D3DFMT_D32;
  }
  else
  {
    return false;
  }

  if (FAILED(SM_D3d::Device()->CreateDepthStencilSurface(uWidth, uHeight, ZFormat, D3DMULTISAMPLE_NONE, &pVideoTexture)))
  {
    goto FAIL;
  }

  rTexture.pSurface=pVideoTexture;;
  rTexture.pTexture=0;

  int iID;
  if ((iID=g_slTextureList.InsertTail(rTexture))==-1)
  {
    goto FAIL;
  }
  

  return (iID);

FAIL:
  if (pVideoTexture)        pVideoTexture->Release();
  
  return (-1);
}

int CreateRenderTexture(unsigned uWidth, unsigned uHeight, D3DFORMAT Format, unsigned uMips)
{
  ResourceTexture rTexture;
  IDirect3DTexture8* pVideoTexture =0;

  
  if (FAILED(SM_D3d::Device()->CreateTexture(uWidth, uHeight, uMips, D3DUSAGE_RENDERTARGET, Format, D3DPOOL_DEFAULT, &pVideoTexture)))
  {
    goto FAIL;
  }



  rTexture.pSurface=0;
  rTexture.pTexture=pVideoTexture;;

  int iID;
  if ((iID=g_slTextureList.InsertTail(rTexture))==-1)
  {
    goto FAIL;
  }
  
  SM_Main::OutputDebug("Created render texture with id %i\n", iID);

  return (iID);

FAIL:
  SM_Main::OutputDebug("Failed to create render texture\n");
  if (pVideoTexture)        pVideoTexture->Release();
  
  return (-1);
}

int GetScratchRenderTexture(unsigned uScratch)
{
  if (uScratch >= SCRATCHTEXTURES)
  {
    return -1;
  }

  if (m_iScratchTextures[uScratch] == -1)
  {
    m_iScratchTextures[uScratch] = CreateRenderTexture(128, 128, D3DFMT_X8R8G8B8);
  }
  
  return m_iScratchTextures[uScratch];
}

int GetScratchDepthTexture(unsigned uDepth)
{
  if (uDepth>= SCRATCHDEPTH)
  {
    return -1;
  }

  if (m_iDepthTextures[uDepth] == -1)
  {
    m_iDepthTextures[uDepth] = CreateDepthTexture (128, 128, D3DFMT_X8R8G8B8);
  }
  
  return m_iDepthTextures[uDepth];
}


int InitMipMapChain(MSurface* pSurface, IDirect3DSurface8** pSurfaces, unsigned uSurfaces, bool bRenormalizeRGB = false)
{
  IDirect3DSurface8** pSystemCopies = new IDirect3DSurface8*[uSurfaces];
  if (!pSystemCopies)

  {
    return -1;
  }

  MSurface* pMips=new MSurface[uSurfaces];
  if (!pMips)
  {
    return -1;
  }

  unsigned i;
  for (i = 0 ; i < uSurfaces ; i++)
  {
    D3DSURFACE_DESC Desc;
    pSurfaces[i]->GetDesc(&Desc);

    if (FAILED(SM_D3d::Device()->CreateImageSurface(Desc.Width, Desc.Height, Desc.Format, &pSystemCopies[i])))
    {
      return -1;
    }

    LockD3DTexture(&pMips[i], pSystemCopies[i]);
  }
     
  // Generate mips
  pSurface->GenerateMipMapChain(pMips, uSurfaces, bRenormalizeRGB);
  
  for (i=0 ; i<uSurfaces ; i++)
  {
    UnlockD3DTexture(&pMips[i], pSystemCopies[i]);    
    SM_D3d::Device()->CopyRects(pSystemCopies[i], NULL, 0, pSurfaces[i], 0);
    pSystemCopies[i]->Release();
  }

  delete[] pMips;
  delete[] pSystemCopies;
    
  return 0;
}

int CreateTexture     (unsigned uWidth, unsigned uHeight, D3DFORMAT Format, unsigned uMips)
{
  ResourceTexture rTexture;
  IDirect3DTexture8* pVideoTexture =0;

  
  if (FAILED(SM_D3d::Device()->CreateTexture(uWidth, uHeight, uMips, 0, Format, D3DPOOL_MANAGED, &pVideoTexture)))
  {
    goto FAIL;
  }



  rTexture.pSurface=0;
  rTexture.pTexture=pVideoTexture;;

  int iID;
  if ((iID=g_slTextureList.InsertTail(rTexture))==-1)
  {
    goto FAIL;
  }
  
  SM_Main::OutputDebug("Created texture with id %i\n", iID);

  return (iID);

FAIL:
  SM_Main::OutputDebug("Failed to create texture\n");
  if (pVideoTexture)        pVideoTexture->Release();
  
  return (-1);
}

int CreateTextureFromSurface(MSurface* pSurface, D3DFORMAT Format, bool bRenormalizeRGB)
{    
  ResourceTexture rTexture;
  unsigned uWidth =pSurface->GetPSurfaceDescriptor()->m_uiWidth;
  unsigned uHeight=pSurface->GetPSurfaceDescriptor()->m_uiHeight;
  unsigned i=0;
  unsigned uLevels=0;
  MSurface* pMips=0;
  IDirect3DTexture8* pVideoTexture = 0;
  IDirect3DSurface8** pSurfaces = 0;

  MSurface DeviceSize;
  if (uWidth>m_iMaxWidth || uHeight>m_iMaxHeight)
  {
    if (uWidth >m_iMaxWidth) uWidth=m_iMaxWidth;
    if (uHeight>m_iMaxHeight)uWidth=m_iMaxHeight;

    MSurfaceDescriptor sd;
    sd=pSurface->GetSurfaceDescriptor();

    sd.m_uiWidth =uWidth ;
    sd.m_uiHeight=uHeight;
    
    DeviceSize.Init(sd,0,0);

    DeviceSize.ScaleAndConvertFrom(*pSurface);
    
    pSurface=&DeviceSize;
  }

  if (((uWidth-1)&uWidth) ||  ((uHeight-1)&uHeight) )
  {
    SM_Main::OutputError("Texturas potencia de 2 por favor!");
    return -1;
  }

  if (FAILED(SM_D3d::Device()->CreateTexture(uWidth, uHeight, 0, 0, Format, D3DPOOL_MANAGED , &pVideoTexture)))
  {
    goto FAIL;
  }

  uLevels = pVideoTexture->GetLevelCount();

  pSurfaces = new IDirect3DSurface8*[uLevels];

  if (!pSurfaces)
  {
    goto FAIL;
  }

  for (i = 0 ; i < uLevels ; i++)
  {
    pVideoTexture->GetSurfaceLevel(i, &pSurfaces[i]);
  }

  InitMipMapChain(pSurface, pSurfaces, uLevels, bRenormalizeRGB);

  for (i = 0 ; i < uLevels ; i++)
  {
    pSurfaces[i]->Release();
  }

  delete[] pSurfaces;

  rTexture.pTexture=pVideoTexture;;

  int iID;
  if ((iID=g_slTextureList.InsertTail(rTexture))==-1)
  {
    goto FAIL;
  }
    
  return (iID);

FAIL:  
  return (-1);
}

IDirect3DTexture8* GetTextureFromID(int iID)
{
  ResourceTexture* pResource;

  if (g_slTextureList.Get(iID, pResource))
  {
    return (0);
  }
  else
  {
    return (pResource->pTexture);
  }  
}

IDirect3DCubeTexture8* GetCubeMapFromID(int iID)
{
  ResourceTexture* pResource;

  if (g_slTextureList.Get(iID, pResource))
  {
    return (0);
  }
  else
  {
    return (pResource->pCubeTexture);
  }  
}

int CreateCubemapFromSurface(MSurface* pSurfaces, D3DFORMAT Format)
{
  IDirect3DSurface8** pFillSurfaces;
  IDirect3DCubeTexture8* pCubeTexture;
  ResourceTexture rTexture;
  

  unsigned uWidth  = pSurfaces[0].GetPSurfaceDescriptor()->m_uiWidth; 
  unsigned uHeight = pSurfaces[0].GetPSurfaceDescriptor()->m_uiHeight; 

  if (uWidth != uHeight)
  {
    return -1;
  }

  unsigned i,j;
  for (i = 0 ; i < 6 ; i++)
  {
    if (pSurfaces[0].GetPSurfaceDescriptor()->m_uiWidth != uWidth ||
        pSurfaces[0].GetPSurfaceDescriptor()->m_uiHeight != uHeight)
    {
      return -1;
    }
  }
    
  if (FAILED(SM_D3d::Device()->CreateCubeTexture(
      uWidth,
      0,
      0,
      Format,
      D3DPOOL_MANAGED ,
      &pCubeTexture
      )))
  {
    return -1;
  }

  unsigned uLevels = pCubeTexture->GetLevelCount();
  pFillSurfaces = new IDirect3DSurface8*[uLevels];
  if (!pFillSurfaces )
  {
    return -1;
  }

  for (i = 0 ; i < 6 ; i++)
  {   
    for (j = 0 ; j < uLevels ; j++)
    {
      if (FAILED(pCubeTexture->GetCubeMapSurface(
                  (D3DCUBEMAP_FACES) i,
                  j,
                  &pFillSurfaces[j])))
      {
        return -1;
      }
    }

    if (InitMipMapChain(&pSurfaces[i], pFillSurfaces, uLevels) != 0)
    {
      return -1;
    }

    for (j = 0 ; j < uLevels ; j++)
    {
      pFillSurfaces[j]->Release();
    }
  }

  delete[] pFillSurfaces;

  rTexture.pCubeTexture=pCubeTexture;;

  int iID;
  if ((iID=g_slTextureList.InsertTail(rTexture))==-1)
  {
    return -1;
  }
    
  return iID;
}

int CreateBumpmapFromSurface(MSurface*  pSurface , D3DFORMAT Format)
{

  MSurface Bump;
  MSurfaceDescriptor sd;
  sd = pSurface->GetSurfaceDescriptor();
  sd.m_pfPixelFormat = CommonPixelDescriptors[E_ARGB32_8888];


  MSurface AuxBump;
  if (AuxBump.Init(sd, NULL, NULL) != 0)
  {
    return -1;
  }

  if (AuxBump.ConvertFrom(*pSurface)!=0)
  {
    return -1;
  }

  
  // Copy properties to bump
  if (Bump.Init(sd, NULL, NULL) != 0)
  {
    return -1;
  }
  
  
  // Only accept ARGB32
  if (!(Bump.GetPSurfaceDescriptor()->m_pfPixelFormat == CommonPixelDescriptors[E_ARGB32_8888]))
  {
    return -1;
  }

  unsigned i,j;

  unsigned uWidth  = Bump.GetPSurfaceDescriptor()->m_uiWidth;
  unsigned uHeight = Bump.GetPSurfaceDescriptor()->m_uiHeight;

  for (j = 0 ; j < uHeight ; j++)
  {
    unsigned* pUp    = (unsigned*) AuxBump.GetSurfacePointer(0, (j)%uHeight);
    unsigned* pDown  = (unsigned*) AuxBump.GetSurfacePointer(0, (j+1)%uHeight);
    unsigned* pTarget= (unsigned*) Bump.GetSurfacePointer(0, j);

    for (i = 0 ; i < uWidth ; i++)
    {
      Vector3D v3d;

      

      v3d = Vector3D( int((pUp[(i+1)%uWidth] & 0xFF)) - int((pUp[i] & 0xFF)),
                      int((pDown[i] & 0xFF)) - int((pUp[i] & 0xFF)),
                    16.0);

      //v3d = Vector3D(0.0f, 0.0f, 1.0f);
      v3d.Normalize();


      int u = 128 + int(v3d.x*127.0);
      int v = 128 + int(v3d.y*127.0);
      int w = 128 + int(v3d.z*127.0);
                                
      unsigned uColor = 0xFF000000 | (u<<16) | (v<<8) | w;
      pTarget[i] = uColor;
    }    
  }
  
  return CreateTextureFromSurface(&Bump, Format, true);
}
  

IDirect3DSurface8* GetSurfaceFromID(int iID)
{
  ResourceTexture* pResource;

  if (g_slTextureList.Get(iID, pResource))
  {
    return (0);
  }
  else
  {
    return (pResource->pSurface);
  }  
}


int ReleaseTexture(int iID)
{
  IDirect3DTexture8* pTexture;
  IDirect3DSurface8* pSurface;
  IDirect3DCubeTexture8* pCubeTexture;

  pTexture=GetTextureFromID(iID);
  if (pTexture)
  {
    pTexture->Release(); pTexture=0;    
  }
  else
  if (pCubeTexture = GetCubeMapFromID(iID))
  {
    pCubeTexture->Release(); pCubeTexture=0;    
  }
  else
  {
    pSurface=GetSurfaceFromID(iID);
    assert(pSurface);
    pSurface->Release(); pSurface=0;    
  }

  g_slTextureList.Delete(iID);
    
  return (0);
}

int                     CreateVertexBuffer      (UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool)
{
  ResourceVB VB;
  
  if (FAILED(SM_D3d::Device()->CreateVertexBuffer(Length, D3DUSAGE_WRITEONLY| Usage, FVF, Pool, &VB.pVertexBuffer)))
  {
    return (-1);
  }

  int iID;
  if ((iID=g_slVBList.InsertTail(VB))==-1)
  {
    VB.pVertexBuffer->Release();
    return (-1);
  }

  VB.uLength = Length;
  VB.uOffset = 0;
  
  return (iID);
}

// Index Buffer
int                     CreateIndexBuffer      (UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool)
{
  ResourceIB IB;
  
  if (FAILED(SM_D3d::Device()->CreateIndexBuffer(Length, Usage, Format, Pool, &IB.pIndexBuffer)))
  {
    return (-1);
  }

  int iID;
  if ((iID=g_slIBList.InsertTail(IB))==-1)
  {
    IB.pIndexBuffer->Release();
    return (-1);
  }

  return (iID);
}


int CreateDynamicVertexBuffer (UINT Length, DWORD FVF)
{
  ResourceVB VB;

  if (FAILED(SM_D3d::Device()->CreateVertexBuffer(
        Length, 
        D3DUSAGE_WRITEONLY| D3DUSAGE_DYNAMIC, 
        FVF, 
        D3DPOOL_DEFAULT, 
        &VB.pVertexBuffer)))
  {
    return (-1);
  }

  VB.uLength = Length;
  VB.uOffset = 0;


  int iID;
  if ((iID=g_slVBList.InsertTail(VB))==-1)
  {
    VB.pVertexBuffer->Release();
    return (-1);
  }
  return (iID);
}


int CreateDynamicIndexBuffer (UINT Length, DWORD FVF)
{
  ResourceIB IB;

  if (FAILED(SM_D3d::Device()->CreateIndexBuffer(
        Length, 
        D3DUSAGE_WRITEONLY| D3DUSAGE_DYNAMIC, 
        D3DFMT_INDEX16 , 
        D3DPOOL_DEFAULT, 
        &IB.pIndexBuffer)))
  {
    return (-1);
  }

  IB.uLength = Length;
  IB.uOffset = 0;


  int iID;
  if ((iID=g_slIBList.InsertTail(IB))==-1)
  {
    IB.pIndexBuffer->Release();
    return (-1);
  }

  

  return (iID);
}

// workaround for nvidia drivers... they screw up 
// dynamic buffers if you do overwrites on a new frame....
bool g_bNewFrame = true;
void                      NewFrame         ()
{
  g_bNewFrame = true;
}

int GiveIBChunk(int iID, unsigned uLength, void** ppData)
{
  ResourceIB* pResource;

  if (g_slIBList.Get(iID, pResource))
  {
    assert(!"Wrong ID");
    return (-1);
  }

  if (uLength > pResource->uLength)
  {
    assert(!"Requested more bytes than dynamic IB can hold");
    return (-1);
  }

  unsigned uFlags;
  if (g_bNewFrame || (pResource->uOffset+uLength > pResource->uLength))
  {
    pResource->uOffset = 0;
    uFlags  = D3DLOCK_DISCARD;        
    g_bNewFrame = false;
  }
  else
  {
    uFlags = D3DLOCK_NOOVERWRITE;    
  }

  if (FAILED(pResource->pIndexBuffer->Lock(pResource->uOffset, uLength, (unsigned char**) ppData, uFlags)))
  {
    return (-1);
  }

  int iReturn=pResource->uOffset;

  pResource->uOffset+=uLength;
  
  return (iReturn);
}

int                     DoneIBChunk                 (int iID)
{
  ResourceIB* pResource;

  if (g_slIBList.Get(iID, pResource))
  {
    assert(!"Wrong ID");
    return (-1);
  }

  return (FAILED(pResource->pIndexBuffer->Unlock())?-1:0);
}



int GiveVBChunk(int iID, unsigned uLength, void** ppData)
{
  ResourceVB* pResource;

  if (g_slVBList.Get(iID, pResource))
  {
    assert(!"Wrong ID");
    return (-1);
  }

  if (uLength > pResource->uLength)
  {
    SM_Main::OutputError("en VB dinamico no caben %i bytes. Probablemente el objeto tenga demasiados poligonos", uLength);
    assert(!"Requested more bytes than dynamic vb can hold");
    return (-1);
  }

  unsigned uFlags;
  if (g_bNewFrame || (pResource->uOffset+uLength > pResource->uLength))
  {

    

    pResource->uOffset = 0;
    uFlags  = D3DLOCK_DISCARD;        
    g_bNewFrame = false;
  }
  else
  {
    uFlags = D3DLOCK_NOOVERWRITE;    
  }

  if (FAILED(pResource->pVertexBuffer->Lock(pResource->uOffset, uLength, (unsigned char**) ppData, uFlags)))
  {
    return (-1);
  }

  int iReturn=pResource->uOffset;

  pResource->uOffset+=uLength;
  
  return (iReturn);
}

int                     DoneVBChunk                 (int iID)
{
  ResourceVB* pResource;

  if (g_slVBList.Get(iID, pResource))
  {
    assert(!"Wrong ID");
    return (-1);
  }

  return (FAILED(pResource->pVertexBuffer->Unlock())?-1:0);
}
  

int                     ReleaseVertexBuffer     (int iID)
{
  IDirect3DVertexBuffer8* pVB=GetVertexBufferFromID(iID);

  assert(pVB);
  pVB->Release(); pVB=0;

  g_slVBList.Delete(iID);

  return (0);
}


IDirect3DVertexBuffer8* GetVertexBufferFromID   (int iID)
{
  ResourceVB* pResource;

  if (g_slVBList.Get(iID, pResource))
  {
    return (0);
  }
  else
  {
    return (pResource->pVertexBuffer);
  }  
}

int                     ReleaseIndexBuffer     (int iID)
{
  IDirect3DIndexBuffer8* pIB=GetIndexBufferFromID(iID);

  assert(pIB);
  pIB->Release(); pIB=0;

  g_slIBList.Delete(iID);

  return (0);
}

IDirect3DIndexBuffer8* GetIndexBufferFromID   (int iID)
{
  ResourceIB* pResource;

  if (g_slIBList.Get(iID, pResource))
  {
    return (0);
  }
  else
  {
    return (pResource->pIndexBuffer);
  }  
}

unsigned GetVertexStreamSize()
{
  return (VERTEXSTREAMSIZE);
}

unsigned GetIndexStreamSize()
{
  return (INDEXSTREAMSIZE);
}








}


