📄 teengine.cpp
字号:
if ( !isReady(computeNeighbourPos(patchPos, TePatch::Direction(i))) && !isScheduled(computeNeighbourPos(patchPos, TePatch::Direction(i))) ) { schedule(computeNeighbourPos(patchPos, TePatch::Direction(i))); } }}//-----------------------------------------------------------------------------/** * Updates scene graph to match object needs. * * This function is called continuously from the timeTick() method and * works in three steps: * \li Pre-generating: schedules patches that are going to be visible shortly. * \li Removes the patches that moved out of camera's field of view. * \li Checks if all visible terrain components (patches and seams) are * in the scene graph. * * \param obj Object used for visibility checking. * * \todo Some optimization should be done here. */void TeEngine::updateGraph(TeObject *obj){ SbVec3f objPos = obj->getPosition(); SbVec2f patchPos = computePatchPosUnderPoint(objPos); TePatch::Direction objPosInside = computePosInsidePatch(patchPos, objPos); TePatch *p = getPatch(patchPos); int i = 0; // first call with this object -> prepare initial 3x3 landscape if (!obj->initialized) { if (!isReady(patchPos) && !isScheduled(patchPos)) schedule(patchPos); prepareNeighbours(patchPos); obj->initialized = TRUE; obj->patchPosUnder = patchPos; obj->posInsidePatch = objPosInside; } // 1) Pre-generating // object is moving, so pre-generate patches in the direction of movement // TODO: aditional logic to select the best according to the movement // speed vector. // - first compare old and current "posInsidePatch" and then // make decision about what to schedule if ( (obj->patchPosUnder == patchPos) // no new patch && (obj->posInsidePatch != objPosInside) // object pos changed && (objPosInside != -1) ) { // not in the middle prepareNeighbours(computeNeighbourPos(patchPos, objPosInside)); } // 2) Removing // - should go first, because later in this function we check if all // visible things are shown and there we'll have a chance to undo // incorrect changes made here. if ( obj->patchPosUnder != patchPos ) { switch (objPosInside) { case TePatch::SOUTH_WEST: switch (obj->posInsidePatch) { case TePatch::EAST: case TePatch::SOUTH_EAST: // same as WEST case below removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::WEST]); removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::SOUTH_WEST]); break; case TePatch::NORTH_EAST: // diagonal removePatch(p->neighbour[TePatch::SOUTH_WEST]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::SOUTH_WEST]->neighbour[TePatch::WEST]); removePatch(p->neighbour[TePatch::SOUTH_WEST]->neighbour[TePatch::SOUTH_WEST]); removePatch(p->neighbour[TePatch::SOUTH_WEST]->neighbour[TePatch::SOUTH]); removePatch(p->neighbour[TePatch::SOUTH_WEST]->neighbour[TePatch::SOUTH_EAST]); break; case TePatch::NORTH_WEST: case TePatch::NORTH: // same as SOUTH case below removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH_WEST]); removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH]); removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH_EAST]); break; default: break; // this will never happen } break; case TePatch::SOUTH_EAST: switch (obj->posInsidePatch) { case TePatch::WEST: case TePatch::SOUTH_WEST: // same as EAST case below removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::NORTH_EAST]); removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::EAST]); removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::SOUTH_EAST]); break; case TePatch::NORTH_WEST: // diagonal removePatch(p->neighbour[TePatch::SOUTH_EAST]->neighbour[TePatch::NORTH_EAST]); removePatch(p->neighbour[TePatch::SOUTH_EAST]->neighbour[TePatch::EAST]); removePatch(p->neighbour[TePatch::SOUTH_EAST]->neighbour[TePatch::SOUTH_EAST]); removePatch(p->neighbour[TePatch::SOUTH_EAST]->neighbour[TePatch::SOUTH]); removePatch(p->neighbour[TePatch::SOUTH_EAST]->neighbour[TePatch::SOUTH_WEST]); break; case TePatch::NORTH_EAST: case TePatch::NORTH: // same as SOUTH case below removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH_WEST]); removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH]); removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH_EAST]); break; default: break; // this will never happen } break; case TePatch::NORTH_WEST: switch (obj->posInsidePatch) { case TePatch::SOUTH: case TePatch::SOUTH_WEST: // same as NORTH case below removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH]); removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH_EAST]); break; case TePatch::SOUTH_EAST: // diagonal removePatch(p->neighbour[TePatch::NORTH_WEST]->neighbour[TePatch::NORTH_EAST]); removePatch(p->neighbour[TePatch::NORTH_WEST]->neighbour[TePatch::NORTH]); removePatch(p->neighbour[TePatch::NORTH_WEST]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::NORTH_WEST]->neighbour[TePatch::WEST]); removePatch(p->neighbour[TePatch::NORTH_WEST]->neighbour[TePatch::SOUTH_WEST]); break; case TePatch::NORTH_EAST: case TePatch::EAST: // same as WEST case below removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::WEST]); removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::SOUTH_WEST]); break; default: break; // this will never happen } break; case TePatch::NORTH_EAST: switch (obj->posInsidePatch) { case TePatch::SOUTH: case TePatch::SOUTH_EAST: // same as NORTH case below removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH]); removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH_EAST]); break; case TePatch::SOUTH_WEST: // diagonal - TODO removePatch(p->neighbour[TePatch::NORTH_EAST]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::NORTH_EAST]->neighbour[TePatch::NORTH]); removePatch(p->neighbour[TePatch::NORTH_EAST]->neighbour[TePatch::NORTH_EAST]); removePatch(p->neighbour[TePatch::NORTH_EAST]->neighbour[TePatch::EAST]); removePatch(p->neighbour[TePatch::NORTH_EAST]->neighbour[TePatch::SOUTH_EAST]); break; case TePatch::NORTH_WEST: case TePatch::WEST: // same as EAST case below removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::NORTH_EAST]); removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::EAST]); removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::SOUTH_EAST]); break; default: break; // this will never happen } break; case TePatch::SOUTH: removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH_WEST]); removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH]); removePatch(p->neighbour[TePatch::SOUTH]->neighbour[TePatch::SOUTH_EAST]); break; case TePatch::WEST: removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::WEST]); removePatch(p->neighbour[TePatch::WEST]->neighbour[TePatch::SOUTH_WEST]); break; case TePatch::EAST: removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::NORTH_EAST]); removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::EAST]); removePatch(p->neighbour[TePatch::EAST]->neighbour[TePatch::SOUTH_EAST]); break; case TePatch::NORTH: removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH_WEST]); removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH]); removePatch(p->neighbour[TePatch::NORTH]->neighbour[TePatch::NORTH_EAST]); break; default: break; // -1, this will never happen } } obj->posInsidePatch = objPosInside; // finally update info // 3) Adding // really simple :( way how to keep scenegraph updated // --------------------------------------------------------------------- // TODO: we are doing this every tick, this SHOULD be done differently // although the performance seems to be quite good // --------------------------------------------------------------------- if (isReady(patchPos)) { // center patch and its seams addNode(p->graph); for (i=0; i<8; i++) { if (p->seamMap[i]) addNode(p->seamGraph[i]); } } if (obj == activeObject) { // only active obj 9x9, all others only 1 under for (i=0; i<8; i++) { // neighbours and theirs seams if (isReady(computeNeighbourPos(patchPos, TePatch::Direction(i)))) { addNode(p->neighbour[i]->graph); switch (i) { case 0: if (p->neighbour[i]->seamMap[TePatch::NORTH]) addNode(p->neighbour[i]->seamGraph[TePatch::NORTH]); if (p->neighbour[i]->seamMap[TePatch::EAST]) addNode(p->neighbour[i]->seamGraph[TePatch::EAST]); break; case 1: if (p->neighbour[i]->seamMap[TePatch::NORTH]) addNode(p->neighbour[i]->seamGraph[TePatch::NORTH]); if (p->neighbour[i]->seamMap[TePatch::WEST]) addNode(p->neighbour[i]->seamGraph[TePatch::WEST]); break; case 2: if (p->neighbour[i]->seamMap[TePatch::SOUTH]) addNode(p->neighbour[i]->seamGraph[TePatch::SOUTH]); if (p->neighbour[i]->seamMap[TePatch::EAST]) addNode(p->neighbour[i]->seamGraph[TePatch::EAST]); break; case 3: if (p->neighbour[i]->seamMap[TePatch::SOUTH]) addNode(p->neighbour[i]->seamGraph[TePatch::SOUTH]); if (p->neighbour[i]->seamMap[TePatch::WEST]) addNode(p->neighbour[i]->seamGraph[TePatch::WEST]); break; default: break; } } } } obj->patchPosUnder = patchPos; // finally update info}//-----------------------------------------------------------------------------/** * Computes position of the patch that is right under the point \a pt. * * The position can be used to get the patch using getPatch() method. * * \param pt Point in 3D space. * \return Position of the patch under the point \a pt. * * \sa getPatch(), computeNeighbourPos() */SbVec2f TeEngine::computePatchPosUnderPoint(SbVec3f pt){ float px = patch0Size.getValue()[0]; float py = patch0Size.getValue()[1]; float divx = pt.getValue()[0]/px; float divy = pt.getValue()[1]/py; float x,y = 0; if (divx - floor(divx) > 0.5f) x = (float)(floor(divx)+1)*px; else x = (float)floor(divx)*px; if (divy - floor(divy) > 0.5f) y = (float)(floor(divy)+1)*py; else y = (float)floor(divy)*py; return SbVec2f(x, y);}//-----------------------------------------------------------------------------/** * Computes position of the selected neighbour of the patch. * * The position can be used to get the neighbour using getPatch() method. * * \param patchPos Position of the center of the patch in world-space. * \param which Neighbour selector. * \return Position of the selected neighbour. * * \sa getPatch(), computePatchPosUnderPoint() */SbVec2f TeEngine::computeNeighbourPos(SbVec2f patchPos, TePatch::Direction which){ // if we put these directly down into switch, will it be faster?? float px = patch0Size.getValue()[0]; float py = patch0Size.getValue()[1]; switch (which) { case TePatch::SOUTH_WEST: return patchPos + SbVec2f(-px, -py); break; case TePatch::SOUTH_EAST: return patchPos + SbVec2f( px, -py); break; case TePatch::NORTH_WEST: return patchPos + SbVec2f(-px, py); break; case TePatch::NORTH_EAST: return patchPos + SbVec2f( px, py); break; case TePatch::SOUTH: return patchPos + SbVec2f( 0, -py); break; case TePatch::WEST: return patchPos + SbVec2f(-px, 0); break; case TePatch::EAST: return patchPos + SbVec2f( px, 0); break; case TePatch::NORTH: return patchPos + SbVec2f( 0, py); break; default: return SbVec2f(0.0f, 0.0f); break; // to avoid warning, this will never happen }}//-----------------------------------------------------------------------------/** * Computes position of the point \a pt above patch at \a patchPos relatively * to the patch borders. * * The position can be used to determine the direction the object is moving. * * \param patchPos Position of the center of the patch in world-space. * \param pt Point in 3D space. * \return TePatch::Direction, if above the central area, returns * Direction(-1). */TePatch::Direction TeEngine::computePosInsidePatch(SbVec2f patchPos, SbVec3f pt){ float px6 = patch0Size.getValue()[0] / 6.0f; float py6 = patch0Size.getValue()[1] / 6.0f; float northBorder = patchPos.getValue()[1] + py6; float southBorder = patchPos.getValue()[1] - py6; float westBorder = patchPos.getValue()[0] - px6; float eastBorder = patchPos.getValue()[0] + px6; float ptx = pt.getValue()[0]; float pty = pt.getValue()[1]; if (ptx < westBorder) { // NW, W, SW if (pty < southBorder) return TePatch::SOUTH_WEST; else if (pty < northBorder) return TePatch::WEST; else return TePatch::NORTH_WEST; } else if (ptx < eastBorder) { // N, -1, S if (pty < southBorder) return TePatch::SOUTH; else if (pty < northBorder) return TePatch::Direction(-1); else return TePatch::NORTH; } else { // NE, E, SE if (pty < southBorder) return TePatch::SOUTH_EAST; else if (pty < northBorder) return TePatch::EAST; else return TePatch::NORTH_EAST; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -