/****************************************************************************\
*                                                                            *
*  ENGINE6.CPP - Source Code Module                                          *
*                                                                            *
*  (c)Copyright 2001 Indotek, LLC. All Rights Reserved.                      *
*                                                                            *
\****************************************************************************/

#include "internal.h"

BOOL R3D_STDCALL
r3d_Get3DModelMaterialCount(int lModelHandle, int *MaterialCount)
{
   if (lModelHandle < 0 || lModelHandle >= _r3d_ModelIndex)
   {
      _r3d_FormulateErrorString("r3d_Get3DModelMaterialCount", "Invalid Model Handle", DD_OK);
      return FALSE;
   }

   *MaterialCount = (int)_r3d_Model[lModelHandle].NumM;

   return TRUE;
}

BOOL R3D_STDCALL
r3d_Get3DModelMaterialHandle(int lModelHandle, int ModelMaterialOffset, int *hMaterial)
{
   _R3D_MATERIAL *pMat0;

   if (lModelHandle < 0 || lModelHandle >= _r3d_ModelIndex)
   {
      _r3d_FormulateErrorString("r3d_Get3DModelMaterialHandle", "Invalid Model Handle", DD_OK);
      return FALSE;
   }
   if (ModelMaterialOffset < 0 || ModelMaterialOffset >= _r3d_Model[lModelHandle].NumM)
   {
      _r3d_FormulateErrorString("r3d_Get3DModelMaterialHandle", "Invalid Model Material Offset (ModelMaterialOffset)", DD_OK);
      return FALSE;
   }

   pMat0 = &_r3d_Material[0];
   *hMaterial = (int)(_r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].m - pMat0);

   return TRUE;
}

BOOL R3D_STDCALL
r3d_Get3DModelMaterialGeometry(int lModelHandle, int ModelMaterialOffset, BOOL **bPreLit, unsigned long **VertexCount, D3DVERTEX **Vertex, unsigned long **TriangleCount, unsigned short **Triangle)
{
   if (lModelHandle < 0 || lModelHandle >= _r3d_ModelIndex)
   {
      _r3d_FormulateErrorString("r3d_Get3DModelMaterialGeometry", "Invalid Model Handle", DD_OK);
      return FALSE;
   }
   if (ModelMaterialOffset < 0 || ModelMaterialOffset >= _r3d_Model[lModelHandle].NumM)
   {
      _r3d_FormulateErrorString("r3d_Get3DModelMaterialGeometry", "Invalid Model Material Offset (ModelMaterialOffset)", DD_OK);
      return FALSE;
   }

   if (bPreLit != NULL)
      *bPreLit = &_r3d_Model[lModelHandle].bPreLight;
   if (VertexCount != NULL)
      *VertexCount = &_r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].NumV;
   if (Vertex != NULL)
      *Vertex = _r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].v;
   if (TriangleCount != NULL)
      *TriangleCount = &_r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].NumT;
   if (Triangle != NULL)
      *Triangle = _r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].t;

   return TRUE;
}

BOOL R3D_STDCALL
r3d_TextureAnimateSwap(int lModelHandle, int ModelMaterialOffset, int hMaterial)
{
   if (lModelHandle < 0 || lModelHandle >= _r3d_ModelIndex)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSwap", "Invalid Model Handle", DD_OK);
      return FALSE;
   }
   if (ModelMaterialOffset < 0 || ModelMaterialOffset >= _r3d_Model[lModelHandle].NumM)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSwap", "Invalid Model Material Offset (ModelMaterialOffset)", DD_OK);
      return FALSE;
   }
   if (hMaterial < 0 || hMaterial >= _r3d_MaterialIndex)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSwap", "Invalid Material Handle (hMaterial)", DD_OK);
      return FALSE;
   }

   _r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].m = &_r3d_Material[hMaterial];

   return TRUE;
}

BOOL R3D_STDCALL
r3d_TextureAnimateScroll(int lModelHandle, int ModelMaterialOffset, float fOffset_tu, float fOffset_tv)
{
   int LoopVar;
   static float fTotalOffsetTu = 0.0F;
   static float fTotalOffsetTv = 0.0F;

   if (lModelHandle < 0 || lModelHandle >= _r3d_ModelIndex)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateScroll", "Invalid Model Handle", DD_OK);
      return FALSE;
   }
   if (ModelMaterialOffset < 0 || ModelMaterialOffset >= _r3d_Model[lModelHandle].NumM)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateScroll", "Invalid Model Material Offset", DD_OK);
      return FALSE;
   }

   for (LoopVar = 0;LoopVar < (int)_r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].NumV;LoopVar++)
   {
      (_r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].v + LoopVar)->tu += fOffset_tu;
      (_r3d_ModelComponent[_r3d_Model[lModelHandle].MCStartIndex + ModelMaterialOffset].v + LoopVar)->tv += fOffset_tv;
   }

   return TRUE;
}

BOOL R3D_STDCALL
r3d_TextureAnimateSurfaceLock(int hMaterial, int *WidthHeight, int *TextureFormat, unsigned char **SurfacePointer, int *SurfacePitch)
{
   DDSURFACEDESC2 ddsd;

   if (hMaterial < 0 || hMaterial >= _r3d_MaterialIndex)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSurfaceLock", "Invalid Material Handle", DD_OK);
      return FALSE;
   }

   if (_r3d_Material[hMaterial].bDuplicate == TRUE)
   {
      // We simply create a reference.
      hMaterial = _r3d_Material[hMaterial].DuplicateIndex;
   }

   if (_r3d_Material[hMaterial].bTexture == FALSE)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSurfaceLock", "No texture in material!", DD_OK);
      return FALSE;
   }

   if (_r3d_Material[hMaterial].bMipMap == TRUE)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSurfaceLock", "Not allowed to lock mip-map texture surfaces!", DD_OK);
      return FALSE;
   }

   // #define _R3D_TEXTUREFORMAT_565	0
   // #define _R3D_TEXTUREFORMAT_1555	1
   // #define _R3D_TEXTUREFORMAT_4444	2
   // #define _R3D_TEXTUREFORMAT_8888	3
   if (_r3d_Material[hMaterial].bAlpha == TRUE)
      *TextureFormat = _r3d_TranslucentTextureFormat;
   else
      *TextureFormat = _r3d_SolidTextureFormat;

   *WidthHeight = _r3d_Material[hMaterial].ddsd.dwWidth;

   memset(&ddsd, 0, sizeof(ddsd));
   ddsd.dwSize = sizeof(ddsd);
   ddsd.dwFlags = DDSD_PITCH;
   _r3d_Material[hMaterial].lpSystemTextureSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
   *SurfacePointer = (unsigned char *)ddsd.lpSurface;
   *SurfacePitch = (int)ddsd.lPitch;

#ifdef EVALUATIONVERSION
   // Save this for redrawing that black plus sign later
   _r3d_ta[hMaterial] = *WidthHeight;
   _r3d_tb[hMaterial] = *TextureFormat;
   _r3d_tc[hMaterial] = (unsigned char *)ddsd.lpSurface;
   _r3d_td[hMaterial] = *SurfacePitch;
#endif

   return TRUE;
}

BOOL R3D_STDCALL
r3d_TextureAnimateSurfaceUnlock(int hMaterial)
{
   if (hMaterial < 0 || hMaterial >= _r3d_MaterialIndex)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSurfaceUnlock", "Invalid Material Handle", DD_OK);
      return FALSE;
   }

   if (_r3d_Material[hMaterial].bDuplicate == TRUE)
   {
      // We simply create a reference.
      hMaterial = _r3d_Material[hMaterial].DuplicateIndex;
   }

   if (_r3d_Material[hMaterial].bTexture == FALSE)
   {
      _r3d_FormulateErrorString("r3d_TextureAnimateSurfaceUnlock", "No texture in material!", DD_OK);
      return FALSE;
   }

#ifdef EVALUATIONVERSION
   // Redraw horizontal and vertical lines
   int x, y, x01, y01, x02, y02;
   // Horizontal lines
   y01 = _r3d_ta[hMaterial] / 3;
   y02 = y01 * 2;
   for (x = 0;x < _r3d_ta[hMaterial];x++)
   {
      if (_r3d_tb[hMaterial] == 0)
         r3d_TextureAnimateSurfaceTexel0(_r3d_tc[hMaterial], _r3d_td[hMaterial], x, y01, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 1)
         r3d_TextureAnimateSurfaceTexel1(_r3d_tc[hMaterial], _r3d_td[hMaterial], x, y01, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 2)
         r3d_TextureAnimateSurfaceTexel2(_r3d_tc[hMaterial], _r3d_td[hMaterial], x, y01, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 3)
         r3d_TextureAnimateSurfaceTexel3(_r3d_tc[hMaterial], _r3d_td[hMaterial], x, y02, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 4)
         r3d_TextureAnimateSurfaceTexel4(_r3d_tc[hMaterial], _r3d_td[hMaterial], x, y02, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 5)
         r3d_TextureAnimateSurfaceTexel5(_r3d_tc[hMaterial], _r3d_td[hMaterial], x, y02, 0, 0, 0, 0);
   }
   // Vertical lines
   x01 = _r3d_ta[hMaterial] / 3;
   x02 = x01 * 2;
   for (y = 0;y < _r3d_ta[hMaterial];y++)
   {
      if (_r3d_tb[hMaterial] == 0)
         r3d_TextureAnimateSurfaceTexel0(_r3d_tc[hMaterial], _r3d_td[hMaterial], x01, y, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 1)
         r3d_TextureAnimateSurfaceTexel1(_r3d_tc[hMaterial], _r3d_td[hMaterial], x01, y, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 2)
         r3d_TextureAnimateSurfaceTexel2(_r3d_tc[hMaterial], _r3d_td[hMaterial], x01, y, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 3)
         r3d_TextureAnimateSurfaceTexel3(_r3d_tc[hMaterial], _r3d_td[hMaterial], x02, y, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 4)
         r3d_TextureAnimateSurfaceTexel4(_r3d_tc[hMaterial], _r3d_td[hMaterial], x02, y, 0, 0, 0, 0);
      if (_r3d_tb[hMaterial] == 5)
         r3d_TextureAnimateSurfaceTexel5(_r3d_tc[hMaterial], _r3d_td[hMaterial], x02, y, 0, 0, 0, 0);
   }
#endif

   // Unlock Surface, Set the Flag, and Exit
   _r3d_Material[hMaterial].lpSystemTextureSurface->Unlock(NULL);
   //_r3d_Material[hMaterial].bInVideo=FALSE;

   return TRUE;
}

