// Draw all tiles that are in lowest lod
static void RenderBatchedTiles(void)
{
  // Set texture wrapping
  gfxSetTextureWrapping(GFX_CLAMP,GFX_CLAMP);
  // Use terrains global top map as texture
  _ptrTerrain->tr_tdTopMap.SetAsCurrent();

  GFXVertex4  *pavVertices     = &_avDelayedVertices[0];
  GFXTexCoord *pauvTexCoords   = &_auvDelayedTexCoords[0];
  GFXTexCoord *pauvShadowMapTC = &_auvDelayedShadowMapTC[0];
  INDEX       *paiIndices      = &_aiDelayedIndices[0];
  INDEX        ctVertices      = _avDelayedVertices.Count();
  INDEX        ctIndices       = _aiDelayedIndices.Count();

  // Prepare white color array
  FillConstColorArray(ctVertices);
  GFXColor    *pacolColors     = &_acolVtxConstColors[0];

  gfxEnableAlphaTest();
  gfxDisableBlend();
  gfxSetVertexArray(pavVertices,ctVertices);
  gfxSetTexCoordArray(pauvTexCoords, FALSE);
  gfxSetColorArray(pacolColors);
  gfxLockArrays();
  gfxDrawElements(ctIndices,paiIndices);
  gfxDisableAlphaTest();
  _ctTris +=ctIndices/2;

  // if shadows are visible
  if(_wrpWorldRenderPrefs.wrp_shtShadows!=CWorldRenderPrefs::SHT_NONE) {
    gfxDepthFunc(GFX_EQUAL);

    gfxBlendFunc(GFX_DST_COLOR,GFX_SRC_COLOR);
    gfxEnableBlend();
    gfxSetTexCoordArray(pauvShadowMapTC, FALSE);
    _ptrTerrain->tr_tdShadowMap.SetAsCurrent();
    gfxDrawElements(ctIndices,paiIndices);
    gfxDepthFunc(GFX_LESS_EQUAL);
  }

  if(_ptrTerrain->GetFlags()&TR_HAS_FOG) {
    RenderFogLayer(-1);
  }
  if(_ptrTerrain->GetFlags()&TR_HAS_HAZE) {
    RenderHazeLayer(-1);
  }
  gfxUnlockArrays();

  // Popall delayed arrays 
  _avDelayedVertices.PopAll();
  _auvDelayedTexCoords.PopAll();
  _auvDelayedShadowMapTC.PopAll();
  _aiDelayedIndices.PopAll();
}
static void RenderHazeLayer(INDEX itt)
{
  FLOAT3D vObjPosition = _ptrTerrain->tr_penEntity->en_plPlacement.pl_PositionVector;

  _fHazeAdd  = -_haze_hp.hp_fNear;
  _fHazeAdd += _vViewer(1) * (vObjPosition(1) - _aprProjection->pr_vViewerPosition(1));
  _fHazeAdd += _vViewer(2) * (vObjPosition(2) - _aprProjection->pr_vViewerPosition(2));
  _fHazeAdd += _vViewer(3) * (vObjPosition(3) - _aprProjection->pr_vViewerPosition(3));

  GFXVertex *pvVtx;
  INDEX     *piIndices;
  INDEX ctVertices;
  INDEX ctIndices;
  // if this is tile 
  if(itt>=0) {
    CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
    pvVtx      = &tt.GetVertices()[0];
    piIndices  = &tt.GetIndices()[0];
    ctVertices = tt.GetVertices().Count();
    ctIndices  = tt.GetIndices().Count();
  // else this are batched tiles
  } else {
    pvVtx      = &_avDelayedVertices[0];
    piIndices  = &_aiDelayedIndices[0];
    ctVertices = _avDelayedVertices.Count();
    ctIndices  = _aiDelayedIndices.Count();
  }

  GFXTexCoord *pfHazeTC  = _atcHaze.Push(ctVertices);
  GFXColor    *pcolHaze  = _acolHaze.Push(ctVertices);

  const COLOR colH = AdjustColor( _haze_hp.hp_colColor, _slTexHueShift, _slTexSaturation);
  GFXColor colHaze(colH);
  // for each vertex in tile
  for(INDEX ivx=0;ivx<ctVertices;ivx++) {
    GetHazeMapInVertex(pvVtx[ivx],pfHazeTC[ivx]);
    pcolHaze[ivx] = colHaze;
  }

  // render haze layer
  gfxDepthFunc(GFX_EQUAL);
  gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
  gfxSetTexture( _haze_ulTexture, _haze_tpLocal);
  gfxSetTexCoordArray(pfHazeTC, FALSE);
  gfxSetColorArray(pcolHaze);
  gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA);
  gfxEnableBlend();
  gfxDrawElements(ctIndices,piIndices);
  gfxDepthFunc(GFX_LESS_EQUAL);

  _atcHaze.PopAll();
  _acolHaze.PopAll();
}
Beispiel #3
0
// Get empty color array for modifying
GFXColor *shaGetNewColorArray(void)
{
  ASSERT(_ctVertices!=0);
  _acolVtxModifyColors.PopAll();
  _acolVtxModifyColors.Push(_ctVertices);
  return &_acolVtxModifyColors[0];
}
Beispiel #4
0
// Get empty texcoords array for modifying
GFXTexCoord *shaGetNewTexCoordArray(void)
{
  ASSERT(_ctVertices!=0);
  _uvUVMapForModify.PopAll();
  _uvUVMapForModify.Push(_ctVertices);
  return &_uvUVMapForModify[0];
}
Beispiel #5
0
// Get empty vertex array for modifying
GFXVertex *shaGetNewVertexArray(void)
{
  ASSERT(_ctVertices!=0);
  _vModifyVertices.PopAll();
  _vModifyVertices.Push(_ctVertices);
  return &_vModifyVertices[0];
}
Beispiel #6
0
// make array of entity offsets in a block
void MakeInfos(CStaticStackArray<EntityBlockInfo> &aebi, 
               UBYTE *pubBlock, SLONG slSize, UBYTE *pubFirst, UBYTE *&pubEnd)
{
  // clear all offsets
  aebi.PopAll();

  // until end of block
  UBYTE *pub = pubFirst;
  while (pub<pubBlock+slSize) {
    // if no more entities
    if (*(ULONG*)pub != ENT4) {
      pubEnd = pub;
      // stop
      return;
    }
    // remember it
    EntityBlockInfo &ebi = aebi.Push();
    ebi.ebi_slOffset = pub-pubBlock;
    pub+=sizeof(ULONG);

    // get id and size
    ULONG ulID = *(ULONG*)pub;
    ebi.ebi_ulID     = ulID;
    pub+=sizeof(ULONG);

    SLONG slSizeChunk = *(SLONG*)pub;
    pub+=sizeof(ULONG);
    ebi.ebi_slSize   = slSizeChunk+sizeof(SLONG)*3;

    pub+=slSizeChunk;
  }
}
Beispiel #7
0
// turn credits on
void Credits_On(INDEX iType)
{
  if (_bCreditsOn) {
    Credits_Off();
  }

  _astrCredits.PopAll();
  
  if (iType==1) {
    _fSpeed = 1.0f;
    LoadOneFile(CTFILENAME("Data\\Intro.txt"));
  } else if (iType==2) {
    _fSpeed = 2.0f;
    LoadOneFile(CTFILENAME("Data\\Credits.txt"));
    LoadOneFile(CTFILENAME("Data\\Credits_End.txt"));
  } else {
    _fSpeed = 2.0f;
#if _SE_DEMO || TECHTESTONLY
    LoadOneFile(CTFILENAME("Data\\Credits_Demo.txt"));
#else
    LoadOneFile(CTFILENAME("Data\\Credits.txt"));
#endif
  }
  // if some file was loaded
  if (_bCreditsOn) {
    // remember start time
    if (iType==1 || iType==2) {
      _bUseRealTime = FALSE;
      _tmStart = _pTimer->GetLerpedCurrentTick();
    } else {
      _bUseRealTime = TRUE;
      _tvStart = _pTimer->GetHighPrecisionTimer();
    }
  }
}
void CCastRay::ClearSectorList(void)
{
  // for each active sector
  for(INDEX ias=0; ias<_aas.Count(); ias++) {
    // mark it as inactive
    _aas[ias].as_pbsc->bsc_ulFlags&=~BSCF_RAYTESTED;
  }
  _aas.PopAll();
}
static void FillConstColorArray(INDEX ctVertices)
{
  INDEX ctColors=_acolVtxConstColors.Count();
  _acolVtxConstColors.PopAll();
  _acolVtxConstColors.Push(ctVertices);
  // if requested array is larger then existing one
  if(ctVertices>ctColors) {
    memset(&_acolVtxConstColors[ctColors],255,(ctVertices-ctColors)*sizeof(GFXColor));
  }
}
Beispiel #10
0
// Clean all values
void shaClean(void)
{
  _ctVertices   = -1;
  _ctIndices    = -1;
  _ctColors     = -1;
  _ctTextures   = -1;
  _ctUVMaps     = -1;
  _ctLights     = -1;

  _colConstant   = 0;
  _ulFlags       = 0;

  _pShader        = NULL;
  _paVertices     = NULL;
  _paNormals      = NULL;
  _paIndices      = NULL;
  _paUVMaps       = NULL;
  _paTextures     = NULL;
  _paColors       = NULL;
  _paFloats       = NULL;
  _pCurrentUVMap  = NULL;
  _pcolVtxColors  = NULL;

  _paFogUVMap     = NULL;
  _paHazeUVMap    = NULL;
  _pacolVtxHaze   = NULL;
  _pmObjToView    = NULL;
  _pmObjToAbs     = NULL;
  _paprProjection = NULL;

  _acolVtxColors.PopAll();
  _acolVtxModifyColors.PopAll();
  _vModifyVertices.PopAll();
  _uvUVMapForModify.PopAll();
  shaCullFace(GFX_BACK);
}
// check all delayed depth points
extern void CheckDelayedDepthPoints( const CDrawPort *pdp, INDEX iMirrorLevel/*=0*/)
{
  // skip if not delayed or mirror level is to high
  gap_iOptimizeDepthReads = Clamp( gap_iOptimizeDepthReads, 0L, 2L);
  if( gap_iOptimizeDepthReads==0 || iMirrorLevel>7) return; 
  ASSERT( pdp!=NULL && iMirrorLevel>=0);

  // check only if time lapse allows
  const CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  const TIME tmDelta = (tvNow-_tvLast[iMirrorLevel]).GetSeconds();
  ASSERT( tmDelta>=0);
  if( gap_iOptimizeDepthReads==2 && tmDelta<0.1f) return;

  // prepare
  _tvLast[iMirrorLevel] = tvNow;
  INDEX ctPoints = _adiDelayed.Count();
  if( ctPoints==0) return; // done if no points in queue

  // for each point
  INDEX iPoint = 0;
  while( iPoint<ctPoints) {
    DepthInfo &di = _adiDelayed[iPoint];
    // if the point is not active any more
    if( iMirrorLevel==di.di_iMirrorLevel && di.di_iSwapLastRequest<_iCheckIteration-KEEP_BEHIND) {
      // delete it by moving the last one on its place
      di = _adiDelayed[ctPoints-1];
      ctPoints--;
    // if the point is still active
    } else {
      // go to next point
      iPoint++;
    }
  }

  // remove unused points at the end
  if( ctPoints==0) _adiDelayed.PopAll();
  else _adiDelayed.PopUntil(ctPoints-1);

  // ignore stalls
  if( tmDelta>1.0f) return;

  // check and update visibility of what has left
  ASSERT( ctPoints == _adiDelayed.Count());
  if( ctPoints>0) UpdateDepthPointsVisibility( pdp, iMirrorLevel, &_adiDelayed[0], ctPoints);

  // mark checking
  _iCheckIteration++;
}
Beispiel #12
0
// Calculate lightning for given model
void shaCalculateLightForSpecular(void)
{
  ASSERT(_paNormals!=NULL);
  _acolVtxColors.PopAll();
  _acolVtxColors.Push(_ctVertices);

  GFXColor colModel   = (GFXColor)_colModel;   // Model color
  GFXColor &colAmbient = (GFXColor)_colAmbient; // Ambient color
  GFXColor &colLight   = (GFXColor)_colLight;   // Light color
  GFXColor &colSurface = (GFXColor)_colConstant; // shader color

  // colModel = MulColors(colModel.r,colSurface.abgr);
  colModel.MultiplyRGBA(colModel,colSurface);

  UBYTE ubColShift = 8;
  SLONG slar = colAmbient.r;
  SLONG slag = colAmbient.g;
  SLONG slab = colAmbient.b;

  if(shaOverBrightningEnabled()) {
    slar = ClampUp(slar,127L);
    slag = ClampUp(slag,127L);
    slab = ClampUp(slab,127L);
    ubColShift = 8;
  } else {
    slar*=2;
    slag*=2;
    slab*=2;
    ubColShift = 7;
  }

  // for each vertex color
  for(INDEX ivx=0;ivx<_ctVertices;ivx++) {
    // calculate vertex light
    FLOAT3D &vNorm = FLOAT3D(_paNormals[ivx].nx,_paNormals[ivx].ny,_paNormals[ivx].nz);
    FLOAT fDot = vNorm % _vLightDir;
    fDot = Clamp(fDot,0.0f,1.0f);
    SLONG slDot = NormFloatToByte(fDot);

    _acolVtxColors[ivx].r = ClampUp(colModel.r * (slar + ((colLight.r * slDot)>>ubColShift))>>8,255L);
    _acolVtxColors[ivx].g = ClampUp(colModel.g * (slag + ((colLight.g * slDot)>>ubColShift))>>8,255L);
    _acolVtxColors[ivx].b = ClampUp(colModel.b * (slab + ((colLight.b * slDot)>>ubColShift))>>8,255L);
    _acolVtxColors[ivx].a = slDot;//colModel.a;//slDot;
  }
  // Set current wertex array 
  _pcolVtxColors = &_acolVtxColors[0];
}
Beispiel #13
0
CRenderModel::~CRenderModel(void)
{
  if( !(rm_ulFlags&RMF_ATTACHMENT)) _armRenderModels.PopAll();
}
void PrepareSmothVertices(INDEX itt)
{
  CTerrainTile &tt  = _ptrTerrain->tr_attTiles[itt];
  const INDEX ctVertices = tt.GetVertices().Count();
  const FLOAT &fLerpFactor = tt.tt_fLodLerpFactor;

  // Allocate memory for all vertices
  _avLerpedVerices.PopAll();
  _avLerpedVerices.Push(ctVertices);
  
  // Get pointers to src and dst vertex arrays
  GFXVertex *pavSrcFirst = &tt.GetVertices()[0];
  GFXVertex *pavDstFirst = &_avLerpedVerices[0];
  GFXVertex *pavSrc = &pavSrcFirst[0];
  GFXVertex *pavDst = &pavDstFirst[0];

  INDEX iFacing=0;
  // for each vertex column
  for(INDEX iy=0;iy<tt.tt_ctLodVtxY;iy++) {
    // for each vertex in row in even column step by 2
    for(INDEX ix=0;ix<tt.tt_ctLodVtxX-2;ix+=2) {
      // Copy first vertex
      pavDst[0] = pavSrc[0];
      // Second vertex is lerped between left and right vertices
      Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
      // Increment vertex pointers
      pavDst+=2;
      pavSrc+=2;
    }
    // Copy last vertex in row
    pavDst[0] = pavSrc[0];
   
    // Increment vertex pointers and go to odd column 
    pavDst++;
    pavSrc++;
    iy++;

    // if this is not last row
    if(iy<tt.tt_ctLodVtxY) {
      // for each vertex in row in odd column step by 2
      for(INDEX ix=0;ix<tt.tt_ctLodVtxX-2;ix+=2) {
        // First vertex is lerped between top and bottom vertices
        Lerp(pavDst[0],pavSrc[0],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX],fLerpFactor);
        // is this odd vertex in row
        #pragma message(">> Fix this")
        if(((ix+iy)/2)%2) {
        // if(iFacing&1)
          // Second vertex (diagonal one) is lerped between topright and bottom left vertices
          Lerp(pavDst[1],pavSrc[1],pavSrc[-tt.tt_ctLodVtxX+2],pavSrc[tt.tt_ctLodVtxX],fLerpFactor);
        } else {
          // Second vertex (diagonal one) is lerped between topleft and bottom right vertices
          Lerp(pavDst[1],pavSrc[1],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX+2],fLerpFactor);
        }
        iFacing++;
        // Increment vertex pointers
        pavDst+=2;
        pavSrc+=2;
      }
      // Last vertex in row is lerped between top and bottom vertices (same as first in row)
      Lerp(pavDst[0],pavSrc[0],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX],fLerpFactor);
    }
    // Increment vertex pointers
    pavDst++;
    pavSrc++;
  }

  pavDst--;
  pavSrc--;
