void Config::updateCanvas( Canvas* canvas ) { postNeedsFinish(); activateCanvas( canvas ); // Create compounds for all new output channels const Segments& segments = canvas->getSegments(); Compound* group = new Compound( this ); for( Segments::const_iterator i=segments.begin(); i != segments.end(); ++i ) { const Segment* segment = *i; const Channels& channels = segment->getDestinationChannels(); if( channels.empty( )) EQWARN << "New segment without destination channels will be ignored" << std::endl; for( Channels::const_iterator j = channels.begin(); j != channels.end(); ++j ) { Channel* channel = *j; EQASSERT( !channel->isActive( )); Compound* compound = new Compound( group ); compound->setIAttribute( Compound::IATTR_STEREO_MODE, fabric::AUTO); compound->setChannel( channel ); } } group->init(); canvas->init(); EQINFO << *this << std::endl; }
/** Pure DB rendering when each node compose result from its pipes and transmit only one set of images to the destination node. */ static void _modeDB( Config* config, const unsigned nChannels, const unsigned nPipes ) { Compound* compound = config->getCompounds()[0]; vector<float> ranges( nChannels + 1, 0 ); ranges[ nChannels ] = 1.0; for( unsigned i = 1; i < nChannels; ++i ) ranges[ i ] = ranges[ i-1 ] + 1.0/nChannels; unsigned i = 0; // for each node for( unsigned n = 0 ; n < nChannels/nPipes; ++n ) { Compound* childNode = compound; if( n != 0 ) // don't create separate compound for dst channel { childNode = new Compound( compound ); std::ostringstream channelName; channelName << "channel" << n*nPipes; Channel* childChannel = config->find< Channel >( channelName.str()); childNode->setChannel( childChannel ); } // for each gpu on the node for( unsigned p = 0; p < nPipes; ++p ) { Compound* childPipe = new Compound( childNode ); childPipe->setRange( eq::Range( ranges[ i ], ranges[ i+1 ] )); if( i != n*nPipes ) { std::ostringstream channelName; channelName << "channel" << i; Channel* childChannel = config->find< Channel >( channelName.str( )); childPipe->setChannel( childChannel ); std::ostringstream frameName; frameName << "frame.channel" << i; childPipe->addOutputFrame( ::Frame::create( frameName )); childNode->addInputFrame( ::Frame::create( frameName )); } i++; } if( n != 0 ) // dst channel has no output { std::ostringstream frameName; frameName << "frame.channel" << n*nPipes; childNode->addOutputFrame( ::Frame::create( frameName )); compound->addInputFrame( ::Frame::create( frameName )); } } }
void FramerateEqualizer::_init() { const Compound* compound = getCompound(); if( _nSamples > 0 || !compound ) return; _nSamples = 1; // Subscribe to child channel load events const Compounds& children = compound->getChildren(); EQASSERT( _loadListeners.empty( )); _loadListeners.resize( children.size( )); for( size_t i = 0; i < children.size(); ++i ) { Compound* child = children[i]; const uint32_t period = child->getInheritPeriod(); LoadListener& loadListener = _loadListeners[i]; loadListener.parent = this; loadListener.period = period; LoadSubscriber subscriber( &loadListener ); child->accept( subscriber ); _nSamples = EQ_MAX( _nSamples, period ); } _nSamples = EQ_MIN( _nSamples, 100 ); }
Compound* Actor::createCompoundFromChunk(const destructible::DestructibleActorImpl& actor, uint32_t partIndex) { Mesh RTmesh; RTmesh.loadFromRenderMesh(*actor.getDestructibleAsset()->getRenderMeshAsset(),partIndex); // Fix texture v's (different between right hand and left hand) RTmesh.flipV(); PxTransform pose(actor.getChunkPose(partIndex)); pose.p = actor.getStructure()->getChunkWorldCentroid(actor.getChunk(partIndex)); Compound* c = createCompound(); c->createFromMesh(&RTmesh,pose,actor.getChunkLinearVelocity(partIndex),actor.getChunkAngularVelocity(partIndex),-1,actor.getScale()); const DestructibleActorParamNS::BehaviorGroup_Type& behaviorGroup = actor.getBehaviorGroup(partIndex); mMinRadius = behaviorGroup.damageSpread.minimumRadius; mRadiusMultiplier = behaviorGroup.damageSpread.radiusMultiplier; // attachment //const DestructibleActorParamNS::RuntimeFracture_Type& params = mActor->getParams()->destructibleParameters.runtimeFracture; DestructibleParameters& params = mActor->getDestructibleParameters(); mAttachmentFlags.posX |= params.rtFractureParameters.attachment.posX; mAttachmentFlags.negX |= params.rtFractureParameters.attachment.negX; mAttachmentFlags.posY |= params.rtFractureParameters.attachment.posY; mAttachmentFlags.negY |= params.rtFractureParameters.attachment.negY; mAttachmentFlags.posZ |= params.rtFractureParameters.attachment.posZ; mAttachmentFlags.negZ |= params.rtFractureParameters.attachment.negZ; attachBasedOnFlags(c); mRenderResourcesDirty = true; return c; }
//--------------------------------------------------------------------------- // exit //--------------------------------------------------------------------------- bool Config::exit() { if( _state != STATE_RUNNING ) EQWARN << "Exiting non-initialized config" << std::endl; EQASSERT( _state == STATE_RUNNING || _state == STATE_INITIALIZING ); _state = STATE_EXITING; const Canvases& canvases = getCanvases(); for( Canvases::const_iterator i = canvases.begin(); i != canvases.end(); ++i ) { Canvas* canvas = *i; canvas->exit(); } for( Compounds::const_iterator i = _compounds.begin(); i != _compounds.end(); ++i ) { Compound* compound = *i; compound->exit(); } const bool success = _updateRunning(); ConfigEvent exitEvent; exitEvent.data.type = Event::EXIT; send( findApplicationNetNode(), exitEvent ); _needsFinish = false; _state = STATE_STOPPED; return success; }
void View::trigger( const Canvas* canvas, const bool active ) { const Mode mode = getMode(); Config* config = getConfig(); // (De)activate destination compounds for canvas/eye(s) for( Channels::const_iterator i = _channels.begin(); i != _channels.end(); ++i ) { Channel* channel = *i; const Canvas* channelCanvas = channel->getCanvas(); const Layout* canvasLayout = channelCanvas->getActiveLayout(); if(( canvas && channelCanvas != canvas ) || ( !canvas && canvasLayout != getLayout( ))) { continue; } const Segment* segment = channel->getSegment(); const uint32_t segmentEyes = segment->getEyes(); const uint32_t eyes = ( mode == MODE_MONO ) ? EYE_CYCLOP & segmentEyes : EYES_STEREO & segmentEyes; if( eyes == 0 ) continue; ConfigDestCompoundVisitor visitor( channel, true /*activeOnly*/ ); config->accept( visitor ); const Compounds& compounds = visitor.getResult(); for( Compounds::const_iterator j = compounds.begin(); j != compounds.end(); ++j ) { Compound* compound = *j; if( active ) { compound->activate( eyes ); LBLOG( LOG_VIEW ) << "Activate " << compound->getName() << std::endl; } else { compound->deactivate( eyes ); LBLOG( LOG_VIEW ) << "Deactivate " << compound->getName() << std::endl; } } } }
/** 2D decomposition based on precalculated grid */ static void _mode2D( Config* config, const vector<float>& xMarks, const vector<float>& yMarks ) { Compound* compound = config->getCompounds()[0]; const size_t rows = yMarks.size() - 1; const size_t columns = xMarks.size() - 1; size_t i = 0; for( size_t y = 0; y < rows; ++y ) for( size_t x = 0; x < columns; ++x ) { Compound* child = new Compound( compound ); std::ostringstream channelName; channelName << "channel" << i; Channel* childChannel = config->find< Channel >( channelName.str( )); child->setChannel( childChannel ); child->setViewport( eq::Viewport( xMarks[x ], yMarks[y ], xMarks[x+1]-xMarks[x], yMarks[y+1]-yMarks[y] )); if( i != 0 ) { std::ostringstream frameName; frameName << "frame.channel" << i; child->addOutputFrame( ::Frame::create( frameName )); compound->addInputFrame( ::Frame::create( frameName )); } i++; } }
//--------------------------------------------------------------------------- // frame //--------------------------------------------------------------------------- void Config::_startFrame( const uint128_t& frameID ) { EQASSERT( _state == STATE_RUNNING ); _verifyFrameFinished( _currentFrame ); _syncClock(); ++_currentFrame; EQLOG( co::base::LOG_ANY ) << "----- Start Frame ----- " << _currentFrame << std::endl; for( Compounds::const_iterator i = _compounds.begin(); i != _compounds.end(); ++i ) { Compound* compound = *i; compound->update( _currentFrame ); } ConfigUpdateDataVisitor configDataVisitor; accept( configDataVisitor ); const Nodes& nodes = getNodes(); co::NodePtr appNode = findApplicationNetNode(); for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i ) { Node* node = *i; node->update( frameID, _currentFrame ); if( node->isRunning() && node->isApplicationNode( )) appNode = 0; // release sent (see below) } if( appNode.isValid( )) // release appNode local sync { ConfigReleaseFrameLocalPacket packet; packet.frameNumber = _currentFrame; send( appNode, packet ); } // Fix 2976899: Config::finishFrame deadlocks when no nodes are active notifyNodeFrameFinished( _currentFrame ); }
void MonitorEqualizer::_updateViewports() { if( !_outputFrames.empty( )) return; Compound* compound = getCompound(); if( !compound ) return; const Frames& inputFrames = compound->getInputFrames(); for( Frames::const_iterator i = inputFrames.begin(); i != inputFrames.end(); ++i ) { const Frame* frame = *i; const Compound* root = compound->getRoot(); // find the output frame OutputFrameFinder frameFinder( frame->getName() ); root->accept( frameFinder ); Frame* outputFrame = frameFinder.getResult(); _outputFrames.push_back( outputFrame ); _viewports.push_back( eq::Viewport::FULL ); if( outputFrame ) { const Channel* channel = outputFrame->getChannel(); const Segment* segment = channel->getSegment(); const View* view = channel->getView(); if( view ) { Viewport viewport( segment->getViewport( )); viewport.intersect( view->getViewport( )); _viewports.back() = viewport; } } } }
void FramerateEqualizer::_exit() { const Compound* compound = getCompound(); if( !compound || _nSamples == 0 ) return; const Compounds& children = compound->getChildren(); EQASSERT( _loadListeners.size() == children.size( )); for( size_t i = 0; i < children.size(); ++i ) { Compound* child = children[i]; LoadListener& loadListener = _loadListeners[i]; LoadUnsubscriber unsubscriber( &loadListener ); child->accept( unsubscriber ); } _loadListeners.clear(); _times.clear(); _nSamples = 0; }
//--------------------------------------------------------------------------- // exit //--------------------------------------------------------------------------- bool Config::exit() { if( _state != STATE_RUNNING ) LBWARN << "Exiting non-initialized config" << std::endl; LBASSERT( _state == STATE_RUNNING || _state == STATE_INITIALIZING ); _state = STATE_EXITING; const Canvases& canvases = getCanvases(); for( Canvases::const_iterator i = canvases.begin(); i != canvases.end(); ++i ) { Canvas* canvas = *i; canvas->exit(); } for( Compounds::const_iterator i = _compounds.begin(); i != _compounds.end(); ++i ) { Compound* compound = *i; compound->exit(); } const bool success = _updateRunning( true ); // send exit event to app, needed if this is called from init() EventOCommand cmd( send( findApplicationNetNode(), fabric::CMD_CONFIG_EVENT )); Event event; event.serial = getSerial(); event.time = getServer()->getTime(); event.originator = getID(); cmd << EVENT_EXIT << event; _needsFinish = false; _state = STATE_STOPPED; return success; }
void Config::updateCanvas( Canvas* canvas ) { postNeedsFinish(); activateCanvas( canvas ); // Create one compound group for all new output channels of each layout const Layouts& layouts = canvas->getLayouts(); for( LayoutsCIter i = layouts.begin(); i != layouts.end(); ++i ) { Compound* group = new Compound( this ); const Layout* layout = *i; const Views& views = layout->getViews(); for( ViewsCIter j = views.begin(); j != views.end(); ++j ) { const View* view = *j; const Channels& channels = view->getChannels(); if( channels.empty( )) LBWARN << "View without destination channels will be ignored" << std::endl; for( ChannelsCIter k = channels.begin(); k != channels.end(); ++k ) { Channel* channel = *k; LBASSERT( !channel->isActive( )); Compound* compound = new Compound( group ); compound->setIAttribute( Compound::IATTR_STEREO_MODE, fabric::AUTO ); compound->setChannel( channel ); } } group->init(); } canvas->init(); LBDEBUG << *this << std::endl; }
int main() { Compound *unknown = new Compound("Unknown"); unknown->Display(); Compound *water = new RitchCompound("Water"); water->Display(); Compound *benzene = new RitchCompound("Benzene"); benzene->Display(); Compound *ethanol = new RitchCompound("Ethanol"); ethanol->Display(); return 0; }
//--------------------------------------------------------------------------- // frame //--------------------------------------------------------------------------- void Config::_startFrame( const uint128_t& frameID ) { LBASSERT( _state == STATE_RUNNING ); _verifyFrameFinished( _currentFrame ); _syncClock(); ++_currentFrame; ++_incarnation; LBLOG( LOG_TASKS ) << "----- Start Frame ----- " << _currentFrame << std::endl; for( Compounds::const_iterator i = _compounds.begin(); i != _compounds.end(); ++i ) { Compound* compound = *i; compound->update( _currentFrame ); } ConfigUpdateDataVisitor configDataVisitor; accept( configDataVisitor ); const Nodes& nodes = getNodes(); co::NodePtr appNode = findApplicationNetNode(); for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i ) { Node* node = *i; node->update( frameID, _currentFrame ); if( node->isRunning() && node->isApplicationNode( )) appNode = 0; // release sent (see below) } if( appNode ) // release appNode local sync send( appNode, fabric::CMD_CONFIG_RELEASE_FRAME_LOCAL ) << _currentFrame; // Fix 2976899: Config::finishFrame deadlocks when no nodes are active notifyNodeFrameFinished( _currentFrame ); }
void Loader::addOutputCompounds( ServerPtr server ) { const Configs& configs = server->getConfigs(); for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i ) { UnusedOutputChannelFinder finder; Config* config = *i; config->accept( finder ); const Channels& channels = finder.getResult(); if( channels.empty( )) continue; Compound* group = new Compound( config ); for( Channels::const_iterator j = channels.begin(); j != channels.end(); ++j ) { Compound* compound = new Compound( group ); Channel* channel = *j; compound->setChannel( channel ); } } }
//--------------------------------------------------------------------------- // exit //--------------------------------------------------------------------------- bool Config::exit() { if( _state != STATE_RUNNING ) LBWARN << "Exiting non-initialized config" << std::endl; LBASSERT( _state == STATE_RUNNING || _state == STATE_INITIALIZING ); _state = STATE_EXITING; const Canvases& canvases = getCanvases(); for( Canvases::const_iterator i = canvases.begin(); i != canvases.end(); ++i ) { Canvas* canvas = *i; canvas->exit(); } for( Compounds::const_iterator i = _compounds.begin(); i != _compounds.end(); ++i ) { Compound* compound = *i; compound->exit(); } const bool success = _updateRunning( true ); // TODO: is this needed? sender of CMD_CONFIG_EXIT is the appNode itself // which sets the running state to false anyway. Besides, this event is // not handled by the appNode because it is already in exiting procedure // and does not call handleEvents anymore // eile: May be needed for reliability? send( findApplicationNetNode(), fabric::CMD_CONFIG_EVENT ) << Event::EXIT; _needsFinish = false; _state = STATE_STOPPED; return success; }
/** DB_ds rendering when each node compose result from its pipes on to first pipe, then result is used in DB_ds compositing between nodes */ static void _modeDS( Config* config, const unsigned nChannels, const unsigned nPipes, const vector< vector<int> >& descr, const vector<float>& xMarks, const vector<float>& yMarks ) { Compound* compound = config->getCompounds()[0]; vector<float> ranges( nChannels + 1, 0 ); ranges[ nChannels ] = 1.0; for( unsigned i = 1; i < nChannels; ++i ) ranges[ i ] = ranges[ i-1 ] + 1.0/nChannels; const unsigned nNodes = nChannels/nPipes; if( descr.size() < nNodes ) { cerr << "Description file is incomplete" << std::endl; return; } const int rows = int( yMarks.size( )) - 1; const int columns = int( xMarks.size( )) - 1; const int cells = rows*columns; // check that all specified viewports are within a grid for( size_t i = 0; i < nNodes; ++i ) { const vector< int >& vals = descr[i]; for( size_t j = 0; j < vals.size(); ++j ) if( vals[j] >= cells || vals[j] < 0 ) { cerr << "description of region is invalid: " << vals[j] << " no such cell" << std::endl; return; } } // fill all viewports for grid vector< eq::Viewport > tmpVP; for( int y = 0; y < rows; ++y ) for( int x = 0; x < columns; ++x ) tmpVP.push_back( eq::Viewport( xMarks[x], yMarks[y], xMarks[x+1]-xMarks[x], yMarks[y+1]-yMarks[y] )); // build per-node viewports vector< eq::Viewport > vp( nNodes ); for( size_t i = 0; i < nNodes; ++i ) { const vector< int >& vals = descr[i]; vp[i] = tmpVP[vals[0]]; for( size_t j = 1; j < vals.size(); ++j ) vp[i].unite( tmpVP[vals[j]] ); } unsigned i = 0; // for each node for( unsigned n = 0 ; n < nNodes; ++n ) { Compound* child = compound; if( n != 0 ) // don't create separate compound for dst channel { child = new Compound( compound ); std::ostringstream channelName; channelName << "channel" << n*nPipes; Channel* childChannel = config->find< Channel >( channelName.str()); child->setChannel( childChannel ); } Compound* childNode = new Compound( child ); // for each gpu on the node for( unsigned p = 0; p < nPipes; ++p ) { Compound* childPipe = new Compound( childNode ); childPipe->setRange( eq::Range( ranges[ i ], ranges[ i+1 ] )); if( i != n*nPipes ) { std::ostringstream channelName; channelName << "channel" << i; Channel* childChannel = config->find< Channel >( channelName.str( )); childPipe->setChannel( childChannel ); std::ostringstream frameName; frameName << "frame.channel" << i; childPipe->addOutputFrame( ::Frame::create( frameName )); childNode->addInputFrame( ::Frame::create( frameName )); } i++; } for( unsigned k = 0; k < nNodes; ++k ) if( k != n ) { // output parts to compose on other nodes std::ostringstream frameName; frameName << "fr" << k*nPipes << ".ch" << n*nPipes; childNode->addOutputFrame( ::Frame::create( frameName, vp[k] )); // input parts from other nodes to compose on current node frameName.str(""); frameName<< "fr" << n*nPipes << ".ch" << k*nPipes; child->addInputFrame( ::Frame::create( frameName )); } // output color result for final compositing on the first node if( n != 0 ) { std::ostringstream frameName; frameName << "frame.channel" << n*nPipes; child->addOutputFrame( ::Frame::create( frameName, vp[n], true )); compound->addInputFrame( ::Frame::create( frameName )); } } }
bool SceneLoader::loadObjects(){ //Falta condicao para nao se repetirem ID's <-- TiXmlElement* objectElement = root->FirstChildElement("objects"); if(objectElement == NULL) { cout << "> Error: objects tag not found!" << endl; return false; } TiXmlElement* objectChild = objectElement->FirstChildElement(); int i=1; for( ; objectChild != NULL; objectChild = objectChild->NextSiblingElement()){ if(i <= maxObjects){ if(!objectChild->Attribute("type")){ cout << " > Error: Could not load type of an Object!" << endl; //Sair imediatamente return NULL; } string type = objectChild->Attribute("type"); if(type == "compound"){ //Tipo composto Compound* compound = new Compound(); if((compound->loadAttributes(objectChild)) == NULL) return false; if(sceneManager->getObjectbyID(objectChild->Attribute("id")) != NULL){ //Objecto já existente no sistema cout << " > Warning: object with ID " << objectChild->Attribute("id") << " is already in the system!!" << endl; continue; } string material; if((material = compound->loadMaterial(objectChild)).empty()) return NULL; if(material != "null"){ Material* mat = this->sceneManager->getMaterialbyID(material); if(mat == NULL){ cout << " > Error: Material with ID: " << material << " not found for Object: " << compound->id << endl; return false; } compound->material = mat; } else{ Material* mat = new Material(); mat->id = "null"; compound->material = mat; } string texture; if((texture = compound->loadTexture(objectChild)).empty()) return NULL; if(texture == "clear"){ Texture* text = new Texture(); text->id = "clear"; compound->texture = text; } else if(texture != "null"){ Texture* text = this->sceneManager->getTexturebyID(texture); if(text == NULL){ cout << " > Error: Texture with ID: " << texture << " not found for Object: " << compound->id << endl; return false; } compound->texture = text; } else{ Texture* text = new Texture(); text->id = "null"; compound->texture = text; } if(objectChild->Attribute("id") == sceneManager->globals->root){ sceneManager->root = compound; } sceneManager->addObject(compound); } else if(type == "simple"){ //Tipo simples Simple* simple = new Simple(); if((simple->loadAttributes(objectChild)) == NULL) return false; if(sceneManager->getObjectbyID(objectChild->Attribute("id")) != NULL) //Objecto já existente no sistema { cout << " > Warning: object with ID " << objectChild->Attribute("id") << " is already in the system!!" << endl; continue; } string material; if((material = simple->loadMaterial(objectChild)).empty()) return NULL; if(material != "null"){ Material* mat = this->sceneManager->getMaterialbyID(material); if(mat == NULL){ cout << " > Error: Material with ID: " << material << " not found for Object: " << simple->id << endl; return false; } simple->material = mat; } else{ Material* mat = new Material(); mat->id = "null"; simple->material = mat; } string texture; if((texture = simple->loadTexture(objectChild)).empty()) return NULL; if(texture == "clear"){ Texture* text = new Texture(); text->id = "clear"; simple->texture = text; } else if(texture != "null"){ Texture* text = this->sceneManager->getTexturebyID(texture); if(text == NULL){ cout << " > Error: Texture with ID: " << texture << " not found for Object: " << simple->id << endl; return false; } simple->texture = text; } else{ Texture* text = new Texture(); text->id = "null"; simple->texture = text; } if(objectChild->Attribute("id") == sceneManager->globals->root){ sceneManager->root = simple; } sceneManager->addObject(simple); } i++; } else { cout << " > Error: Maximum number of Objects reached!" << endl; return false; } } if(i == 1){ cout << " > Error: You need to have at least 1 object!" << endl; return false; } if(sceneManager->root == NULL) //O objecto raiz nao existe { cout << " > Error: Cannot load root element. There's no object with ID " << sceneManager->globals->root << endl; return false; } //Adicionar os objectos filhos aos objectos compostos if(!this->sceneManager->setChildrenObjects()) return false; return true; }
void TreeEqualizer::_assign( Node* node, const Viewport& vp, const Range& range ) { LBLOG( LOG_LB2 ) << "assign " << vp << ", " << range << " time " << node->time << " split " << node->split << std::endl; LBASSERTINFO( vp.isValid(), vp ); LBASSERTINFO( range.isValid(), range ); LBASSERTINFO( node->resources > 0.f || !vp.hasArea() || !range.hasData(), "Assigning work to unused compound: " << vp << ", " << range); Compound* compound = node->compound; if( compound ) { LBASSERTINFO( vp == Viewport::FULL || range == Range::ALL, "Mixed 2D/DB load-balancing not implemented" ); compound->setViewport( vp ); compound->setRange( range ); LBLOG( LOG_LB2 ) << compound->getChannel()->getName() << " set " << vp << ", " << range << std::endl; return; } switch( node->mode ) { case MODE_VERTICAL: { // Ensure minimum size const Compound* root = getCompound(); const float pvpW = float( root->getInheritPixelViewport().w ); const float end = vp.getXEnd(); const float boundary = float( node->boundary2i.x( )) / pvpW; float absoluteSplit = vp.x + vp.w * node->split; if( node->left->resources == 0.f ) absoluteSplit = vp.x; else if( node->right->resources == 0.f ) absoluteSplit = end; else if( boundary > 0 ) { const float right = vp.getXEnd() - absoluteSplit; const float left = absoluteSplit - vp.x; const float maxRight = float( node->right->maxSize.x( )) / pvpW; const float maxLeft = float( node->left->maxSize.x( )) / pvpW; if( right > maxRight ) absoluteSplit = end - maxRight; else if( left > maxLeft ) absoluteSplit = vp.x + maxLeft; if( (absoluteSplit - vp.x) < boundary ) absoluteSplit = vp.x + boundary; if( (end - absoluteSplit) < boundary ) absoluteSplit = end - boundary; const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f ); absoluteSplit = ratio * boundary; } absoluteSplit = LB_MAX( absoluteSplit, vp.x ); absoluteSplit = LB_MIN( absoluteSplit, end); node->split = (absoluteSplit - vp.x ) / vp.w; LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X " << node->split << std::endl; // traverse children Viewport childVP = vp; childVP.w = (absoluteSplit - vp.x); _assign( node->left, childVP, range ); childVP.x = childVP.getXEnd(); childVP.w = end - childVP.x; // Fix 2994111: Rounding errors with 2D LB and 16 sources // Floating point rounding may create a width for the 'right' // child which is slightly below the parent width. Correct it. while( childVP.getXEnd() < end ) childVP.w += std::numeric_limits< float >::epsilon(); _assign( node->right, childVP, range ); break; } case MODE_HORIZONTAL: { // Ensure minimum size const Compound* root = getCompound(); const float pvpH = float( root->getInheritPixelViewport().h ); const float end = vp.getYEnd(); const float boundary = float( node->boundary2i.y( )) / pvpH; float absoluteSplit = vp.y + vp.h * node->split; if( node->left->resources == 0.f ) absoluteSplit = vp.y; else if( node->right->resources == 0.f ) absoluteSplit = end; else if( boundary > 0 ) { const float right = vp.getYEnd() - absoluteSplit; const float left = absoluteSplit - vp.y; const float maxRight = float( node->right->maxSize.y( )) / pvpH; const float maxLeft = float( node->left->maxSize.y( )) / pvpH; if( right > maxRight ) absoluteSplit = end - maxRight; else if( left > maxLeft ) absoluteSplit = vp.y + maxLeft; if( (absoluteSplit - vp.y) < boundary ) absoluteSplit = vp.y + boundary; if( (end - absoluteSplit) < boundary ) absoluteSplit = end - boundary; const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f ); absoluteSplit = ratio * boundary; } absoluteSplit = LB_MAX( absoluteSplit, vp.y ); absoluteSplit = LB_MIN( absoluteSplit, end); node->split = (absoluteSplit - vp.y ) / vp.h; LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X " << node->split << std::endl; // traverse children Viewport childVP = vp; childVP.h = (absoluteSplit - vp.y); _assign( node->left, childVP, range ); childVP.y = childVP.getYEnd(); childVP.h = end - childVP.y; // Fix 2994111: Rounding errors with 2D LB and 16 sources // Floating point rounding may create a width for the 'right' // child which is slightly below the parent width. Correct it. while( childVP.getYEnd() < end ) childVP.h += std::numeric_limits< float >::epsilon(); _assign( node->right, childVP, range ); break; } case MODE_DB: { LBASSERT( vp == Viewport::FULL ); const float end = range.end; float absoluteSplit = range.start + (range.end-range.start)*node->split; const float boundary( node->boundaryf ); if( node->left->resources == 0.f ) absoluteSplit = range.start; else if( node->right->resources == 0.f ) absoluteSplit = end; const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f ); absoluteSplit = ratio * boundary; if( (absoluteSplit - range.start) < boundary ) absoluteSplit = range.start; if( (end - absoluteSplit) < boundary ) absoluteSplit = end; node->split = (absoluteSplit-range.start) / (range.end-range.start); LBLOG( LOG_LB2 ) << "Constrained split " << range << " at pos " << node->split << std::endl; Range childRange = range; childRange.end = absoluteSplit; _assign( node->left, vp, childRange ); childRange.start = childRange.end; childRange.end = range.end; _assign( node->right, vp, childRange); break; } default: LBUNIMPLEMENTED; } }