diff --git a/include/cinder/gl/SdfTextMesh.h b/include/cinder/gl/SdfTextMesh.h index db424f7..c52c91c 100644 --- a/include/cinder/gl/SdfTextMesh.h +++ b/include/cinder/gl/SdfTextMesh.h @@ -140,6 +140,7 @@ class SdfTextMesh { void setWrapped( bool value ) { mOptions.setWrapped( value ); } const Rectf& getFitRect() const { return mOptions.getFitRect(); } void setFitRect( const Rectf &value ) { mOptions.setFitRect( value ); } + const Rectf& getBounds() const { return mBounds; } private: Run( SdfTextMesh *sdfTextMesh, const std::string& utf8, const SdfTextRef& sdfText, const vec2 &baseline, const Run::Options &drawOptions ); Run( SdfTextMesh *sdfTextMesh, const std::string& utf8, const SdfTextRef& sdfText, const Rectf &fitRect, const Run::Options &drawOptions ); @@ -150,6 +151,7 @@ class SdfTextMesh { uint32_t mDirty = Feature::NONE; std::string mUtf8; Run::Options mOptions; + Rectf mBounds = Rectf( 0, 0, 0, 0 ); }; virtual ~SdfTextMesh() {} @@ -162,6 +164,9 @@ class SdfTextMesh { SdfTextMesh::RunRef appendTextWrapped( const std::string &utf8, const SdfTextRef &sdfText, const Rectf &fitRect, const Run::Options &options = Run::Options() ); SdfTextMesh::RunRef appendTextWrapped( const std::string &utf8, const SdfText::Font &font, const Rectf &fitRect, const Run::Options &options = Run::Options() ); + //! Returns the runs associated with \a sdfText. If \a sdfText is null, all runs gets returned. + std::vector getRuns( const SdfTextRef &sdfText = SdfTextRef() ) const; + void cache(); void draw( bool premultiply = true, float gamma = 2.2f ); diff --git a/samples/MeshPages/assets/Alike.sdft b/samples/MeshPages/assets/Alike.sdft index 49b2bd2..5547f9e 100644 Binary files a/samples/MeshPages/assets/Alike.sdft and b/samples/MeshPages/assets/Alike.sdft differ diff --git a/samples/MeshPages/src/MeshPagesApp.cpp b/samples/MeshPages/src/MeshPagesApp.cpp index 8c073e9..1e424ec 100644 --- a/samples/MeshPages/src/MeshPagesApp.cpp +++ b/samples/MeshPages/src/MeshPagesApp.cpp @@ -43,9 +43,10 @@ class MeshPagesApp : public App { gl::SdfText::Font mFont; gl::SdfTextRef mSdfText; gl::SdfTextMeshRef mSdfTextMesh; - bool mPremultiply = false; + bool mPremultiply = true; gl::SdfText::Alignment mAlignment = gl::SdfText::Alignment::LEFT; bool mJustify = true; + bool mDrawBounds = false; std::vector mPageNumRuns; std::vector mPageTextRuns; @@ -134,6 +135,11 @@ void MeshPagesApp::keyDown( KeyEvent event ) } break; + case 'b': + case 'B': + mDrawBounds = ! mDrawBounds; + break; + case '1': moveToPage( 1 ); break; case '2': moveToPage( 2 ); break; case '3': moveToPage( 3 ); break; @@ -163,6 +169,19 @@ void MeshPagesApp::draw() auto drawOptions = gl::SdfText::DrawOptions().premultiply( mPremultiply ); + if( mDrawBounds ) { + gl::ScopedModelMatrix scopedModel; + gl::translate( mOffset.value() ); + + auto runs = mSdfTextMesh->getRuns(); + gl::lineWidth( 1.0f ); + gl::color( Color( 0.1f, 0.8f, 0.9f ) ); + for( const auto &run : runs ) { + const auto &bounds = run->getBounds(); + gl::drawStrokedRect( bounds ); + } + } + gl::color( Color( 0.1f, 0.1f, 0.1f ) ); drawOptions.scale( 2.0f ); mSdfText->drawString( "Gulliver's Travels into Several Remote Nations of the World", vec2( 1.5f * kPageBorder, 2.5f * kPageBorder ), drawOptions ); diff --git a/samples/MeshPages/vc2013/MeshPages.vcxproj b/samples/MeshPages/vc2013/MeshPages.vcxproj index 1764bf3..79095cb 100644 --- a/samples/MeshPages/vc2013/MeshPages.vcxproj +++ b/samples/MeshPages/vc2013/MeshPages.vcxproj @@ -19,7 +19,7 @@ - {1DBAE4DA-7CC4-4BDD-904D-971A2901C3DE} + {022DEB01-A1F9-438F-9A33-3204F8C04816} Basic Win32Proj diff --git a/src/cinder/gl/SdfTextMesh.cpp b/src/cinder/gl/SdfTextMesh.cpp index 9b43932..34752c9 100644 --- a/src/cinder/gl/SdfTextMesh.cpp +++ b/src/cinder/gl/SdfTextMesh.cpp @@ -176,6 +176,23 @@ void SdfTextMesh::appendText( const SdfTextMesh::RunRef &run ) updateDirty( run.get() ); } +std::vector SdfTextMesh::getRuns( const SdfTextRef &sdfText ) const +{ + std::vector result; + if( sdfText ) { + auto it = mRunMaps.find( sdfText ); + if( mRunMaps.end() != it ) { + result = it->second; + } + } + else { + for( const auto &it : mRunMaps ) { + std::copy( std::begin( it.second ), std::end( it.second ), std::back_inserter( result ) ); + } + } + return result; +} + void SdfTextMesh::updateFeatures( const Run *run ) { const auto& sdfText = run->getSdfText(); @@ -253,9 +270,9 @@ void SdfTextMesh::cache() return; } - for( auto& runMapIt : mRunMaps ) { - auto& sdfText = runMapIt.first; - auto& runs = runMapIt.second; + for( auto &runMapIt : mRunMaps ) { + auto &sdfText = runMapIt.first; + auto &runs = runMapIt.second; // Get textures std::vector textures; @@ -269,24 +286,33 @@ void SdfTextMesh::cache() std::unordered_map> runVertRanges; std::unordered_map texToMesh; - for( const auto& run : runs ) { + for( const auto &run : runs ) { std::pair vertRange = std::make_pair( 0, 0 ); - const auto& options = run->getOptions(); + const auto &options = run->getOptions(); + auto &bounds = run->mBounds; std::vector>> placements; if( run->getWrapped() ) { - placements = sdfText->placeStringWrapped( run->getUtf8(), run->getFitRect(), vec2( run->getPosition() ), options.getDrawOptions() ); + const Rectf &fitRect = run->getFitRect(); + vec2 offset = vec2( run->getPosition() ); + placements = sdfText->placeStringWrapped( run->getUtf8(), fitRect, offset, options.getDrawOptions() ); + bounds = sdfText->measureStringBoundsWrapped( run->getUtf8(), fitRect, options.getDrawOptions() ); + bounds += vec2( fitRect.x1, fitRect.y1 ); + bounds += offset; } else { - placements = sdfText->placeString( run->getUtf8(), vec2( run->getBaseline() ), options.getDrawOptions() ); + vec2 baseline = vec2( run->getBaseline() ); + placements = sdfText->placeString( run->getUtf8(), baseline, options.getDrawOptions() ); + bounds = sdfText->measureStringBounds( run->getUtf8(),options.getDrawOptions() ); + bounds += baseline; } - for( const auto& placementsIt : placements ) { + for( const auto &placementsIt : placements ) { Texture2dRef tex = textures[placementsIt.first]; const auto& charPlacements = placementsIt.second; if( charPlacements.empty() ) { continue; } - auto& mesh = texToMesh[tex]; + auto &mesh = texToMesh[tex]; vertRange.first = static_cast( mesh.getNumIndices() ); for( const auto& place : charPlacements ) { const auto& srcTexCoords = place.mSrcTexCoords;