#include "stdafx.h" #include "TerrainNode.h" #include "RenderSystem.h" #include "ResourceManager.h" #include "Ray.h" #include "LightSceneNode.h" #include "../TerrainEditor.h" /// Äøµ¿ë NiFrustumPlanes* cTerrainNode::mFrustum = 0; tArray* cTerrainNode::mVisibleArray = 0; /// Ãæµ¹ °Ë»ç¿ë const cRay* cTerrainNode::mRay = 0; float* cTerrainNode::mDistance = 0; NiPoint3* cTerrainNode::mContact = 0; const cSphere* cTerrainNode::mSphere = 0; tArray* cTerrainNode::mPickedArray = 0; cTerrainNode::cTerrainNode( cTerrainBranchNode* parent, unsigned int xi, unsigned int yi, unsigned int cellCount ) : mParent( parent ) { /// °æ°è »óÀÚ¸¦ ¼³Á¤ float unitsPerVertex = TERRAIN->GetUnitsPerVertex(); float minx = float(xi) * unitsPerVertex; float miny = float(yi) * unitsPerVertex; float maxx = minx + float(cellCount) * unitsPerVertex; float maxy = miny + float(cellCount) * unitsPerVertex; mBoundBox.Set( minx, miny, -1.0f, maxx, maxy, 1.0f ); mCenter.x = (minx + maxx) * 0.5f; mCenter.y = (miny + maxy) * 0.5f; mCenter.z = 0.0f; mRadius = (mBoundBox.GetMax() - mBoundBox.GetMin()).Length() * 0.5f; } cTerrainNode::~cTerrainNode() { } cTerrainBranchNode::cTerrainBranchNode( cTerrainBranchNode* parent, unsigned int xi, unsigned int yi, unsigned int cellCount ) : cTerrainNode( parent, xi, yi, cellCount ) { /// ÀÚ½Ä ³ëµå¸¦ »ý¼º unsigned int childCount = cellCount / 2; if( childCount > cTerrainLeafNode::mCellCount[0] ) { mChild[0] = new cTerrainBranchNode( this, xi, yi, childCount ); mChild[1] = new cTerrainBranchNode( this, xi + childCount, yi, childCount ); mChild[2] = new cTerrainBranchNode( this, xi, yi + childCount, childCount ); mChild[3] = new cTerrainBranchNode( this, xi + childCount, yi + childCount, childCount ); } else if( childCount == cTerrainLeafNode::mCellCount[0] ) { mChild[0] = new cTerrainLeafNode( this, xi, yi, childCount ); mChild[1] = new cTerrainLeafNode( this, xi + childCount, yi, childCount ); mChild[2] = new cTerrainLeafNode( this, xi, yi + childCount, childCount ); mChild[3] = new cTerrainLeafNode( this, xi + childCount, yi + childCount, childCount ); } else { assert( 0 && "invalid cell count" ); } assert( mChild[0] && mChild[1] && mChild[2] && mChild[3] ); } cTerrainBranchNode::~cTerrainBranchNode() { delete mChild[0]; delete mChild[1]; delete mChild[2]; delete mChild[3]; } void cTerrainBranchNode::UpdateBoundUpward() { /// °æ°è »óÀÚ¸¦ °»½Å cBox box; box.AddBox( mChild[0]->GetBoundBox() ); box.AddBox( mChild[1]->GetBoundBox() ); box.AddBox( mChild[2]->GetBoundBox() ); box.AddBox( mChild[3]->GetBoundBox() ); mBoundBox = box; mCenter = (mBoundBox.GetMin() + mBoundBox.GetMax()) * 0.5f; mRadius = (mBoundBox.GetMax() - mBoundBox.GetMin()).Length() * 0.5f; /// ºÎ¸ðÀÇ °æ°è »óÀÚ¸¦ °»½Å if( mParent ) mParent->UpdateBoundUpward(); } void cTerrainBranchNode::SyncHeight() { /// ÀÚ½Ä ³ëµå¿¡ ´ëÇØ Àç±Í È£Ãâ mChild[0]->SyncHeight(); mChild[1]->SyncHeight(); mChild[2]->SyncHeight(); mChild[3]->SyncHeight(); } void cTerrainBranchNode::SyncAlpha() { /// ÀÚ½Ä ³ëµå¿¡ ´ëÇØ Àç±Í È£Ãâ mChild[0]->SyncAlpha(); mChild[1]->SyncAlpha(); mChild[2]->SyncAlpha(); mChild[3]->SyncAlpha(); } void cTerrainBranchNode::SyncPaintAlpha() { mChild[0]->SyncPaintAlpha(); mChild[1]->SyncPaintAlpha(); mChild[2]->SyncPaintAlpha(); mChild[3]->SyncPaintAlpha(); } void cTerrainBranchNode::SyncColor() { /// ÀÚ½Ä ³ëµå¿¡ ´ëÇØ Àç±Í È£Ãâ mChild[0]->SyncColor(); mChild[1]->SyncColor(); mChild[2]->SyncColor(); mChild[3]->SyncColor(); } bool cTerrainBranchNode::CollideRay() { bool ret = false; float scale = NI_INFINITY; if( mBoundBox.IntersectRay( *mRay, scale ) ) { /// Àڽĵ鿡 ´ëÇØ ±³Â÷ °Ë»ç ret |= mChild[0]->CollideRay(); ret |= mChild[1]->CollideRay(); ret |= mChild[2]->CollideRay(); ret |= mChild[3]->CollideRay(); } return ret; } bool cTerrainBranchNode::CollideSphere() { bool ret = false; if( mBoundBox.IntersectSphere( *mSphere ) ) { /// Àڽĵ鿡 ´ëÇØ ±³Â÷ °Ë»ç ret |= mChild[0]->CollideSphere(); ret |= mChild[1]->CollideSphere(); ret |= mChild[2]->CollideSphere(); ret |= mChild[3]->CollideSphere(); } return ret; } unsigned int cTerrainLeafNode::mVersion = 0; unsigned int cTerrainLeafNode::mCellCount[TERRAIN_LOD_COUNT] = { 0 }; unsigned int cTerrainLeafNode::mLineCount[TERRAIN_LOD_COUNT] = { 0 }; cTerrainLeafNode::cTerrainLeafNode( cTerrainBranchNode* parent, unsigned int xi, unsigned int yi, unsigned int cellCount ) : cTerrainNode( parent, xi, yi, cellCount ) , mXIndex( xi ) , mYIndex( yi ) , mVisible( true ) , mTexture0( 0 ) , mTexture1( 0 ) , mTexture2( 0 ) , mTextureValue0( 0 ) , mTextureValue1( 0 ) , mLight( 0 ) , mLod( UINT_MAX ) , mCrackIndex( UINT_MAX ) , mIndexByLight( 0xFFFFFFFF ) { assert( cellCount == mCellCount[0] && "not leaf node!" ); mSiblingLeafNode[0] = 0; mSiblingLeafNode[1] = 0; mSiblingLeafNode[2] = 0; mSiblingLeafNode[3] = 0; /// ÁöÇüÀÇ ¸®ÇÁ ³ëµå ¹è¿­¿¡ ¼³Á¤ TERRAIN->SetLeafNode( xi / mCellCount[0], yi / mCellCount[0], this ); /// ¹öÆÛ¸¦ ¼³Á¤ mBuffer = TERRAIN->GetBuffer( xi, yi ); /// ÅØ½ºÃ³¸¦ ¼³Á¤ cTerrainTexture* tex = TERRAIN->GetTexture(0); SetTextures( tex, tex, tex ); /// À§Ä¡ ¹è¿­À» »ý¼º mHeights = new float[mLineCount[0] * mLineCount[0]]; /// ¾ËÆÄ ¹è¿­À» »ý¼º mAlphas = NiNew NiPoint3[mLineCount[0] * mLineCount[0]]; mPaintAlphas = NiNew NiPoint3[mLineCount[0] * mLineCount[0]]; /// »ö»ó ¹è¿­À» »ý¼º mColors = NiNew NiColor[mLineCount[0] * mLineCount[0]]; } cTerrainLeafNode::~cTerrainLeafNode() { Clear(); mSiblingLeafNode[0] = 0; mSiblingLeafNode[1] = 0; mSiblingLeafNode[2] = 0; mSiblingLeafNode[3] = 0; /// ¹è¿­À» Á¦°Å if( mHeights ) { delete [] mHeights; mHeights = 0; } if( mPaintAlphas ) { NiDelete [] mPaintAlphas; mPaintAlphas = 0; } if( mAlphas ) { NiDelete [] mAlphas; mAlphas = 0; } if( mColors ) { NiDelete [] mColors; mColors = 0; } /// Á¶¸í¿¡¼­ Å»Âø if( mLight ) { mLight->Detach( this ); mLight = 0; } } void cTerrainLeafNode::Clear() { /// ÅØ½ºÃ³¸¦ ÇØÁ¦ mTextureValue0 = 0; mTextureValue1 = 0; if( mTexture0 ) { mTexture0->Drop(); mTexture0 = 0; } if( mTexture1 ) { mTexture1->Drop(); mTexture1 = 0; } if( mTexture2 ) { mTexture2->Drop(); mTexture2 = 0; } } void cTerrainLeafNode::UpdateBoundUpward() { /// ¸®ÇÁ ³ëµå ¾ÈÀÇ ¸ðµç Á¤Á¡À¸·ÎºÎÅÍ ÃÖ¼Ò°ª, ÃÖ´ë°ªÀ» °è»ê float minz = +NI_INFINITY; float maxz = -NI_INFINITY; float z = 0.0f; for( unsigned int yi = 0; yi < mLineCount[0]; ++yi ) { for( unsigned int xi = 0; xi < mLineCount[0]; ++xi ) { z = TERRAIN->GetHeightFast( mXIndex + xi, mYIndex + yi ); if( z < minz ) minz = z; if( z > maxz ) maxz = z; } } /// °æ°è »óÀÚ¸¦ °»½Å NiPoint3 min = mBoundBox.GetMin(); NiPoint3 max = mBoundBox.GetMax(); min.z = minz; max.z = maxz; mBoundBox.Set( min, max ); mCenter = (min + max) * 0.5f; mRadius = (max - min).Length() * 0.5f; /// ºÎ¸ðÀÇ °æ°è »óÀÚ¸¦ °»½Å mParent->UpdateBoundUpward(); } void cTerrainLeafNode::UpdatePosCoords() { assert( mBuffer ); /// ¹ý¼± ¹è¿­À» °»½Å TERRAIN->ComputeNormals( mXIndex, mYIndex, mXIndex + mLineCount[0], mYIndex + mLineCount[0] ); /// ¹öÆÛ¸¦ °»½Å mBuffer->UpdatePosCoord( TERRAIN, mXIndex, mYIndex, mLineCount[0] ); /*// ¸®½ºÆ®¸¦ °»½Å for( unsigned int i = 0; i < TERRAIN_LOD_COUNT; ++i ) { unsigned int gridSize = mGridSize[i]; NiPoint3* posCoords = mPosCoords[i]; for( unsigned int j = 0; j < gridSize; ++j ) { mCrackPosCoords[i][0][j] = posCoords[0 + j]; mCrackPosCoords[i][1][j] = posCoords[cellCount * gridSize + j]; mCrackPosCoords[i][2][j] = posCoords[j * gridSize + 0]; mCrackPosCoords[i][3][j] = posCoords[j * gridSize + cellCount]; } for( unsigned int j = 0; j < 4; ++j ) { NiGeometryData* geomData = mTriCracks[i][j]->GetModelData(); //geomData->Replace( // unsigned short(gridSize), // mCrackPosCoords[i][j], // mCrackAlphas[i][j], // mCrackColors[i][j], // mCrackTexCoords[i][j], // 1, // NiGeometryData::NBT_METHOD_NONE ); geomData->MarkAsChanged( NiGeometryData::VERTEX_MASK ); //mTriCracks[i][j]->Update( 0.0f ); } } */ } void cTerrainLeafNode::UpdateColors() { assert( mBuffer ); mBuffer->UpdateColor( TERRAIN, mXIndex, mYIndex, mLineCount[0] ); /*// ¸®½ºÆ®¸¦ °»½Å for( unsigned int i = 0; i < TERRAIN_LOD_COUNT; ++i ) { unsigned int gridSize = mGridSize[i]; NiColorA* colors = mColors[i]; for( unsigned int j = 0; j < gridSize; ++j ) { mCrackColors[i][0][j] = colors[0 + j]; mCrackColors[i][1][j] = colors[cellCount * gridSize + j]; mCrackColors[i][2][j] = colors[j * gridSize + 0]; mCrackColors[i][3][j] = colors[j * gridSize + cellCount]; } for( unsigned int j = 0; j < 4; ++j ) { NiGeometryData* geomData = mTriCracks[i][j]->GetModelData(); //geomData->Replace( // unsigned short(gridSize), // mCrackPosCoords[i][j], // mCrackAlphas[i][j], // mCrackColors[i][j], // mCrackTexCoords[i][j], // 1, // NiGeometryData::NBT_METHOD_NONE ); geomData->MarkAsChanged( NiGeometryData::COLOR_MASK ); } } */ } void cTerrainLeafNode::UpdateAlphas() { assert( mBuffer ); mBuffer->UpdateAlpha( TERRAIN, mXIndex, mYIndex, mLineCount[0] ); /*// ¸®½ºÆ®¸¦ °»½Å for( unsigned int i = 0; i < TERRAIN_LOD_COUNT; ++i ) { unsigned int gridSize = mGridSize[i]; NiPoint3* alphas = mAlphas[i]; for( unsigned int j = 0; j < gridSize; ++j ) { mCrackAlphas[i][0][j] = alphas[0 + j]; mCrackAlphas[i][1][j] = alphas[cellCount * gridSize + j]; mCrackAlphas[i][2][j] = alphas[j * gridSize + 0]; mCrackAlphas[i][3][j] = alphas[j * gridSize + cellCount]; } for( unsigned int j = 0; j < 4; ++j ) { NiGeometryData* geomData = mTriCracks[i][j]->GetModelData(); //geomData->Replace( // unsigned short(gridSize), // mCrackPosCoords[i][j], // mCrackAlphas[i][j], // mCrackColors[i][j], // mCrackTexCoords[i][j], // 1, // NiGeometryData::NBT_METHOD_NONE ); geomData->MarkAsChanged( NiGeometryData::NORMAL_MASK ); } } */ } void cTerrainLeafNode::SyncHeight() { /// À§Ä¡ ¹è¿­À» °»½Å unsigned int lineCount = mLineCount[0]; for( unsigned int yi = 0, i = 0; yi < lineCount; ++yi ) { for( unsigned int xi = 0; xi < lineCount; ++xi, ++i ) { mHeights[i] = TERRAIN->GetHeightFast( mXIndex + xi, mYIndex + yi ); } } /* for( unsigned int i = 1, step = 2; i < TERRAIN_LOD_COUNT; ++i, step *= 2 ) { gridSize = mGridSize[i]; for( unsigned int j = 0, y = 0; y < gridSize; ++y ) { for( unsigned int x = 0; x < gridSize; ++x, ++j ) { mPosCoords[i][j].z = mPosCoords[0][y * step * mLineCount[0] + x * step].z; } } } */ /// °æ°è »óÀÚ¸¦ °»½Å UpdateBoundUpward(); } void cTerrainLeafNode::SyncAlpha() { /// »ö»ó ¹è¿­À» °»½Å unsigned int lineCount = mLineCount[0]; for( unsigned int yi = 0, i = 0; yi < lineCount; ++yi ) { for( unsigned int xi = 0; xi < lineCount; ++xi, ++i ) { mAlphas[i] = TERRAIN->GetAlphaFast( mXIndex + xi, mYIndex + yi ); } } /* for( unsigned int i = 1, step = 2; i < TERRAIN_LOD_COUNT; ++i, step *= 2 ) { gridSize = mGridSize[i]; for( unsigned int j = 0, y = 0; y < gridSize; ++y ) { for( unsigned int x = 0; x < gridSize; ++x, ++j ) { mAlphas[i][j] = mAlphas[0][y * step * mLineCount[0] + x * step]; } } } */ } void cTerrainLeafNode::SyncPaintAlpha() { unsigned int lineCount = mLineCount[0]; for( unsigned int yi = 0, i = 0; yi < lineCount; ++yi ) { for( unsigned int xi = 0; xi < lineCount; ++xi, ++i ) { mPaintAlphas[i] = TERRAIN->GetPaintAlphaFast( mXIndex + xi, mYIndex + yi ); } } } void cTerrainLeafNode::SyncColor() { /// »ö»ó ¹è¿­À» °»½Å unsigned int lineCount = mLineCount[0]; for( unsigned int yi = 0, i = 0; yi < lineCount; ++yi ) { for( unsigned int xi = 0; xi < lineCount; ++xi, ++i ) { mColors[i] = TERRAIN->GetColorFast( mXIndex + xi, mYIndex + yi ); } } /* for( unsigned int i = 1, step = 2; i < TERRAIN_LOD_COUNT; ++i, step *= 2 ) { gridSize = mGridSize[i]; for( unsigned int j = 0, y = 0; y < gridSize; ++y ) { for( unsigned int x = 0; x < gridSize; ++x, ++j ) { mColors[i][j] = mColors[0][y * step * mLineCount[0] + x * step]; } } } */ } bool cTerrainLeafNode::CollideRay() { float scale = NI_INFINITY; if( mBoundBox.IntersectRay( *mRay, scale ) == false ) return false; /// »ï°¢Çüµé¿¡ ´ëÇØ ±³Â÷ °Ë»ç bool ret = false; NiPoint3 p0, p1, p2, p3, out; for( unsigned int yi = mYIndex, yend = mYIndex + mCellCount[0]; yi < yend; ++yi ) { for( unsigned int xi = mXIndex, xend = mXIndex + mCellCount[0]; xi < xend; ++xi ) { float x0 = xi * 100.0f; float y0 = yi * 100.0f; p0.x = x0; p0.y = y0; p0.z = TERRAIN->GetHeightFast( xi, yi ); p1.x = x0 + 100.0f; p1.y = y0 + 100.0f; p1.z = TERRAIN->GetHeightFast( xi + 1, yi + 1 ); p2.x = x0; p2.y = y0 + 100.0f; p2.z = TERRAIN->GetHeightFast( xi, yi + 1 ); p3.x = x0 + 100.0f; p3.y = y0; p3.z = TERRAIN->GetHeightFast( xi + 1, yi ); /// ¿ÞÂÊ À§ »ï°¢Çü if( mRay->IntersectTri( &out, p0, p1, p2 ) == true ) { ret = true; float d = (out - mRay->GetOrigin()).Length(); if( d < *mDistance ) { *mDistance = d; *mContact = out; } } /// ¿À¸¥ÂÊ ¾Æ·¡ »ï°¢Çü if( mRay->IntersectTri( &out, p0, p3, p1 ) == true ) { ret = true; float d = (out - mRay->GetOrigin()).Length(); if( d < *mDistance ) { *mDistance = d; *mContact = out; } } } } return ret; } bool cTerrainLeafNode::CollideSphere() { if( mBoundBox.IntersectSphere( *mSphere ) ) { mPickedArray->PushBack( this ); return true; } return false; } void cTerrainLeafNode::SetLight( cLightSceneNode* light, unsigned int indexByLight ) { if( mLight == light ) return; if( mLight ) mLight->Detach( this ); mLight = light; mIndexByLight = indexByLight; } bool cTerrainLeafNode::CalcRange( unsigned int* xbegin, unsigned int* ybegin, unsigned int* xend, unsigned int* yend, const NiPoint3& pos, float outerRadius ) { int lineCount = (int)mLineCount[0]; float unitsPerVertex = TERRAIN->GetUnitsPerVertex(); float x = pos.x; float y = pos.y; int xb = (int)((x - outerRadius) / unitsPerVertex) - mXIndex; int yb = (int)((y - outerRadius) / unitsPerVertex) - mYIndex; int xe = (int)((x + outerRadius) / unitsPerVertex) - mXIndex; int ye = (int)((y + outerRadius) / unitsPerVertex) - mYIndex; --xb; --yb; ++xe; ++ye; if( xb < 0 ) xb = 0; if( yb < 0 ) yb = 0; if( xe > lineCount ) xe = lineCount; if( ye > lineCount ) ye = lineCount; if( xb >= xe || yb >= ye ) { return false; } *xbegin = xb; *ybegin = yb; *xend = xe; *yend = ye; return true; } void cTerrainLeafNode::SetTextures( cTerrainTexture* tex0, cTerrainTexture* tex1, cTerrainTexture* tex2 ) { if( tex0 == 0 || tex1 == 0 || tex2 == 0 ) { assert( 0 ); return; } if( tex0 != mTexture0 ) { tex0->Grab(); if( mTexture0 ) mTexture0->Drop(); mTexture0 = 0; mTexture0 = tex0; } if( tex1 != mTexture1 ) { tex1->Grab(); if( mTexture1 ) mTexture1->Drop(); mTexture1 = 0; mTexture1 = tex1; } if( tex2 != mTexture2 ) { tex2->Grab(); if( mTexture2 ) mTexture2->Drop(); mTexture2 = 0; mTexture2 = tex2; } CalcTextureValue(); } void cTerrainLeafNode::SetTexture0( cTerrainTexture* tex ) { if( tex == 0 ) { assert( 0 ); return; } if( tex != mTexture0 ) { tex->Grab(); if( mTexture0 ) mTexture0->Drop(); mTexture0 = 0; mTexture0 = tex; CalcTextureValue(); } } void cTerrainLeafNode::SetTexture1( cTerrainTexture* tex ) { if( tex == 0 ) { assert( 0 ); return; } if( tex != mTexture1 ) { tex->Grab(); if( mTexture1 ) mTexture1->Drop(); mTexture1 = 0; mTexture1 = tex; CalcTextureValue(); } } void cTerrainLeafNode::SetTexture2( cTerrainTexture* tex ) { if( tex == 0 ) { assert( 0 ); return; } if( tex != mTexture2 ) { tex->Grab(); if( mTexture2 ) mTexture2->Drop(); mTexture2 = 0; mTexture2 = tex; CalcTextureValue(); } } void cTerrainLeafNode::CalcTextureValue() { assert( mTexture0 ); assert( mTexture1 ); assert( mTexture2 ); unsigned int val[3] = { 0, 0, 0 }; unsigned int tex[3] = { mTexture0->mIndexByTerrain, mTexture1->mIndexByTerrain, mTexture2->mIndexByTerrain }; for( int i = 0; i < 3; ++i ) { for( int j = 2; j >= 0; --j ) { if( tex[i] > val[j] ) { for( int k = 1; k <= j; ++k ) { val[k-1] = val[k]; } val[j] = tex[i]; break; } } } mTextureValue0 = val[0] * 10000 + val[1] * 100 + val[2]; mTextureValue1 = tex[0] * 10000 + tex[1] * 100 + tex[2]; }