/*
  // Copy border vertices
  GFXVertex *pvBorderDst = pavDst;
  GFXVertex *pvBorderSrc = pavSrc;

  for(INDEX ivx=tt.tt_ctNonBorderVertices;ivx<ctVertices;ivx++) {
    //*pavDst++ = *pavSrc++;
    pvBorderDst[0] = pvBorderSrc[0];
    pvBorderDst++;
    pvBorderSrc++;
  }
*/
  // Lerp top border vertices
  const INDEX &iTopNeigbour = tt.tt_aiNeighbours[NB_TOP];
  // if top neighbour exists
  if(iTopNeigbour>=0) {
    CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopNeigbour];
    const FLOAT &fLerpFactor = ttTop.tt_fLodLerpFactor;
    // Get source vertex pointer in top neighbour (vertex in bottom left corner of top neighbour)
    const INDEX iSrcVtx = ttTop.tt_ctLodVtxX * (ttTop.tt_ctLodVtxY-1);
    GFXVertex *pavSrc = &ttTop.GetVertices()[iSrcVtx];
    // Calculate num of vertices that needs to be lerped
    const INDEX ctLerps = (ttTop.tt_ctLodVtxX-1)/2;

    // is top tile in same lod as this tile and has smaller or equal lerp factor
    if(tt.tt_iLod==ttTop.tt_iLod && fLerpFactor<=tt.tt_fLodLerpFactor) {
      // Get destination vertex pointer in this tile (first vertex in top left corner of this tile - first vertex in array)
      const INDEX iDstVtx = 0;
      GFXVertex *pavDst = &pavDstFirst[iDstVtx];

      // for each vertex in bottom row of top tile that needs to be lerped
      for(INDEX ivx=0;ivx<ctLerps;ivx++) {
        // First vertex is same as in top tile
        pavDst[0] = pavSrc[0];
        // Second vertex is lerped between left and right vertices
        Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
        pavDst+=2;
        pavSrc+=2;
      }
    // is top tile in higher lod
    } else if(tt.tt_iLod>ttTop.tt_iLod) {
      const INDEX iVtxDiff = (ttTop.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
      // Get destination vertex pointer to copy vertices from top neighbour (first vertex in top left corner of this tile - first vertex in array)
      // Get destination vertex pointer to lerp vertices from top neighbour (first vertex added as additional top border vertex)
      const INDEX iDstCopyVtx = 0;
      const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_TOP];
      GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
      GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];

      // if diference is in one lod
      if(iVtxDiff==2) {
        // for each vertex in bottom row of top tile that needs to be lerped
        for(INDEX ivx=0;ivx<ctLerps;ivx++) {
          // Copy src vertex in normal dst vertex array
          pavDstCopy[0] = pavSrc[0];
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
          pavDstLerp++;
          pavDstCopy++;
          pavSrc+=2;
        }
      // diference is more than one lod
      } else {
        INDEX ctbv = tt.tt_ctBorderVertices[NB_TOP];
        INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex 
        // for each border vertex
        for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
          // if this border vertex is not last in quad
          if(ivxInQuad!=iVtxDiff) {
            // Copy second border vertex
            pavDstLerp[1] = pavSrc[2];
            pavDstLerp+=2;
            ivxInQuad+=2;
          // this is last border vertex
          } else {
            // Copy second non border vertex
            pavDstCopy[1] = pavSrc[2];
            pavDstCopy++;
            // since this wasn't border vertex, fix border vertex loop counter
            ctbv++;
            pavDstLerp++;
            ivxInQuad=2;
          }
          pavSrc+=2;
        }
      }
    }
  }

  // Lerp bottom border vertices
  const INDEX &iBottomNeigbour = tt.tt_aiNeighbours[NB_BOTTOM];
  // if bottom neighbour exists
  if(iBottomNeigbour>=0) {
    CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomNeigbour];
    const FLOAT &fLerpFactor = ttBottom.tt_fLodLerpFactor;
    // Get source vertex pointer in bottom neighbour (vertex in top left corner of bottom neighbour - first vertex in array) 
    const INDEX iSrcVtx = 0;
    GFXVertex *pavSrc = &ttBottom.GetVertices()[iSrcVtx];
    // Calculate num of vertices that needs to be lerped
    const INDEX ctLerps = (ttBottom.tt_ctLodVtxX-1)/2;

    // is bottom tile in same lod as this tile and has smaller lerp factor
    if(tt.tt_iLod==ttBottom.tt_iLod && fLerpFactor<tt.tt_fLodLerpFactor) {
      // Get destination vertex pointer in this tile (first vertex in bottom left corner of this tile)
      const INDEX iDstVtx = tt.tt_ctLodVtxX * (tt.tt_ctLodVtxY-1);
      GFXVertex *pavDst = &pavDstFirst[iDstVtx];

      // for each vertex in top row of bottom tile that needs to be lerped
      for(INDEX ivx=0;ivx<ctLerps;ivx++) {
        // First vertex is same as in bottom tile
        pavDst[0] = pavSrc[0];
        // Second vertex is lerped between left and right vertices
        Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
        pavDst+=2;
        pavSrc+=2;
      }
    // is bottom tile in higher lod
    } else if(tt.tt_iLod>ttBottom.tt_iLod) {
      const INDEX iVtxDiff = (ttBottom.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
      // Get destination vertex pointer to copy vertices from bottom neighbour (first vertex in bottom left corner of this tile)
      // Get destination vertex pointer to lerp vertices from bottom neighbour (first vertex added as additional bottom border vertex)
      const INDEX iDstCopyVtx = tt.tt_ctLodVtxX * (tt.tt_ctLodVtxY-1);
      const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_BOTTOM];
      GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
      GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];

      // if diference is in one lod
      if(iVtxDiff==2) {
        // for each vertex in top row of bottom tile that needs to be lerped
        for(INDEX ivx=0;ivx<ctLerps;ivx++) {
          // Copy src vertex in normal dst vertex array
          pavDstCopy[0] = pavSrc[0];
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
          pavDstLerp++;
          pavDstCopy++;
          pavSrc+=2;
        }
      // diference is more than one lod
      } else {
        INDEX ctbv = tt.tt_ctBorderVertices[NB_BOTTOM];
        INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex 
        // for each border vertex
        for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
          // if this border vertex is not last in quad
          if(ivxInQuad!=iVtxDiff) {
            // Copy second border vertex
            pavDstLerp[1] = pavSrc[2];
            pavDstLerp+=2;
            ivxInQuad+=2;
          // this is last border vertex
          } else {
            // Copy second non border vertex
            pavDstCopy[1] = pavSrc[2];
            pavDstCopy++;
            // since this wasn't border vertex, fix border vertex loop counter
            ctbv++;
            pavDstLerp++;
            ivxInQuad=2;
          }
          pavSrc+=2;
        }
      }
    }
  }

  // Lerp left border vertices
  const INDEX &iLeftNeigbour = tt.tt_aiNeighbours[NB_LEFT];
  // if left neighbour exists
  if(iLeftNeigbour>=0) {
    CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftNeigbour];
    const FLOAT &fLerpFactor = ttLeft.tt_fLodLerpFactor;
    // Get source vertex pointer in left neighbour (vertex in top right corner of left neighbour) 
    const INDEX iSrcVtx = ttLeft.tt_ctLodVtxX-1;
    const INDEX iSrcStep = ttLeft.tt_ctLodVtxX;
    GFXVertex *pavSrc = &ttLeft.GetVertices()[iSrcVtx];
    // Calculate num of vertices that needs to be lerped
    const INDEX ctLerps = (ttLeft.tt_ctLodVtxX-1)/2;

    // is left tile in same lod as this tile and has smaller or equal lerp factor
    if(tt.tt_iLod==ttLeft.tt_iLod && fLerpFactor<=tt.tt_fLodLerpFactor) {
      // Get destination vertex pointer in this tile (first vertex in top left corner of this tile - first vertex in array)
      const INDEX iDstVtx = 0;
      const INDEX iDstStep = tt.tt_ctLodVtxX;
      GFXVertex *pavDst = &pavDstFirst[iDstVtx];

      // for each vertex in last column of left tile that needs to be lerped
      for(INDEX ivx=0;ivx<ctLerps;ivx++) {
        // First vertex is same as in left tile
        pavDst[0] = pavSrc[0];
        // Second vertex is lerped between top and bottom vertices
        Lerp(pavDst[iDstStep],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
        pavDst+=iDstStep*2;
        pavSrc+=iSrcStep*2;
      }
    // is left tile in higher lod
    } else if(tt.tt_iLod>ttLeft.tt_iLod) {
      const INDEX iVtxDiff = (ttLeft.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
      // Get destination vertex pointer to copy vertices from left neighbour (first vertex in top left corner of this tile - first vertex in array)
      // Get destination vertex pointer to lerp vertices from left neighbour (first vertex added as additional left border vertex)
      const INDEX iDstCopyVtx = 0;
      const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_LEFT];
      const INDEX iDstStep = tt.tt_ctLodVtxX;
      GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
      GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];

      // if diference is in one lod
      if(iVtxDiff==2) {
        // for each vertex in last column of left tile that needs to be lerped
        for(INDEX ivx=0;ivx<ctLerps;ivx++) {
          // Copy src vertex in normal dst vertex array
          pavDstCopy[0] = pavSrc[0];
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
          pavDstLerp++;
          pavDstCopy+=iDstStep;
          pavSrc+=iSrcStep*2;
        }
      // diference is more than one lod
      } else {
        INDEX ctbv = tt.tt_ctBorderVertices[NB_LEFT];
        INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex 
        // for each border vertex
        for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
          // if this border vertex is not last in quad
          if(ivxInQuad!=iVtxDiff) {
            // Copy second border vertex
            pavDstLerp[1] = pavSrc[iSrcStep*2];
            pavDstLerp+=2;
            ivxInQuad+=2;
          // this is last border vertex
          } else {
            // Copy second non border vertex
            pavDstCopy[iDstStep] = pavSrc[iSrcStep*2];
            pavDstCopy+=iDstStep;
            // since this wasn't border vertex, fix border vertex loop counter
            ctbv++;
            pavDstLerp++;
            ivxInQuad=2;
          }
          pavSrc+=iSrcStep*2;
        }
      }
    }
  }

  // Lerp right border vertices
  const INDEX &iRightNeigbour = tt.tt_aiNeighbours[NB_RIGHT];
  // if right neighbour exists
  if(iRightNeigbour>=0) {
    CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightNeigbour];
    const FLOAT &fLerpFactor = ttRight.tt_fLodLerpFactor;
    // Get source vertex pointer in right neighbour (vertex in top left corner of left neighbour - first vertex in array) 
    const INDEX iSrcVtx = 0;
    const INDEX iSrcStep = ttRight.tt_ctLodVtxX;
    GFXVertex *pavSrc = &ttRight.GetVertices()[iSrcVtx];
    // Calculate num of vertices that needs to be lerped
    const INDEX ctLerps = (ttRight.tt_ctLodVtxX-1)/2;

    // is right tile in same lod as this tile and has smaller lerp factor
    if(tt.tt_iLod==ttRight.tt_iLod && fLerpFactor<tt.tt_fLodLerpFactor) {
      // Get destination vertex pointer in this tile (first vertex in top right corner of this tile)
      INDEX iDstVtx = tt.tt_ctLodVtxX-1;
      INDEX iDstStep = tt.tt_ctLodVtxX;
      GFXVertex *pavDst = &pavDstFirst[iDstVtx];

      // for each vertex in first column of right tile that needs to be lerped
      for(INDEX ivx=0;ivx<ctLerps;ivx++) {
        // First vertex is same as in right tile
        pavDst[0] = pavSrc[0];
        // Second vertex is lerped between top and bottom vertices
        Lerp(pavDst[iDstStep],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
        pavDst+=iDstStep*2;
        pavSrc+=iSrcStep*2;
      }
    // is right tile in higher lod
    } else if(tt.tt_iLod>ttRight.tt_iLod) {
      const INDEX iVtxDiff = (ttRight.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
      // Get destination vertex pointer to copy vertices from right neighbour (first vertex in top right corner of this tile)
      // Get destination vertex pointer to lerp vertices from right neighbour (first vertex added as additional right border vertex)
      const INDEX iDstCopyVtx = tt.tt_ctLodVtxX-1;
      const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_RIGHT];
      const INDEX iDstStep = tt.tt_ctLodVtxX;
      GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
      GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];

      // if diference is in one lod
      if(iVtxDiff==2) {
        // for each vertex in first column of right tile that needs to be lerped
        for(INDEX ivx=0;ivx<ctLerps;ivx++) {
          // Copy src vertex in normal dst vertex array
          pavDstCopy[0] = pavSrc[0];
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
          pavDstLerp++;
          pavDstCopy+=iDstStep;
          pavSrc+=iSrcStep*2;
        }
      // diference is more than one lod
      } else {
        INDEX ctbv = tt.tt_ctBorderVertices[NB_RIGHT];
        INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex 
        // for each border vertex
        for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
          // Lerp left and right src vertices in border dst vertex
          Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
          // if this border vertex is not last in quad
          if(ivxInQuad!=iVtxDiff) {
            // Copy second border vertex
            pavDstLerp[1] = pavSrc[iSrcStep*2];
            pavDstLerp+=2;
            ivxInQuad+=2;
          // this is last border vertex
          } else {
            // Copy second non border vertex
            pavDstCopy[iDstStep] = pavSrc[iSrcStep*2];
            pavDstCopy+=iDstStep;
            // since this wasn't border vertex, fix border vertex loop counter
            ctbv++;
            pavDstLerp++;
            ivxInQuad=2;
          }
          pavSrc+=iSrcStep*2;
        }
      }
    }
  }
}
void PrepareSmothVerticesOnTileLayer(INDEX iTerrainTile, INDEX iTileLayer)
{
  CTerrainTile &tt  = _ptrTerrain->tr_attTiles[iTerrainTile];
  CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[iTileLayer];
  TileLayer &ttl    = tt.GetTileLayers()[iTileLayer];

  ASSERT(tt.tt_iLod==0);

  const INDEX ctVertices = ttl.tl_avVertices.Count();
  const FLOAT &fLerpFactor = tt.tt_fLodLerpFactor;

  // Allocate memory for all vertices
  _avLerpedTileLayerVertices.PopAll();
  _avLerpedTileLayerVertices.Push(ctVertices);
  
  // Get pointers to src and dst vertex arrays
  GFXVertex *pavSrcFirst = &ttl.tl_avVertices[0];
  GFXVertex *pavDstFirst = &_avLerpedTileLayerVertices[0];
  GFXVertex *pavSrc = &pavSrcFirst[0];
  GFXVertex *pavDst = &pavDstFirst[0];

  INDEX ctQuadsPerRow   = _ptrTerrain->tr_ctQuadsInTileRow;
  INDEX ctVerticesInRow = _ptrTerrain->tr_ctQuadsInTileRow*2;
  INDEX iFacing = 1;

  // Minimize popping on vertices using 4 quads, 2 from current row and 2 from next row in same tile
  for(INDEX iz=0;iz<ctQuadsPerRow;iz+=2) {
    for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
      // Get pointer for quads in next row
      GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2];
      GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2];

      pavDst[0]   = pavSrc[0];
      Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[5],fLerpFactor);
      Lerp(pavDst[2],pavSrc[2],pavSrc[0],pavNRSrc[2],fLerpFactor);

      if(iFacing&1) {
        Lerp(pavDst[3],pavSrc[3],pavSrc[0],pavNRSrc[7],fLerpFactor);
      } else {
        Lerp(pavDst[3],pavSrc[3],pavSrc[5],pavNRSrc[2],fLerpFactor);
      }

      pavDst[4]   = pavDst[1];
      pavDst[5]   = pavSrc[5];
      pavDst[6]   = pavDst[3];
      Lerp(pavDst[7],pavSrc[7],pavSrc[5],pavNRSrc[7],fLerpFactor);
      pavNRDst[0] = pavDst[2];
      pavNRDst[1] = pavDst[3];
      pavNRDst[2] = pavNRSrc[2];
      Lerp(pavNRDst[3],pavNRSrc[3],pavNRSrc[2],pavNRSrc[7],fLerpFactor);
      pavNRDst[4] = pavDst[3];
      pavNRDst[5] = pavDst[7];
      pavNRDst[6] = pavNRDst[3];
      pavNRDst[7] = pavNRSrc[7];

      // Increment vertex pointers
      pavSrc+=8;
      pavDst+=8;
      iFacing++;
    }
    iFacing++;
    pavSrc+=ctVerticesInRow*2;
    pavDst+=ctVerticesInRow*2;
  }

  // Lerp top border
  INDEX iTopNeighbour = tt.tt_aiNeighbours[NB_TOP];
  // if top border exists
  if(iTopNeighbour>=0) {
    CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopNeighbour];
    const FLOAT fTopLerpFactor = ttTop.tt_fLodLerpFactor;
    // is top tile in highest lod and has smaller or equal lerp factor
    if(ttTop.tt_iLod==0 && fTopLerpFactor<=fLerpFactor) {
      TileLayer &ttl = ttTop.GetTileLayers()[iTileLayer];
      INDEX iFirstVertex = ctVerticesInRow*(ctVerticesInRow-2);
      GFXVertex *pavSrc = &ttl.tl_avVertices[iFirstVertex];
      GFXVertex *pavDst = &_avLerpedTileLayerVertices[0];
      // for each quad
      for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
        Lerp(pavDst[1],pavSrc[6],pavSrc[2],pavSrc[7],fTopLerpFactor);
        pavDst[4] = pavDst[1];
        pavSrc+=8;
        pavDst+=8;
      }
    }
  }

  // Lerp bottom border
  INDEX iBottomNeighbour = tt.tt_aiNeighbours[NB_BOTTOM];
  // if bottom border exists
  if(iBottomNeighbour>=0) {
    CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomNeighbour];
    const FLOAT fBottomLerpFactor = ttBottom.tt_fLodLerpFactor;
    // is bottom tile in highest lod and has smaller lerp factor
    if(ttBottom.tt_iLod==0 && fBottomLerpFactor<fLerpFactor) {
      TileLayer &ttl = ttBottom.GetTileLayers()[iTileLayer];
      INDEX iFirstVertex = ctVerticesInRow*(ctVerticesInRow-2);
      GFXVertex *pavSrc = &ttl.tl_avVertices[0];
      GFXVertex *pavDst = &_avLerpedTileLayerVertices[iFirstVertex];
      // for each quad
      for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
        Lerp(pavDst[3],pavSrc[1],pavSrc[0],pavSrc[5],fBottomLerpFactor);
        pavDst[6] = pavDst[3];
        pavSrc+=8;
        pavDst+=8;
      }
    }
  }

  // Lerp left border
  INDEX iLeftNeighbour = tt.tt_aiNeighbours[NB_LEFT];
  // if left neightbour exits
  if(iLeftNeighbour>=0) {
    CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftNeighbour];
    const FLOAT fLeftLerpFactor = ttLeft.tt_fLodLerpFactor;
    // is left tile in highest lod and has smaller or equal left factor
    if(ttLeft.tt_iLod==0 && fLeftLerpFactor<=fLerpFactor) {
      TileLayer &ttl = ttLeft.GetTileLayers()[iTileLayer];
      INDEX iFirstVertex = ctVerticesInRow*2-8;
      GFXVertex *pavSrc = &ttl.tl_avVertices[iFirstVertex];
      GFXVertex *pavDst = &_avLerpedTileLayerVertices[0];
      // for each quad
      for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
        GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2];
        GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2];

        Lerp(pavDst[2],pavSrc[7],pavSrc[5],pavNRSrc[7],fLeftLerpFactor);
        pavNRDst[0] = pavDst[2];
        pavSrc+=ctVerticesInRow*4;
        pavDst+=ctVerticesInRow*4;
      }
    }
  }

  // Lerp right border
  INDEX iRightNeighbour = tt.tt_aiNeighbours[NB_RIGHT];
  // if right neightbour exits
  if(iRightNeighbour>=0) {
    CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightNeighbour];
    const FLOAT fRightLerpFactor = ttRight.tt_fLodLerpFactor;
    // is right tile in highest lod and has smaller left factor
    if(ttRight.tt_iLod==0 && fRightLerpFactor<fLerpFactor) {
      TileLayer &ttl = ttRight.GetTileLayers()[iTileLayer];
      INDEX iFirstVertex = ctVerticesInRow*2-8;
      GFXVertex *pavSrc = &ttl.tl_avVertices[0];
      GFXVertex *pavDst = &_avLerpedTileLayerVertices[iFirstVertex];
      // for each quad
      for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
        GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2];
        GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2];

        Lerp(pavDst[7],pavSrc[2],pavSrc[0],pavNRSrc[2],fRightLerpFactor);
        pavNRDst[5] = pavDst[7];
        pavSrc+=ctVerticesInRow*4;
        pavDst+=ctVerticesInRow*4;
      }
    }
  }
}
Beispiel #16
0
// Calculate lightning for given model
void shaCalculateLight(void)
{
  // if full bright
  if(shaGetFlags()&BASE_FULL_BRIGHT) {
    GFXColor colLight = _colConstant;
    GFXColor colAmbient;
    GFXColor colConstant;
    // is over brightning enabled
    if(shaOverBrightningEnabled()) {
      colAmbient = 0x7F7F7FFF;
    } else {
      colAmbient = 0xFFFFFFFF;
    }
    colConstant.MultiplyRGBA(colLight,colAmbient);
    shaSetConstantColor(ByteSwap(colConstant.abgr));
    // no vertex colors
    return;
  }

  ASSERT(_paNormals!=NULL);
  _acolVtxColors.PopAll();
  _acolVtxColors.Push(_ctVertices);

  GFXColor colModel   = (GFXColor)_colModel;   // Model color
  GFXColor &colAmbient = (GFXColor)_colAmbient; // Ambient color
  GFXColor &colLight   = (GFXColor)_colLight;   // Light color
  GFXColor &colSurface = (GFXColor)_colConstant; // shader color

  colModel.MultiplyRGBA(colModel,colSurface);

  UBYTE ubColShift = 8;
  SLONG slar = colAmbient.r;
  SLONG slag = colAmbient.g;
  SLONG slab = colAmbient.b;

  if(shaOverBrightningEnabled()) {
    slar = ClampUp(slar,127L);
    slag = ClampUp(slag,127L);
    slab = ClampUp(slab,127L);
    ubColShift = 8;
  } else {
    slar*=2;
    slag*=2;
    slab*=2;
    ubColShift = 7;
  }

  // for each vertex color
  for(INDEX ivx=0;ivx<_ctVertices;ivx++) {
    // calculate vertex light
    FLOAT3D &vNorm = FLOAT3D(_paNormals[ivx].nx,_paNormals[ivx].ny,_paNormals[ivx].nz);
    FLOAT fDot = vNorm % _vLightDir;
    fDot = Clamp(fDot,0.0f,1.0f);
    SLONG slDot = NormFloatToByte(fDot);

    _acolVtxColors[ivx].r = ClampUp(colModel.r * (slar + ((colLight.r * slDot)>>ubColShift))>>8,255L);
    _acolVtxColors[ivx].g = ClampUp(colModel.g * (slag + ((colLight.g * slDot)>>ubColShift))>>8,255L);
    _acolVtxColors[ivx].b = ClampUp(colModel.b * (slab + ((colLight.b * slDot)>>ubColShift))>>8,255L);
    _acolVtxColors[ivx].a = colModel.a;//slDot;
  }
  // Set current vertex color array 
  _pcolVtxColors = &_acolVtxColors[0];
}
// read depth buffer and update visibility flag of depth points
static void UpdateDepthPointsVisibility( const CDrawPort *pdp, const INDEX iMirrorLevel,
                                         DepthInfo *pdi, const INDEX ctCount)
{
  const GfxAPIType eAPI = _pGfx->gl_eCurrentAPI;
  ASSERT(GfxValidApi(eAPI));
  ASSERT( pdp!=NULL && ctCount>0);
  const CRaster *pra = pdp->dp_Raster;

  // OpenGL
  if( eAPI==GAT_OGL)
  { 
    _sfStats.StartTimer(CStatForm::STI_GFXAPI);
    FLOAT fPointOoK;
    // for each stored point
    for( INDEX idi=0; idi<ctCount; idi++) {
      DepthInfo &di = pdi[idi];
      // skip if not in required mirror level or was already checked in this iteration
      if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest) continue;
      const PIX pixJ = pra->ra_Height-1 - di.di_pixJ; // OpenGL has Y-inversed buffer!
      pglReadPixels( di.di_pixI, pixJ, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &fPointOoK);
      OGL_CHECKERROR;
      // it is visible if there is nothing nearer in z-buffer already
      di.di_bVisible = (di.di_fOoK<fPointOoK);
    }
    // done
    _sfStats.StopTimer(CStatForm::STI_GFXAPI);
    return;
  }

  // Direct3D
#ifdef SE1_D3D
  if( eAPI==GAT_D3D)
  {
    _sfStats.StartTimer(CStatForm::STI_GFXAPI);
    // ok, this will get really complicated ...
    // We'll have to do it thru back buffer because darn DX8 won't let us have values from z-buffer;
    // Anyway, we'll lock backbuffer, read color from the lens location and try to write little triangle there
    // with slightly modified color. Then we'll readout that color and see if triangle passes z-test. Voila! :)
    // P.S. To avoid lock-modify-lock, we need to batch all the locks in one. Uhhhh ... :(
    COLOR col;
    INDEX idi;
    SLONG slColSize;
    HRESULT hr;
    D3DLOCKED_RECT rectLocked;
    D3DSURFACE_DESC surfDesc;
    LPDIRECT3DSURFACE8 pBackBuffer;
    // fetch back buffer (different for full screen and windowed mode)
    const BOOL bFullScreen = _pGfx->gl_ulFlags & GLF_FULLSCREEN;
    if( bFullScreen) {
      hr = _pGfx->gl_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
    } else {
      hr = pra->ra_pvpViewPort->vp_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
    }
    // what, cannot get a back buffer?
    if( hr!=D3D_OK) { 
      // to hell with it all
      _sfStats.StopTimer(CStatForm::STI_GFXAPI);
      return;
    }
    // keep format of back-buffer
    pBackBuffer->GetDesc(&surfDesc);
    const D3DFORMAT d3dfBack = surfDesc.Format;
    
    // prepare array that'll back-buffer colors from depth point locations
    _acolDelayed.Push(ctCount);
    // store all colors
    for( idi=0; idi<ctCount; idi++) {
      DepthInfo &di = pdi[idi];
      // skip if not in required mirror level or was already checked in this iteration
      if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest) continue;
      // fetch pixel
      _acolDelayed[idi] = 0;
      const RECT rectToLock = { di.di_pixI, di.di_pixJ, di.di_pixI+1, di.di_pixJ+1 };
      hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY);
      if( hr!=D3D_OK) continue; // skip if lock didn't make it
      // read, convert and store original color
      _acolDelayed[idi] = UnpackColor_D3D( (UBYTE*)rectLocked.pBits, d3dfBack, slColSize) | CT_OPAQUE;
      pBackBuffer->UnlockRect();
    }

    // prepare to draw little triangles there with slightly adjusted colors
    _sfStats.StopTimer(CStatForm::STI_GFXAPI);
    gfxEnableDepthTest();
    gfxDisableDepthWrite();
    gfxDisableBlend();
    gfxDisableAlphaTest();
    gfxDisableTexture();
    _sfStats.StartTimer(CStatForm::STI_GFXAPI);
    // prepare array and shader
    _avtxDelayed.Push(ctCount*3);
    d3dSetVertexShader(D3DFVF_CTVERTEX);

    // draw one trianle around each depth point
    INDEX ctVertex = 0;
    for( idi=0; idi<ctCount; idi++) {
      DepthInfo &di = pdi[idi];
      col = _acolDelayed[idi];
      // skip if not in required mirror level or was already checked in this iteration, or wasn't fetched at all
      if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest || col==0) continue;
      const ULONG d3dCol = rgba2argb(col^0x20103000);
      const PIX pixI = di.di_pixI - pdp->dp_MinI; // convert raster loc to drawport loc
      const PIX pixJ = di.di_pixJ - pdp->dp_MinJ;
      // batch it and advance to next triangle
      CTVERTEX &vtx0 = _avtxDelayed[ctVertex++];
      CTVERTEX &vtx1 = _avtxDelayed[ctVertex++];
      CTVERTEX &vtx2 = _avtxDelayed[ctVertex++];
      vtx0.fX=pixI;   vtx0.fY=pixJ-2; vtx0.fZ=di.di_fOoK; vtx0.ulColor=d3dCol; vtx0.fU=vtx0.fV=0;
      vtx1.fX=pixI-2; vtx1.fY=pixJ+2; vtx1.fZ=di.di_fOoK; vtx1.ulColor=d3dCol; vtx1.fU=vtx0.fV=0;
      vtx2.fX=pixI+2; vtx2.fY=pixJ;   vtx2.fZ=di.di_fOoK; vtx2.ulColor=d3dCol; vtx2.fU=vtx0.fV=0;
    }
    // draw a bunch
    hr = _pGfx->gl_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, ctVertex/3, &_avtxDelayed[0], sizeof(CTVERTEX));
    D3D_CHECKERROR(hr);

    // readout colors again and compare to old ones
    for( idi=0; idi<ctCount; idi++) {
      DepthInfo &di = pdi[idi];
      col = _acolDelayed[idi];
      // skip if not in required mirror level or was already checked in this iteration, or wasn't fetched at all
      if( iMirrorLevel!=di.di_iMirrorLevel || _iCheckIteration!=di.di_iSwapLastRequest || col==0) continue;
      // fetch pixel
      const RECT rectToLock = { di.di_pixI, di.di_pixJ, di.di_pixI+1, di.di_pixJ+1 };
      hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY);
      if( hr!=D3D_OK) continue; // skip if lock didn't make it
      // read new color
      const COLOR colNew = UnpackColor_D3D( (UBYTE*)rectLocked.pBits, d3dfBack, slColSize) | CT_OPAQUE;
      pBackBuffer->UnlockRect();
      // if we managed to write adjusted color, point is visible!
      di.di_bVisible = (col!=colNew);
    }
    // phew, done! :)
    D3DRELEASE( pBackBuffer, TRUE);
    _acolDelayed.PopAll();
    _avtxDelayed.PopAll();
    _sfStats.StopTimer(CStatForm::STI_GFXAPI);
    return;
  }
