void World::buildQuadTree(QuadTreeNode *node, std::vector<QuadTreeNode*>& leafs) { float halfSize = node->getSize()/2.f; if (node->getSize() <= mMinBatchSize) { // We arrived at a leaf float minZ,maxZ; Ogre::Vector2 center = node->getCenter(); float cellWorldSize = getStorage()->getCellWorldSize(); if (mStorage->getMinMaxHeights(node->getSize(), center, minZ, maxZ)) { Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)); convertBounds(bounds); node->setBoundingBox(bounds); leafs.push_back(node); } else node->markAsDummy(); // no data available for this node, skip it return; } if (node->getCenter().x - halfSize > mMaxX || node->getCenter().x + halfSize < mMinX || node->getCenter().y - halfSize > mMaxY || node->getCenter().y + halfSize < mMinY ) // Out of bounds of the actual terrain - this will happen because // we rounded the size up to the next power of two { node->markAsDummy(); return; } // Not a leaf, create its children node->createChild(SW, halfSize, node->getCenter() - halfSize/2.f); node->createChild(SE, halfSize, node->getCenter() + Ogre::Vector2(halfSize/2.f, -halfSize/2.f)); node->createChild(NW, halfSize, node->getCenter() + Ogre::Vector2(-halfSize/2.f, halfSize/2.f)); node->createChild(NE, halfSize, node->getCenter() + halfSize/2.f); buildQuadTree(node->getChild(SW), leafs); buildQuadTree(node->getChild(SE), leafs); buildQuadTree(node->getChild(NW), leafs); buildQuadTree(node->getChild(NE), leafs); // if all children are dummy, we are also dummy for (int i=0; i<4; ++i) { if (!node->getChild((ChildDirection)i)->isDummy()) return; } node->markAsDummy(); }
bool ElTerrain::create(unsigned int size, bool lod /* = true */, float tileSizeLength /* = 1.0f */) { assert(size >= 1); mNumTilePerSide = (unsigned int)pow((long double)2, (int)size); mSideLengthScalar = tileSizeLength; mLod = lod; mTopLod = size - 1; // setup variables and data calculateVariables(); preAllocMemory(); createVertexDel(); // build vertices buildVertices(); // build structure for organization of indices if (mLod) { buildQuadTree(); buildQuadTreeBound(); } else buildPatchList(); // create shader if (!createShader()) return false; return true; }
World::World(Ogre::SceneManager* sceneMgr, Storage* storage, int visibilityFlags, bool distantLand, bool shaders, Alignment align, float minBatchSize, float maxBatchSize) : mStorage(storage) , mMinBatchSize(minBatchSize) , mMaxBatchSize(maxBatchSize) , mSceneMgr(sceneMgr) , mVisibilityFlags(visibilityFlags) , mDistantLand(distantLand) , mShaders(shaders) , mVisible(true) , mAlign(align) , mMaxX(0) , mMinX(0) , mMaxY(0) , mMinY(0) , mChunksLoading(0) , mWorkQueueChannel(0) , mCache(storage->getCellVertices()) , mLayerLoadPending(true) { #if TERRAIN_USE_SHADER == 0 if (mShaders) std::cerr << "Compiled Terrain without shader support, disabling..." << std::endl; mShaders = false; #endif mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); /// \todo make composite map size configurable Ogre::Camera* compositeMapCam = mCompositeMapSceneMgr->createCamera("a"); mCompositeMapRenderTexture = Ogre::TextureManager::getSingleton().createManual( "terrain/comp/rt", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 128, 128, 0, Ogre::PF_A8B8G8R8, Ogre::TU_RENDERTARGET); mCompositeMapRenderTarget = mCompositeMapRenderTexture->getBuffer()->getRenderTarget(); mCompositeMapRenderTarget->setAutoUpdated(false); mCompositeMapRenderTarget->addViewport(compositeMapCam); storage->getBounds(mMinX, mMaxX, mMinY, mMaxY); int origSizeX = mMaxX-mMinX; int origSizeY = mMaxY-mMinY; // Dividing a quad tree only works well for powers of two, so round up to the nearest one int size = nextPowerOfTwo(std::max(origSizeX, origSizeY)); // Adjust the center according to the new size float centerX = (mMinX+mMaxX)/2.f + (size-origSizeX)/2.f; float centerY = (mMinY+mMaxY)/2.f + (size-origSizeY)/2.f; mRootSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); // While building the quadtree, remember leaf nodes since we need to load their layers LayersRequestData data; data.mPack = getShadersEnabled(); mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(centerX, centerY), NULL); buildQuadTree(mRootNode, data.mNodes); //loadingListener->indicateProgress(); mRootNode->initAabb(); //loadingListener->indicateProgress(); mRootNode->initNeighbours(); //loadingListener->indicateProgress(); Ogre::WorkQueue* wq = Ogre::Root::getSingleton().getWorkQueue(); mWorkQueueChannel = wq->getChannel("LargeTerrain"); wq->addRequestHandler(mWorkQueueChannel, this); wq->addResponseHandler(mWorkQueueChannel, this); // Start loading layers in the background (for leaf nodes) wq->addRequest(mWorkQueueChannel, REQ_ID_LAYERS, Ogre::Any(data)); }