void TerrainCuller::apply(osg::Node& node) { // push the node's state. osg::StateSet* node_state = node.getStateSet(); TileNode* tileNode = dynamic_cast<TileNode*>(&node); if (tileNode) { _currentTileNode = tileNode; _currentTileDrawCommands = 0u; if (!_terrain.patchLayers().empty()) { // todo: check for patch/virtual const RenderBindings& bindings = _context->getRenderBindings(); TileRenderModel& renderModel = _currentTileNode->renderModel(); bool pushedMatrix = false; for (PatchLayerVector::const_iterator i = _terrain.patchLayers().begin(); i != _terrain.patchLayers().end(); ++i) { PatchLayer* layer = i->get(); if (layer->getAcceptCallback() == 0L || layer->getAcceptCallback()->acceptKey(_currentTileNode->getKey())) { // Push this tile's matrix if we haven't already done so: if (!pushedMatrix) { SurfaceNode* surface = tileNode->getSurfaceNode(); // push the surface matrix: osg::Matrix mvm = *getModelViewMatrix(); surface->computeLocalToWorldMatrix(mvm, this); pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame()); pushedMatrix = true; } // Add the draw command: DrawTileCommand* cmd = addDrawCommand(layer->getUID(), &renderModel, 0L, tileNode); if (cmd) { cmd->_drawPatch = true; cmd->_drawCallback = layer->getDrawCallback(); ++_currentTileDrawCommands; } } } if (pushedMatrix) { popModelViewMatrix(); } } } else { SurfaceNode* surface = dynamic_cast<SurfaceNode*>(&node); if (surface) { TileRenderModel& renderModel = _currentTileNode->renderModel(); // push the surface matrix: osg::Matrix mvm = *getModelViewMatrix(); surface->computeLocalToWorldMatrix(mvm, this); pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame()); // First go through any legit rendering pass data in the Tile and // and add a DrawCommand for each. for (unsigned p = 0; p < renderModel._passes.size(); ++p) { const RenderingPass& pass = renderModel._passes[p]; if (pass._layer.valid() && pass._layer->getRenderType() == Layer::RENDERTYPE_TILE) { if (addDrawCommand(pass._sourceUID, &renderModel, &pass, _currentTileNode)) { ++_currentTileDrawCommands; } } } // Next, add a DrawCommand for each tile layer not represented in the TerrainTileModel // as a rendering pass. for (LayerVector::const_iterator i = _terrain.tileLayers().begin(); i != _terrain.tileLayers().end(); ++i) { Layer* layer = i->get(); if (addDrawCommand(layer->getUID(), &renderModel, 0L, _currentTileNode)) { ++_currentTileDrawCommands; } } // If the culler added no draw commands for this tile... do something! if (_currentTileDrawCommands == 0) { //OE_INFO << LC << "Adding blank render.\n"; addDrawCommand(-1, &renderModel, 0L, _currentTileNode); } popModelViewMatrix(); _terrain._drawState->_bs.expandBy(surface->getBound()); _terrain._drawState->_box.expandBy(_terrain._drawState->_bs); } } traverse(node); }
void TerrainCuller::apply(osg::Node& node) { // push the node's state. osg::StateSet* node_state = node.getStateSet(); TileNode* tileNode = dynamic_cast<TileNode*>(&node); if (tileNode) { _currentTileNode = tileNode; // reset the pointer to the first DrawTileCommand. We keep track of this so // we can set it's "order" member to zero at the end, so the rendering engine // knows to blend it with the terrain geometry color. _firstTileDrawCommandForTile = 0L; //_currentTileDrawCommands = 0u; if (!_terrain.patchLayers().empty()) { // todo: check for patch/virtual const RenderBindings& bindings = _context->getRenderBindings(); TileRenderModel& renderModel = _currentTileNode->renderModel(); bool pushedMatrix = false; for (PatchLayerVector::const_iterator i = _terrain.patchLayers().begin(); i != _terrain.patchLayers().end(); ++i) { PatchLayer* layer = i->get(); if (layer->getAcceptCallback() == 0L || layer->getAcceptCallback()->acceptKey(_currentTileNode->getKey())) { // Push this tile's matrix if we haven't already done so: if (!pushedMatrix) { SurfaceNode* surface = tileNode->getSurfaceNode(); // push the surface matrix: osg::Matrix mvm = *getModelViewMatrix(); surface->computeLocalToWorldMatrix(mvm, this); pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame()); pushedMatrix = true; } // Add the draw command: DrawTileCommand* cmd = addDrawCommand(layer->getUID(), &renderModel, 0L, tileNode); if (cmd) { cmd->_drawPatch = true; cmd->_drawCallback = layer->getDrawCallback(); } } } if (pushedMatrix) { popModelViewMatrix(); } } } else { SurfaceNode* surface = dynamic_cast<SurfaceNode*>(&node); if (surface) { TileRenderModel& renderModel = _currentTileNode->renderModel(); // push the surface matrix: osg::Matrix mvm = *getModelViewMatrix(); surface->computeLocalToWorldMatrix(mvm, this); pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame()); int order = 0; // First go through any legit rendering pass data in the Tile and // and add a DrawCommand for each. for (unsigned p = 0; p < renderModel._passes.size(); ++p) { const RenderingPass& pass = renderModel._passes[p]; DrawTileCommand* cmd = addDrawCommand(pass.sourceUID(), &renderModel, &pass, _currentTileNode); if (cmd) { if (_firstTileDrawCommandForTile == 0L) { _firstTileDrawCommandForTile = cmd; } else if (cmd->_order < _firstTileDrawCommandForTile->_order) { //_firstTileDrawCommandForTile->_order = 1; _firstTileDrawCommandForTile = cmd; } } } // If the culler added no draw commands for this tile... we still need // to draw something or else there will be a hole! So draw a blank tile. // UID = -1 is the special UID code for a blank. if (_firstTileDrawCommandForTile == 0L) { //OE_INFO << LC << "Adding blank render for tile " << _currentTileNode->getKey().str() << std::endl; DrawTileCommand* cmd = addDrawCommand(-1, &renderModel, 0L, _currentTileNode); if (cmd) cmd->_order = 0; } // Set the layer order of the first draw command for this tile to zero, // to support proper terrain blending. if (_firstTileDrawCommandForTile) { _firstTileDrawCommandForTile->_order = 0; } // pop the matrix from the cull stack popModelViewMatrix(); // update our bounds _terrain._drawState->_bs.expandBy(surface->getBound()); _terrain._drawState->_box.expandBy(_terrain._drawState->_bs); } } // Handle any CullCallbacks and traverse. osg::Callback* cullCallback = node.getCullCallback(); if (cullCallback) cullCallback->run(&node, this); else traverse(node); }