#endif // SE1_D3D
}
static void RenderFogLayer(INDEX itt)
{
  FLOATmatrix3D &mViewer = _aprProjection->pr_ViewerRotationMatrix;
  FLOAT3D vObjPosition = _ptrTerrain->tr_penEntity->en_plPlacement.pl_PositionVector;

  // get viewer -z in object space
  _vFViewerObj = FLOAT3D(0,0,-1) * !_mObjectToView;
  // get fog direction in object space
  _vHDirObj = _fog_vHDirAbs * !(!mViewer*_mObjectToView);
  // get viewer offset
  _fFogAddZ  = _vViewer(1) * (vObjPosition(1) - _aprProjection->pr_vViewerPosition(1));
  _fFogAddZ += _vViewer(2) * (vObjPosition(2) - _aprProjection->pr_vViewerPosition(2));
  _fFogAddZ += _vViewer(3) * (vObjPosition(3) - _aprProjection->pr_vViewerPosition(3));
  // get fog offset
  _fFogAddH = (_fog_vHDirAbs % vObjPosition) + _fog_fp.fp_fH3;

  GFXVertex *pvVtx;
  INDEX     *piIndices;
  INDEX ctVertices;
  INDEX ctIndices;
  // if this is tile 
  if(itt>=0) {
    CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
    pvVtx      = &tt.GetVertices()[0];
    piIndices  = &tt.GetIndices()[0];
    ctVertices = tt.GetVertices().Count();
    ctIndices  = tt.GetIndices().Count();
  // else this are batched tiles
  } else {
    pvVtx      = &_avDelayedVertices[0];
    piIndices  = &_aiDelayedIndices[0];
    ctVertices = _avDelayedVertices.Count();
    ctIndices  = _aiDelayedIndices.Count();
  }

  GFXTexCoord *pfFogTC  = _atcHaze.Push(ctVertices);
  GFXColor    *pcolFog  = _acolHaze.Push(ctVertices);

  const COLOR colF = AdjustColor( _fog_fp.fp_colColor, _slTexHueShift, _slTexSaturation);
  GFXColor colFog(colF);

  // for each vertex in tile
  for(INDEX ivx=0;ivx<ctVertices;ivx++) {
    GetFogMapInVertex(pvVtx[ivx],pfFogTC[ivx]);
    pcolFog[ivx] = colFog;
  }

  // render fog layer
  gfxDepthFunc(GFX_EQUAL);
  gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
  gfxSetTexture( _fog_ulTexture, _fog_tpLocal);
  gfxSetTexCoordArray(pfFogTC, FALSE);
  gfxSetColorArray(pcolFog);
  gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA);
  gfxEnableBlend();
  gfxDisableAlphaTest();
  gfxDrawElements(ctIndices,piIndices);
  gfxDepthFunc(GFX_LESS_EQUAL);

  _atcHaze.PopAll();
  _acolHaze.PopAll();
}