afTerrainPatch.cpp
资源名称:AirForce.rar [点击查看]
上传用户:kaiguan
上传日期:2007-10-28
资源大小:1074k
文件大小:44k
源码类别:
其他游戏
开发平台:
Visual C++
- #include "stdafx.h"
- #include "afTerrainPatch.h"
- #include "afLog.h"
- #include "afMatrix.h"
- #include "afPlane.h"
- #include "afTerrain.h"
- #include <assert.h>
- #define setD3DVec(v1, v0) { v1.x = v0.x; v1.y = v0.y; v1.z = v0.z; }
- struct PATCHVERTEX_MORPH_HW
- {
- float posX,posZ;
- float texX,texY;
- float posY, yMoveSelf, v0,v1,
- yMoveLeft, yMoveLeft2, yMoveRight, yMoveRight2,
- yMoveBottom, yMoveBottom2, yMoveTop, yMoveTop2;
- };
- afTerrainPatch::afTerrainPatch(afTerrain* nMaster, int nX, int nY) : active(false), scale(1.0f, 1.0f, 1.0f)
- {
- visFlags = 0;
- gridX = nX;
- gridY = nY;
- minY = maxY = -1.0f;
- master = nMaster;
- realSelfTes = newRealSelfTes = newSelfTes = selfTes = leftTes = rightTes = topTes = bottomTes = 5;
- oldRealSelfTes = 5;
- vertices = NULL;
- indices = NULL;
- indexMap = NULL;
- next = prev = NULL;
- left = right = bottom = top = NULL;
- lowVertMethod2 = false;
- currentError = -1.0f;
- vBuffer = NULL;
- iBuffer = NULL;
- verticesLow = NULL;
- yMoveSelf = yMoveLeft = yMoveLeft2 = yMoveRight = yMoveRight2 = yMoveBottom = yMoveBottom2 = yMoveTop = yMoveTop2 = NULL;
- newFollowsLeft = followsLeft = newFollowsRight = followsRight = newFollowsBottom = followsBottom = newFollowsTop = followsTop = false;
- recalcBorderLeft = recalcBorderRight = recalcBorderBottom = recalcBorderTop = false;
- forceRetessellation = false;
- }
- void afTerrainPatch::setNeighbors(const afTerrainPatch* nLeft, const afTerrainPatch* nRight, const afTerrainPatch *nBottom, const afTerrainPatch* nTop)
- {
- left = nLeft;
- right = nRight;
- bottom = nBottom;
- top = nTop;
- }
- void afTerrainPatch::init()
- {
- newSelfTes = selfTes = leftTes = rightTes = topTes = bottomTes = 5;
- oldRealSelfTes = 5;
- vertices = new PATCHVERTEX[MAX_VERTICES];
- indices = new unsigned short[MAX_INDICES];
- indexMap = new unsigned short[MAX_VERTICES];
- numIndices = numVertices = 0;
- numNewVertices = numNewIndices = 0;
- forceBufferCreate = true;
- active = true;
- addToActiveList();
- verticesLow = new PATCHVERTEX[MAX_VERTICES];
- yMoveSelf = new float[MAX_VERTICES];
- yMoveLeft = new float[MAX_VERTICES];
- yMoveLeft2 = new float[MAX_VERTICES];
- yMoveRight = new float[MAX_VERTICES];
- yMoveRight2 = new float[MAX_VERTICES];
- yMoveTop = new float[MAX_VERTICES];
- yMoveTop2 = new float[MAX_VERTICES];
- yMoveBottom = new float[MAX_VERTICES];
- yMoveBottom2 = new float[MAX_VERTICES];
- newFollowsLeft = followsLeft = newFollowsRight = followsRight = newFollowsBottom = followsBottom = newFollowsTop = followsTop = false;
- recalcBorderLeft = recalcBorderRight = recalcBorderBottom = recalcBorderTop = false;
- forceRetessellation = false;
- }
- void afTerrainPatch::deinit()
- {
- if(vertices)
- delete vertices;
- vertices = NULL;
- if(indices)
- delete indices;
- indices = NULL;
- if(indexMap)
- delete indexMap;
- indexMap = NULL;
- currentError = -1.0f;
- active = false;
- removeFromActiveList();
- if(verticesLow)
- delete verticesLow;
- verticesLow = NULL;
- if(yMoveSelf)
- delete yMoveSelf;
- yMoveSelf = NULL;
- if(yMoveLeft)
- delete yMoveLeft;
- yMoveLeft = NULL;
- if(yMoveLeft2)
- delete yMoveLeft2;
- yMoveLeft2 = NULL;
- if(yMoveRight)
- delete yMoveRight;
- yMoveRight = NULL;
- if(yMoveRight2)
- delete yMoveRight2;
- yMoveRight2 = NULL;
- if(yMoveBottom)
- delete yMoveBottom;
- yMoveBottom = NULL;
- if(yMoveBottom2)
- delete yMoveBottom2;
- yMoveBottom2 = NULL;
- if(yMoveTop)
- delete yMoveTop;
- yMoveTop = NULL;
- if(yMoveTop2)
- delete yMoveTop2;
- yMoveTop2 = NULL;
- deleteDeviceObjects();
- }
- void afTerrainPatch::addToActiveList()
- {
- assert(master);
- assert(prev==NULL);
- assert(next==NULL);
- prev = NULL;
- next = master->getActiveList();
- if(next)
- next->prev = this;
- master->getActiveList() = this;
- }
- void afTerrainPatch::removeFromActiveList()
- {
- if(prev)
- prev->next = next;
- if(next)
- next->prev = prev;
- if(master->getActiveList() == this)
- {
- assert(prev==NULL);
- master->getActiveList() = next;
- }
- prev = next = NULL;
- }
- void afTerrainPatch::deleteDeviceObjects()
- {
- SAFE_RELEASE(iBuffer);
- SAFE_RELEASE(vBuffer);
- }
- bool afTerrainPatch::restoreDeviceObjects()
- {
- forceBufferCreate = true;
- return true;
- }
- int afTerrainPatch::fillBaseVertices(afTerrainPatch::PATCHVERTEX* nDest)
- {
- memcpy(nDest, vertices, numVertices*sizeof(afTerrainPatch::PATCHVERTEX));
- return numVertices;
- }
- void afTerrainPatch::setScale(const afVec3& nScale)
- {
- scale = nScale;
- }
- void afTerrainPatch::setHeightMapPosition(int nX0, int nY0)
- {
- hmX0 = nX0;
- hmY0 = nY0;
- }
- void afTerrainPatch::setRealTessellation(int nTes)
- {
- oldRealSelfTes = realSelfTes;
- newRealSelfTes = nTes;
- }
- bool afTerrainPatch::updateTessellation()
- {
- if(left && left->oldRealSelfTes<5 && left->newRealSelfTes!=left->oldRealSelfTes)
- recalcBorderLeft = true;
- if(right && right->oldRealSelfTes<5 && right->newRealSelfTes!=right->oldRealSelfTes)
- recalcBorderRight = true;
- if(bottom && bottom->oldRealSelfTes<5 && bottom->newRealSelfTes!=bottom->oldRealSelfTes)
- recalcBorderBottom = true;
- if(top && top->oldRealSelfTes<5 && top->newRealSelfTes!=top->oldRealSelfTes)
- recalcBorderTop = true;
- int lT = left->getNewTessellationSafe(),
- rT = right->getNewTessellationSafe(),
- bT = bottom->getNewTessellationSafe(),
- tT = top->getNewTessellationSafe();
- //oldRealSelfTes = realSelfTes;
- //bool lReTes = leftTes!=lT && lT>selfTes;
- if(forceBufferCreate || newRealSelfTes!=realSelfTes || newSelfTes!=selfTes || leftTes!=lT || rightTes!=rT || bottomTes!=bT || topTes!=tT)
- {
- realSelfTes = newRealSelfTes;
- selfTes = newSelfTes;
- leftTes = lT;
- rightTes = rT;
- bottomTes = bT;
- topTes = tT;
- //selfTes = 1;
- //leftTes = rightTes = topTes = bottomTes = 2;
- assert(selfTes-lT<=1);
- assert(selfTes-rT<=1);
- assert(selfTes-bT<=1);
- assert(selfTes-tT<=1);
- createTessellation(selfTes, leftTes, rightTes, bottomTes, topTes);
- forceBufferCreate = false;
- //numVertices = numNewVertices;
- //numIndices = numNewIndices;
- forceBufferCreate = true;
- }
- float er0 = errors[realSelfTes].diff,
- er1 = errors[realSelfTes+1].diff,
- maxErr = master->getMaxError();
- if(realSelfTes>=MAX_SUBDIV)
- er1 = 2.0f*er0;
- currentError = (maxErr-er0)/(er1-er0);
- if(realSelfTes>=4 && currentError>1.0f)
- currentError = 1.0f;
- assert(currentError<=1.0f);
- return false;
- }
- bool afTerrainPatch::updateTessellation2()
- {
- float selfTesEx = getExactTessellation(),
- leftTesEx = (left && left->isActive()) ? left->getExactTessellation() : -1.0f,
- rightTesEx = (right && right->isActive()) ? right->getExactTessellation() : -1.0f,
- bottomTesEx = (bottom && bottom->isActive()) ? bottom->getExactTessellation() : -1.0f,
- topTesEx = (top && top->isActive()) ? top->getExactTessellation() : -1.0f;
- newFollowsLeft = (selfTesEx<leftTesEx) || (selfTesEx==leftTesEx&& !left->newFollowsRight);
- newFollowsRight = (selfTesEx<rightTesEx) || (selfTesEx==rightTesEx && !right->newFollowsLeft);
- newFollowsBottom = (selfTesEx<bottomTesEx) || (selfTesEx==bottomTesEx && !bottom->newFollowsTop);
- newFollowsTop = (selfTesEx<topTesEx) || (selfTesEx==topTesEx && !top->newFollowsBottom);
- // check if this patch does no longer follow a neighbor
- // if there was no retessellation due to some other reason, we have to do one NOW
- if(!forceBufferCreate)
- if((!newFollowsLeft && followsLeft) || (!newFollowsRight && followsRight) ||
- (!newFollowsBottom && followsBottom) || (!newFollowsTop && followsTop))
- {
- assert(selfTes-leftTes<=1);
- assert(selfTes-rightTes<=1);
- assert(selfTes-bottomTes<=1);
- assert(selfTes-topTes<=1);
- createTessellation(selfTes, leftTes, rightTes, bottomTes, topTes);
- numVertices = numNewVertices;
- numIndices = numNewIndices;
- forceRetessellation = true;
- }
- fillMorphVertices();
- return false;
- }
- bool afTerrainPatch::updateTessellation3()
- {
- checkBorderLeft();
- checkBorderRight();
- checkBorderBottom();
- checkBorderTop();
- fillBuffers();
- followsLeft = newFollowsLeft;
- followsRight = newFollowsRight;
- followsBottom = newFollowsBottom;
- followsTop = newFollowsTop;
- recalcBorderLeft = false;
- recalcBorderRight = false;
- recalcBorderBottom = false;
- recalcBorderTop = false;
- forceRetessellation = false;
- return false;
- }
- int afTerrainPatch::render()
- {
- if(!isVisible())
- return 0;
- if(iBuffer==NULL || vBuffer==NULL) // nothing to do ?
- return 0;
- float factorLeft2=0.0f, factorRight2=0.0f, factorBottom2=0.0f, factorTop2=0.0f;
- assert(selfTes>=0 && selfTes<=MAX_SUBDIV);
- factorSelf = 1.0f-currentError;
- factorLeft = left ? 1.0f-left->getCurrentError() : 0.0f;
- factorRight = right ? 1.0f-right->getCurrentError() : 0.0f;
- factorBottom = bottom ? 1.0f-bottom->getCurrentError() : 0.0f;
- factorTop = top ? 1.0f-top->getCurrentError() : 0.0f;
- assert(factorSelf>=0.0f);
- assert(factorLeft>=0.0f);
- assert(factorRight>=0.0f);
- assert(factorBottom>=0.0f);
- assert(factorTop>=0.0f);
- // clamping for patches which use selfTes!=realSelfTes
- //
- if(factorSelf>=1.0f)
- factorSelf = 1.0f;
- if(factorLeft>=1.0f)
- factorLeft = 1.0f;
- if(factorRight>=1.0f)
- factorRight = 1.0f;
- if(factorBottom>=1.0f)
- factorBottom = 1.0f;
- if(factorTop>=1.0f)
- factorTop = 1.0f;
- factorLeft2 = (1.0f-factorSelf) * factorLeft;
- factorRight2 = (1.0f-factorSelf) * factorRight;
- factorBottom2 = (1.0f-factorSelf) * factorBottom;
- factorTop2 = (1.0f-factorSelf) * factorTop;
- D3DXVECTOR4 weights0(factorSelf, 0.0f, 0.5f, 1.0f),
- weights2(factorLeft, factorLeft2, factorRight, factorRight2),
- weights3(factorBottom, factorBottom2, factorTop, factorTop2);
- pd3dDevice->SetVertexShaderConstantF(0, (float*)&weights0, 1);
- pd3dDevice->SetVertexShaderConstantF(2, (float*)&weights2, 1);
- pd3dDevice->SetVertexShaderConstantF(3, (float*)&weights3, 1);
- pd3dDevice->SetStreamSource(0, vBuffer, 0,sizeof(PATCHVERTEX_MORPH_HW));
- pd3dDevice->SetIndices(iBuffer);
- // draw the patch with one single D3D call
- HRESULT hr = pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0, 0, numVertices, 0, numIndices-2);
- if(hr==D3D_OK)
- return numIndices-2;
- else
- return 0;
- }
- // check if the patch is visible on the screen (clipping)
- //
- bool afTerrainPatch::checkVisibility(const D3DXMATRIX* nMatrix, const afPlane nPlanes[6])
- {
- D3DXVECTOR3 pt0,pt1,pt2,pt3,pt4,pt5,pt6,pt7, tpt0,tpt1,tpt2,tpt3,tpt4,tpt5,tpt6,tpt7, tp0,tp1,tp2,tp3;
- const D3DXMATRIX& mat = *nMatrix;
- //visible = true;
- //return;
- // create and transform the cubes corners vertices
- //
- pt0.x = pos.x; pt0.y = pos.y + minY; pt0.z = pos.z;
- pt1.x = pos.x + scale.x; pt1.y = pos.y + minY; pt1.z = pos.z;
- pt2.x = pos.x; pt2.y = pos.y + minY; pt2.z = pos.z + scale.z;
- pt3.x = pos.x + scale.x; pt3.y = pos.y + minY; pt3.z = pos.z + scale.z;
- pt4.x = pt0.x; pt4.y = pt0.y + maxY; pt4.z = pt0.z;
- pt5.x = pt1.x; pt5.y = pt1.y + maxY; pt5.z = pt1.z;
- pt6.x = pt2.x; pt6.y = pt2.y + maxY; pt6.z = pt2.z;
- pt7.x = pt3.x; pt7.y = pt3.y + maxY; pt7.z = pt3.z;
- D3DXVec3TransformCoord(&tpt0, &pt0, &mat);
- D3DXVec3TransformCoord(&tpt1, &pt1, &mat);
- D3DXVec3TransformCoord(&tpt2, &pt2, &mat);
- D3DXVec3TransformCoord(&tpt3, &pt3, &mat);
- D3DXVec3TransformCoord(&tpt4, &pt4, &mat);
- D3DXVec3TransformCoord(&tpt5, &pt5, &mat);
- D3DXVec3TransformCoord(&tpt6, &pt6, &mat);
- D3DXVec3TransformCoord(&tpt7, &pt7, &mat);
- // check against all six planes
- //
- for(int i=0; i<6; i++)
- {
- const afPlane& p = nPlanes[i];
- bool v = false;
- if(tpt0.x*p.x + tpt0.y*p.y + tpt0.z*p.z < p.d)
- v = true;
- else
- if(tpt1.x*p.x + tpt1.y*p.y + tpt1.z*p.z < p.d)
- v = true;
- else
- if(tpt2.x*p.x + tpt2.y*p.y + tpt2.z*p.z < p.d)
- v = true;
- else
- if(tpt3.x*p.x + tpt3.y*p.y + tpt3.z*p.z < p.d)
- v = true;
- else
- if(tpt4.x*p.x + tpt4.y*p.y + tpt4.z*p.z < p.d)
- v = true;
- else
- if(tpt5.x*p.x + tpt5.y*p.y + tpt5.z*p.z < p.d)
- v = true;
- else
- if(tpt6.x*p.x + tpt6.y*p.y + tpt6.z*p.z < p.d)
- v = true;
- else
- if(tpt7.x*p.x + tpt7.y*p.y + tpt7.z*p.z < p.d)
- v = true;
- if(v==false)
- {
- setVisible(false);
- return false;
- }
- }
- setVisible(true);
- return true;
- }
- void afTerrainPatch::setVisible(bool nVis)
- {
- visible = nVis;
- if(visible)
- {
- flagActive = true;
- if(!active)
- init();
- }
- else if(active)
- deinit();
- }
- void afTerrainPatch::calcMinMaxY()
- {
- afVec3 p;
- minY = scale.y;
- maxY = 0.0f;
- for(int x=0; x<SOURCE_WIDTH; x++)
- for(int y=0; y<SOURCE_HEIGHT; y++)
- {
- getVertex(x,y, p);
- if(p.y<minY)
- minY = p.y;
- if(p.y>maxY)
- maxY = p.y;
- }
- }
- void afTerrainPatch::updateProjectedErrors(const D3DXMATRIX* nMatrix)
- {
- D3DXVECTOR3 corr0, real0, corr, real;
- setD3DVec(corr0, errors[1].correct);
- D3DXVec3TransformCoord(&corr, &corr0, nMatrix);
- assert(corr.z>0.0f);
- if(corr.z<0.0f)
- corr.z = 0.0f;
- for(int i=1; i<=MAX_SUBDIV; i++)
- {
- setD3DVec(real0, errors[i].real);
- D3DXVec3TransformCoord(&real, &real0, nMatrix);
- assert(real.z>0.0f);
- if(real.z<0.0f)
- real.z = 0.0f;
- afVec3 diff(corr.x-real.x, corr.y-real.y, corr.z-real.z);
- errors[i].diff = diff.length();
- if(errors[i].diff<errors[i-1].diff*1.1f)
- errors[i].diff = errors[i-1].diff*1.1f;
- }
- }
- void afTerrainPatch::calcErrors()
- {
- for(int i=0; i<=MAX_SUBDIV; i++)
- calcError(i);
- }
- void afTerrainPatch::calcError(int nTes)
- {
- float sumError = 0.0f;
- int numErrors = 0;
- if(nTes!=0)
- {
- int pow = getPowerTwo(nTes),
- x0,y0, xi,yi;
- for(y0=0; y0<SOURCE_HEIGHT-pow; y0+=pow)
- for(x0=0; x0<SOURCE_WIDTH-pow; x0+=pow)
- for(yi=1; yi<pow; yi++)
- for(xi=1; xi<pow; xi++)
- {
- int x = x0+xi,
- y = y0+yi;
- float fx0 = (float)xi/(float)pow, fx1 = 1.0f-fx0,
- fy0 = (float)yi/(float)pow, fy1 = 1.0f-fy0;
- float height00 = getHeight(x0,y0),
- height10 = getHeight(x0+pow,y0),
- height01 = getHeight(x0,y0+pow),
- height11 = getHeight(x0+pow,y0+pow);
- float paintHeight = fx1*fy1 * height00 +
- fx0*fy1 * height10 +
- fx1*fy0 * height01 +
- fx0*fy0 * height11,
- correctHeight = getHeight(x,y);
- float er = (float)fabs(correctHeight - paintHeight);
- numErrors++;
- sumError += er;
- }
- float error = sumError / numErrors;
- getVertex(SOURCE_WIDTH/2, SOURCE_HEIGHT/2, errors[nTes].correct);
- errors[nTes].real = errors[nTes].correct;
- errors[nTes].real.y += error;
- errors[nTes].diff = error;
- }
- }
- float afTerrainPatch::getExactTessellation() const
- {
- if(realSelfTes<0)
- return -1.0f;
- if(currentError<0.0f)
- return (float)realSelfTes;
- else
- return (float)realSelfTes + currentError;
- }
- int afTerrainPatch::getPowerTwo(int nVal)
- {
- switch(nVal)
- {
- case 0:
- default:
- return 1;
- case 1:
- return 2;
- case 2:
- return 4;
- case 3:
- return 8;
- case 4:
- return 16;
- case 5:
- return 32;
- case 6:
- return 64;
- }
- }
- void afTerrainPatch::createTessellation(int nCenter, int nLeft, int nRight, int nBottom, int nTop)
- {
- assert(indexMap);
- assert(vertices);
- assert(indices);
- memset(indexMap, 0xff, MAX_VERTICES*sizeof(unsigned short));
- numNewVertices = numNewIndices = 0;
- int pow = getPowerTwo(nCenter);
- assert(nCenter-nLeft<=1);
- assert(nCenter-nRight<=1);
- assert(nCenter-nBottom<=1);
- assert(nCenter-nTop<=1);
- bool bLeft(nLeft<nCenter), bRight(nRight<nCenter), bBottom(nBottom<nCenter), bTop(nTop<nCenter);
- if(pow==16)
- addLevel4PatchTriangles(bLeft, bRight, bBottom, bTop);
- else
- for(int y=0; y<SOURCE_HEIGHT-pow; y+=pow)
- addTriangleRow(y, pow, bLeft, bRight, bBottom, bTop);
- assert((numNewIndices&1) == 0); // indices must always be an even number (we store quads as two triangles)
- if(realSelfTes>selfTes)
- reduceShapeTo(realSelfTes, vertices);
- makeBordersSimpler(vertices);
- }
- /****************************************************************************************
- * *
- * *
- * Tessellation Sub Methods *
- * *
- * *
- ****************************************************************************************/
- // calls makeSimpler() sequentially to make a mesh with
- // selfTes<nTes to look like being created with nTes
- void afTerrainPatch::reduceShapeTo(int nTes, PATCHVERTEX *nData)
- {
- for(int t=nTes; t>0; t--)
- if(selfTes<t)
- makeSimpler(t, nData);
- }
- void afTerrainPatch::makeBordersSimpler(PATCHVERTEX *nData)
- {
- int sT = selfTes;
- int x,y, idx,idx0,idx1, pow,
- lDiff = sT-leftTes,
- rDiff = sT-rightTes,
- bDiff = sT-bottomTes,
- tDiff = sT-topTes;
- if((lDiff==1 || lDiff==-1) && left)
- {
- pow = getPowerTwo(min(leftTes,sT));
- for(y=pow; y<SOURCE_HEIGHT-1; y+=2*pow)
- {
- idx = indexMap[0 + y*SOURCE_WIDTH];
- idx0 = indexMap[0 + (y-pow)*SOURCE_WIDTH];
- idx1 = indexMap[0 + (y+pow)*SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idx0!=0xffff);
- assert(idx1!=0xffff);
- nData[idx].pos.y = (nData[idx0].pos.y + nData[idx1].pos.y)/2.0f;
- }
- }
- if((rDiff==1 || rDiff==-1) && right)
- {
- pow = getPowerTwo(min(rightTes,sT));
- for(y=pow; y<SOURCE_HEIGHT-1; y+=2*pow)
- {
- idx = indexMap[SOURCE_WIDTH-1 + y*SOURCE_WIDTH];
- idx0 = indexMap[SOURCE_WIDTH-1 + (y-pow)*SOURCE_WIDTH];
- idx1 = indexMap[SOURCE_WIDTH-1 + (y+pow)*SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idx0!=0xffff);
- assert(idx1!=0xffff);
- nData[idx].pos.y = (nData[idx0].pos.y + nData[idx1].pos.y)/2.0f;
- }
- }
- if((bDiff==1 || bDiff==-1) && bottom)
- {
- pow = getPowerTwo(min(bottomTes, sT));
- for(x=pow; x<SOURCE_WIDTH-1; x+=2*pow)
- {
- idx = indexMap[x + 0*SOURCE_WIDTH];
- idx0 = indexMap[x-pow + 0*SOURCE_WIDTH];
- idx1 = indexMap[x+pow + 0*SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idx0!=0xffff);
- assert(idx1!=0xffff);
- nData[idx].pos.y = (nData[idx0].pos.y + nData[idx1].pos.y)/2.0f;
- }
- }
- if((tDiff==1 || tDiff==-1) && top)
- {
- pow = getPowerTwo(min(topTes,sT));
- for(x=pow; x<SOURCE_WIDTH-1; x+=2*pow)
- {
- idx = indexMap[x + (SOURCE_HEIGHT-1)*SOURCE_WIDTH];
- idx0 = indexMap[x-pow + (SOURCE_HEIGHT-1)*SOURCE_WIDTH];
- idx1 = indexMap[x+pow + (SOURCE_HEIGHT-1)*SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idx0!=0xffff);
- assert(idx1!=0xffff);
- nData[idx].pos.y = (nData[idx0].pos.y + nData[idx1].pos.y)/2.0f;
- }
- }
- }
- // this methods makes the mesh looking simpler by
- // putting vertices into position inbetween its neighbors
- // this method can do only for one step at a time
- // (to make a tes_1 mesh look like tes_3 first call
- // makeSimpler(3,...) then makeSimpler(2,...)
- // Call reduceShapeTo() which cares about those constraints
- // automatically
- void afTerrainPatch::makeSimpler(int nTes, PATCHVERTEX *nData)
- {
- assert(selfTes<nTes);
- assert(nTes>0);
- int pow = getPowerTwo(nTes-1),
- x,y, xc,yc;
- for(yc=y=0; y<SOURCE_HEIGHT; y+=pow,yc++)
- for(xc=x=0; x<SOURCE_WIDTH; x+=pow,xc++)
- calculateInbetweenVertex(x, y, xc, yc, pow, nData);
- }
- void afTerrainPatch::calculateInbetweenVertex(int x, int y, int xc, int yc, int pow, PATCHVERTEX *nData)
- {
- float heightLeftTop=0.0f, heightRightBottom=0.0f;
- int idx, idxLT,idxRB;
- idx = calculateDiagonalVertices(x, y, xc, yc, pow, nData, heightLeftTop, idxLT, heightRightBottom, idxRB);
- if(idx>=0)
- nData[idx].pos.y = (heightLeftTop + heightRightBottom) / 2.0f;
- }
- int afTerrainPatch::calculateDiagonalVertices(int x, int y, int xc, int yc, int pow, PATCHVERTEX *nData,
- float& nHeightLeftTop, int& idxLT, float& nHeightRightBottom, int& idxRB)
- {
- int c = (xc&1) + (yc&1)*2,
- idx = indexMap[x + y*SOURCE_WIDTH];
- assert(idx!=0xffff);
- switch(c)
- {
- case 0: // even-x & even-y
- // nothing to do...
- return -1;
- case 1: // odd-x & even-y
- assert(x>0 && x<SOURCE_WIDTH-1);
- idxLT = indexMap[x-pow + y*SOURCE_WIDTH];
- idxRB = indexMap[x+pow + y*SOURCE_WIDTH];
- assert(idxLT!=0xffff);
- assert(idxRB!=0xffff);
- nHeightLeftTop = nData[idxLT].pos.y;
- nHeightRightBottom = nData[idxRB].pos.y;
- return idx;
- case 2: // even-x & odd-y
- assert(y>0 && y<SOURCE_HEIGHT-1);
- idxLT = indexMap[x + (y+pow)*SOURCE_WIDTH];
- idxRB = indexMap[x + (y-pow)*SOURCE_WIDTH];
- assert(idxLT!=0xffff);
- assert(idxRB!=0xffff);
- nHeightLeftTop = nData[idxLT].pos.y;
- nHeightRightBottom = nData[idxRB].pos.y;
- return idx;
- case 3: // odd-x & odd-y
- assert(x>0 && x<SOURCE_WIDTH-1);
- assert(y>0 && y<SOURCE_HEIGHT-1);
- idxLT = indexMap[x-pow + (y+pow)*SOURCE_WIDTH];
- idxRB = indexMap[x+pow + (y-pow)*SOURCE_WIDTH];
- assert(idxLT!=0xffff);
- assert(idxRB!=0xffff);
- nHeightLeftTop = nData[idxLT].pos.y;
- nHeightRightBottom = nData[idxRB].pos.y;
- return idx;
- default:
- assert(false); // should never come here...
- return -1;
- }
- //nData[idx].pos.y = (y0+y1)/2.0f;
- }
- void afTerrainPatch::addTriangleRow(int nY, int nPow, bool nLeft, bool nRight, bool nBottom, bool nTop)
- {
- int powH = nPow/2;
- // special case: bottom line with nBottom
- //
- if(nY==0 && nBottom)
- {
- addTriangleBottomRow(nPow, nLeft, nRight);
- return;
- }
- if(nY!=0)
- {
- addLastIndexAgain();
- addIndex(getIndex(0,nY));
- }
- // special case: top line with nTop
- //
- if(nY>=SOURCE_HEIGHT-2*nPow && nTop)
- {
- addTriangleTopRow(nPow, nLeft, nRight);
- return;
- }
- // all other cases
- //
- int x, x0=0, x1=SOURCE_WIDTH;
- if(nLeft)
- {
- assert(powH>=1);
- addIndex(getIndex(0,nY));
- addIndex(getIndex(0,nY+powH));
- addIndex(getIndex(nPow,nY));
- addIndex(getIndex(0,nY+nPow));
- addIndex(getIndex(nPow,nY+nPow));
- addLastIndexAgain(); // finalize sub-strip
- x0 = nPow;
- }
- if(nRight)
- x1 -= nPow;
- for(x=x0; x<x1; x+=nPow)
- {
- addIndex(getIndex(x,nY));
- addIndex(getIndex(x,nY+nPow));
- }
- if(nRight)
- {
- assert(powH>=1);
- addIndex(getIndex(SOURCE_WIDTH-1-nPow,nY));
- addLastIndexAgain(); // reverse oriented triangles
- addIndex(getIndex(SOURCE_WIDTH-1,nY));
- addIndex(getIndex(SOURCE_WIDTH-1-nPow,nY+nPow));
- addIndex(getIndex(SOURCE_WIDTH-1,nY+powH));
- addIndex(getIndex(SOURCE_WIDTH-1,nY+nPow));
- }
- }
- void afTerrainPatch::addTriangleBottomRow(int nPow, bool nLeft, bool nRight)
- {
- int powH = nPow/2;
- int x0=0, x1=SOURCE_WIDTH-1;
- assert(powH>=1);
- if(nLeft)
- {
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,nPow));
- addIndex(getIndex(nPow,0));
- addIndex(getIndex(nPow,nPow));
- x0 = nPow;
- }
- assert((numNewIndices&1) == 0);
- if(nRight)
- x1 -= nPow;
- for(int x=x0; x<x1; x+=nPow)
- {
- addIndex(getIndex(x,0));
- addLastIndexAgain(); // reverse oriented triangles
- addIndex(getIndex(x+powH,0));
- addIndex(getIndex(x,nPow));
- addIndex(getIndex(x+nPow,0));
- addIndex(getIndex(x+nPow,nPow));
- }
- assert((numNewIndices&1) == 0);
- if(nRight)
- {
- addIndex(getIndex(SOURCE_WIDTH-1-nPow,0));
- addIndex(getIndex(SOURCE_WIDTH-1-nPow,nPow));
- addIndex(getIndex(SOURCE_WIDTH-1-powH,0));
- addIndex(getIndex(SOURCE_WIDTH-1,0));
- addLastIndexAgain(); // finalize sub-strip
- addIndex(getIndex(SOURCE_WIDTH-1-nPow,nPow));
- addIndex(getIndex(SOURCE_WIDTH-1,powH));
- addIndex(getIndex(SOURCE_WIDTH-1,nPow));
- }
- assert((numNewIndices&1) == 0);
- }
- void afTerrainPatch::addTriangleTopRow(int nPow, bool nLeft, bool nRight)
- {
- int powH = nPow/2;
- int x0=0, x1=SOURCE_WIDTH-1;
- assert(powH>=1);
- if(nLeft)
- {
- addIndex(getIndex(0,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(0,SOURCE_HEIGHT-1-powH));
- addIndex(getIndex(nPow,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(0,SOURCE_HEIGHT-1));
- addIndex(getIndex(powH,SOURCE_HEIGHT-1));
- addLastIndexAgain(); // reverse oriented triangles
- addIndex(getIndex(nPow,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(nPow,SOURCE_HEIGHT-1));
- x0 = nPow;
- }
- assert((numNewIndices&1) == 0);
- if(nRight)
- x1 -= nPow;
- for(int x=x0; x<x1; x+=nPow)
- {
- addIndex(getIndex(x,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(x,SOURCE_HEIGHT-1));
- addIndex(getIndex(x+nPow,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(x+powH,SOURCE_HEIGHT-1));
- addIndex(getIndex(x+nPow,SOURCE_HEIGHT-1));
- addLastIndexAgain(); // reverse oriented triangles
- }
- if(nRight)
- {
- addIndex(getIndex(x,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(x,SOURCE_HEIGHT-1));
- addIndex(getIndex(x+nPow,SOURCE_HEIGHT-1-nPow));
- addIndex(getIndex(x+powH,SOURCE_HEIGHT-1));
- addIndex(getIndex(x+nPow,SOURCE_HEIGHT-1-powH));
- addIndex(getIndex(x+nPow,SOURCE_HEIGHT-1));
- }
- }
- void afTerrainPatch::addLevel4PatchTriangles(bool nLeft, bool nRight, bool nBottom, bool nTop)
- {
- const int powH = 8, pow = 16;
- int code = (nLeft ? 1 : 0) | (nRight ? 2 : 0) | (nBottom ? 4 : 0) | (nTop ? 8 : 0);
- // use the created code for fast selection of the case to build...
- //
- switch(code)
- {
- case 0:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(pow,pow));
- break;
- case 1:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,pow));
- addLastIndexAgain();
- break;
- case 2:
- addIndex(getIndex(pow,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,0));
- addLastIndexAgain();
- break;
- case 3:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(pow,pow));
- break;
- case 4:
- addIndex(getIndex(0,0));
- addLastIndexAgain();
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(pow,pow));
- break;
- case 5:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(pow,pow));
- break;
- case 6:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(pow,0));
- addLastIndexAgain();
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(pow,pow));
- break;
- case 7:
- addIndex(getIndex(pow,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,0));
- addLastIndexAgain();
- break;
- case 8:
- addIndex(getIndex(pow,pow));
- addLastIndexAgain();
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(0,0));
- break;
- case 9:
- addIndex(getIndex(pow,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(0,pow));
- addLastIndexAgain();
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(0,0));
- break;
- case 10:
- addIndex(getIndex(pow,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(0,0));
- break;
- case 11:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,pow));
- addLastIndexAgain();
- break;
- case 12:
- addIndex(getIndex(0,0));
- addLastIndexAgain();
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,pow));
- addLastIndexAgain();
- break;
- case 13:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,pow));
- addLastIndexAgain();
- break;
- case 14:
- addIndex(getIndex(pow,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,0));
- addLastIndexAgain();
- break;
- case 15:
- addIndex(getIndex(0,0));
- addIndex(getIndex(0,powH));
- addIndex(getIndex(powH,0));
- addIndex(getIndex(0,pow));
- addIndex(getIndex(pow,0));
- addIndex(getIndex(powH,pow));
- addIndex(getIndex(pow,powH));
- addIndex(getIndex(pow,pow));
- break;
- }
- assert((numNewIndices&1) == 0); // indices must always be an even number (we store quads as two triangles)
- }
- inline float afTerrainPatch::getHeight(int nX, int nY) const
- {
- assert(nX>=0 && nX<SOURCE_WIDTH);
- assert(nY>=0 && nY<SOURCE_HEIGHT);
- assert(master);
- return pos.y + scale.y * master->getHeight(hmX0+nX, hmY0+nY); // - scale.y*0.5f;
- }
- inline void afTerrainPatch::getVertex(int nX, int nY, afVec3& nPoint) const
- {
- assert(nX>=0 && nX<SOURCE_WIDTH);
- assert(nY>=0 && nY<SOURCE_HEIGHT);
- nPoint.x = pos.x+scale.x*nX / (float)(SOURCE_WIDTH-1);
- nPoint.y = getHeight(nX,nY);
- nPoint.z = pos.z+scale.z*nY / (float)(SOURCE_HEIGHT-1);
- }
- inline void afTerrainPatch::getTexCoord(int nX, int nY, afVec2& nTCoord) const
- {
- assert(nX>=0 && nX<SOURCE_WIDTH);
- assert(nY>=0 && nY<SOURCE_HEIGHT);
- assert(master);
- master->getTexCoord(hmX0+nX, hmY0+nY, nTCoord);
- }
- inline void afTerrainPatch::getNormal(int nX, int nY, afVec3& nNormal) const
- {
- assert(nX>=0 && nX<SOURCE_WIDTH);
- assert(nY>=0 && nY<SOURCE_HEIGHT);
- assert(master);
- master->getNormal(hmX0+nX, hmY0+nY, nNormal);
- }
- unsigned short afTerrainPatch::getIndex(int nX, int nY)
- {
- int idx = nX + nY * SOURCE_WIDTH;
- assert(nX>=0 && nX<SOURCE_WIDTH);
- assert(nY>=0 && nY<SOURCE_HEIGHT);
- assert(idx<MAX_VERTICES);
- if(indexMap[idx]==0xffff)
- {
- indexMap[idx] = (unsigned short)numNewVertices;
- getVertex(nX,nY, vertices[numNewVertices].pos);
- getTexCoord(nX,nY, vertices[numNewVertices].tex);
- numNewVertices++;
- }
- return indexMap[idx];
- }
- int afTerrainPatch::getNewTessellationSafe() const
- {
- if(this==NULL)
- return MAX_SUBDIV;
- if(!isVisible())
- return selfTes; // MAX_SUBDIV;
- return getNewTessellation();
- }
- void afTerrainPatch::fillMorphVertices()
- {
- if(forceBufferCreate || forceRetessellation)
- {
- memcpy(verticesLow, vertices, numNewVertices*sizeof(PATCHVERTEX));
- if(realSelfTes<4)
- {
- reduceShapeTo(realSelfTes+1, verticesLow);
- makeBordersSimpler(verticesLow);
- }
- //if(selfTes==realSelfTes+1)
- // memcpy(verticesLow, vertices, numNewVertices*sizeof(PATCHVERTEX));
- for(int i=0; i<numNewVertices; i++)
- yMoveSelf[i] = vertices[i].pos.y - verticesLow[i].pos.y;
- }
- }
- void afTerrainPatch::checkBorderLeft()
- {
- int i, y,yc, pow;
- if(forceBufferCreate || forceRetessellation || followsLeft!=newFollowsLeft)
- {
- for(i=0; i<numNewVertices; i++)
- yMoveLeft[i] = 0.0f;
- for(i=0; i<numNewVertices; i++)
- yMoveLeft2[i] = 0.0f;
- }
- if(newFollowsLeft && (!followsLeft || forceBufferCreate || forceRetessellation || recalcBorderLeft))
- {
- // copy shared border column
- //
- assert(selfTes==left->rightTes);
- assert(leftTes==left->selfTes);
- assert(left->indexMap);
- pow = getPowerTwo(min(selfTes,leftTes));
- for(y=pow; y<SOURCE_HEIGHT-1; y+=pow)
- {
- int idx = indexMap[0 + y * SOURCE_WIDTH],
- idxL = left->indexMap[SOURCE_WIDTH-1 + y * SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idxL!=0xffff);
- verticesLow[idx].pos.y = left->verticesLow[idxL].pos.y;
- vertices[idx].pos.y = left->vertices[idxL].pos.y;
- yMoveLeft[idx] = left->yMoveSelf[idxL];
- yMoveSelf[idx] = 0.0f;
- }
- if(selfTes>=3)
- return;
- // correct border neighbors
- //
- pow = getPowerTwo(selfTes);
- for(y=pow,yc=1; y<SOURCE_HEIGHT-1; y+=pow,yc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(pow, y, 1, yc, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- float moveLT = vertices[idxLT].pos.y - verticesLow[idxLT].pos.y;
- verticesLow[idx].pos.y = (yLT + yRB) / 2.0f;
- // our vertex is moved 50% by the left (-top) neighbor
- // this garanties that this vertex is on the diagonal when currentError is 0.0f
- yMoveLeft2[idx] = moveLT * 0.5f;
- yMoveSelf[idx] = vertices[idx].pos.y - verticesLow[idx].pos.y;
- }
- // correct neighbors to lie on a diagonal
- //
- if(selfTes!=realSelfTes)
- {
- pow = getPowerTwo(selfTes);
- for(y=pow,yc=1; y<SOURCE_HEIGHT-1; y+=pow,yc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(pow, y, 1, yc, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- verticesLow[idx].pos.y = (yLT + yRB) * 0.5f;
- vertices[idx].pos.y = (vertices[idxLT].pos.y + vertices[idxRB].pos.y) * 0.5f;
- // the real new part: this vertex always STAYS on the diagonal
- //
- yMoveLeft2[idx] = 0.0f;
- yMoveLeft[idx] = (vertices[idxLT].pos.y - verticesLow[idxLT].pos.y) * 0.5f;
- yMoveSelf[idx] = (vertices[idxRB].pos.y - verticesLow[idxRB].pos.y) * 0.5f;
- }
- // necessary to recorrect the shared right-top border neighbor
- //
- if(followsBottom)
- recalcBorderBottom = true;
- }
- }
- }
- void afTerrainPatch::checkBorderRight()
- {
- int i, y,yc, pow, xcMax;
- if(forceBufferCreate || forceRetessellation || followsRight!=newFollowsRight)
- {
- for(i=0; i<numNewVertices; i++)
- yMoveRight[i] = 0.0f;
- for(i=0; i<numNewVertices; i++)
- yMoveRight2[i] = 0.0f;
- }
- if(newFollowsRight && (!followsRight || forceBufferCreate || forceRetessellation || recalcBorderRight))
- {
- // copy shared border column
- //
- assert(selfTes==right->leftTes);
- assert(rightTes==right->selfTes);
- assert(right->indexMap);
- pow = getPowerTwo(min(selfTes,rightTes));
- for(y=pow; y<SOURCE_HEIGHT-1; y+=pow)
- {
- int idx = indexMap[SOURCE_WIDTH-1 + y * SOURCE_WIDTH],
- idxR = right->indexMap[0 + y * SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idxR!=0xffff);
- verticesLow[idx].pos.y = right->verticesLow[idxR].pos.y;
- vertices[idx].pos.y = right->vertices[idxR].pos.y;
- yMoveRight[idx] = right->yMoveSelf[idxR];
- yMoveSelf[idx] = 0.0f;
- }
- // correct border neighbors
- //
- if(realSelfTes<3)
- {
- pow = getPowerTwo(realSelfTes);
- xcMax = (SOURCE_WIDTH-1-pow)/pow;
- for(y=pow,yc=1; y<SOURCE_HEIGHT-1; y+=pow,yc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(SOURCE_WIDTH-1-pow, y, xcMax, yc, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- verticesLow[idx].pos.y = (yLT + yRB) * 0.5f;
- // our vertex is moved 50% by the right (-bottom) neighbor
- // this garanties that this vertex is on the diagonal when currentError is 0.0f
- yMoveRight2[idx] = (vertices[idxRB].pos.y - verticesLow[idxRB].pos.y) * 0.5f;
- yMoveSelf[idx] = vertices[idx].pos.y - verticesLow[idx].pos.y;
- }
- }
- // correct neighbors to lie on a diagonal
- //
- if(selfTes!=realSelfTes)
- {
- pow = getPowerTwo(selfTes);
- xcMax = (SOURCE_WIDTH-1-pow)/pow;
- for(y=pow,yc=1; y<SOURCE_HEIGHT-1; y+=pow,yc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(SOURCE_WIDTH-1-pow, y, xcMax, yc, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- verticesLow[idx].pos.y = (yLT + yRB) * 0.5f;
- vertices[idx].pos.y = (vertices[idxLT].pos.y + vertices[idxRB].pos.y) * 0.5f;
- // the real new part: this vertex always STAYS on the diagonal
- //
- yMoveRight2[idx] = 0.0f;
- yMoveRight[idx] = (vertices[idxRB].pos.y - verticesLow[idxRB].pos.y) * 0.5f;
- yMoveSelf[idx] = (vertices[idxLT].pos.y - verticesLow[idxLT].pos.y) * 0.5f;
- }
- // necessary to recorrect the shared right-top border neighbor
- //
- if(followsTop)
- recalcBorderTop = true;
- }
- }
- }
- void afTerrainPatch::checkBorderBottom()
- {
- int i, x,xc, pow;
- if(forceBufferCreate || forceRetessellation || followsBottom!=newFollowsBottom)
- {
- for(i=0; i<numNewVertices; i++)
- yMoveBottom[i] = 0.0f;
- for(i=0; i<numNewVertices; i++)
- yMoveBottom2[i] = 0.0f;
- }
- if(newFollowsBottom && (!followsBottom || forceBufferCreate || forceRetessellation || recalcBorderBottom))
- {
- // copy shared border column
- //
- assert(selfTes==bottom->topTes);
- assert(bottomTes==bottom->selfTes);
- assert(bottom->indexMap);
- pow = getPowerTwo(min(selfTes,bottomTes));
- for(x=pow; x<SOURCE_WIDTH-1; x+=pow)
- {
- int idx = indexMap[x + 0 * SOURCE_WIDTH],
- idxB = bottom->indexMap[x + (SOURCE_WIDTH-1) * SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idxB!=0xffff);
- verticesLow[idx].pos.y = bottom->verticesLow[idxB].pos.y;
- vertices[idx].pos.y = bottom->vertices[idxB].pos.y;
- yMoveBottom[idx] = bottom->yMoveSelf[idxB];
- yMoveSelf[idx] = 0.0f;
- }
- if(selfTes>=3)
- return;
- // correct border neighbors
- //
- pow = getPowerTwo(selfTes);
- for(x=pow,xc=1; x<SOURCE_WIDTH-1; x+=pow,xc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(x, pow, xc, 1, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- float moveRB = vertices[idxRB].pos.y - verticesLow[idxRB].pos.y;
- verticesLow[idx].pos.y = (yLT + yRB) / 2.0f;
- // our vertex is moved 50% by the right (-bottom) neighbor
- // this garanties that this vertex is on the diagonal when currentError is 0.0f
- yMoveBottom2[idx] = moveRB * 0.5f;
- yMoveSelf[idx] = vertices[idx].pos.y - verticesLow[idx].pos.y;
- }
- // correct neighbors to lie on a diagonal
- //
- if(selfTes!=realSelfTes)
- {
- pow = getPowerTwo(selfTes);
- for(x=pow,xc=1; x<SOURCE_WIDTH-1; x+=pow,xc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(x, pow, xc, 1, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- verticesLow[idx].pos.y = (yLT + yRB) * 0.5f;
- vertices[idx].pos.y = (vertices[idxLT].pos.y + vertices[idxRB].pos.y) * 0.5f;
- // the real new part: this vertex always STAYS on the diagonal
- //
- yMoveBottom2[idx] = 0.0f;
- yMoveBottom[idx] = (vertices[idxRB].pos.y - verticesLow[idxRB].pos.y) * 0.5f;
- if(yMoveLeft[idx]==0.0f)
- yMoveSelf[idx] = (vertices[idxLT].pos.y - verticesLow[idxLT].pos.y) * 0.5f;
- else
- yMoveSelf[idx] = 0.0f;
- }
- }
- }
- }
- void afTerrainPatch::checkBorderTop()
- {
- int i, x,xc, pow, ycMax;
- if(forceBufferCreate || forceRetessellation || followsTop!=newFollowsTop)
- {
- for(i=0; i<numNewVertices; i++)
- yMoveTop[i] = 0.0f;
- for(i=0; i<numNewVertices; i++)
- yMoveTop2[i] = 0.0f;
- }
- if(newFollowsTop && (!followsTop || forceBufferCreate || forceRetessellation || recalcBorderTop))
- {
- // copy shared border column
- //
- assert(selfTes==top->bottomTes);
- assert(topTes==top->selfTes);
- assert(top->indexMap);
- pow = getPowerTwo(min(selfTes,topTes));
- for(x=pow; x<SOURCE_WIDTH-1; x+=pow)
- {
- int idx = indexMap[x + (SOURCE_HEIGHT-1) * SOURCE_WIDTH],
- idxT = top->indexMap[x + 0 * SOURCE_WIDTH];
- assert(idx!=0xffff);
- assert(idxT!=0xffff);
- verticesLow[idx].pos.y = top->verticesLow[idxT].pos.y;
- vertices[idx].pos.y = top->vertices[idxT].pos.y;
- yMoveTop[idx] = top->yMoveSelf[idxT];
- yMoveSelf[idx] = 0.0f;
- }
- if(selfTes>=3)
- return;
- // correct border neighbors
- //
- pow = getPowerTwo(selfTes);
- ycMax = (SOURCE_WIDTH-1-pow)/pow;
- for(x=pow,xc=1; x<SOURCE_WIDTH-1; x+=pow,xc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(x, SOURCE_HEIGHT-1-pow, xc, ycMax, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- float moveLT = vertices[idxLT].pos.y - verticesLow[idxLT].pos.y;
- verticesLow[idx].pos.y = (yLT + yRB) / 2.0f;
- // our vertex is moved 50% by the left (-top) neighbor
- // this garanties that this vertex is on the diagonal when currentError is 0.0f
- yMoveTop2[idx] = moveLT * 0.5f;
- yMoveSelf[idx] = vertices[idx].pos.y - verticesLow[idx].pos.y;
- }
- // correct neighbors to lie on a diagonal
- //
- if(selfTes!=realSelfTes)
- {
- pow = getPowerTwo(selfTes);
- ycMax = (SOURCE_WIDTH-1-pow)/pow;
- for(x=pow,xc=1; x<SOURCE_WIDTH-1; x+=pow,xc++)
- {
- float yLT=0.0f,yRB=0.0f;
- int idx, idxLT=0,idxRB=0;
- idx = calculateDiagonalVertices(x, SOURCE_HEIGHT-1-pow, xc, ycMax, pow, verticesLow, yLT,idxLT, yRB,idxRB);
- assert(idx>=0 && idx!=0xffff);
- verticesLow[idx].pos.y = (yLT + yRB) * 0.5f;
- vertices[idx].pos.y = (vertices[idxLT].pos.y + vertices[idxRB].pos.y) * 0.5f;
- // the real new part: this vertex always STAYS on the diagonal
- //
- yMoveTop2[idx] = 0.0f;
- yMoveTop[idx] = (vertices[idxLT].pos.y - verticesLow[idxLT].pos.y) * 0.5f;
- if(yMoveRight[idx]==0.0f)
- yMoveSelf[idx] = (vertices[idxRB].pos.y - verticesLow[idxRB].pos.y) * 0.5f;
- else
- yMoveSelf[idx] = 0.0f;
- }
- }
- }
- }
- bool afTerrainPatch::fillBuffers()
- {
- if(master->getMergePatches() && selfTes==4)
- {
- numIndices = numNewIndices;
- numVertices = numNewVertices;
- forceBufferCreate = false;
- return true;
- }
- if(!forceBufferCreate && !forceRetessellation &&
- followsLeft==newFollowsLeft && !recalcBorderLeft &&
- followsRight==newFollowsRight && !recalcBorderRight &&
- followsBottom==newFollowsBottom && !recalcBorderBottom &&
- followsTop==newFollowsTop && !recalcBorderTop)
- return true;
- if(!checkBuffers())
- return false;
- if(numVertices==0 || numIndices==0) // nothing to do ???
- return true;
- int i;
- //if(forceBufferCreate)
- master->addBufferCreateCount();
- // fill vertex buffer
- //
- PATCHVERTEX_MORPH_HW* pVertices = NULL;
- vBuffer->Lock(0, 0, (void**)&pVertices, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
- for(i=0; i<numVertices; i++)
- {
- pVertices[i].posX = vertices[i].pos.x;
- pVertices[i].posZ = vertices[i].pos.z;
- pVertices[i].texX = vertices[i].tex.x;
- pVertices[i].texY = vertices[i].tex.y;
- pVertices[i].posY = verticesLow[i].pos.y;
- pVertices[i].yMoveSelf = yMoveSelf[i];
- pVertices[i].v0 = 0.0f,
- pVertices[i].v1 = 1.0f,
- pVertices[i].yMoveLeft = yMoveLeft[i];
- pVertices[i].yMoveLeft2 = yMoveLeft2[i];
- pVertices[i].yMoveRight = yMoveRight[i];
- pVertices[i].yMoveRight2 = yMoveRight2[i];
- pVertices[i].yMoveBottom = yMoveBottom[i];
- pVertices[i].yMoveBottom2 = yMoveBottom2[i];
- pVertices[i].yMoveTop = yMoveTop[i];
- pVertices[i].yMoveTop2 = yMoveTop2[i];
- }
- vBuffer->Unlock();
- // fill index buffer
- //
- WORD* pIndices = NULL;
- iBuffer->Lock(0, 0, (void**)&pIndices, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
- for(i=0; i<numIndices; i++)
- {
- pIndices[i] = indices[i];
- //pgLog::trace("%d: %dn", i, indices[i]);
- }
- iBuffer->Unlock();
- //pgLog::trace("patch buffers (%d|%d) filledn", gridX,gridY);
- return true;
- }
- bool afTerrainPatch::checkBuffers()
- {
- // create new buffers if the size changed
- //
- if(numIndices<numNewIndices || forceBufferCreate)
- {
- numIndices = numNewIndices;
- SAFE_RELEASE(iBuffer)
- if(numIndices>0)
- if(FAILED(pd3dDevice->CreateIndexBuffer(numIndices * sizeof(WORD), D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC,
- D3DFMT_INDEX16, D3DPOOL_DEFAULT, &iBuffer,NULL)))
- {
- afLog::error("creating index buffer for terrainpatch failed");
- return false;
- }
- //pgLog::trace("index-buffer (%d|%d) recreatedn", gridX,gridY);
- }
- if(numVertices<numNewVertices || forceBufferCreate)
- {
- numVertices = numNewVertices;
- SAFE_RELEASE(vBuffer)
- if(numVertices>0)
- if(FAILED(pd3dDevice->CreateVertexBuffer(numVertices * sizeof(PATCHVERTEX_MORPH_HW), D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC,
- 0, D3DPOOL_DEFAULT, &vBuffer,NULL)))
- {
- afLog::error("creating base vertex buffer for terrainpatch failed");
- SAFE_RELEASE(iBuffer);
- return false;
- }
- }
- forceBufferCreate = false;
- return true;
- }