BOOL R3D_STDCALL
r3d_TextureAnimateSurfaceBlit(int hSrc, int WidthHeight, int TextureFormat, unsigned char *SurfacePointer, int SurfacePitch, int SrcMinx, int SrcMaxx, int SrcMiny, int SrcMaxy, int DstMinx, int DstMaxx, int DstMiny, int DstMaxy)
{
   unsigned long x, y, SrcY, LookUp;
   BOOL bScale;
   unsigned char *SrcRGBA;
   unsigned long DstW, DstH, SrcW, SrcH;
   unsigned long HRatio, WRatio;

   if (_r3d_bSurfaceDoesNotExist[hSrc] == TRUE)
   {
      _r3d_FormulateErrorString("r3d_2DBlit", "Invalid Surface Handle", DD_OK);
      return FALSE;
   }

   _R3D_BLITCLIP((int)(_r3d_Surface[hSrc]->dwWidth), (int)(_r3d_Surface[hSrc]->dwHeight), (int)(WidthHeight), (int)(WidthHeight), SrcMinx, SrcMaxx, SrcMiny, SrcMaxy, DstMinx, DstMaxx, DstMiny, DstMaxy);

   // Determine Scale Size
   DstW = (DstMaxx - DstMinx) + 1;
   DstH = (DstMaxy - DstMiny) + 1;
   SrcW = (SrcMaxx - SrcMinx) + 1;
   SrcH = (SrcMaxy - SrcMiny) + 1;
   if (DstW == SrcW && DstH == SrcH)
   {
      bScale = FALSE;
   }
   else
   {
      bScale = TRUE;
      WRatio = (SrcW << 16) / DstW;
      HRatio = (SrcH << 16) / DstH;
   }

   // Let's build the scanline lookup table
   //
   if (bScale == TRUE)
   {
      for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         _r3d_ScanLineLookUpTable[x - DstMinx] = (((((x - DstMinx) * WRatio) >> 16) + SrcMinx) << 2);
   }
   else
   {
      // We could actually create a pre built table when we initialize R3D
      for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         _r3d_ScanLineLookUpTable[x - DstMinx] = (((x - DstMinx) + SrcMinx) << 2);
   }

   // Blit it
   SrcRGBA = (unsigned char *)r3d_SurfaceGet(hSrc);
   switch (TextureFormat)
   {
   case 0:
      for (y = (unsigned long)DstMiny;y <= (unsigned long)DstMaxy;y++)
      {
         if (bScale == TRUE)
            SrcY = ((((y - DstMiny) * HRatio) >> 16) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         else
            SrcY = ((y - DstMiny) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         {
            LookUp = SrcY + _r3d_ScanLineLookUpTable[x - DstMinx];
            r3d_TextureAnimateSurfaceTexel0(SurfacePointer, SurfacePitch, x, y, SrcRGBA[LookUp+3], SrcRGBA[LookUp], SrcRGBA[LookUp+1], SrcRGBA[LookUp+2]);
         }
      }
      break;
   case 1:
      for (y = (unsigned long)DstMiny;y <= (unsigned long)DstMaxy;y++)
      {
         if (bScale == TRUE)
            SrcY = ((((y - DstMiny) * HRatio) >> 16) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         else
            SrcY = ((y - DstMiny) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         {
            LookUp = SrcY + _r3d_ScanLineLookUpTable[x - DstMinx];
            r3d_TextureAnimateSurfaceTexel1(SurfacePointer, SurfacePitch, x, y, SrcRGBA[LookUp+3], SrcRGBA[LookUp], SrcRGBA[LookUp+1], SrcRGBA[LookUp+2]);
         }
      }
      break;
   case 2:
      for (y = (unsigned long)DstMiny;y <= (unsigned long)DstMaxy;y++)
      {
         if (bScale == TRUE)
            SrcY = ((((y - DstMiny) * HRatio) >> 16) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         else
            SrcY = ((y - DstMiny) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         {
            LookUp = SrcY + _r3d_ScanLineLookUpTable[x - DstMinx];
            r3d_TextureAnimateSurfaceTexel2(SurfacePointer, SurfacePitch, x, y, SrcRGBA[LookUp+3], SrcRGBA[LookUp], SrcRGBA[LookUp+1], SrcRGBA[LookUp+2]);
         }
      }
      break;
   case 3:
      for (y = (unsigned long)DstMiny;y <= (unsigned long)DstMaxy;y++)
      {
         if (bScale == TRUE)
            SrcY = ((((y - DstMiny) * HRatio) >> 16) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         else
            SrcY = ((y - DstMiny) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         {
            LookUp = SrcY + _r3d_ScanLineLookUpTable[x - DstMinx];
            r3d_TextureAnimateSurfaceTexel3(SurfacePointer, SurfacePitch, x, y, SrcRGBA[LookUp+3], SrcRGBA[LookUp], SrcRGBA[LookUp+1], SrcRGBA[LookUp+2]);
         }
      }
      break;
   case 4:
      for (y = (unsigned long)DstMiny;y <= (unsigned long)DstMaxy;y++)
      {
         if (bScale == TRUE)
            SrcY = ((((y - DstMiny) * HRatio) >> 16) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         else
            SrcY = ((y - DstMiny) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         {
            LookUp = SrcY + _r3d_ScanLineLookUpTable[x - DstMinx];
            r3d_TextureAnimateSurfaceTexel4(SurfacePointer, SurfacePitch, x, y, SrcRGBA[LookUp+3], SrcRGBA[LookUp], SrcRGBA[LookUp+1], SrcRGBA[LookUp+2]);
         }
      }
      break;
   case 5:
      for (y = (unsigned long)DstMiny;y <= (unsigned long)DstMaxy;y++)
      {
         if (bScale == TRUE)
            SrcY = ((((y - DstMiny) * HRatio) >> 16) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         else
            SrcY = ((y - DstMiny) + SrcMiny) * (_r3d_Surface[hSrc]->dwWidth << 2);
         for (x = (unsigned long)DstMinx;x <= (unsigned long)DstMaxx;x++)
         {
            LookUp = SrcY + _r3d_ScanLineLookUpTable[x - DstMinx];
            r3d_TextureAnimateSurfaceTexel5(SurfacePointer, SurfacePitch, x, y, SrcRGBA[LookUp+3], SrcRGBA[LookUp], SrcRGBA[LookUp+1], SrcRGBA[LookUp+2]);
         }
      }
      break;
   }

   return TRUE;
}

void R3D_STDCALL
r3d_ForceAlphaRendering(BOOL bEnable)
{
   gbForceAlpha = bEnable;
}