afTerrain.cpp
资源名称:AirForce.rar [点击查看]
上传用户:kaiguan
上传日期:2007-10-28
资源大小:1074k
文件大小:30k
源码类别:
其他游戏
开发平台:
Visual C++
- #include "afTerrain.h"
- #include "afMatrix.h"
- #include "afPlane.h"
- #include "afTime.h"
- #include "afSettings.h"
- #include "afTerrainPatch.h"
- #include "afApplication.h"
- inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }
- afTerrain::afTerrain() : iBuffer(NULL), vBuffer(NULL), fogColor(1.0f, 1.0f, 1.0f, 1.0f),
- profileUpdate("update()"), profileRender("render()")
- {
- for(int i=0; i<=4; i++)
- patchCount[i] = 0;
- bufferCreateCount = 0;
- mergeSmallPatches = true;
- // default value
- pvs = NULL;
- patches = NULL;
- patchesX = patchesY = 0;
- heightmap = NULL;
- hmData=NULL;
- normals = NULL;
- maxError = 0.015f;
- desiredFPS = 0;
- activePatches = NULL;
- forceBufferCreate = true;
- skySpeedX = skySpeedY = 0.0f;
- fogNear = fogFar = 0.0f;
- mipFilter = afTextureStage::FILTER_LINEAR;
- m_pTerrainDecl=NULL;
- m_pTerrainShader=NULL;
- numNewVertices = numNewIndices = numVertices = numIndices = 0;
- useUnitDistance = true;
- updateWorldMatrix();
- }
- void afTerrain::setPatchSize(float nX, float nY, float nZ)
- {
- patchDX = nX;
- patchDY = nY;
- patchDZ = nZ;
- }
- void afTerrain::setHeightMap(afImage* nImage)
- {
- if(nImage==NULL)
- return;
- heightmap = nImage;
- hmData = heightmap->getData();
- hmWidth = heightmap->getWidth();
- hmHeight = heightmap->getHeight();
- }
- void afTerrain::setSkyMap(afTexture* nSkyMap, float nX, float nY, float nSpeedX, float nSpeedY)
- {
- fillPassInfo(&skyPass, nSkyMap, nX, nY, NULL);
- skyPosX = skyPosY = 0.0f;
- skySpeedX = nSpeedX;
- skySpeedY = nSpeedY;
- }
- inline void afTerrain::updateSkyMatrix()
- {
- if(!skyPass.texColor)
- return;
- float ftime = afTime::getLastFrameTime();
- skyPosX += ftime * skySpeedX;
- skyPosY += ftime * skySpeedY;
- D3DXMatrixScaling(&skyPass.matrix, skyPass.repeatX, skyPass.repeatY, 1.0f);
- skyPass.matrix._31 = skyPosX;
- skyPass.matrix._32 = skyPosY;
- }
- void afTerrain::fillPassInfo(MultiPassInfo* nPass, afTexture* nTexture, float nRepeatX, float nRepeatY, afTexture* nModTexture)
- {
- nPass->texColor = nTexture;
- nPass->texMod = nModTexture;
- if(nRepeatX==0.0f) nRepeatX = 1.0f;
- if(nRepeatY==0.0f) nRepeatY = 1.0f;
- nPass->repeatX = nRepeatX;
- nPass->repeatY = nRepeatY;
- D3DXMatrixScaling(&nPass->matrix, nPass->repeatX, nPass->repeatY, 1.0f);
- }
- void afTerrain::addPass(afTexture* nColorTexture, float nRepeatX, float nRepeatY, afTexture* nTransTexture)
- {
- MultiPassInfo* pass = new MultiPassInfo();
- multiPassInfos.addTail(pass);
- fillPassInfo(pass, nColorTexture, nRepeatX, nRepeatY, nTransTexture);
- }
- void afTerrain::calcPassVisibility(MultiPassInfo* nInfo, int nX, int nY)
- {
- int dx = nInfo->texMod->getWidth(),
- dy = nInfo->texMod->getHeight();
- int px = dx / patchesX,
- py = dy / patchesY;
- int x0 = nX*px, x1 = nX*px+px,
- y0 = nY*py, y1 = nY*py+py,
- x,y;
- unsigned char *data = nInfo->visData,
- min = 10, max = 245;
- int pitch = nInfo->visPitch;
- nInfo->inVis = nInfo->fullVis = true;
- for(x=x0; x<x1; x++)
- for(y=y0; y<y1; y++)
- {
- int idx = 4*x + (dy-1-y)*pitch + 3;
- unsigned char d = data[idx];
- if(d>=min)
- nInfo->inVis = false;
- if(d<=max)
- nInfo->fullVis = false;
- }
- }
- void afTerrain::build()
- {
- int x,y, pass, pass2;
- if(!heightmap)
- return;
- patches = new afTerrainPatchPPtr[patchesY];
- for(y=0; y<patchesY; y++)
- patches[y] = new afTerrainPatchPtr[patchesX];
- sizeX = patchDX * patchesX;
- sizeY = patchDY;
- sizeZ = patchDZ * patchesY;
- if(pvsName.getLength()>0)
- {
- pvs = new afTerrainPVS();
- if(!pvs->load(afSettings::tmpFullPath(pvsName+".pvs")))
- {
- delete pvs;
- pvs = NULL;
- }
- }
- for(pass=1; pass<multiPassInfos.getSize(); pass++)
- {
- MultiPassInfo* p = multiPassInfos[pass];
- bool ok = p->texMod->getData(p->visData, p->visPitch);
- assert(ok);
- }
- for(y=0; y<patchesY; y++)
- for(x=0; x<patchesX; x++)
- {
- afTerrainPatch* patch = createPatch(x,y);
- patches[y][x] = patch;
- patch->setScale(afVec3(patchDX, patchDY, patchDZ));
- patch->setPosition(afVec3(x*patchDX, 0.0f, y*patchDZ));
- patch->setHeightMapPosition(x*(afTerrainPatch::SOURCE_WIDTH-1),
- y*(afTerrainPatch::SOURCE_HEIGHT-1));
- patch->calcErrors();
- patch->calcMinMaxY();
- // calculate for each pass if there is anything to draw
- // (check the alpha map)
- int visFlags = 0,
- numPasses = multiPassInfos.getSize();
- for(pass=1; pass<numPasses; pass++)
- calcPassVisibility(multiPassInfos[pass], x,y);
- visFlags = afTerrainPatch::VIS_LAYERALL;
- for(pass=1; pass<numPasses; pass++) // base pass checking
- if(multiPassInfos[pass]->fullVis)
- visFlags &= ~afTerrainPatch::VIS_BASE;
- for(pass=1; pass<numPasses; pass++) // additional passes
- {
- if(multiPassInfos[pass]->inVis) // is this pass invisible ? (also no need to check on)
- {
- visFlags &= ~afTerrainPatch::getAddLayerFlag(pass);
- continue;
- }
- for(pass2=pass+1; pass2<numPasses; pass2++) // see if another pass completely covers this pass
- if(multiPassInfos[pass2]->fullVis)
- {
- visFlags &= ~afTerrainPatch::getAddLayerFlag(pass);
- break;
- }
- }
- patch->setVisFlags(visFlags);
- }
- // tell each patch about its neighbors
- //
- for(y=0; y<patchesY; y++)
- for(x=0; x<patchesX; x++)
- patches[y][x]->setNeighbors(x>0 ? patches[y][x-1] : NULL,
- x<patchesX-1 ? patches[y][x+1] : NULL,
- y>0 ? patches[y-1][x] : NULL,
- y<patchesY-1 ? patches[y+1][x] : NULL);
- for(pass=1; pass<multiPassInfos.getSize(); pass++)
- {
- MultiPassInfo* p = multiPassInfos[pass];
- p->texMod->releaseData();
- }
- BuildVertexShader();
- }
- void afTerrain::update()
- {
- if(!patches)
- return;
- afVec3 cPos, lPos,rPos;
- float fact=(float)tan(g_pApp->m_Camera.GetFOVX()/2.0f),
- farP =g_pApp->m_Camera.GetFarPlane();
- int x=0,y=0;
- D3DXVECTOR3 pt0,pt1,pt2, tpt0,tpt1,tpt2;
- D3DXMATRIX vMat, tMat;
- afTerrainPatchPtr curPatch;
- afPlane planes[6];
- profileUpdate.beginSection();
- if(desiredFPS>0)
- {
- if(afTime::getFPS()<desiredFPS*0.95f && maxError<0.5f)
- maxError *= 1.03f;
- else
- if(afTime::getFPS()>desiredFPS*1.05f && maxError>0.005f)
- maxError *= 0.97f;
- }
- numPatchesProcessed = 0;
- updateSkyMatrix();
- updateWorldMatrix();
- // calculate which rectangle of the map
- // is visible from the clipping frustum
- lPos = cPos + afVec3(-farP*fact, 0.0f, farP);
- rPos = cPos + afVec3( farP*fact, 0.0f, farP);
- pt0.x=cPos.x; pt0.y=cPos.y; pt0.z=cPos.z;
- pt1.x=lPos.x; pt1.y=lPos.y; pt1.z=lPos.z;
- pt2.x=rPos.x; pt2.y=rPos.y; pt2.z=rPos.z;
- D3DXMatrixInverse(&vMat, NULL, g_pApp->m_Camera.GetViewMatrix());
- D3DXMatrixMultiply(&tMat, &worldMatrix, &vMat);
- D3DXVec3TransformCoord(&tpt0, &pt0, &tMat);
- D3DXVec3TransformCoord(&tpt1, &pt1, &tMat);
- D3DXVec3TransformCoord(&tpt2, &pt2, &tMat);
- int x0 = (int)(tpt0.x / patchDX), y0 = (int)(tpt0.z / patchDZ),
- x1 = (int)(tpt1.x / patchDX), y1 = (int)(tpt1.z / patchDZ),
- x2 = (int)(tpt2.x / patchDX), y2 = (int)(tpt2.z / patchDZ);
- maxX = -1; maxY = -1; minX = patchesX+1; minY = patchesY+1;
- if(x0<minX) minX = x0;
- if(y0<minY) minY = y0;
- if(x0>maxX) maxX = x0;
- if(y0>maxY) maxY = y0;
- if(x1<minX) minX = x1;
- if(y1<minY) minY = y1;
- if(x1>maxX) maxX = x1;
- if(y1>maxY) maxY = y1;
- if(x2<minX) minX = x2;
- if(y2<minY) minY = y2;
- if(x2>maxX) maxX = x2;
- if(y2>maxY) maxY = y2;
- minX-=2; minY-=2; maxX+=2; maxY+=2;
- if(minX<0) minX = 0;
- if(minY<0) minY = 0;
- if(maxX>=patchesX) maxX = patchesX-1;
- if(g_pApp->m_Camera.getUpdateVisibility())
- {
- // mark all patches in the list as non active
- // (checkVisibility will set this to active, if
- // it is in the list and is active)
- curPatch = activePatches;
- while(curPatch)
- {
- curPatch->setFlagActive(false);
- curPatch = curPatch->getNextActive();
- }
- // create and transform the clipping planes
- // (we transform them here, so that checkVisibility()
- // doesn't need to transform any corner points)
- g_pApp->m_Camera.createClippingPlanes(planes);
- // first determine for each patch if
- // it will be visible during the next rendering
- int pvsX=-1, pvsY=-1, pvsZ=-1;
- if(pvs)
- {
- pvsX = tpt0.x>=0.0f ? (int)(tpt0.x / patchDX) : -1;
- pvsY = tpt0.z>=0.0f ? patchesY-1 - (int)(tpt0.z / patchDZ) : -1;
- pvsZ = (int)((tpt0.y / patchDY) * 255) / pvs->getDataDZ();
- }
- D3DXMATRIX mat;
- D3DXMatrixMultiply(&mat, &worldMatrix, g_pApp->m_Camera.GetViewMatrix());
- for(y=minY; y<=maxY; y++)
- for(x=minX; x<=maxX; x++)
- if(patches[y][x])
- {
- if(patches[y][x]->checkVisibility(&mat, planes) && pvs)
- {
- // if the patch could not be frustum-culled we try pvs (if there is pvs...)
- //
- if(!pvs->isVisible(pvsX,pvsY,pvsZ, x,patchesY-1-y))
- patches[y][x]->setVisible(false);
- }
- numPatchesProcessed++;
- }
- // deinit all patches will are still in the
- // list, but where checkVisibility() has not been called
- curPatch = activePatches;
- while(curPatch)
- {
- if(!curPatch->getFlagActive())
- curPatch->deinit();
- curPatch = curPatch->getNextActive();
- }
- // next update the projected error
- // and tesselation stage
- D3DXMATRIX mat2, matT;
- D3DXMatrixTranslation(&matT, 0.0f, 0.0f, 1.2f*max(patchDY,max(patchDX,patchDZ)));
- D3DXMatrixMultiply(&mat2, &matT, g_pApp->m_Camera.GetProjMatrix());
- D3DXMatrixMultiply(&mat, g_pApp->m_Camera.GetViewMatrix(), &mat2);
- D3DXMatrixMultiply(&mat2, &worldMatrix, &mat);
- curPatch = activePatches;
- while(curPatch)
- {
- curPatch->updateProjectedErrors(&mat2);
- for(int i=afTerrainPatch::MAX_SUBDIV; i>=0; i--)
- if(curPatch->getProjectedError(i)<maxError)
- {
- curPatch->setRealTessellation(i);
- curPatch->setTessellation(i);
- break;
- }
- curPatch = curPatch->getNextActive();
- }
- // next check that each neighbor has only a
- // tesselation stage difference at max. 1
- if(useUnitDistance)
- {
- bool changed;
- do
- {
- changed=false;
- curPatch = activePatches;
- while(curPatch)
- {
- int tes = curPatch->getNewTessellation(),
- lT = curPatch->getLeft()->getNewTessellationSafe(),
- rT = curPatch->getRight()->getNewTessellationSafe(),
- bT = curPatch->getBottom()->getNewTessellationSafe(),
- tT = curPatch->getTop()->getNewTessellationSafe();
- int sT = min(min(lT+1,rT+1) , min(bT+1,tT+1));
- if(tes>sT)
- {
- curPatch->setTessellation(sT);
- //curPatch->setRealTessellation(sT);
- changed = true;
- }
- curPatch = curPatch->getNextActive();
- }
- } while(changed);
- }
- // finally update tesselation to be correct to
- // all the neighbours' tesselation stages
- numNewVertices = numNewIndices = 0;
- curPatch = activePatches;
- while(curPatch)
- {
- int tes = curPatch->getNewTessellation(),
- lT = curPatch->getLeft()->getNewTessellationSafe(),
- rT = curPatch->getRight()->getNewTessellationSafe(),
- bT = curPatch->getBottom()->getNewTessellationSafe(),
- tT = curPatch->getTop()->getNewTessellationSafe();
- assert(tes-lT<=1);
- assert(tes-rT<=1);
- assert(tes-bT<=1);
- assert(tes-tT<=1);
- curPatch->updateTessellation();
- numNewVertices += curPatch->getNumVertices();
- numNewIndices += curPatch->getNumIndices() + 2; // two more for degen-tris
- curPatch = curPatch->getNextActive();
- }
- // some patch types may need a second update method
- // (e.g.: to adapt to each other)
- curPatch = activePatches;
- while(curPatch)
- {
- curPatch->updateTessellation2();
- curPatch = curPatch->getNextActive();
- }
- // some patch types may need a third update method
- // (e.g.: to adapt to each other)
- curPatch = activePatches;
- while(curPatch)
- {
- curPatch->updateTessellation3();
- curPatch = curPatch->getNextActive();
- }
- }
- if(numNewIndices>0)
- numNewIndices -= 2; // the last patch does not need degen-tris
- profileUpdate.endSection();
- }
- inline void afTerrain::setupTextureStages(MultiPassInfo* nPass, bool nBasePass,bool bForceSoftware)
- {
- // texture stages setup
- //
- pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
- pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
- pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, nBasePass ? D3DTOP_DISABLE : D3DTOP_SELECTARG1);
- pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
- pd3dDevice->SetSamplerState(0,D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
- pd3dDevice->SetSamplerState(0,D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- pd3dDevice->SetSamplerState(0,D3DSAMP_MIPFILTER, mipFilter);
- pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
- if(nPass->texMod)
- {
- pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
- pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
- pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, nBasePass ? D3DTOP_DISABLE : D3DTOP_SELECTARG1);
- pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
- pd3dDevice->SetSamplerState(1,D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
- pd3dDevice->SetSamplerState(1,D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- pd3dDevice->SetSamplerState(1,D3DSAMP_MIPFILTER, mipFilter);
- pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX,bForceSoftware?0:1);
- pd3dDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);
- pd3dDevice->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- }
- else
- {
- pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
- pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- }
- // zbuffer, filling & culling setup
- //
- pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
- pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
- // fog setup
- //
- if(fogNear!=0.0f || fogFar!=0.0f)
- {
- float fogDens = 1.0f;
- pd3dDevice->SetRenderState(D3DRS_FOGENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_COLORVALUE(fogColor[0], fogColor[1], fogColor[2], fogColor[3]));
- pd3dDevice->SetRenderState(D3DRS_FOGSTART, FtoDW(fogNear));
- pd3dDevice->SetRenderState(D3DRS_FOGEND, FtoDW(fogFar));
- pd3dDevice->SetRenderState(D3DRS_FOGDENSITY, FtoDW(fogDens));
- pd3dDevice->SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
- }
- else
- pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
- // set textures
- //
- pd3dDevice->SetTexture(0, nPass->texColor->getD3DTexture());
- pd3dDevice->SetTexture(1, nPass->texMod->getD3DTexture());
- // setup lighting & blending
- //
- pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
- if(nBasePass)
- pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
- else
- {
- pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
- pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
- }
- // setup texture matrix for stage 0
- //
- if(bForceSoftware)
- {
- if(nPass->repeatX!=1.0f || nPass->repeatY!=1.0f)
- {
- pd3dDevice->SetTransform(D3DTS_TEXTURE0, &nPass->matrix);
- pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
- }
- else
- pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
- }
- else
- {
- D3DXMATRIX matTranspose;
- D3DXMatrixTranspose(&matTranspose, &nPass->matrix);
- g_pApp->m_pd3dDevice->SetVertexShaderConstantF(8,(float*)&matTranspose, 4);
- }
- pd3dDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
- }
- inline void afTerrain::setupTextureStagesForSky(bool bForceSoftware)
- {
- // texture stages setup
- //
- pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
- pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
- pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
- pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
- pd3dDevice->SetSamplerState(0,D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
- pd3dDevice->SetSamplerState(0,D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- pd3dDevice->SetSamplerState(0,D3DSAMP_MIPFILTER, mipFilter);
- pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
- pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
- pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- // zbuffer, filling & culling setup
- //
- pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
- pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
- // fog setup
- //
- if(fogNear!=0.0f || fogFar!=0.0f)
- {
- float fogDens = 0.0f;
- pd3dDevice->SetRenderState(D3DRS_FOGENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_COLORVALUE(fogColor[0], fogColor[1], fogColor[2], fogColor[3]));
- pd3dDevice->SetRenderState(D3DRS_FOGSTART, FtoDW(fogNear));
- pd3dDevice->SetRenderState(D3DRS_FOGEND, FtoDW(fogFar));
- pd3dDevice->SetRenderState(D3DRS_FOGDENSITY, FtoDW(fogDens));
- pd3dDevice->SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
- pd3dDevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_NONE);
- }
- else
- pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
- // set texture
- //
- pd3dDevice->SetTexture(0, skyPass.texColor->getD3DTexture());
- // setup lighting & blending
- //
- pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
- pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
- pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
- pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
- // setup texture matrix for stage 0
- //
- if(bForceSoftware)
- {
- if(skyPass.repeatX!=1.0f || skyPass.repeatY!=1.0f)
- {
- g_pApp->m_pd3dDevice->SetTransform(D3DTS_TEXTURE0, &skyPass.matrix);
- g_pApp->m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
- }
- else
- g_pApp->m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
- }
- else
- {
- D3DXMATRIX matTranspose;
- D3DXMatrixTranspose(&matTranspose, &skyPass.matrix);
- g_pApp->m_pd3dDevice->SetVertexShaderConstantF(8,(float*)&matTranspose, 4);
- }
- pd3dDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
- }
- inline void afTerrain::updateWorldMatrix()
- {
- D3DXMATRIX matScale, matMove, matRot, mat;
- afVec3 scale(1.0f, 1.0f, 1.0f);
- D3DXMatrixScaling(&matScale, scale.x, scale.y, scale.z);
- D3DXMatrixTranslation(&matMove, pos.x,pos.y,pos.z);
- D3DXMatrixRotationYawPitchRoll(&matRot, rot.x,rot.y,rot.z);
- D3DXMatrixMultiply(&mat, &matRot, &matMove);
- D3DXMatrixMultiply(&worldMatrix, &matScale, &mat);
- }
- void afTerrain::checkBuffers()
- {
- if(mergeSmallPatches)
- {
- assert(numNewIndices < 0xffff);
- if(numNewIndices > numIndices || forceBufferCreate)
- {
- SAFE_RELEASE(iBuffer);
- if(numNewIndices>0)
- if(FAILED(pd3dDevice->CreateIndexBuffer(numNewIndices * sizeof(WORD), D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
- D3DFMT_INDEX16, D3DPOOL_DEFAULT, &iBuffer,NULL)))
- {
- afLog::error("creating index buffer for terrain failed");
- return;
- }
- }
- numIndices = numNewIndices;
- if(numNewVertices > numVertices || forceBufferCreate)
- {
- SAFE_RELEASE(vBuffer);
- if(numNewVertices>0)
- {
- if(FAILED(pd3dDevice->CreateVertexBuffer(numNewVertices * sizeof(afTerrainPatch::PATCHVERTEX),
- D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
- D3DFVF_PATCHVERTEX, D3DPOOL_DEFAULT, &vBuffer,NULL)))
- {
- afLog::error("creating vertex buffer for terrain failed");
- SAFE_RELEASE(iBuffer);
- return;
- }
- }
- }
- numVertices = numNewVertices;
- }
- forceBufferCreate = false;
- }
- void afTerrain::render()
- {
- profileRender.beginSection();
- // activate the morph shader
- SetupVertexShader();
- afTerrainPatch* patch;
- afTerrainPatch::PATCHVERTEX* pVertices = NULL;
- WORD* pIndices = NULL;
- int i, pass, numTris=0, numPasses = multiPassInfos.getSize(), numPassesP;
- for(i=0; i<=afTerrainPatch::MAX_SUBDIV; i++)
- patchCount[i] = 0;
- numPatchesRendered = numPatchesPassesRendered = 0;
- if(mergeSmallPatches)
- {
- numNewVertices = 0;
- numNewIndices = 0;
- patch = activePatches;
- while(patch)
- {
- if(patch->getNewTessellation()==4)
- {
- numNewVertices += patch->getNumVertices();
- numNewIndices += patch->getNumIndices()+2;
- }
- patch = patch->getNextActive();
- }
- checkBuffers();
- }
- numPassesP = skyPass.texColor ? numPasses+1 : numPasses;
- for(pass=0; pass<numPassesP; pass++)
- {
- int numV=0, numI=0;
- if(pass<numPasses)
- setupTextureStages(multiPassInfos[pass], false,false);
- else
- setupTextureStagesForSky(false);
- if(mergeSmallPatches && vBuffer && iBuffer)
- {
- if(!SetupVertexShader())
- return;
- vBuffer->Lock(0, 0, (void**)&pVertices, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
- iBuffer->Lock(0, 0, (void**)&pIndices, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
- }
- patch = activePatches;
- while(patch)
- {
- int tes = patch->getNewTessellation();
- assert(tes>=0 && tes<=afTerrainPatch::MAX_SUBDIV);
- if(pass==0)
- {
- numPatchesRendered++;
- patchCount[tes]++;
- patch->setRendered(false);
- }
- if(pass<numPasses || patch->getVisFlags()&afTerrainPatch::getAddLayerFlag(pass))
- {
- if(mergeSmallPatches && tes==4)
- {
- // copy the vertex data
- //
- int numNewV = patch->fillBaseVertices(pVertices+numV);
- // then copy the indices, which must be updated to
- // reflect the moved vertex data (index shifts)
- //
- const WORD* indices = patch->getIndices();
- int n = patch->getNumIndices();
- if(numI>0) // add degen-tris to concenate strips
- {
- pIndices[numI++] = pIndices[numI-1];
- pIndices[numI++] = (unsigned short)(indices[0] + numV);
- }
- for(i=0; i<n; i++)
- pIndices[numI++] = (unsigned short)(indices[i] + numV);
- numV += numNewV;
- }
- else
- {
- numTris = patch->render();
- }
- patch->setRendered(true);
- numPatchesPassesRendered++;
- }
- patch = patch->getNextActive();
- }
- if(mergeSmallPatches && vBuffer && iBuffer)
- {
- if(pass<numPasses)
- setupTextureStages(multiPassInfos[pass], false,true);
- else
- setupTextureStagesForSky(true);
- iBuffer->Unlock();
- vBuffer->Unlock();
- assert(numV<=numNewVertices);
- assert(numI<=numNewIndices);
- pd3dDevice->SetVertexShader(NULL);
- pd3dDevice->SetFVF(D3DFVF_PATCHVERTEX);
- pd3dDevice->SetStreamSource(0, vBuffer,0,sizeof(afTerrainPatch::PATCHVERTEX));
- pd3dDevice->SetIndices(iBuffer);
- pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,0, numV, 0, numI-2);
- }
- }
- //afLog::info("numPatchesRendered:%d,numPatchesPassesRendered:%d",numPatchesRendered,numPatchesPassesRendered);
- profileRender.endSection();
- }
- float afTerrain::getHeightDif(int nX0, int nY0, int nX1, int nY1)
- {
- return getHeight(nX0,nY0) - getHeight(nX1,nY1);
- }
- void afTerrain::createNormals()
- {
- int x,y, w=heightmap->getWidth(), h=heightmap->getHeight();
- if(normals)
- delete normals;
- normals = new afVec3[w*h];
- for(y=0; y<h; y++)
- for(x=0; x<w; x++)
- {
- int idx = y*w+x;
- float dxp=0.0f,dxm=0.0f, dyp=0.0f,dym=0.0f;
- if(x>0 && x<w-1 && y>0 && y<w-1)
- {
- dxp = getHeightDif(x,y, x+1,y);
- dxm = getHeightDif(x,y, x-1,y);
- dyp = getHeightDif(x,y, x,y+1);
- dym = getHeightDif(x,y, x,y-1);
- }
- normals[idx].x = ((dxp - dxm)/2.0f) * patchDX * afTerrainPatch::SOURCE_WIDTH;
- normals[idx].y = patchDY;
- normals[idx].z = ((dyp - dym)/2.0f) * patchDZ * afTerrainPatch::SOURCE_HEIGHT;
- normals[idx].normalize();
- }
- normals[0] = normals[1+w];
- normals[w-1] = normals[w+w-2];
- normals[(h-1)*w] = normals[(h-2)*w+1];
- normals[(h-1)*w+w-1] = normals[(h-2)*w+w-2];
- for(x=1; x<w-1; x++)
- {
- normals[x] = normals[x+w];
- normals[x+(y-1)*w] = normals[x+(y-2)*w];
- }
- for(y=1; y<h-1; y++)
- {
- normals[y*w] = normals[y*w+1];
- normals[y*w+w-1] = normals[y*w+w-2];
- }
- }
- void afTerrain::deleteDeviceObjects()
- {
- int x,y;
- SAFE_RELEASE(iBuffer);
- SAFE_RELEASE(vBuffer);
- if(patches)
- {
- for(y=0; y<patchesY; y++)
- for(x=0; x<patchesX; x++)
- if(patches[y][x])
- patches[y][x]->deleteDeviceObjects();
- }
- SAFE_DELETE(pvs);
- for(int pass=0; pass<multiPassInfos.getSize(); pass++)
- {
- MultiPassInfo* p = multiPassInfos[pass];
- SAFE_DELETE(p);
- }
- DestroyVertexShader();
- }
- bool afTerrain::restoreDeviceObjects()
- {
- int x,y;
- forceBufferCreate = true;
- if(!patches)
- return true;
- for(y=0; y<patchesY; y++)
- for(x=0; x<patchesX; x++)
- if(patches[y][x])
- patches[y][x]->restoreDeviceObjects();
- return true;
- }
- void afTerrain::fillInfoString(afString& nStr)
- {
- float factor = (float)numPatchesPassesRendered/(float)numPatchesRendered;
- nStr.set("Terr: %d processed %d (%d passes -> x%.2f) rendered", numPatchesProcessed, numPatchesRendered, numPatchesPassesRendered, factor);
- }
- void afTerrain::fillInfoString2(afString& nStr)
- {
- nStr.set("%d %d %d %d %d | %d", patchCount[0], patchCount[1], patchCount[2], patchCount[3], patchCount[4], bufferCreateCount);
- bufferCreateCount = 0;
- }
- // this method is not yet working correctly...
- //
- bool afTerrain::intersectLine(const afVec3& nPos0, const afVec3& nPos1, float& nScalarPos) const
- {
- D3DXMATRIX mat;
- D3DXVECTOR3 p0,p1, tp0,tp1, ds, p;
- float len, flatLen, f = 0.0f, h;
- bool startAbove=false, curAbove=false, startAboveInit=false;
- D3DXMatrixInverse(&mat, NULL, &worldMatrix);
- p0.x=nPos0.x; p0.y=nPos0.y; p0.z=nPos0.z;
- p1.x=nPos1.x; p1.y=nPos1.y; p1.z=nPos1.z;
- D3DXVec3TransformCoord(&tp0, &p0, &mat);
- D3DXVec3TransformCoord(&tp1, &p1, &mat);
- tp0.x /= sizeX; tp0.y /= sizeY; tp0.z /= sizeZ;
- tp1.x /= sizeX; tp1.y /= sizeY; tp1.z /= sizeZ;
- if((tp0.x<0.0f && tp1.x<0.0f) || (tp0.x>1.0f && tp1.x>1.0f) ||
- (tp0.z<0.0f && tp1.z<0.0f) || (tp0.z>1.0f && tp1.z>1.0f))
- return false;
- ds = tp1-tp0;
- //ds.x *= 255.0f;
- //ds.z *= 255.0f;
- flatLen = (float)(sqrt(ds.x*ds.x + ds.z*ds.z));
- if(flatLen>0.0f)
- {
- ds.x /= flatLen;
- ds.y /= (255.0f*flatLen);
- ds.z /= flatLen;
- }
- len = (float)(sqrt(ds.x*ds.x + ds.y*ds.y + ds.z*ds.z));
- p = tp0;
- do
- {
- if(p.x>=0.0f && p.x<=hmWidth && p.z>=0.0f && p.z<=hmHeight)
- {
- if(!startAboveInit)
- {
- startAboveInit = true;
- startAbove = getHeight((int)p.x, (int)p.z) < p.y;
- }
- p += ds;
- f += 1.0f;
- h = getHeight((int)p.x, (int)p.z);
- curAbove = h < p.y;
- if(startAboveInit && curAbove!=startAbove)
- {
- //nScalarPos = (p-tp0).GetLength() / (tp1-tp0).length();
- nScalarPos = 0.0f;
- return true;
- }
- }
- else
- {
- p += ds;
- f += 1.0f;
- }
- } while(f<flatLen);
- return false;
- }
- bool afTerrain::projectDown(const afVec3& nPos, afVec3& nProjected) const
- {
- D3DXMATRIX mat;
- D3DXVECTOR3 p, tp;
- D3DXMatrixInverse(&mat, NULL, &worldMatrix);
- p.x=nPos.x; p.y=nPos.y; p.z=nPos.z;
- D3DXVec3TransformCoord(&tp, &p, &mat);
- tp.x /= sizeX; tp.y /= sizeY; tp.z /= sizeZ;
- float x = hmWidth*tp.x,
- y = hmHeight*tp.z;
- x -= 0.5f;
- y -= 0.5f;
- int ix = (int)x,
- iy = (int)y;
- float u = x - ix,
- v = y - iy;
- if(ix<0 || iy<0 || ix>=hmWidth-1 || iy>=hmHeight-1)
- return false;
- float h00 = getHeight(ix+0, iy+0),
- h10 = getHeight(ix+1, iy+0),
- h01 = getHeight(ix+0, iy+1),
- h11 = getHeight(ix+1, iy+1);
- tp.y = (1.0f-v) * ((1.0f-u)*h00 + u*h10) +
- v * ((1.0f-u)*h01 + u*h11);
- tp.x *= sizeX; tp.y *= sizeY; tp.z *= sizeZ;
- D3DXVec3TransformCoord(&p, &tp, &worldMatrix);
- nProjected.x=p.x; nProjected.y=p.y; nProjected.z=p.z;
- return true;
- }
- bool afTerrain::moveAboveSurface(afVec3& nPos, float nHeight, float /*nGlideFactor*/) const
- {
- afVec3 downPos;
- if(projectDown(nPos, downPos))
- {
- if(nPos.y < downPos.y + nHeight)
- {
- nPos.y = downPos.y + nHeight;
- return true;
- }
- }
- return false;
- }
- afTerrainPatch* afTerrain::createPatch(int nX, int nY)
- {
- return new afTerrainPatch(this, nX,nY);
- }
- bool afTerrain::BuildVertexShader()
- {
- D3DVERTEXELEMENT9 declTerrain[] =
- {
- { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
- { 0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
- { 0, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
- { 0, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
- D3DDECL_END()
- };
- HRESULT hr;
- if(FAILED( hr =g_pApp->m_pd3dDevice->CreateVertexDeclaration(declTerrain, &m_pTerrainDecl)))
- return false;
- LPD3DXBUFFER pCode = NULL;
- if( FAILED( hr = D3DXAssembleShaderFromFile(afSettings::tmpFullPath("shader/terrainMorph.vsh"), NULL, NULL, 0, &pCode, NULL)))
- return false;
- if( FAILED( hr = g_pApp->m_pd3dDevice->CreateVertexShader( (DWORD*)pCode->GetBufferPointer(),
- &m_pTerrainShader)))
- {
- SAFE_RELEASE( pCode );
- return false;
- }
- SAFE_RELEASE( pCode);
- return true;
- }
- void afTerrain::DestroyVertexShader()
- {
- SAFE_RELEASE(m_pTerrainShader);
- SAFE_RELEASE(m_pTerrainDecl);
- }
- inline bool afTerrain::SetupVertexShader()
- {
- D3DXMATRIX mat, matTranspose;
- D3DXMatrixMultiply(&mat, g_pApp->m_Camera.GetViewMatrix(),g_pApp->m_Camera.GetProjMatrix());
- D3DXMatrixTranspose(&matTranspose, &mat);
- g_pApp->m_pd3dDevice->SetVertexShaderConstantF(4,(float*)&matTranspose, 4);
- g_pApp->m_pd3dDevice->SetVertexDeclaration(m_pTerrainDecl);
- if(m_pTerrainShader)
- return(g_pApp->m_pd3dDevice->SetVertexShader(m_pTerrainShader)==S_OK);
- return false;
- }