void RenderTerrainNode::updateVertexBuffer( RenderVertexBuffer* posbuf,const Rect& rect ) { ph_assert (rect.left >= m_offsetX && rect.right <= m_boundaryX && rect.top >= m_offsetY && rect.bottom <= m_boundaryY); resetBounds(rect); long destOffsetX = rect.left <= m_offsetX ? 0 : (rect.left - m_offsetX); long destOffsetY = rect.top <= m_offsetY ? 0 : (rect.top - m_offsetY); scalar uvScale = 1.0f / (m_terrain->getSize() - 1); const float* pBaseHeight = m_terrain->getHeightData(rect.left, rect.top); uint16 rowskip = m_terrain->getSize(); uint16 destPosRowSkip = 0, destDeltaRowSkip = 0; unsigned char* pRootPosBuf = 0; unsigned char* pRowPosBuf = 0; if (posbuf) { destPosRowSkip = m_terrain->getBatchSize() * posbuf->getVertexSize(); pRootPosBuf = static_cast<unsigned char*>(posbuf->lock()); pRowPosBuf = pRootPosBuf; pRowPosBuf += destOffsetY * destPosRowSkip + destOffsetX * posbuf->getVertexSize(); } Vector3 pos; bool vcompress = m_terrain->getUseVertexCompression(); for (long y = rect.top; y < rect.bottom; y ++) { const float* pHeight = pBaseHeight; float* pPosBuf = static_cast<float*>(static_cast<void*>(pRowPosBuf)); for (long x = rect.left; x < rect.right; x ++) { if (pPosBuf) { m_terrain->getPoint(x, y, *pHeight, &pos); mergeIntoBounds(x, y, pos); //pos -= m_localCentre; writePosVertex(vcompress, (uint16)x, (uint16)y, *pHeight, pos, uvScale, &pPosBuf); pHeight ++; } } pBaseHeight += rowskip; if (pRowPosBuf) { pRowPosBuf += destPosRowSkip; } } if (posbuf) { posbuf->unlock(); } }
//---------------------------------------------------------------------- void TerrainQuadTreeNode::updateVertexBuffer(const Rect& rect) { _AST (rect.left >= mOffsetX && rect.right <= mBoundaryX && rect.top >= mOffsetY && rect.bottom <= mBoundaryY); // potentially reset our bounds depending on coverage of the update resetBounds(rect); // Main data uint16 inc = (mTerrain->getSize()-1) / (mVertexDataRecord->resolution-1); long destOffsetX = rect.left <= mOffsetX ? 0 : (rect.left - mOffsetX) / inc; long destOffsetY = rect.top <= mOffsetY ? 0 : (rect.top - mOffsetY) / inc; // Fill the buffers float uvScale = 1.0f / (mTerrain->getSize() - 1); const float* pBaseHeight = mTerrain->getHeightData(rect.left, rect.top); const float* pBaseDelta = mTerrain->getDeltaData(rect.left, rect.top); uint16 rowskip = mTerrain->getSize() * inc; uint16 destPosRowSkip = 0, destDeltaRowSkip = 0; unsigned char* pRootPosBuf = 0; unsigned char* pRootDeltaBuf = 0; unsigned char* pRowPosBuf = 0; unsigned char* pRowDeltaBuf = 0; const uint32 nVertSizePos = sizeof(uint16) * 2 + sizeof(float); const uint32 nVertSizeDelta = sizeof(float) * 2; if (mVertexDataRecord->cpuVertexPosData) { destPosRowSkip = mVertexDataRecord->size * nVertSizePos; pRootPosBuf = static_cast<unsigned char*>(mVertexDataRecord->cpuVertexPosData); pRowPosBuf = pRootPosBuf; // skip dest buffer in by left/top pRowPosBuf += destOffsetY * destPosRowSkip + destOffsetX * nVertSizePos; } if (mVertexDataRecord->cpuVertexDeltaData) { destDeltaRowSkip = mVertexDataRecord->size * nVertSizeDelta; pRootDeltaBuf = static_cast<unsigned char*>(mVertexDataRecord->cpuVertexDeltaData); pRowDeltaBuf = pRootDeltaBuf; // skip dest buffer in by left/top pRowDeltaBuf += destOffsetY * destDeltaRowSkip + destOffsetX * nVertSizeDelta; } VEC3 pos; for (uint16 y = rect.top; y < rect.bottom; y += inc) { const float* pHeight = pBaseHeight; const float* pDelta = pBaseDelta; float* pPosBuf = static_cast<float*>(static_cast<void*>(pRowPosBuf)); float* pDeltaBuf = static_cast<float*>(static_cast<void*>(pRowDeltaBuf)); for (uint16 x = rect.left; x < rect.right; x += inc) { if (pPosBuf) { mTerrain->getPoint(x, y, *pHeight, &pos); // Update bounds *before* making relative mergeIntoBounds(x, y, pos); // relative to local centre pos -= mLocalCentre; writePosVertex(x, y, *pHeight, pos, uvScale, &pPosBuf); pHeight += inc; } if (pDeltaBuf) { // delta, and delta LOD threshold // we want delta to apply to LODs no higher than this value // at runtime this will be combined with a per-renderable parameter // to ensure we only apply morph to the correct LOD writeDeltaVertex(x, y, *pDelta, (float)mTerrain->getLODLevelWhenVertexEliminated(x, y) - 1.0f, &pDeltaBuf); pDelta += inc; } } pBaseHeight += rowskip; pBaseDelta += rowskip; if (pRowPosBuf) pRowPosBuf += destPosRowSkip; if (pRowDeltaBuf) pRowDeltaBuf += destDeltaRowSkip; } // Skirts now // skirt spacing based on top-level resolution (* inc to cope with resolution which is not the max) uint16 skirtSpacing = mVertexDataRecord->skirtRowColSkip * inc; VEC3 skirtOffset; mTerrain->getVector(0, 0, -mTerrain->getSkirtSize(), &skirtOffset); // skirt rows // clamp rows to skirt spacing (round up) long skirtStartX = rect.left; long skirtStartY = rect.top; // for rows, clamp Y to skirt frequency, X to inc (LOD resolution vs top) if (skirtStartY % skirtSpacing) skirtStartY += skirtSpacing - (skirtStartY % skirtSpacing); if (skirtStartX % inc) skirtStartX += inc - (skirtStartX % inc); skirtStartY = std::max(skirtStartY, (long)mOffsetY); pBaseHeight = mTerrain->getHeightData(skirtStartX, skirtStartY); if (mVertexDataRecord->cpuVertexPosData) { // position dest buffer just after the main vertex data pRowPosBuf = pRootPosBuf + nVertSizePos * mVertexDataRecord->size * mVertexDataRecord->size; // move it onwards to skip the skirts we don't need to update pRowPosBuf += destPosRowSkip * ((skirtStartY - mOffsetY) / skirtSpacing); pRowPosBuf += nVertSizePos * (skirtStartX - mOffsetX) / inc; } if (mVertexDataRecord->cpuVertexDeltaData) { // position dest buffer just after the main vertex data pRowDeltaBuf = pRootDeltaBuf + nVertSizeDelta * mVertexDataRecord->size * mVertexDataRecord->size; // move it onwards to skip the skirts we don't need to update pRowDeltaBuf += destDeltaRowSkip * (skirtStartY - mOffsetY) / skirtSpacing; pRowDeltaBuf += nVertSizeDelta * (skirtStartX - mOffsetX) / inc; } for (uint16 y = skirtStartY; y < rect.bottom; y += skirtSpacing) { const float* pHeight = pBaseHeight; float* pPosBuf = static_cast<float*>(static_cast<void*>(pRowPosBuf)); float* pDeltaBuf = static_cast<float*>(static_cast<void*>(pRowDeltaBuf)); for (uint16 x = skirtStartX; x < rect.right; x += inc) { if (mVertexDataRecord->cpuVertexPosData) { mTerrain->getPoint(x, y, *pHeight, &pos); // relative to local centre pos -= mLocalCentre; pos += skirtOffset; writePosVertex(x, y, *pHeight - mTerrain->getSkirtSize(), pos, uvScale, &pPosBuf); pHeight += inc; } if (mVertexDataRecord->cpuVertexDeltaData) { // delta (none) // delta threshold (irrelevant) writeDeltaVertex(x, y, 0, 99, &pDeltaBuf); } } pBaseHeight += mTerrain->getSize() * skirtSpacing; if (pRowPosBuf) pRowPosBuf += destPosRowSkip; if (pRowDeltaBuf) pRowDeltaBuf += destDeltaRowSkip; } // skirt cols // clamp cols to skirt spacing (round up) skirtStartX = rect.left; if (skirtStartX % skirtSpacing) skirtStartX += skirtSpacing - (skirtStartX % skirtSpacing); // clamp Y to inc (LOD resolution vs top) skirtStartY = rect.top; if (skirtStartY % inc) skirtStartY += inc - (skirtStartY % inc); skirtStartX = std::max(skirtStartX, (long)mOffsetX); if (mVertexDataRecord->cpuVertexPosData) { // position dest buffer just after the main vertex data and skirt rows pRowPosBuf = pRootPosBuf + nVertSizePos * mVertexDataRecord->size * mVertexDataRecord->size; // skip the row skirts pRowPosBuf += mVertexDataRecord->numSkirtRowsCols * mVertexDataRecord->size * nVertSizePos; // move it onwards to skip the skirts we don't need to update pRowPosBuf += destPosRowSkip * (skirtStartX - mOffsetX) / skirtSpacing; pRowPosBuf += nVertSizePos * (skirtStartY - mOffsetY) / inc; } if (mVertexDataRecord->cpuVertexDeltaData) { // Delta dest buffer just after the main vertex data and skirt rows pRowDeltaBuf = pRootDeltaBuf + nVertSizeDelta * mVertexDataRecord->size * mVertexDataRecord->size; // skip the row skirts pRowDeltaBuf += mVertexDataRecord->numSkirtRowsCols * mVertexDataRecord->size * nVertSizeDelta; // move it onwards to skip the skirts we don't need to update pRowDeltaBuf += destDeltaRowSkip * (skirtStartX - mOffsetX) / skirtSpacing; pRowDeltaBuf += nVertSizeDelta * (skirtStartY - mOffsetY) / inc; } for (uint16 x = skirtStartX; x < rect.right; x += skirtSpacing) { float* pPosBuf = static_cast<float*>(static_cast<void*>(pRowPosBuf)); float* pDeltaBuf = static_cast<float*>(static_cast<void*>(pRowDeltaBuf)); for (uint16 y = skirtStartY; y < rect.bottom; y += inc) { if (mVertexDataRecord->cpuVertexPosData) { float height = mTerrain->getHeightAtPoint(x, y); mTerrain->getPoint(x, y, height, &pos); // relative to local centre pos -= mLocalCentre; pos += skirtOffset; writePosVertex(x, y, height - mTerrain->getSkirtSize(), pos, uvScale, &pPosBuf); } if (mVertexDataRecord->cpuVertexDeltaData) { // delta (none) // delta threshold (irrelevant) writeDeltaVertex(x, y, 0, 99, &pDeltaBuf); } } if (pRowPosBuf) pRowPosBuf += destPosRowSkip; if (pRowDeltaBuf) pRowDeltaBuf += destDeltaRowSkip; } }