void RenderClusterOffMapV( S32 x, S32 z) { S32 xc = x / (S32) heightField.meterPerCell; S32 zc = z / (S32) heightField.meterPerCell; ASSERT(xc != 0 || zc != 0); /* if (zc > 0 || xc < heightField.cellWidth) { return; } */ F32 xs = F32(x) - OffsetX(); F32 zs = F32(z) - OffsetZ(); F32 xend = xs + (F32) meterPerClus; F32 zend = zs + (F32) meterPerClus; F32 xy[5], zy[5], dx, dxx, dz = 0, dzz = 0, ymin = F32_MAX, ymax = -F32_MAX; S32 zcc = zc; S32 xcc = xc; S32 corners = 0; if (xc < 0) { for (U32 i = 0; i < 5; i++, zcc++) { S32 tzc = zcc < 0 ? 0 : zcc > (S32) heightField.cellHeight ? heightField.cellHeight : zcc; xy[i] = heightField.cellList[ tzc * heightField.cellPitch].height; ymin = Min<F32>( ymin, xy[i]); ymax = Max<F32>( ymax, xy[i]); } dx = (F32) -xc * (F32) heightField.meterPerCell; dxx = - (F32) heightField.meterPerCell; corners |= 1; } else if (xc >= (S32) heightField.cellWidth) { for (U32 i = 0; i < 5; i++, zcc++) { S32 tzc = zcc < 0 ? 0 : zcc > (S32) heightField.cellHeight ? heightField.cellHeight : zcc; xy[i] = heightField.cellList[ tzc * heightField.cellPitch + heightField.cellWidth].height; ymin = Min<F32>( ymin, xy[i]); ymax = Max<F32>( ymax, xy[i]); } dx = (F32(xc) - F32(heightField.cellWidth)) * (F32) heightField.meterPerCell; dxx = (F32) heightField.meterPerCell; corners |= 1; } else { for (U32 i = 0; i < 5; i++, zcc++) { S32 tzc = zcc < 0 ? 0 : zcc > (S32) heightField.cellHeight ? heightField.cellHeight : zcc; xy[i] = heightField.cellList[ tzc * heightField.cellPitch + xc].height; ymin = Min<F32>( ymin, xy[i]); ymax = Max<F32>( ymax, xy[i]); } dx = 0; dxx = (F32) heightField.meterPerCell; } if (zc < 0) { for (U32 i = 0; i < 5; i++, xcc++) { S32 txc = xcc < 0 ? 0 : xcc > (S32) heightField.cellWidth ? heightField.cellWidth : xcc; zy[i] = heightField.cellList[ txc].height; ymin = Min<F32>( ymin, zy[i]); ymax = Max<F32>( ymax, zy[i]); } dz = (F32) -zc * (F32) heightField.meterPerCell; dzz = - (F32) heightField.meterPerCell; corners |= 2; } else if (zc >= (S32) heightField.cellHeight) { for (U32 i = 0; i < 5; i++, xcc++) { S32 txc = xcc < 0 ? 0 : xcc > (S32) heightField.cellWidth ? heightField.cellWidth : xcc; zy[i] = heightField.cellList[ heightField.cellHeight * heightField.cellPitch + txc].height; ymin = Min<F32>( ymin, zy[i]); ymax = Max<F32>( ymax, zy[i]); } dz = F32(zc - heightField.cellHeight) * (F32) heightField.meterPerCell; dzz = (F32) heightField.meterPerCell; corners |= 2; } // DyDx = (dy12 * dz02 - dy02 * dz12) * dx; // DyDz = (dy12 * dx02 - dy02 * dx12) * -dx; Vector offset( (xend + xs) * .5f, (ymin + ymax) * .5f, (zend + zs) * .5f); Bounds bounds; bounds.Set( (F32) fabs( xend - xs), ymax - ymin, (F32) fabs( zend - zs)); U32 clipFlags = Vid::CurCamera().BoundsTestBox( offset, bounds); if (clipFlags == clipOUTSIDE) { // cluster is completely outside the view frustrum return; } Vid::SetBucketFlags( RS_BLEND_DEF | DP_DONOTLIGHT | renderFlags | ((clipFlags & clipALL) ? 0 : DP_DONOTCLIP) ); Vid::SetTranBucketZMax( Vid::sortTERRAIN0 + 1); Vid::SetBucketMaterial( Vid::defMaterial); Vid::SetBucketTexture( NULL, FALSE); F32 dxy[5], dzy[5]; U32 iz = 0; for (; iz < 5; iz++) { dxy[iz] = (offMapHeight - xy[iz]) / 1000; dzy[iz] = (offMapHeight - zy[iz]) / 1000; } VertexC * vertmem; U16 * indexmem; if (!Vid::LockIndexedPrimitiveMem( (void **)&vertmem, 25, &indexmem, 96)) { LOG_WARN( ("Terrain::RenderCluster: can't lock bucket!") ); return; } VertexC * v = vertmem; iz = 0; for ( zs; zs <= zend; zs += heightField.meterPerCell, iz++, dz += dzz, zc++) { U32 ix = 0; F32 ddx = dx; S32 xcc = xc; for (F32 x = xs; x <= xend; x += heightField.meterPerCell, ix++, v++, ddx += dxx, xcc++) { v->vv.x = x; v->vv.z = zs; v->nv.Zero(); v->diffuse = 0xff000000; switch (corners) { case 3: { v->vv.y = xy[iz] + dxy[iz] * ddx; F32 zz = zs < 0 ? -zs : zs >= (S32) heightField.meterHeight ? zs - heightField.meterHeight : zs; F32 xx = x < 0 ? -x : x >= (S32) heightField.meterWidth ? x - heightField.meterWidth : x; if (zz > xx) { F32 dy = zy[ix] + dzy[ix] * dz; dy = (dy - v->vv.y) / zz; v->vv.y += dy * (zz - xx); } break; } case 2: v->vv.y = zy[ix] + dzy[ix] * dz; break; case 1: v->vv.y = xy[iz] + dxy[iz] * ddx; break; } } } Utils::Memcpy( indexmem, clusterI, 96 << 1); Vid::UnlockIndexedPrimitiveMem( 25, 96); #ifdef DOSTATISTICS if (clipFlags == clipNONE) { Statistics::noClipTris += 2; } else { Statistics::clipTris += 2; } #endif }