PathTraversalState Path::traversalStateAtLength(float length, bool& success) const { PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength, length); apply(&traversalState, pathLengthApplierFunction); success = traversalState.success(); return traversalState; }
float Path::normalAngleAtLength(float length, bool& ok) { PathTraversalState traversalState(PathTraversalState::TraversalNormalAngleAtLength); traversalState.m_desiredLength = length; apply(&traversalState, pathLengthApplierFunction); ok = traversalState.m_success; return traversalState.m_normalAngle; }
FloatPoint Path::pointAtLength(float length, bool& ok) const { PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength); traversalState.m_desiredLength = length; apply(&traversalState, pathLengthApplierFunction); ok = traversalState.m_success; return traversalState.m_current; }
float Path::normalAngleAtLength(float length, bool& ok) const { PathTraversalState traversalState(PathTraversalState::TraversalNormalAngleAtLength); traversalState.m_desiredLength = length ? length : std::numeric_limits<float>::epsilon(); apply(&traversalState, pathLengthApplierFunction); ok = traversalState.m_success; return traversalState.m_normalAngle; }
float Path::length() const { PathTraversalState traversalState(PathTraversalState::Action::TotalLength); apply([&traversalState](const PathElement& element) { traversalState.processPathElement(element); }); return traversalState.totalLength(); }
PathTraversalState Path::traversalStateAtLength(float length, bool& success) const { PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength, length); apply([&traversalState](const PathElement& element) { traversalState.processPathElement(element); }); success = traversalState.success(); return traversalState; }
bool getSVGPathSegAtLengthFromSVGPathByteStream(const SVGPathByteStream& stream, float length, unsigned& pathSeg) { if (stream.isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::Action::SegmentAtLength); SVGPathTraversalStateBuilder builder(traversalState, length); SVGPathByteStreamSource source(stream); bool ok = SVGPathParser::parse(source, builder); pathSeg = builder.pathSegmentIndex(); return ok; }
bool getTotalLengthOfSVGPathByteStream(const SVGPathByteStream& stream, float& totalLength) { if (stream.isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::Action::TotalLength); SVGPathTraversalStateBuilder builder(traversalState); SVGPathByteStreamSource source(stream); bool ok = SVGPathParser::parse(source, builder); totalLength = builder.totalLength(); return ok; }
bool getPointAtLengthOfSVGPathByteStream(const SVGPathByteStream& stream, float length, SVGPoint& point) { if (stream.isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength); SVGPathTraversalStateBuilder builder(traversalState, length); SVGPathByteStreamSource source(stream); bool ok = SVGPathParser::parse(source, builder); point = builder.currentPoint(); return ok; }
unsigned SVGPathSegList::getPathSegAtLength(float) { // FIXME : to be useful this will need to support non-normalized SVGPathSegLists ExceptionCode ec = 0; int len = numberOfItems(); // FIXME: Eventually this will likely move to a "path applier"-like model, until then PathTraversalState is less useful as we could just use locals PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength); for (int i = 0; i < len; ++i) { SVGPathSeg* segment = getItem(i, ec).get(); float segmentLength = 0; switch (segment->pathSegType()) { case SVGPathSeg::PATHSEG_MOVETO_ABS: { SVGPathSegMovetoAbs* moveTo = static_cast<SVGPathSegMovetoAbs*>(segment); segmentLength = traversalState.moveTo(FloatPoint(moveTo->x(), moveTo->y())); break; } case SVGPathSeg::PATHSEG_LINETO_ABS: { SVGPathSegLinetoAbs* lineTo = static_cast<SVGPathSegLinetoAbs*>(segment); segmentLength = traversalState.lineTo(FloatPoint(lineTo->x(), lineTo->y())); break; } case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS: { SVGPathSegCurvetoCubicAbs* curveTo = static_cast<SVGPathSegCurvetoCubicAbs*>(segment); segmentLength = traversalState.cubicBezierTo(FloatPoint(curveTo->x1(), curveTo->y1()), FloatPoint(curveTo->x2(), curveTo->y2()), FloatPoint(curveTo->x(), curveTo->y())); break; } case SVGPathSeg::PATHSEG_CLOSEPATH: segmentLength = traversalState.closeSubpath(); break; default: ASSERT(false); // FIXME: This only works with normalized/processed path data. break; } traversalState.m_totalLength += segmentLength; if ((traversalState.m_action == PathTraversalState::TraversalSegmentAtLength) && (traversalState.m_totalLength > traversalState.m_desiredLength)) { return traversalState.m_segmentIndex; } traversalState.m_segmentIndex++; } return 0; // The SVG spec is unclear as to what to return when the distance is not on the path }
bool SVGPathParserFactory::getSVGPathSegAtLengthFromSVGPathSegList(SVGPathSegList* pathSegList, float length, unsigned long& pathSeg) { ASSERT(pathSegList); if (!pathSegList->numberOfItems()) return false; PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length); OwnPtr<SVGPathSegListSource> source = SVGPathSegListSource::create(pathSegList); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); pathSeg = builder->pathSegmentIndex(); parser->cleanup(); return ok; }
bool getPointAtLengthOfSVGPathByteStream(SVGPathByteStream* stream, float length, FloatPoint& point) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length); OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); point = builder->currentPoint(); parser->cleanup(); return ok; }
bool SVGPathParserFactory::getTotalLengthOfSVGPathByteStream(SVGPathByteStream* stream, float& totalLength) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::TraversalTotalLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0); OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); totalLength = builder->totalLength(); parser->cleanup(); return ok; }
bool SVGPathParserFactory::getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByteStream* stream, float length, unsigned& pathSeg) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length); OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); pathSeg = builder->pathSegmentIndex(); parser->cleanup(); return ok; }
bool getTotalLengthOfSVGPathByteStream(const SVGPathByteStream* stream, float& totalLength) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::TraversalTotalLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0); SVGPathByteStreamSource source(stream); SVGPathParser* parser = globalSVGPathParser(&source, builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); totalLength = builder->totalLength(); parser->cleanup(); return ok; }
bool getPointAtLengthOfSVGPathByteStream(SVGPathByteStream* stream, float length, SVGPoint& point) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length); auto source = std::make_unique<SVGPathByteStreamSource>(stream); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); point = builder->currentPoint(); parser->cleanup(); return ok; }
bool getTotalLengthOfSVGPathByteStream(SVGPathByteStream* stream, float& totalLength) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::Action::TotalLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0); auto source = std::make_unique<SVGPathByteStreamSource>(stream); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); totalLength = builder->totalLength(); parser->cleanup(); return ok; }
bool getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByteStream* stream, float length, unsigned& pathSeg) { ASSERT(stream); if (stream->isEmpty()) return false; PathTraversalState traversalState(PathTraversalState::Action::SegmentAtLength); SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length); auto source = std::make_unique<SVGPathByteStreamSource>(stream); SVGPathParser* parser = globalSVGPathParser(source.get(), builder); bool ok = parser->parsePathDataFromSource(NormalizedParsing); pathSeg = builder->pathSegmentIndex(); parser->cleanup(); return ok; }
float SVGPathQuery::getTotalLength() const { SVGPathTraversalState traversalState(PathTraversalState::TraversalTotalLength); executeQuery(m_pathByteStream, traversalState); return traversalState.totalLength(); }
float Path::length() const { PathTraversalState traversalState(PathTraversalState::TraversalTotalLength); apply(&traversalState, pathLengthApplierFunction); return traversalState.m_totalLength; }
unsigned SVGPathQuery::getPathSegIndexAtLength(float length) const { SVGPathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength, length); executeQuery(m_pathByteStream, traversalState); return traversalState.segmentIndex(); }
FloatPoint SVGPathQuery::getPointAtLength(float length) const { SVGPathTraversalState traversalState(PathTraversalState::TraversalPointAtLength, length); executeQuery(m_pathByteStream, traversalState); return traversalState.computedPoint(); }
void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone ) { AssertFatal( this == gClientSceneGraph, "SceneManager::_buildSceneGraph - Only the client scenegraph can support this call!" ); PROFILE_SCOPE( SceneGraph_batchRenderImages ); // In the editor, override the type mask for diffuse passes. if( gEditingMission && state->isDiffusePass() ) objectMask = EDITOR_RENDER_TYPEMASK; // Update the zoning state and traverse zones. if( getZoneManager() ) { // Update. getZoneManager()->updateZoningState(); // If zone culling isn't disabled, traverse the // zones now. if( !state->getCullingState().disableZoneCulling() ) { // Find the start zone if we haven't already. if( !baseObject ) { getZoneManager()->findZone( state->getCameraPosition(), baseObject, baseZone ); AssertFatal( baseObject != NULL, "SceneManager::_renderScene - findZone() did not return an object" ); } // Traverse zones starting in base object. SceneTraversalState traversalState( &state->getCullingState() ); PROFILE_START( Scene_traverseZones ); baseObject->traverseZones( &traversalState, baseZone ); PROFILE_END(); // Set the scene render box to the area we have traversed. state->setRenderArea( traversalState.getTraversedArea() ); } } // Set the query box for the container query. Never // make it larger than the frustum's AABB. In the editor, // always query the full frustum as that gives objects // the opportunity to render editor visualizations even if // they are otherwise not in view. if( !state->getFrustum().getBounds().isOverlapped( state->getRenderArea() ) ) { // This handles fringe cases like flying backwards into a zone where you // end up pretty much standing on a zone border and looking directly into // its "walls". In that case the traversal area will be behind the frustum // (remember that the camera isn't where visibility starts, it's the near // distance). return; } Box3F queryBox = state->getFrustum().getBounds(); if( !gEditingMission ) { queryBox.minExtents.setMax( state->getRenderArea().minExtents ); queryBox.maxExtents.setMin( state->getRenderArea().maxExtents ); } PROFILE_START( Scene_cullObjects ); //TODO: We should split the codepaths here based on whether the outdoor zone has visible space. // If it has, we should use the container query-based path. // If it hasn't, we should fill the object list directly from the zone lists which will usually // include way fewer objects. // Gather all objects that intersect the scene render box. mBatchQueryList.clear(); getContainer()->findObjectList( queryBox, objectMask, &mBatchQueryList ); // Cull the list. U32 numRenderObjects = state->getCullingState().cullObjects( mBatchQueryList.address(), mBatchQueryList.size(), !state->isDiffusePass() ? SceneCullingState::CullEditorOverrides : 0 // Keep forced editor stuff out of non-diffuse passes. ); //HACK: If the control object is a Player and it is not in the render list, force // it into it. This really should be solved by collision bounds being separate from // object bounds; only because the Player class is using bounds not encompassing // the actual player object is it that we have this problem in the first place. // Note that we are forcing the player object into ALL passes here but such // is the power of proliferation of things done wrong. GameConnection* connection = GameConnection::getConnectionToServer(); if( connection ) { Player* player = dynamic_cast< Player* >( connection->getControlObject() ); if( player ) { mBatchQueryList.setSize( numRenderObjects ); if( !mBatchQueryList.contains( player ) ) { mBatchQueryList.push_back( player ); numRenderObjects ++; } } } PROFILE_END(); // Render the remaining objects. PROFILE_START( Scene_renderObjects ); state->renderObjects( mBatchQueryList.address(), numRenderObjects ); PROFILE_END(); // Render bounding boxes, if enabled. if( smRenderBoundingBoxes && state->isDiffusePass() ) { GFXDEBUGEVENT_SCOPE( Scene_renderBoundingBoxes, ColorI::WHITE ); GameBase* cameraObject = 0; if( connection ) cameraObject = connection->getCameraObject(); GFXStateBlockDesc desc; desc.setFillModeWireframe(); desc.setZReadWrite( true, false ); for( U32 i = 0; i < numRenderObjects; ++ i ) { SceneObject* object = mBatchQueryList[ i ]; // Skip global bounds object. if( object->isGlobalBounds() ) continue; // Skip camera object as we're viewing the scene from it. if( object == cameraObject ) continue; const Box3F& worldBox = object->getWorldBox(); GFX->getDrawUtil()->drawObjectBox( desc, Point3F( worldBox.len_x(), worldBox.len_y(), worldBox.len_z() ), worldBox.getCenter(), MatrixF::Identity, ColorI::WHITE ); } } }