📄 naturepatchmanager.cpp
字号:
nz = cz;
nIdx = (nz * QUADTREE_SIZE) + nx;
if (nx > EDGE_LENGTH)
{
nIdx -= EDGE_LENGTH;
mEastNeighbor[node] = -mQuadNodeLookup[nIdx];
mEastEdgeQuad[cz] = node;
}
else
mEastNeighbor[node] = mQuadNodeLookup[nIdx];
// if not at lowest level, descend into children
if (level < (QUADTREE_DEPTH - 1))
{
int w4 = EDGE_LENGTH >> (level + 2);
// northwest child
computeNeighborLookup(cx - w4, cz - w4, (node<<2)+1, level+1);
// northeast child
computeNeighborLookup(cx + w4, cz - w4, (node<<2)+2, level+1);
// southwest child
computeNeighborLookup(cx - w4, cz + w4, (node<<2)+3, level+1);
// southeast child
computeNeighborLookup(cx + w4, cz + w4, (node<<2)+4, level+1);
}
}
//----------------------------------------------------------------------------
void NaturePatchManager::setTargetQuality(Real quality)
{
mTargetQuality = quality;
for (int i = 0; i < 324; i++)
{
if (mPatches[i] != 0)
addToRenderQueue(mPatches[i]);
}
}
//----------------------------------------------------------------------------
void NaturePatchManager::setMinimumQuality(Real quality)
{
mMinimumQuality = quality;
for (int i = 0; i < 324; i++)
{
if (mPatches[i] != 0)
addToRenderQueue(mPatches[i]);
}
}
//----------------------------------------------------------------------------
void NaturePatchManager::renderPatches()
{
queue<NaturePatch *> regenQueue;
bool empty = mRenderQueue.empty();
while (!mRenderQueue.empty())
{
NaturePatch *patch = mRenderQueue.front();
mRenderQueue.pop();
// rebuild mesh
patch->mNeedRendering = false;
patch->prepareMesh();
/* if (patch->mNorthNeighbor != 0) patch->mNorthNeighbor->prepareMesh();
if (patch->mSouthNeighbor != 0) patch->mSouthNeighbor->prepareMesh();
if (patch->mWestNeighbor != 0) patch->mWestNeighbor->prepareMesh();
if (patch->mEastNeighbor != 0) patch->mEastNeighbor->prepareMesh();
*/
if (patch->mNorthNeighbor != 0) patch->mNorthNeighbor->mNeedRendering = true;
if (patch->mSouthNeighbor != 0) patch->mSouthNeighbor->mNeedRendering = true;
if (patch->mWestNeighbor != 0) patch->mWestNeighbor->mNeedRendering = true;
if (patch->mEastNeighbor != 0) patch->mEastNeighbor->mNeedRendering = true;
// add to regen queue
regenQueue.push(patch);
}
while (!regenQueue.empty())
{
NaturePatch *patch = regenQueue.front();
regenQueue.pop();
// regenerate the mesh
patch->generateMesh();
// regenerate neighbors (to keep edges up to date)
if (patch->mNorthNeighbor != 0) patch->mNorthNeighbor->generateMesh();
if (patch->mSouthNeighbor != 0) patch->mSouthNeighbor->generateMesh();
if (patch->mWestNeighbor != 0) patch->mWestNeighbor->generateMesh();
if (patch->mEastNeighbor != 0) patch->mEastNeighbor->generateMesh();
}
}
//----------------------------------------------------------------------------
void NaturePatchManager::addToRenderQueue(NaturePatch *patch)
{
mRenderQueue.push(patch);
}
//----------------------------------------------------------------------------
bool NaturePatchManager::loadPatch(int x, int y, int edge)
{
bool loaded = false;
// calculate index into patch array
int ax = (x < 0) ? ((x % mPageSize) + mPageSize) : (x % mPageSize);
int ay = (y < 0) ? ((y % mPageSize) + mPageSize) : (y % mPageSize);
int idx = ay * mPageSize + ax;
if (mPatches[idx] == 0)
{
NaturePatch::NaturePatchData *data;
Vector3 world, zone, scale;
// request data for this patch from the loader
data = mMapLoader->requestData(x, y, &world, &zone, &scale);
if (data != 0)
{
switch (data->type)
{
case NaturePatch::TYPE_TERRAIN:
mPatches[idx] = new NatureTerrainPatch();
break;
// INFO: ADD MORE PATCH TYPES HERE
default:
std::cout << "ERROR: Unsupported patch type!!!\n";
}
if (mPatches[idx] != 0)
{
mPatches[idx]->initialise(world, zone, scale, data);
addToRenderQueue(mPatches[idx]);
String name = "NaturePatch["+toString(x)+","+toString(y)+"]";
SceneNode *sn = mSceneRoot->createChildSceneNode(name);
sn->attachObject(mPatches[idx]);
// std::cout << "ADDING: " << name << std::endl;
// setup neighbor pointers
NaturePatch *n = 0, *s = 0, *w = 0, *e = 0;
int maxIdx = mPageSize * mPageSize;
if ((edge & 0x01) == 0)
{
// link north neighbor
if (idx >= mPageSize) n = mPatches[idx - mPageSize];
else n = mPatches[maxIdx + (idx - mPageSize)];
}
if ((edge & 0x02) == 0)
{
// link south neighbor
if (idx < (maxIdx - mPageSize)) s = mPatches[idx + mPageSize];
else s = mPatches[(idx + mPageSize) - maxIdx];
}
if ((edge & 0x04) == 0)
{
// link west neighbor
if ((idx % mPageSize) > 0) w = mPatches[idx - 1];
else w = mPatches[idx + (mPageSize - 1)];
}
if ((edge & 0x08) == 0)
{
// link east neighbor
if ((idx % mPageSize) < (mPageSize - 1)) e = mPatches[idx + 1];
else e = mPatches[idx - (mPageSize - 1)];
}
// attach patch to its neighbors
mPatches[idx]->attach(n, s, w, e);
loaded = true;
}
}
}
return loaded;
}
//----------------------------------------------------------------------------
void NaturePatchManager::unloadPatch(int x, int y)
{
// calculate index into patch array
int ax = (x < 0) ? ((x % mPageSize) + mPageSize) : (x % mPageSize);
int ay = (y < 0) ? ((y % mPageSize) + mPageSize) : (y % mPageSize);
int idx = ay * mPageSize + ax;
// std::cout << "UNLOADING: " << ax << ", " << x << " idx: " << idx << std::endl;
if (mPatches[idx] != 0)
{
// unlink neighbors
mPatches[idx]->detach();
// remove patch from the scene
String name = "NaturePatch[" + toString(x) + "," + toString(y) + "]";
mSceneRoot->removeAndDestroyChild(name);
// std::cout << "REMOVING: " << name << std::endl;
// inform the patchloader that we no longer need this data
mMapLoader->releaseData(mPatches[idx]->mData);
// delete patch
delete mPatches[idx];
mPatches[idx] = 0;
}
}
//----------------------------------------------------------------------------
void NaturePatchManager::updatePatches(Camera *cam)
{
int cx, cy;
mMapLoader->getPatchAtPosition(cam->getPosition(), &cx, &cy);
int diffx = cx - mCenterPatchX;
int diffy = cy - mCenterPatchY;
int ps2 = mPageSize / 2, x, y;
// load in new patches
for (y = -ps2; y <= ps2; y++)
{
for (x = -ps2; x <= ps2; x++)
{
int edge = 0;
if (y == -ps2) edge |= 0x01;
else if (y == ps2) edge |= 0x02;
if (x == -ps2) edge |= 0x04;
else if (x == ps2) edge |= 0x08;
// TODO: move patch loading to separate thread?
if (loadPatch(x + mCenterPatchX, y + mCenterPatchY, edge))
return;
}
}
if (diffy != 0 || diffx != 0)
{
// unload patches on x axis
if (diffy > 0)
{
if (diffy > mPageSize) diffy = mPageSize;
for (y = -ps2; y < (-ps2 + diffy); y++)
for (x = -ps2; x <= ps2; x++)
unloadPatch(x + mCenterPatchX, y + mCenterPatchY);
}
else if (diffy < 0)
{
if (diffy < -mPageSize) diffy = -mPageSize;
for (y = ps2; y > (ps2 + diffy); y--)
for (x = -ps2; x <= ps2; x++)
unloadPatch(x + mCenterPatchX, y + mCenterPatchY);
}
// unload patches on y axis
if (diffx > 0)
{
if (diffx > mPageSize) diffx = mPageSize;
for (x = -ps2; x < -ps2 + diffx; x++)
for (y = -ps2; y <= ps2; y++)
unloadPatch(x + mCenterPatchX, y + mCenterPatchY);
}
else if (diffx < 0)
{
if (diffx < -mPageSize) diffx = -mPageSize;
for (x = ps2; x > (ps2 + diffx); x--)
for (y = -ps2; y <= ps2; y++)
unloadPatch(x + mCenterPatchX, y + mCenterPatchY);
}
// update center position
mCenterPatchX = cx;
mCenterPatchY = cy;
}
}
NaturePatch* NaturePatchManager::getPatchAtPosition(const Vector3& pos)
{
// NB only works if loaded
// Get location
int x, y;
mMapLoader->getPatchAtPosition(pos, &x, &y);
int idx = y * mPageSize + x;
return mPatches[idx];
}
void NaturePatchManager::getPatchRenderOpsInBox(const AxisAlignedBox& box, std::list<RenderOperation>& opList)
{
// Get the patches at the 4 corners at the bottom of the box, ie 0, 3, 6, 7
std::set<NaturePatch*> uniqueSet;
const Vector3* corners = box.getAllCorners();
uniqueSet.insert(getPatchAtPosition(corners[0]));
uniqueSet.insert(getPatchAtPosition(corners[3]));
uniqueSet.insert(getPatchAtPosition(corners[6]));
uniqueSet.insert(getPatchAtPosition(corners[7]));
// Iterate over uniques
std::set<NaturePatch*>::iterator i, iend;
RenderOperation op;
for (i = uniqueSet.begin(); i != iend; ++i)
{
(*i)->getRenderOperation(op);
opList.push_back(op);
}
}
} // namespace Ogre
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -