├── .gitignore ├── LICENSE ├── README.md ├── addon_config.mk ├── example-labels ├── Makefile ├── Project.xcconfig ├── addons.make ├── bin │ └── data │ │ ├── .gitkeep │ │ └── Champagne & Limousines.ttf ├── config.make ├── example.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── example-labels Debug.xcscheme │ │ └── example-labels Release.xcscheme ├── openFrameworks-Info.plist └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-shader ├── Makefile ├── Project.xcconfig ├── addons.make ├── bin │ └── data │ │ ├── .gitkeep │ │ ├── Champagne & Limousines.ttf │ │ └── shader.frag ├── config.make ├── example.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── example-labels Debug.xcscheme │ │ └── example-labels Release.xcscheme ├── openFrameworks-Info.plist └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-simple ├── Makefile ├── Project.xcconfig ├── addons.make ├── bin │ └── data │ │ └── .gitkeep ├── config.make ├── example.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── example-labels Debug.xcscheme │ │ └── example-labels Release.xcscheme ├── openFrameworks-Info.plist └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── images ├── 01.gif ├── 02.gif ├── 03.gif ├── 04.gif ├── 05.gif ├── 06.gif ├── 07.gif ├── hud.jpg └── projection.png ├── libs ├── glmFontstash │ ├── fontstash │ │ ├── fontstash.h │ │ ├── glfontstash.h │ │ ├── sdf.h │ │ └── stb_truetype.h │ ├── glmFont.cpp │ └── glmFont.h └── glmTile │ ├── Labels │ ├── glmAnchorLine.cpp │ ├── glmAnchorLine.h │ ├── glmFeatureLabel.cpp │ ├── glmFeatureLabel.h │ ├── glmFeatureLabelLine.cpp │ ├── glmFeatureLabelLine.h │ ├── glmFeatureLabelPoint.cpp │ ├── glmFeatureLabelPoint.h │ ├── glmLabelManager.cpp │ └── glmLabelManager.h │ ├── glmFeature.h │ ├── glmGeometryBuilder.cpp │ ├── glmGeometryBuilder.h │ ├── glmTile.cpp │ └── glmTile.h ├── ofxaddons_thumbnail.png └── src ├── ofxVectorBuilder.cpp ├── ofxVectorBuilder.h ├── ofxVectorLabels.cpp ├── ofxVectorLabels.h ├── ofxVectorTile.cpp └── ofxVectorTile.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Some general ignore patterns 2 | build/ 3 | obj/ 4 | *.o 5 | Debug*/ 6 | Release*/ 7 | *.mode* 8 | *.app/ 9 | *.pyc 10 | .svn/ 11 | 12 | 13 | #XCode 14 | *.pbxuser 15 | *.perspective 16 | *.perspectivev3 17 | *.mode1v3 18 | *.mode2v3 19 | #XCode 4 20 | xcuserdata 21 | *.xcworkspace 22 | 23 | #Code::Blocks 24 | *.depend 25 | *.layout 26 | 27 | #Visual Studio 28 | *.sdf 29 | *.opensdf 30 | *.suo 31 | ipch/ 32 | 33 | #Eclipse 34 | .metadata 35 | local.properties 36 | .externalToolBuilders 37 | 38 | 39 | # OS-specific ignore patterns 40 | 41 | #Linux 42 | *~ 43 | # KDE 44 | .directory 45 | 46 | #OSX 47 | .DS_Store 48 | *.swp 49 | *~.nib 50 | # Thumbnails 51 | ._* 52 | 53 | #Windows 54 | # Windows image file caches 55 | Thumbs.db 56 | # Folder config file 57 | Desktop.ini 58 | 59 | #Android 60 | .csettings 61 | /libs/openFrameworksCompiled/project/android/paths.make 62 | 63 | # Miscellaneous 64 | .mailmap 65 | 66 | /week1-movingRec/bin/data/park6/ 67 | /week1-movingRec/bin/data/park5/ 68 | /week1-movingRec/bin/data/park4/ 69 | /week1-movingRec/bin/data/park3/ 70 | /week1-movingRec/bin/data/park2/ 71 | /week1-movingRec/bin/data/park1/ 72 | /week1-movingRec/bin/data/Archive.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mapzen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 3 | 4 | ## VectorTile 5 | 6 | This addon is a wrapper from a [Mapzen](mapzen.com) [Tangram](https://github.com/tangrams) experiment on 3D Labels 7 | 8 | ## Install 9 | 10 | Install addons dependences: 11 | 12 | ``` 13 | cd openFrameworks/addons 14 | git clone --depth 1 http://github.com/patriciogonzalezvivo/ofxGlmTools.git 15 | git clone --depth 1 http://github.com/jefftimesten/ofxJSON.git 16 | ``` 17 | 18 | ## Add to project 19 | 20 | Install ```ofxVectorTile``` to your project using the ProjectGenerator, dragging folder or Adam’s [OFPlugin](https://github.com/admsyn/OFPlugin). 21 | 22 | On the project Properties (the blue icons with the name of your project) go to `Building Settings` > `Linking` > `Other Linker Flags` and add `-lcurl` 23 | 24 | ## Dependences 25 | 26 | - [ofxGlmTools](https://github.com/patriciogonzalezvivo/ofxGlmTools) 27 | - [ofxJSON](https://github.com/jefftimesten/ofxJSON) 28 | 29 | ## Sources 30 | 31 | - [glmTile](https://github.com/tangrams/glmTile) 32 | 33 | * [cURL](http://curl.haxx.se/libcurl/) 34 | * [JsonCpp](https://github.com/open-source-parsers/jsoncpp) 35 | * [Fontstash](https://github.com/memononen/fontstash) 36 | 37 | 38 | ## The Problem 39 | Labels in maps are a huge headache, and have been for a long time. There are lots of solutions for 2D mapping, but not so many when you work in 3D, and especially not when your map shifts between 2D and 3D. 40 | 41 | ## The Experiments 42 | 43 | The main trick is a 2D projection of the geometry to place the text, within the canvas. Like a heads-up display layer between the 3D geometry and the camera. 44 | 45 | In the canvas: 46 | ![projection](images/projection.png) 47 | 48 | Pros: 49 | 50 | * Fonts don’t need to be resized on zoom 51 | 52 | * No off-screen computations 53 | 54 | * We know exactly what the user sees 55 | 56 | Cons: 57 | 58 | * Occlusion becomes a problem: Should labels be visible through buildings? Which labels to prioritize, how to prioritize them? For now, these have no occlusion. 59 | 60 | ### Line Labels 61 | 62 | * Fit and repeat 63 | 64 | ``` 65 | float lastSeed = 0.0; 66 | for (int i = 0; i < _anchorLine.size()-1; i++) { 67 | float offset = _anchorLine.getDistances()[i]; 68 | float segmentLength = _anchorLine.getDistances()[i+1]-_anchorLine.getDistances()[i];//_anchorLine.getPolars()[i].r; 69 | 70 | // Fits? 71 | // 72 | if( segmentLength >= (m_label.width+_maxDistance) ){ 73 | // How many times? 74 | int nTimes = segmentLength/(m_label.width+_maxDistance); 75 | 76 | // At what distance between each other? 77 | float margin = (segmentLength-m_label.width*(float)nTimes)/((float)nTimes+1.0); 78 | 79 | // Add anchors points for seeds 80 | float seed = margin; 81 | for (int i = 0; i < nTimes; i++) { 82 | float potentialSeed = offset + seed ; 83 | if( potentialSeed-lastSeed > _minDistance ){ 84 | lastSeed = potentialSeed; 85 | _anchorLine.marks.push_back(lastSeed); 86 | seed += m_label.width+margin; 87 | } 88 | } 89 | } else if ( segmentLength >= m_label.width+_minDistance){ 90 | // Only one time 91 | // 92 | float margin = (segmentLength-m_label.width)*0.5; 93 | float potentialSeed = offset + margin ; 94 | if( potentialSeed-lastSeed > _minDistance){ 95 | lastSeed = potentialSeed; 96 | _anchorLine.marks.push_back(lastSeed); 97 | } 98 | } 99 | } 100 | ``` 101 | 102 | ![01](images/01.gif) 103 | 104 | * Fade according to tilt angle 105 | 106 | ``` 107 | float angle = glm::dot(glm::normalize( *m_cameraPos - shapes[0].getCentroid()),glm::vec3(0.,0.,1.)); 108 | m_alpha = lerpValue(m_alpha,powf( CLAMP(angle,0.01,1.0), 1.15 ),0.1); 109 | ``` 110 | 111 | ![02](images/02.gif) 112 | 113 | * Curved path following 114 | 115 | ``` 116 | float angle = PI; 117 | glm::vec3 diff = _anchorLine[0]-_anchorLine[_anchorLine.size()-1]; 118 | angle = atan2f(-diff.y, diff.x); 119 | 120 | if(angle < PI*0.5 && angle > -PI*0.5){ 121 | for (int i = m_text.length()-1; i >=0 ; i--) { 122 | glm::vec3 src = _anchorLine.getPositionAt(_offset); 123 | if(screen.inside(src)){ 124 | double rot = _anchorLine.getAngleAt(_offset); 125 | glPushMatrix(); 126 | glTranslated(src.x, src.y, src.z); 127 | glScalef(1,-1,1); 128 | glRotated(rot*RAD_TO_DEG, 0, 0, -1); 129 | glScaled(-1, -1, 1); 130 | glTranslated(-m_lettersWidth[i], 0, 0); 131 | glTranslatef(0., -m_label.height*0.5,0.); 132 | m_font->drawString( std::string(1,m_text[i]), m_alpha ); 133 | glPopMatrix(); 134 | _offset += m_lettersWidth[i]; 135 | } else { 136 | break; 137 | } 138 | } 139 | } else { 140 | for (int i = 0; i < m_text.length(); i++) { 141 | glm::vec3 src = _anchorLine.getPositionAt(_offset); 142 | if(screen.inside(src)){ 143 | double rot = _anchorLine.getAngleAt(_offset); 144 | glPushMatrix(); 145 | glTranslated(src.x, src.y, src.z); 146 | glScalef(1,-1,1); 147 | glRotated(rot*RAD_TO_DEG, 0, 0, -1); 148 | glTranslatef(0., -m_label.height*0.5,0.); 149 | m_font->drawString( std::string(1,m_text[i]), m_alpha ); 150 | glPopMatrix(); 151 | _offset += m_lettersWidth[i]; 152 | } else { 153 | break; 154 | } 155 | } 156 | } 157 | ``` 158 | 159 | ![07](images/07.gif) 160 | 161 | ### Point Labels 162 | 163 | * Project top points 164 | 165 | ``` 166 | glm::ivec4 viewport; 167 | glm::mat4x4 mvmatrix, projmatrix; 168 | glGetIntegerv(GL_VIEWPORT, &viewport[0]); 169 | glGetFloatv(GL_MODELVIEW_MATRIX, &mvmatrix[0][0]); 170 | glGetFloatv(GL_PROJECTION_MATRIX, &projmatrix[0][0]); 171 | m_anchorPoint = glm::project(m_centroid+m_offset, mvmatrix, projmatrix, viewport); 172 | ``` 173 | 174 | ![03](images/03.gif) 175 | 176 | * Mutual occlusion using depth sort and bounding boxes 177 | 178 | ``` 179 | bool depthSort(const glmFeatureLabelPointRef &_A, const glmFeatureLabelPointRef &_B){ 180 | return _A->getAnchorPoint().z < _B->getAnchorPoint().z; 181 | } 182 | 183 | … 184 | 185 | std::sort(pointLabels.begin(),pointLabels.end(), depthSort); 186 | for (int i = 0; i < pointLabels.size(); i++) { 187 | if(pointLabels[i]->bVisible){ 188 | for (int j = i-1; j >= 0 ; j--) { 189 | if (pointLabels[i]->isOver( pointLabels[j].get() ) ){ 190 | pointLabels[i]->bVisible = false; 191 | break; 192 | } 193 | } 194 | } 195 | } 196 | ``` 197 | 198 | 199 | ![04](images/04.gif) 200 | 201 | * Occlude line labels with bounding box 202 | 203 | ``` 204 | double rot = _anchorLine.getAngleAt(_offset); 205 | glmRectangle boundingBox = glmPolyline(m_label,angle).getBoundingBox(); 206 | boundingBox.translate(_anchorLine.getPositionAt(_offset+m_label.width*0.5)); 207 | 208 | bool bOver = false; 209 | for (int i = 0; i < pointLabels->size(); i++ ){ 210 | if(pointLabels->at(i)->bVisible){ 211 | if( boundingBox.intersects(pointLabels->at(i)->getLabel(0) ) ){ 212 | bOver = true; 213 | break; 214 | } 215 | } 216 | } 217 | ``` 218 | 219 | ![06](images/06.gif) 220 | 221 | * Street level point of view 222 | ![05](images/05.gif) 223 | 224 | 225 | -------------------------------------------------------------------------------- /addon_config.mk: -------------------------------------------------------------------------------- 1 | meta: 2 | ADDON_NAME = ofxVectorTile 3 | ADDON_DESCRIPTION = 3D Vector Map Tile builder with Labels 4 | ADDON_AUTHOR = Patricio Gonzalez Vivo 5 | ADDON_TAGS = map geo 3D shaders 6 | ADDON_URL = http://github.com/tangrams/ofxVectorTile 7 | 8 | common: 9 | # dependencies with other addons, a list of them separated by spaces 10 | # or use += in several lines 11 | ADDON_DEPENDENCIES = ofxJSON 12 | ADDON_DEPENDENCIES += ofxGlmTools 13 | 14 | # include search paths, this will be usually parsed from the file system 15 | # but if the addon or addon libraries need special search paths they can be 16 | # specified here separated by spaces or one per line using += 17 | ADDON_INCLUDES = 18 | 19 | # any special flag that should be passed to the compiler when using this 20 | # addon 21 | ADDON_CFLAGS = 22 | 23 | # any special flag that should be passed to the linker when using this 24 | # addon, also used for system libraries with -lname 25 | ADDON_LDFLAGS = -lcurl 26 | 27 | # linux only, any library that should be included in the project using 28 | # pkg-config 29 | ADDON_PKG_CONFIG_LIBRARIES = 30 | 31 | # osx/iOS only, any framework that should be included in the project 32 | ADDON_FRAMEWORKS = 33 | 34 | # source files, these will be usually parsed from the file system looking 35 | # in the src folders in libs and the root of the addon. if your addon needs 36 | # to include files in different places or a different set of files per platform 37 | # they can be specified here 38 | ADDON_SOURCES = 39 | 40 | # binary libraries, these will be usually parsed from the file system but some 41 | # libraries need to passed to the linker in a specific order 42 | ADDON_LIBS = 43 | 44 | # some addons need resources to be copied to the bin/data folder of the project 45 | # specify here any files that need to be copied, you can use wildcards like * and ? 46 | ADDON_DATA = copy_to_data_GUI/* 47 | 48 | linux64: 49 | # when parsing the file system looking for libraries exclude this for all or 50 | # a specific platform 51 | ADDON_LIBS_EXCLUDE = libs/kiss 52 | 53 | linux: 54 | ADDON_LIBS_EXCLUDE = libs/kiss 55 | 56 | linuxarmv6l: 57 | ADDON_LIBS_EXCLUDE = libs/kiss 58 | 59 | linuxarmv7l: 60 | ADDON_LIBS_EXCLUDE = libs/kiss 61 | 62 | osx: 63 | win_cb: 64 | vs2010: 65 | iphone: 66 | android: 67 | -------------------------------------------------------------------------------- /example-labels/Makefile: -------------------------------------------------------------------------------- 1 | # Attempt to load a config.make file. 2 | # If none is found, project defaults in config.project.make will be used. 3 | ifneq ($(wildcard config.make),) 4 | include config.make 5 | endif 6 | 7 | # make sure the the OF_ROOT location is defined 8 | ifndef OF_ROOT 9 | OF_ROOT=../../.. 10 | endif 11 | 12 | # call the project makefile! 13 | include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk 14 | -------------------------------------------------------------------------------- /example-labels/Project.xcconfig: -------------------------------------------------------------------------------- 1 | //THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT. 2 | //THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED 3 | OF_PATH = ../../.. 4 | 5 | //THIS HAS ALL THE HEADER AND LIBS FOR OF CORE 6 | #include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig" 7 | 8 | //ICONS - NEW IN 0072 9 | ICON_NAME_DEBUG = icon-debug.icns 10 | ICON_NAME_RELEASE = icon.icns 11 | ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/ 12 | 13 | //IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to: 14 | //ICON_FILE_PATH = bin/data/ 15 | 16 | OTHER_LDFLAGS = $(OF_CORE_LIBS) 17 | HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) 18 | -------------------------------------------------------------------------------- /example-labels/addons.make: -------------------------------------------------------------------------------- 1 | ofxGlmTools 2 | ofxJSON 3 | ofxVectorTile 4 | -------------------------------------------------------------------------------- /example-labels/bin/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/example-labels/bin/data/.gitkeep -------------------------------------------------------------------------------- /example-labels/bin/data/Champagne & Limousines.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/example-labels/bin/data/Champagne & Limousines.ttf -------------------------------------------------------------------------------- /example-labels/config.make: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # CONFIGURE PROJECT MAKEFILE (optional) 3 | # This file is where we make project specific configurations. 4 | ################################################################################ 5 | 6 | ################################################################################ 7 | # OF ROOT 8 | # The location of your root openFrameworks installation 9 | # (default) OF_ROOT = ../../.. 10 | ################################################################################ 11 | # OF_ROOT = ../../.. 12 | 13 | ################################################################################ 14 | # PROJECT ROOT 15 | # The location of the project - a starting place for searching for files 16 | # (default) PROJECT_ROOT = . (this directory) 17 | # 18 | ################################################################################ 19 | # PROJECT_ROOT = . 20 | 21 | ################################################################################ 22 | # PROJECT SPECIFIC CHECKS 23 | # This is a project defined section to create internal makefile flags to 24 | # conditionally enable or disable the addition of various features within 25 | # this makefile. For instance, if you want to make changes based on whether 26 | # GTK is installed, one might test that here and create a variable to check. 27 | ################################################################################ 28 | # None 29 | 30 | ################################################################################ 31 | # PROJECT EXTERNAL SOURCE PATHS 32 | # These are fully qualified paths that are not within the PROJECT_ROOT folder. 33 | # Like source folders in the PROJECT_ROOT, these paths are subject to 34 | # exlclusion via the PROJECT_EXLCUSIONS list. 35 | # 36 | # (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) 37 | # 38 | # Note: Leave a leading space when adding list items with the += operator 39 | ################################################################################ 40 | # PROJECT_EXTERNAL_SOURCE_PATHS = 41 | 42 | ################################################################################ 43 | # PROJECT EXCLUSIONS 44 | # These makefiles assume that all folders in your current project directory 45 | # and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations 46 | # to look for source code. The any folders or files that match any of the 47 | # items in the PROJECT_EXCLUSIONS list below will be ignored. 48 | # 49 | # Each item in the PROJECT_EXCLUSIONS list will be treated as a complete 50 | # string unless teh user adds a wildcard (%) operator to match subdirectories. 51 | # GNU make only allows one wildcard for matching. The second wildcard (%) is 52 | # treated literally. 53 | # 54 | # (default) PROJECT_EXCLUSIONS = (blank) 55 | # 56 | # Will automatically exclude the following: 57 | # 58 | # $(PROJECT_ROOT)/bin% 59 | # $(PROJECT_ROOT)/obj% 60 | # $(PROJECT_ROOT)/%.xcodeproj 61 | # 62 | # Note: Leave a leading space when adding list items with the += operator 63 | ################################################################################ 64 | # PROJECT_EXCLUSIONS = 65 | 66 | ################################################################################ 67 | # PROJECT LINKER FLAGS 68 | # These flags will be sent to the linker when compiling the executable. 69 | # 70 | # (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs 71 | # 72 | # Note: Leave a leading space when adding list items with the += operator 73 | ################################################################################ 74 | 75 | # Currently, shared libraries that are needed are copied to the 76 | # $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to 77 | # add a runtime path to search for those shared libraries, since they aren't 78 | # incorporated directly into the final executable application binary. 79 | # TODO: should this be a default setting? 80 | # PROJECT_LDFLAGS=-Wl,-rpath=./libs 81 | 82 | ################################################################################ 83 | # PROJECT DEFINES 84 | # Create a space-delimited list of DEFINES. The list will be converted into 85 | # CFLAGS with the "-D" flag later in the makefile. 86 | # 87 | # (default) PROJECT_DEFINES = (blank) 88 | # 89 | # Note: Leave a leading space when adding list items with the += operator 90 | ################################################################################ 91 | # PROJECT_DEFINES = 92 | 93 | ################################################################################ 94 | # PROJECT CFLAGS 95 | # This is a list of fully qualified CFLAGS required when compiling for this 96 | # project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS 97 | # defined in your platform specific core configuration files. These flags are 98 | # presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. 99 | # 100 | # (default) PROJECT_CFLAGS = (blank) 101 | # 102 | # Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in 103 | # your platform specific configuration file will be applied by default and 104 | # further flags here may not be needed. 105 | # 106 | # Note: Leave a leading space when adding list items with the += operator 107 | ################################################################################ 108 | # PROJECT_CFLAGS = 109 | 110 | ################################################################################ 111 | # PROJECT OPTIMIZATION CFLAGS 112 | # These are lists of CFLAGS that are target-specific. While any flags could 113 | # be conditionally added, they are usually limited to optimization flags. 114 | # These flags are added BEFORE the PROJECT_CFLAGS. 115 | # 116 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. 117 | # 118 | # (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) 119 | # 120 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. 121 | # 122 | # (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) 123 | # 124 | # Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the 125 | # PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration 126 | # file will be applied by default and further optimization flags here may not 127 | # be needed. 128 | # 129 | # Note: Leave a leading space when adding list items with the += operator 130 | ################################################################################ 131 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE = 132 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG = 133 | 134 | ################################################################################ 135 | # PROJECT COMPILERS 136 | # Custom compilers can be set for CC and CXX 137 | # (default) PROJECT_CXX = (blank) 138 | # (default) PROJECT_CC = (blank) 139 | # Note: Leave a leading space when adding list items with the += operator 140 | ################################################################################ 141 | # PROJECT_CXX = 142 | # PROJECT_CC = 143 | -------------------------------------------------------------------------------- /example-labels/example.xcodeproj/xcshareddata/xcschemes/example-labels Debug.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /example-labels/example.xcodeproj/xcshareddata/xcschemes/example-labels Release.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /example-labels/openFrameworks-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | cc.openFrameworks.ofapp 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | APPL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | 1.0 19 | CFBundleIconFile 20 | ${ICON} 21 | 22 | 23 | -------------------------------------------------------------------------------- /example-labels/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofMain.h" 2 | #include "ofApp.h" 3 | 4 | //======================================================================== 5 | int main( ){ 6 | ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context 7 | 8 | // this kicks off the running of my app 9 | // can be OF_WINDOW or OF_FULLSCREEN 10 | // pass in width and height too: 11 | ofRunApp(new ofApp()); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example-labels/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | //-------------------------------------------------------------- 4 | void ofApp::setup(){ 5 | ofSetVerticalSync(true); 6 | ofEnableAlphaBlending(); 7 | 8 | light.setDiffuseColor(ofFloatColor(0.9)); 9 | light.setPosition(ofPoint(0,0,100)); 10 | 11 | // Load Label Fonts 12 | // 13 | labels.loadFont("Champagne & Limousines.ttf", 10); 14 | labels.setFontColor(ofFloatColor(1.0), ofFloatColor(0.0)); 15 | 16 | // Link the label manager with the builder 17 | // 18 | builder.setLabelManager(&labels); 19 | 20 | // Request a new tile to the builder 21 | // 22 | tile = builder.getFromWeb(19299,24631,16); 23 | 24 | // Make a VBO from the tile (FASTER) 25 | // 26 | tileMesh = tile.getMesh(); 27 | 28 | fbo.allocate(ofGetWidth(),ofGetHeight()); 29 | } 30 | 31 | //-------------------------------------------------------------- 32 | void ofApp::update(){ 33 | labels.updateCameraPosition(cam.getPosition()); 34 | 35 | // Update the scene 36 | // 37 | fbo.begin(); 38 | ofClear(0,0,0,0); 39 | cam.begin(); 40 | ofEnableDepthTest(); 41 | 42 | ofEnableLighting(); 43 | light.enable(); 44 | 45 | // tile.draw(); 46 | tileMesh.draw(); 47 | 48 | light.disable(); 49 | ofDisableLighting(); 50 | 51 | labels.draw3D(); 52 | labels.updateProjection(); 53 | 54 | ofDisableDepthTest(); 55 | cam.end(); 56 | fbo.end(); 57 | } 58 | 59 | //-------------------------------------------------------------- 60 | void ofApp::draw(){ 61 | ofBackgroundGradient(ofColor::gray,ofColor::black); 62 | 63 | ofSetColor(255); 64 | fbo.draw(0,0); 65 | 66 | labels.draw2D(); 67 | 68 | ofDrawBitmapString(" 'p' : toogle point labels debug", 10,15); 69 | ofDrawBitmapString(" 'l' : toogle line labels debug", 10,35); 70 | } 71 | 72 | //-------------------------------------------------------------- 73 | void ofApp::keyPressed(int key){ 74 | 75 | if(key == 'f'){ 76 | ofToggleFullscreen(); 77 | } else if (key == 'p'){ 78 | labels.bDebugPoints = !labels.bDebugPoints; 79 | } else if (key == 'l'){ 80 | labels.bDebugLines = !labels.bDebugLines; 81 | } 82 | 83 | } 84 | 85 | //-------------------------------------------------------------- 86 | void ofApp::keyReleased(int key){ 87 | 88 | } 89 | 90 | //-------------------------------------------------------------- 91 | void ofApp::mouseMoved(int x, int y ){ 92 | 93 | } 94 | 95 | //-------------------------------------------------------------- 96 | void ofApp::mouseDragged(int x, int y, int button){ 97 | 98 | } 99 | 100 | //-------------------------------------------------------------- 101 | void ofApp::mousePressed(int x, int y, int button){ 102 | 103 | } 104 | 105 | //-------------------------------------------------------------- 106 | void ofApp::mouseReleased(int x, int y, int button){ 107 | 108 | } 109 | 110 | //-------------------------------------------------------------- 111 | void ofApp::windowResized(int w, int h){ 112 | fbo.allocate(w,h); 113 | } 114 | 115 | //-------------------------------------------------------------- 116 | void ofApp::gotMessage(ofMessage msg){ 117 | 118 | } 119 | 120 | //-------------------------------------------------------------- 121 | void ofApp::dragEvent(ofDragInfo dragInfo){ 122 | 123 | } 124 | -------------------------------------------------------------------------------- /example-labels/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxVectorTile.h" 5 | #include "ofxVectorBuilder.h" 6 | #include "ofxVectorLabels.h" 7 | 8 | class ofApp : public ofBaseApp{ 9 | public: 10 | void setup(); 11 | void update(); 12 | void draw(); 13 | 14 | void keyPressed(int key); 15 | void keyReleased(int key); 16 | void mouseMoved(int x, int y ); 17 | void mouseDragged(int x, int y, int button); 18 | void mousePressed(int x, int y, int button); 19 | void mouseReleased(int x, int y, int button); 20 | void windowResized(int w, int h); 21 | void dragEvent(ofDragInfo dragInfo); 22 | void gotMessage(ofMessage msg); 23 | 24 | ofEasyCam cam; 25 | ofLight light; 26 | ofFbo fbo; 27 | 28 | ofxVectorTile tile; 29 | ofxVectorBuilder builder; 30 | ofxVectorLabels labels; 31 | ofVboMesh tileMesh; 32 | }; 33 | -------------------------------------------------------------------------------- /example-shader/Makefile: -------------------------------------------------------------------------------- 1 | # Attempt to load a config.make file. 2 | # If none is found, project defaults in config.project.make will be used. 3 | ifneq ($(wildcard config.make),) 4 | include config.make 5 | endif 6 | 7 | # make sure the the OF_ROOT location is defined 8 | ifndef OF_ROOT 9 | OF_ROOT=../../.. 10 | endif 11 | 12 | # call the project makefile! 13 | include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk 14 | -------------------------------------------------------------------------------- /example-shader/Project.xcconfig: -------------------------------------------------------------------------------- 1 | //THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT. 2 | //THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED 3 | OF_PATH = ../../.. 4 | 5 | //THIS HAS ALL THE HEADER AND LIBS FOR OF CORE 6 | #include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig" 7 | 8 | //ICONS - NEW IN 0072 9 | ICON_NAME_DEBUG = icon-debug.icns 10 | ICON_NAME_RELEASE = icon.icns 11 | ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/ 12 | 13 | //IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to: 14 | //ICON_FILE_PATH = bin/data/ 15 | 16 | OTHER_LDFLAGS = $(OF_CORE_LIBS) 17 | HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) 18 | -------------------------------------------------------------------------------- /example-shader/addons.make: -------------------------------------------------------------------------------- 1 | ofxGlmTools 2 | ofxJSON 3 | ofxVectorTile 4 | -------------------------------------------------------------------------------- /example-shader/bin/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/example-shader/bin/data/.gitkeep -------------------------------------------------------------------------------- /example-shader/bin/data/Champagne & Limousines.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/example-shader/bin/data/Champagne & Limousines.ttf -------------------------------------------------------------------------------- /example-shader/bin/data/shader.frag: -------------------------------------------------------------------------------- 1 | // Created by Patricio Gonzalez Vivo on 10/10/14. 2 | // 3 | // 4 | 5 | uniform sampler2DRect colorTex; // Color Buffer 6 | uniform sampler2DRect depthTex; // Depth Buffer 7 | 8 | float offset = 0.59; 9 | float flatPct = 0.87; 10 | float pct = 1.0; 11 | 12 | float focalDistance = 0.15; 13 | float focalRange = 0.14; 14 | 15 | float getIntensity(vec2 u){ 16 | vec3 a = texture2DRect(colorTex,u).xyz; 17 | return (a.x+a.y+a.z)/3.0; 18 | } 19 | 20 | float LinearizeDepth(float zoverw){ 21 | float n = 1.0; 22 | float f = 20000.0; 23 | return (2.0 * n) / (f + n - zoverw * (f - n)); 24 | } 25 | 26 | float FocalValue(vec2 pos){ 27 | float depth = LinearizeDepth( texture2DRect(depthTex, pos).r ) * 20000.; 28 | float value = abs(depth - (focalDistance*10000.) ) / (focalRange*20000.); 29 | return min( value , 1.0); 30 | } 31 | 32 | void main(){ 33 | vec2 uv = gl_TexCoord[0].st; 34 | vec2 p = vec2(offset); 35 | 36 | float rangeTexel = FocalValue(gl_TexCoord[0].st); 37 | 38 | float avg = 0.0; 39 | avg += FocalValue(uv+vec2(p.x,0.0)); 40 | avg += FocalValue(uv+vec2(-p.x,0.0)); 41 | avg += FocalValue(uv+vec2(0.0,p.y)); 42 | avg += FocalValue(uv+vec2(0.0,-p.y)); 43 | avg += FocalValue(uv+vec2(p.x,p.y)); 44 | avg += FocalValue(uv+vec2(-p.x,-p.y)); 45 | avg += FocalValue(uv+vec2(p.x,-p.y)); 46 | avg += FocalValue(uv+vec2(-p.x,p.y)); 47 | avg /= 8.0; 48 | 49 | float focalPoint = 1.0-FocalValue(uv); 50 | float result = (focalPoint) + avg; 51 | result = (1.0-result)*(1000.0*pct); 52 | 53 | gl_FragColor.rgb = vec3(1.-result)-vec3((getIntensity(uv))*flatPct); 54 | gl_FragColor.a = 1.0; 55 | } -------------------------------------------------------------------------------- /example-shader/config.make: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # CONFIGURE PROJECT MAKEFILE (optional) 3 | # This file is where we make project specific configurations. 4 | ################################################################################ 5 | 6 | ################################################################################ 7 | # OF ROOT 8 | # The location of your root openFrameworks installation 9 | # (default) OF_ROOT = ../../.. 10 | ################################################################################ 11 | # OF_ROOT = ../../.. 12 | 13 | ################################################################################ 14 | # PROJECT ROOT 15 | # The location of the project - a starting place for searching for files 16 | # (default) PROJECT_ROOT = . (this directory) 17 | # 18 | ################################################################################ 19 | # PROJECT_ROOT = . 20 | 21 | ################################################################################ 22 | # PROJECT SPECIFIC CHECKS 23 | # This is a project defined section to create internal makefile flags to 24 | # conditionally enable or disable the addition of various features within 25 | # this makefile. For instance, if you want to make changes based on whether 26 | # GTK is installed, one might test that here and create a variable to check. 27 | ################################################################################ 28 | # None 29 | 30 | ################################################################################ 31 | # PROJECT EXTERNAL SOURCE PATHS 32 | # These are fully qualified paths that are not within the PROJECT_ROOT folder. 33 | # Like source folders in the PROJECT_ROOT, these paths are subject to 34 | # exlclusion via the PROJECT_EXLCUSIONS list. 35 | # 36 | # (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) 37 | # 38 | # Note: Leave a leading space when adding list items with the += operator 39 | ################################################################################ 40 | # PROJECT_EXTERNAL_SOURCE_PATHS = 41 | 42 | ################################################################################ 43 | # PROJECT EXCLUSIONS 44 | # These makefiles assume that all folders in your current project directory 45 | # and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations 46 | # to look for source code. The any folders or files that match any of the 47 | # items in the PROJECT_EXCLUSIONS list below will be ignored. 48 | # 49 | # Each item in the PROJECT_EXCLUSIONS list will be treated as a complete 50 | # string unless teh user adds a wildcard (%) operator to match subdirectories. 51 | # GNU make only allows one wildcard for matching. The second wildcard (%) is 52 | # treated literally. 53 | # 54 | # (default) PROJECT_EXCLUSIONS = (blank) 55 | # 56 | # Will automatically exclude the following: 57 | # 58 | # $(PROJECT_ROOT)/bin% 59 | # $(PROJECT_ROOT)/obj% 60 | # $(PROJECT_ROOT)/%.xcodeproj 61 | # 62 | # Note: Leave a leading space when adding list items with the += operator 63 | ################################################################################ 64 | # PROJECT_EXCLUSIONS = 65 | 66 | ################################################################################ 67 | # PROJECT LINKER FLAGS 68 | # These flags will be sent to the linker when compiling the executable. 69 | # 70 | # (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs 71 | # 72 | # Note: Leave a leading space when adding list items with the += operator 73 | ################################################################################ 74 | 75 | # Currently, shared libraries that are needed are copied to the 76 | # $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to 77 | # add a runtime path to search for those shared libraries, since they aren't 78 | # incorporated directly into the final executable application binary. 79 | # TODO: should this be a default setting? 80 | # PROJECT_LDFLAGS=-Wl,-rpath=./libs 81 | 82 | ################################################################################ 83 | # PROJECT DEFINES 84 | # Create a space-delimited list of DEFINES. The list will be converted into 85 | # CFLAGS with the "-D" flag later in the makefile. 86 | # 87 | # (default) PROJECT_DEFINES = (blank) 88 | # 89 | # Note: Leave a leading space when adding list items with the += operator 90 | ################################################################################ 91 | # PROJECT_DEFINES = 92 | 93 | ################################################################################ 94 | # PROJECT CFLAGS 95 | # This is a list of fully qualified CFLAGS required when compiling for this 96 | # project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS 97 | # defined in your platform specific core configuration files. These flags are 98 | # presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. 99 | # 100 | # (default) PROJECT_CFLAGS = (blank) 101 | # 102 | # Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in 103 | # your platform specific configuration file will be applied by default and 104 | # further flags here may not be needed. 105 | # 106 | # Note: Leave a leading space when adding list items with the += operator 107 | ################################################################################ 108 | # PROJECT_CFLAGS = 109 | 110 | ################################################################################ 111 | # PROJECT OPTIMIZATION CFLAGS 112 | # These are lists of CFLAGS that are target-specific. While any flags could 113 | # be conditionally added, they are usually limited to optimization flags. 114 | # These flags are added BEFORE the PROJECT_CFLAGS. 115 | # 116 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. 117 | # 118 | # (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) 119 | # 120 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. 121 | # 122 | # (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) 123 | # 124 | # Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the 125 | # PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration 126 | # file will be applied by default and further optimization flags here may not 127 | # be needed. 128 | # 129 | # Note: Leave a leading space when adding list items with the += operator 130 | ################################################################################ 131 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE = 132 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG = 133 | 134 | ################################################################################ 135 | # PROJECT COMPILERS 136 | # Custom compilers can be set for CC and CXX 137 | # (default) PROJECT_CXX = (blank) 138 | # (default) PROJECT_CC = (blank) 139 | # Note: Leave a leading space when adding list items with the += operator 140 | ################################################################################ 141 | # PROJECT_CXX = 142 | # PROJECT_CC = 143 | -------------------------------------------------------------------------------- /example-shader/example.xcodeproj/xcshareddata/xcschemes/example-labels Debug.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /example-shader/example.xcodeproj/xcshareddata/xcschemes/example-labels Release.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /example-shader/openFrameworks-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | cc.openFrameworks.ofapp 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | APPL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | 1.0 19 | CFBundleIconFile 20 | ${ICON} 21 | 22 | 23 | -------------------------------------------------------------------------------- /example-shader/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofMain.h" 2 | #include "ofApp.h" 3 | 4 | //======================================================================== 5 | int main( ){ 6 | ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context 7 | 8 | // this kicks off the running of my app 9 | // can be OF_WINDOW or OF_FULLSCREEN 10 | // pass in width and height too: 11 | ofRunApp(new ofApp()); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example-shader/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorTile 3 | // 4 | // Created by Patricio Gonzalez Vivo on 10/10/14. 5 | // 6 | // 7 | 8 | #include "ofApp.h" 9 | 10 | //-------------------------------------------------------------- 11 | void ofApp::setup(){ 12 | ofSetVerticalSync(true); 13 | ofEnableAlphaBlending(); 14 | 15 | light.setDiffuseColor(ofFloatColor(0.9)); 16 | light.setPosition(ofPoint(0,0,1000)); 17 | 18 | // Load Label Fonts 19 | // 20 | labels.loadFont("Champagne & Limousines.ttf", 10); 21 | labels.setFontColor(ofColor::black, ofColor::white); 22 | 23 | // Link the label manager with the builder 24 | // 25 | builder.setLabelManager(&labels); 26 | 27 | // Request a new tile to the builder 28 | // 29 | tile = builder.getFromWeb(19299,24631,16); 30 | 31 | // Make a VBO from the tile (FASTER) 32 | // 33 | tileMesh = tile.getMesh(); 34 | 35 | ofFbo::Settings settings; 36 | settings.width = ofGetWidth(); 37 | settings.height = ofGetHeight(); 38 | settings.internalformat = GL_RGB; 39 | settings.numSamples = 0; 40 | settings.useDepth = true; 41 | settings.useStencil = true; 42 | settings.depthStencilAsTexture = true; 43 | #ifdef TARGET_OPENGLES 44 | settings.textureTarget = GL_TEXTURE_2D; 45 | #else 46 | settings.textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; 47 | #endif 48 | fbo.allocate(settings); 49 | shader.load("", "shader.frag"); 50 | 51 | bShader = true; 52 | } 53 | 54 | //-------------------------------------------------------------- 55 | void ofApp::update(){ 56 | labels.updateCameraPosition(cam.getPosition()); 57 | 58 | // Update the scene 59 | // 60 | fbo.begin(); 61 | ofClear(0,0,0,0); 62 | cam.begin(); 63 | ofEnableDepthTest(); 64 | 65 | ofEnableLighting(); 66 | light.enable(); 67 | 68 | // tile.draw(); 69 | tileMesh.draw(); 70 | 71 | light.disable(); 72 | ofDisableLighting(); 73 | 74 | labels.draw3D(); 75 | labels.updateProjection(); 76 | 77 | ofDisableDepthTest(); 78 | cam.end(); 79 | fbo.end(); 80 | } 81 | 82 | //-------------------------------------------------------------- 83 | void ofApp::draw(){ 84 | ofBackground(ofColor::black); 85 | 86 | ofSetColor(255); 87 | 88 | if(bShader){ 89 | shader.begin(); 90 | shader.setUniformTexture("colorTex", fbo, 0); 91 | shader.setUniformTexture("depthTex", fbo.getDepthTexture(), 1); 92 | fbo.draw(0,0); 93 | shader.end(); 94 | } else { 95 | fbo.draw(0,0); 96 | } 97 | 98 | 99 | labels.draw2D(); 100 | 101 | if(bShader){ 102 | ofSetColor(0); 103 | } else { 104 | ofSetColor(255); 105 | } 106 | 107 | ofDrawBitmapString(" 'p' : toogle point labels debug", 10,15); 108 | ofDrawBitmapString(" 'l' : toogle line labels debug", 10,35); 109 | ofDrawBitmapString(" 's' : toogle shader", 10,55); 110 | } 111 | 112 | //-------------------------------------------------------------- 113 | void ofApp::keyPressed(int key){ 114 | 115 | if(key == 'f'){ 116 | ofToggleFullscreen(); 117 | } else if (key == 'p'){ 118 | labels.bDebugPoints = !labels.bDebugPoints; 119 | } else if (key == 'l'){ 120 | labels.bDebugLines = !labels.bDebugLines; 121 | } else if (key == 's'){ 122 | bShader = !bShader; 123 | 124 | if(bShader){ 125 | labels.setFontColor(ofColor::black, ofColor::white); 126 | } else { 127 | labels.setFontColor(ofColor::white, ofColor::black); 128 | } 129 | } 130 | 131 | } 132 | 133 | //-------------------------------------------------------------- 134 | void ofApp::keyReleased(int key){ 135 | 136 | } 137 | 138 | //-------------------------------------------------------------- 139 | void ofApp::mouseMoved(int x, int y ){ 140 | 141 | } 142 | 143 | //-------------------------------------------------------------- 144 | void ofApp::mouseDragged(int x, int y, int button){ 145 | 146 | } 147 | 148 | //-------------------------------------------------------------- 149 | void ofApp::mousePressed(int x, int y, int button){ 150 | 151 | } 152 | 153 | //-------------------------------------------------------------- 154 | void ofApp::mouseReleased(int x, int y, int button){ 155 | 156 | } 157 | 158 | //-------------------------------------------------------------- 159 | void ofApp::windowResized(int w, int h){ 160 | fbo.allocate(w,h); 161 | } 162 | 163 | //-------------------------------------------------------------- 164 | void ofApp::gotMessage(ofMessage msg){ 165 | 166 | } 167 | 168 | //-------------------------------------------------------------- 169 | void ofApp::dragEvent(ofDragInfo dragInfo){ 170 | 171 | } 172 | -------------------------------------------------------------------------------- /example-shader/src/ofApp.h: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorTile 3 | // 4 | // Created by Patricio Gonzalez Vivo on 10/10/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include "ofMain.h" 11 | #include "ofxVectorTile.h" 12 | #include "ofxVectorLabels.h" 13 | #include "ofxVectorBuilder.h" 14 | 15 | class ofApp : public ofBaseApp{ 16 | public: 17 | void setup(); 18 | void update(); 19 | void draw(); 20 | 21 | void keyPressed(int key); 22 | void keyReleased(int key); 23 | void mouseMoved(int x, int y ); 24 | void mouseDragged(int x, int y, int button); 25 | void mousePressed(int x, int y, int button); 26 | void mouseReleased(int x, int y, int button); 27 | void windowResized(int w, int h); 28 | void dragEvent(ofDragInfo dragInfo); 29 | void gotMessage(ofMessage msg); 30 | 31 | ofEasyCam cam; 32 | ofLight light; 33 | ofFbo fbo; 34 | ofShader shader; 35 | 36 | ofxVectorTile tile; 37 | ofxVectorBuilder builder; 38 | ofxVectorLabels labels; 39 | ofVboMesh tileMesh; 40 | 41 | bool bShader; 42 | }; 43 | -------------------------------------------------------------------------------- /example-simple/Makefile: -------------------------------------------------------------------------------- 1 | # Attempt to load a config.make file. 2 | # If none is found, project defaults in config.project.make will be used. 3 | ifneq ($(wildcard config.make),) 4 | include config.make 5 | endif 6 | 7 | # make sure the the OF_ROOT location is defined 8 | ifndef OF_ROOT 9 | OF_ROOT=../../.. 10 | endif 11 | 12 | # call the project makefile! 13 | include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk 14 | -------------------------------------------------------------------------------- /example-simple/Project.xcconfig: -------------------------------------------------------------------------------- 1 | //THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT. 2 | //THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED 3 | OF_PATH = ../../.. 4 | 5 | //THIS HAS ALL THE HEADER AND LIBS FOR OF CORE 6 | #include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig" 7 | 8 | //ICONS - NEW IN 0072 9 | ICON_NAME_DEBUG = icon-debug.icns 10 | ICON_NAME_RELEASE = icon.icns 11 | ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/ 12 | 13 | //IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to: 14 | //ICON_FILE_PATH = bin/data/ 15 | 16 | OTHER_LDFLAGS = $(OF_CORE_LIBS) 17 | HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) 18 | -------------------------------------------------------------------------------- /example-simple/addons.make: -------------------------------------------------------------------------------- 1 | ofxGlmTools 2 | ofxJSON 3 | ofxVectorTile 4 | -------------------------------------------------------------------------------- /example-simple/bin/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/example-simple/bin/data/.gitkeep -------------------------------------------------------------------------------- /example-simple/config.make: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # CONFIGURE PROJECT MAKEFILE (optional) 3 | # This file is where we make project specific configurations. 4 | ################################################################################ 5 | 6 | ################################################################################ 7 | # OF ROOT 8 | # The location of your root openFrameworks installation 9 | # (default) OF_ROOT = ../../.. 10 | ################################################################################ 11 | # OF_ROOT = ../../.. 12 | 13 | ################################################################################ 14 | # PROJECT ROOT 15 | # The location of the project - a starting place for searching for files 16 | # (default) PROJECT_ROOT = . (this directory) 17 | # 18 | ################################################################################ 19 | # PROJECT_ROOT = . 20 | 21 | ################################################################################ 22 | # PROJECT SPECIFIC CHECKS 23 | # This is a project defined section to create internal makefile flags to 24 | # conditionally enable or disable the addition of various features within 25 | # this makefile. For instance, if you want to make changes based on whether 26 | # GTK is installed, one might test that here and create a variable to check. 27 | ################################################################################ 28 | # None 29 | 30 | ################################################################################ 31 | # PROJECT EXTERNAL SOURCE PATHS 32 | # These are fully qualified paths that are not within the PROJECT_ROOT folder. 33 | # Like source folders in the PROJECT_ROOT, these paths are subject to 34 | # exlclusion via the PROJECT_EXLCUSIONS list. 35 | # 36 | # (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) 37 | # 38 | # Note: Leave a leading space when adding list items with the += operator 39 | ################################################################################ 40 | # PROJECT_EXTERNAL_SOURCE_PATHS = 41 | 42 | ################################################################################ 43 | # PROJECT EXCLUSIONS 44 | # These makefiles assume that all folders in your current project directory 45 | # and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations 46 | # to look for source code. The any folders or files that match any of the 47 | # items in the PROJECT_EXCLUSIONS list below will be ignored. 48 | # 49 | # Each item in the PROJECT_EXCLUSIONS list will be treated as a complete 50 | # string unless teh user adds a wildcard (%) operator to match subdirectories. 51 | # GNU make only allows one wildcard for matching. The second wildcard (%) is 52 | # treated literally. 53 | # 54 | # (default) PROJECT_EXCLUSIONS = (blank) 55 | # 56 | # Will automatically exclude the following: 57 | # 58 | # $(PROJECT_ROOT)/bin% 59 | # $(PROJECT_ROOT)/obj% 60 | # $(PROJECT_ROOT)/%.xcodeproj 61 | # 62 | # Note: Leave a leading space when adding list items with the += operator 63 | ################################################################################ 64 | # PROJECT_EXCLUSIONS = 65 | 66 | ################################################################################ 67 | # PROJECT LINKER FLAGS 68 | # These flags will be sent to the linker when compiling the executable. 69 | # 70 | # (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs 71 | # 72 | # Note: Leave a leading space when adding list items with the += operator 73 | ################################################################################ 74 | 75 | # Currently, shared libraries that are needed are copied to the 76 | # $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to 77 | # add a runtime path to search for those shared libraries, since they aren't 78 | # incorporated directly into the final executable application binary. 79 | # TODO: should this be a default setting? 80 | # PROJECT_LDFLAGS=-Wl,-rpath=./libs 81 | 82 | ################################################################################ 83 | # PROJECT DEFINES 84 | # Create a space-delimited list of DEFINES. The list will be converted into 85 | # CFLAGS with the "-D" flag later in the makefile. 86 | # 87 | # (default) PROJECT_DEFINES = (blank) 88 | # 89 | # Note: Leave a leading space when adding list items with the += operator 90 | ################################################################################ 91 | # PROJECT_DEFINES = 92 | 93 | ################################################################################ 94 | # PROJECT CFLAGS 95 | # This is a list of fully qualified CFLAGS required when compiling for this 96 | # project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS 97 | # defined in your platform specific core configuration files. These flags are 98 | # presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. 99 | # 100 | # (default) PROJECT_CFLAGS = (blank) 101 | # 102 | # Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in 103 | # your platform specific configuration file will be applied by default and 104 | # further flags here may not be needed. 105 | # 106 | # Note: Leave a leading space when adding list items with the += operator 107 | ################################################################################ 108 | # PROJECT_CFLAGS = 109 | 110 | ################################################################################ 111 | # PROJECT OPTIMIZATION CFLAGS 112 | # These are lists of CFLAGS that are target-specific. While any flags could 113 | # be conditionally added, they are usually limited to optimization flags. 114 | # These flags are added BEFORE the PROJECT_CFLAGS. 115 | # 116 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. 117 | # 118 | # (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) 119 | # 120 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. 121 | # 122 | # (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) 123 | # 124 | # Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the 125 | # PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration 126 | # file will be applied by default and further optimization flags here may not 127 | # be needed. 128 | # 129 | # Note: Leave a leading space when adding list items with the += operator 130 | ################################################################################ 131 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE = 132 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG = 133 | 134 | ################################################################################ 135 | # PROJECT COMPILERS 136 | # Custom compilers can be set for CC and CXX 137 | # (default) PROJECT_CXX = (blank) 138 | # (default) PROJECT_CC = (blank) 139 | # Note: Leave a leading space when adding list items with the += operator 140 | ################################################################################ 141 | # PROJECT_CXX = 142 | # PROJECT_CC = 143 | -------------------------------------------------------------------------------- /example-simple/example.xcodeproj/xcshareddata/xcschemes/example-labels Debug.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /example-simple/example.xcodeproj/xcshareddata/xcschemes/example-labels Release.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /example-simple/openFrameworks-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | cc.openFrameworks.ofapp 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | APPL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | 1.0 19 | CFBundleIconFile 20 | ${ICON} 21 | 22 | 23 | -------------------------------------------------------------------------------- /example-simple/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofMain.h" 2 | #include "ofApp.h" 3 | 4 | //======================================================================== 5 | int main( ){ 6 | ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context 7 | 8 | // this kicks off the running of my app 9 | // can be OF_WINDOW or OF_FULLSCREEN 10 | // pass in width and height too: 11 | ofRunApp(new ofApp()); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example-simple/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | //-------------------------------------------------------------- 4 | void ofApp::setup(){ 5 | ofSetVerticalSync(true); 6 | ofEnableDepthTest(); 7 | 8 | light.setDiffuseColor(ofFloatColor(0.9)); 9 | light.setPosition(ofPoint(0,0,100)); 10 | 11 | ofxVectorBuilder builder; 12 | tile = builder.getMesh(19299,24631,16); 13 | } 14 | 15 | //-------------------------------------------------------------- 16 | void ofApp::update(){ 17 | 18 | } 19 | 20 | //-------------------------------------------------------------- 21 | void ofApp::draw(){ 22 | ofBackground(0); 23 | 24 | cam.begin(); 25 | light.enable(); 26 | ofEnableLighting(); 27 | 28 | tile.draw(); 29 | 30 | ofDisableLighting(); 31 | light.disable(); 32 | cam.end(); 33 | 34 | } 35 | 36 | //-------------------------------------------------------------- 37 | void ofApp::keyPressed(int key){ 38 | 39 | } 40 | 41 | //-------------------------------------------------------------- 42 | void ofApp::keyReleased(int key){ 43 | 44 | } 45 | 46 | //-------------------------------------------------------------- 47 | void ofApp::mouseMoved(int x, int y ){ 48 | 49 | } 50 | 51 | //-------------------------------------------------------------- 52 | void ofApp::mouseDragged(int x, int y, int button){ 53 | 54 | } 55 | 56 | //-------------------------------------------------------------- 57 | void ofApp::mousePressed(int x, int y, int button){ 58 | 59 | } 60 | 61 | //-------------------------------------------------------------- 62 | void ofApp::mouseReleased(int x, int y, int button){ 63 | 64 | } 65 | 66 | //-------------------------------------------------------------- 67 | void ofApp::windowResized(int w, int h){ 68 | 69 | } 70 | 71 | //-------------------------------------------------------------- 72 | void ofApp::gotMessage(ofMessage msg){ 73 | 74 | } 75 | 76 | //-------------------------------------------------------------- 77 | void ofApp::dragEvent(ofDragInfo dragInfo){ 78 | 79 | } 80 | -------------------------------------------------------------------------------- /example-simple/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | 5 | #include "ofxVectorBuilder.h" 6 | 7 | class ofApp : public ofBaseApp{ 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | void keyPressed(int key); 14 | void keyReleased(int key); 15 | void mouseMoved(int x, int y ); 16 | void mouseDragged(int x, int y, int button); 17 | void mousePressed(int x, int y, int button); 18 | void mouseReleased(int x, int y, int button); 19 | void windowResized(int w, int h); 20 | void dragEvent(ofDragInfo dragInfo); 21 | void gotMessage(ofMessage msg); 22 | 23 | ofEasyCam cam; 24 | ofLight light; 25 | 26 | ofVboMesh tile; 27 | }; 28 | -------------------------------------------------------------------------------- /images/01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/01.gif -------------------------------------------------------------------------------- /images/02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/02.gif -------------------------------------------------------------------------------- /images/03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/03.gif -------------------------------------------------------------------------------- /images/04.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/04.gif -------------------------------------------------------------------------------- /images/05.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/05.gif -------------------------------------------------------------------------------- /images/06.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/06.gif -------------------------------------------------------------------------------- /images/07.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/07.gif -------------------------------------------------------------------------------- /images/hud.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/hud.jpg -------------------------------------------------------------------------------- /images/projection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/images/projection.png -------------------------------------------------------------------------------- /libs/glmFontstash/fontstash/glfontstash.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org 3 | // 4 | // This software is provided 'as-is', without any express or implied 5 | // warranty. In no event will the authors be held liable for any damages 6 | // arising from the use of this software. 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 1. The origin of this software must not be misrepresented; you must not 11 | // claim that you wrote the original software. If you use this software 12 | // in a product, an acknowledgment in the product documentation would be 13 | // appreciated but is not required. 14 | // 2. Altered source versions must be plainly marked as such, and must not be 15 | // misrepresented as being the original software. 16 | // 3. This notice may not be removed or altered from any source distribution. 17 | // 18 | #ifndef GLFONTSTASH_H 19 | #define GLFONTSTASH_H 20 | 21 | #include "glmGL.h" 22 | #include "type_ptr.hpp" 23 | #include "matrix_transform.hpp" 24 | 25 | #include 26 | #include "fontstash.h" 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | typedef unsigned int fsuint; 34 | 35 | #define BUFFER_SIZE 2 36 | #define N_GLYPH_VERTS 6 37 | 38 | struct GLFONSvbo { 39 | int nverts; 40 | GLuint buffers[BUFFER_SIZE]; 41 | }; 42 | 43 | typedef struct GLFONSvbo GLFONSvbo; 44 | 45 | struct GLStash { 46 | GLFONSvbo* vbo; 47 | FONSeffectType effect; 48 | glm::vec4 bbox; 49 | float* glyphsXOffset; 50 | float length; 51 | int nbGlyph; 52 | }; 53 | 54 | typedef struct GLStash GLStash; 55 | 56 | struct GLFONScontext { 57 | GLuint tex; 58 | int width, height; 59 | // the id counter 60 | fsuint idct; 61 | 62 | GLuint sdfShaderProgram; 63 | GLuint defaultShaderProgram; 64 | 65 | GLuint posAttrib; 66 | GLuint texCoordAttrib; 67 | GLuint colorAttrib; 68 | 69 | std::map* stashes; 70 | 71 | std::stack matrixStack; 72 | glm::mat4 projectionMatrix; 73 | 74 | glm::vec4 color; 75 | glm::vec4 outlineColor; 76 | 77 | glm::vec4 sdfProperties; 78 | float sdfMixFactor; 79 | 80 | glm::mat4 transform; 81 | }; 82 | 83 | typedef struct GLFONScontext GLFONScontext; 84 | 85 | #define STRINGIFY(A) #A 86 | 87 | static const GLchar* vertexShaderSrc = STRINGIFY( 88 | #ifdef GL_ES 89 | precision mediump float; 90 | #endif 91 | attribute vec4 a_position; 92 | attribute vec2 a_texCoord; 93 | 94 | uniform mat4 u_mvp; 95 | varying vec2 v_uv; 96 | 97 | void main() { 98 | gl_Position = u_mvp * a_position; 99 | v_uv = a_texCoord; 100 | } 101 | ); 102 | 103 | static const GLchar* sdfFragShaderSrc = STRINGIFY( 104 | #ifdef GL_ES 105 | precision mediump float; 106 | #endif 107 | uniform sampler2D u_tex; 108 | uniform vec4 u_color; 109 | uniform vec4 u_outlineColor; 110 | uniform float u_mixFactor; 111 | uniform float u_minOutlineD; 112 | uniform float u_maxOutlineD; 113 | uniform float u_minInsideD; 114 | uniform float u_maxInsideD; 115 | 116 | varying vec2 v_uv; 117 | 118 | const float gamma = 2.2; 119 | 120 | void main(void) { 121 | float distance = texture2D(u_tex, v_uv).a; 122 | 123 | float a1 = smoothstep(u_minInsideD, u_maxInsideD, distance); 124 | float a2 = smoothstep(u_minOutlineD, u_maxOutlineD, distance); 125 | 126 | a1 = pow(a1, 1.0 / gamma); 127 | a2 = pow(a2, 1.0 / gamma); 128 | 129 | gl_FragColor = mix(u_outlineColor * a2, u_color * a1, u_mixFactor); 130 | } 131 | ); 132 | 133 | static const GLchar* defaultFragShaderSrc = STRINGIFY( 134 | #ifdef GL_ES 135 | precision mediump float; 136 | #endif 137 | uniform sampler2D u_tex; 138 | uniform vec4 u_color; 139 | 140 | varying vec2 v_uv; 141 | void main(void) { 142 | vec4 texColor = texture2D(u_tex, v_uv); 143 | vec3 invColor = 1.0 - texColor.rgb; 144 | gl_FragColor = vec4(invColor * u_color.rgb, u_color.a * texColor.a); 145 | } 146 | ); 147 | 148 | FONScontext* glfonsCreate(int width, int height, int flags); 149 | void glfonsDelete(FONScontext* ctx); 150 | 151 | void glfonsBufferText(FONScontext* ctx, const char* s, fsuint* id, FONSeffectType effect); 152 | void glfonsUnbufferText(FONScontext* ctx, fsuint id); 153 | 154 | void glfonsRotate(FONScontext* ctx, float angle); 155 | void glfonsTranslate(FONScontext* ctx, float x, float y); 156 | void glfonsScale(FONScontext* ctx, float x, float y); 157 | 158 | void glfonsDrawText(FONScontext* ctx, fsuint id); 159 | void glfonsDrawText(FONScontext* ctx, fsuint id, unsigned int from, unsigned int to); 160 | void glfonsSetColor(FONScontext* ctx, float r, float g, float b, float a); 161 | void glfonsSetOutlineColor(FONScontext* ctx, float r, float g, float b, float a); 162 | void glfonsSetSDFProperties(FONScontext* ctx, float minOutlineD, float maxOutlineD, float minInsideD, float maxInsideD, float mixFactor); 163 | 164 | void glfonsUpdateViewport(FONScontext* ctx); 165 | 166 | void glfonsPushMatrix(FONScontext* ctx); 167 | void glfonsPopMatrix(FONScontext* ctx); 168 | 169 | void glfonsGetBBox(FONScontext* ctx, fsuint id, float* x0, float* y0, float* x1, float* y1); 170 | float glfonsGetGlyphOffset(FONScontext* ctx, fsuint id, int i); 171 | float glfonsGetLength(FONScontext* ctx, fsuint id); 172 | 173 | unsigned int glfonsRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a); 174 | 175 | #endif 176 | 177 | #ifdef GLFONTSTASH_IMPLEMENTATION 178 | 179 | #define FONTSTASH_IMPLEMENTATION 180 | #include "fontstash.h" 181 | 182 | static void printShaderInfoLog(GLuint shader) { 183 | GLint length = 0; 184 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); 185 | if(length > 1) { 186 | char* log = (char*)malloc(sizeof(char) * length); 187 | glGetShaderInfoLog(shader, length, NULL, log); 188 | printf("Log: %s\n", log); 189 | free(log); 190 | } 191 | } 192 | 193 | static GLuint compileShader(const GLchar* src, GLenum type) { 194 | GLuint shader = glCreateShader(type); 195 | glShaderSource(shader, 1, &src, NULL); 196 | glCompileShader(shader); 197 | GLint status; 198 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 199 | 200 | if(!status) { 201 | printShaderInfoLog(shader); 202 | glDeleteShader(shader); 203 | exit(-1); 204 | } 205 | return shader; 206 | } 207 | 208 | static GLuint linkShaderProgram(const GLchar* vertexSrc, const GLchar* fragmentSrc) { 209 | GLuint program = glCreateProgram(); 210 | GLuint vertex = compileShader(vertexSrc, GL_VERTEX_SHADER); 211 | GLuint fragment = compileShader(fragmentSrc, GL_FRAGMENT_SHADER); 212 | glAttachShader(program, vertex); 213 | glAttachShader(program, fragment); 214 | glLinkProgram(program); 215 | GLint linkStatus; 216 | glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 217 | 218 | if(!linkStatus) { 219 | printShaderInfoLog(program); 220 | glDeleteProgram(program); 221 | exit(-1); 222 | } 223 | return program; 224 | } 225 | 226 | static int glfons__renderCreate(void* userPtr, int width, int height) { 227 | GLFONScontext* gl = (GLFONScontext*)userPtr; 228 | // Create may be called multiple times, delete existing texture. 229 | if (gl->tex != 0) { 230 | glDeleteTextures(1, &gl->tex); 231 | gl->tex = 0; 232 | } 233 | gl->idct = 0; 234 | gl->stashes = new std::map(); 235 | 236 | // create texture 237 | glGenTextures(1, &gl->tex); 238 | if (!gl->tex) return 0; 239 | gl->width = width; 240 | gl->height = height; 241 | 242 | glBindTexture(GL_TEXTURE_2D, gl->tex); 243 | glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gl->width, gl->height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); 244 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 245 | 246 | GLint viewport[4]; 247 | glGetIntegerv(GL_VIEWPORT, viewport); 248 | gl->projectionMatrix = glm::ortho(0.0, (double)viewport[2], (double)viewport[3], 0.0, -1.0, 1.0); 249 | 250 | // create shader 251 | gl->defaultShaderProgram = linkShaderProgram(vertexShaderSrc, defaultFragShaderSrc); 252 | gl->sdfShaderProgram = linkShaderProgram(vertexShaderSrc, sdfFragShaderSrc); 253 | 254 | gl->posAttrib = glGetAttribLocation(gl->defaultShaderProgram, "a_position"); 255 | gl->texCoordAttrib = glGetAttribLocation(gl->defaultShaderProgram, "a_texCoord"); 256 | gl->colorAttrib = glGetAttribLocation(gl->defaultShaderProgram, "a_color"); 257 | 258 | gl->posAttrib = glGetAttribLocation(gl->sdfShaderProgram, "a_position"); 259 | gl->texCoordAttrib = glGetAttribLocation(gl->sdfShaderProgram, "a_texCoord"); 260 | gl->colorAttrib = glGetAttribLocation(gl->sdfShaderProgram, "a_color"); 261 | 262 | gl->matrixStack.push(glm::mat4(1.0)); 263 | gl->color = glm::vec4(1.0); 264 | gl->transform = glm::mat4(1.0); 265 | 266 | return 1; 267 | } 268 | 269 | static int glfons__renderResize(void* userPtr, int width, int height) { 270 | // Reuse create to resize too. 271 | return glfons__renderCreate(userPtr, width, height); 272 | } 273 | 274 | static void glfons__renderUpdate(void* userPtr, int* rect, const unsigned char* data) { 275 | GLFONScontext* gl = (GLFONScontext*)userPtr; 276 | if (gl->tex == 0) return; 277 | 278 | int w = rect[2] - rect[0]; 279 | int h = rect[3] - rect[1]; 280 | 281 | glBindTexture(GL_TEXTURE_2D, gl->tex); 282 | const unsigned char* subdata = data + rect[1] * gl->width; 283 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect[1], gl->width, h, GL_ALPHA, GL_UNSIGNED_BYTE, subdata); 284 | 285 | glBindTexture(GL_TEXTURE_2D, 0); 286 | } 287 | 288 | static void glfons__renderDraw(void* userPtr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) { 289 | // called by fontstash, but has nothing to do 290 | } 291 | 292 | static void glfons__renderDelete(void* userPtr) { 293 | GLFONScontext* gl = (GLFONScontext*)userPtr; 294 | 295 | if (gl->tex != 0) { 296 | glDeleteTextures(1, &gl->tex); 297 | } 298 | 299 | for(auto& elmt : *gl->stashes) { 300 | GLStash* stash = elmt.second; 301 | if(stash != NULL) { 302 | glDeleteBuffers(BUFFER_SIZE, stash->vbo->buffers); 303 | delete stash->vbo; 304 | delete[] stash->glyphsXOffset; 305 | delete stash; 306 | } 307 | } 308 | 309 | glDeleteProgram(gl->defaultShaderProgram); 310 | glDeleteProgram(gl->sdfShaderProgram); 311 | 312 | delete gl->stashes; 313 | delete gl; 314 | } 315 | 316 | void glfonsUpdateViewport(FONScontext* ctx) { 317 | GLFONScontext* gl = (GLFONScontext*) ctx->params.userPtr; 318 | GLint viewport[4]; 319 | glGetIntegerv(GL_VIEWPORT, viewport); 320 | gl->projectionMatrix = glm::ortho(0.0, (double)viewport[2], (double)viewport[3], 0.0, -1.0, 1.0); 321 | } 322 | 323 | FONScontext* glfonsCreate(int width, int height, int flags) { 324 | FONSparams params; 325 | GLFONScontext* gl = new GLFONScontext; 326 | 327 | params.width = width; 328 | params.height = height; 329 | params.flags = (unsigned char)flags; 330 | params.renderCreate = glfons__renderCreate; 331 | params.renderResize = glfons__renderResize; 332 | params.renderUpdate = glfons__renderUpdate; 333 | params.renderDraw = glfons__renderDraw; 334 | params.renderDelete = glfons__renderDelete; 335 | params.userPtr = gl; 336 | 337 | return fonsCreateInternal(¶ms); 338 | } 339 | 340 | void glfonsDelete(FONScontext* ctx) { 341 | fonsDeleteInternal(ctx); 342 | } 343 | 344 | unsigned int glfonsRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { 345 | return (r) | (g << 8) | (b << 16) | (a << 24); 346 | } 347 | 348 | void glfonsBufferText(FONScontext* ctx, const char* s, fsuint* id, FONSeffectType effect) { 349 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 350 | GLStash* stash = new GLStash; 351 | 352 | stash->vbo = new GLFONSvbo; 353 | 354 | *id = ++glctx->idct; 355 | 356 | fonsDrawText(ctx, 0, 0, s, NULL, 0); 357 | 358 | stash->effect = effect; 359 | stash->glyphsXOffset = new float[ctx->nverts / N_GLYPH_VERTS]; 360 | 361 | int j = 0; 362 | for(int i = 0; i < ctx->nverts * 2; i += N_GLYPH_VERTS * 2) { 363 | stash->glyphsXOffset[j++] = ctx->verts[i]; 364 | } 365 | 366 | float inf = std::numeric_limits::infinity(); 367 | float x0 = inf, x1 = -inf, y0 = inf, y1 = -inf; 368 | for(int i = 0; i < ctx->nverts * 2; i += 2) { 369 | x0 = ctx->verts[i] < x0 ? ctx->verts[i] : x0; 370 | x1 = ctx->verts[i] > x1 ? ctx->verts[i] : x1; 371 | y0 = ctx->verts[i+1] < y0 ? ctx->verts[i+1] : y0; 372 | y1 = ctx->verts[i+1] > y1 ? ctx->verts[i+1] : y1; 373 | } 374 | 375 | stash->bbox[0] = x0; stash->bbox[1] = y0; 376 | stash->bbox[2] = x1; stash->bbox[3] = y1; 377 | 378 | stash->length = ctx->verts[(ctx->nverts*2)-2]; 379 | 380 | glGenBuffers(BUFFER_SIZE, stash->vbo->buffers); 381 | 382 | glBindBuffer(GL_ARRAY_BUFFER, stash->vbo->buffers[0]); 383 | glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(float) * ctx->nverts, ctx->verts, GL_STATIC_DRAW); 384 | 385 | glBindBuffer(GL_ARRAY_BUFFER, stash->vbo->buffers[1]); 386 | glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(float) * ctx->nverts, ctx->tcoords, GL_STATIC_DRAW); 387 | 388 | glBindBuffer(GL_ARRAY_BUFFER, 0); 389 | 390 | stash->vbo->nverts = ctx->nverts; 391 | 392 | // hack : reset fontstash state 393 | ctx->nverts = 0; 394 | 395 | glctx->stashes->insert(std::pair(*id, stash)); 396 | } 397 | 398 | void glfonsUnbufferText(FONScontext* ctx, fsuint id) { 399 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 400 | 401 | if(glctx->stashes->find(id) != glctx->stashes->end()) { 402 | GLStash* stash = glctx->stashes->at(id); 403 | 404 | glDeleteBuffers(BUFFER_SIZE, stash->vbo->buffers); 405 | // WIP : maybe release cpu mem 406 | } 407 | } 408 | 409 | void glfonsRotate(FONScontext* ctx, float angle) { 410 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 411 | glm::vec3 raxis = glm::vec3(0.0, 0.0, -1.0); 412 | glctx->transform = glm::rotate(glctx->transform, angle, raxis); 413 | } 414 | 415 | void glfonsTranslate(FONScontext* ctx, float x, float y) { 416 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 417 | glctx->transform = glm::translate(glctx->transform, glm::vec3(x, y, 0.0)); 418 | } 419 | 420 | void glfonsScale(FONScontext* ctx, float x, float y) { 421 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 422 | glctx->transform = glm::scale(glctx->transform, glm::vec3(x, y, 1.0)); 423 | } 424 | 425 | void glfonsDrawText(FONScontext* ctx, fsuint id, unsigned int from, unsigned int to) { 426 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 427 | 428 | if(glctx->tex == 0) 429 | return; 430 | 431 | int d = (to - from) + 1; 432 | int iFirst = from * N_GLYPH_VERTS; 433 | int count = d * N_GLYPH_VERTS; 434 | 435 | GLStash* stash = glctx->stashes->at(id); 436 | 437 | glm::mat4 mvp = glctx->projectionMatrix * glctx->transform; 438 | 439 | glActiveTexture(GL_TEXTURE0); 440 | glBindTexture(GL_TEXTURE_2D, glctx->tex); 441 | glEnable(GL_TEXTURE_2D); 442 | 443 | GLuint program; 444 | switch (stash->effect) { 445 | case FONS_EFFECT_DISTANCE_FIELD: 446 | program = glctx->sdfShaderProgram; 447 | break; 448 | default: 449 | program = glctx->defaultShaderProgram; 450 | } 451 | 452 | glUseProgram(program); 453 | glUniform1i(glGetUniformLocation(program, "u_tex"), 0); 454 | glUniformMatrix4fv(glGetUniformLocation(program, "u_mvp"), 1, GL_FALSE, glm::value_ptr(mvp)); 455 | glUniform4f(glGetUniformLocation(program, "u_color"), glctx->color.r, glctx->color.g, glctx->color.b, glctx->color.a); 456 | 457 | if(stash->effect == FONS_EFFECT_DISTANCE_FIELD) { 458 | glUniform4f(glGetUniformLocation(program, "u_outlineColor"), glctx->outlineColor.r, glctx->outlineColor.g, glctx->outlineColor.b, glctx->outlineColor.a); 459 | glUniform1f(glGetUniformLocation(program, "u_mixFactor"), glctx->sdfMixFactor); 460 | glUniform1f(glGetUniformLocation(program, "u_minOutlineD"), glctx->sdfProperties[0]); 461 | glUniform1f(glGetUniformLocation(program, "u_maxOutlineD"), glctx->sdfProperties[1]); 462 | glUniform1f(glGetUniformLocation(program, "u_minInsideD"), glctx->sdfProperties[2]); 463 | glUniform1f(glGetUniformLocation(program, "u_maxInsideD"), glctx->sdfProperties[3]); 464 | } 465 | 466 | glBindBuffer(GL_ARRAY_BUFFER, stash->vbo->buffers[0]); 467 | glVertexAttribPointer(glctx->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); 468 | glEnableVertexAttribArray(glctx->posAttrib); 469 | 470 | glBindBuffer(GL_ARRAY_BUFFER, stash->vbo->buffers[1]); 471 | glVertexAttribPointer(glctx->texCoordAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); 472 | glEnableVertexAttribArray(glctx->texCoordAttrib); 473 | 474 | glDrawArrays(GL_TRIANGLES, iFirst, count); 475 | 476 | glDisableVertexAttribArray(glctx->posAttrib); 477 | glDisableVertexAttribArray(glctx->texCoordAttrib); 478 | glDisableVertexAttribArray(glctx->colorAttrib); 479 | 480 | glBindBuffer(GL_ARRAY_BUFFER, 0); 481 | glUseProgram(0); 482 | glDisable(GL_TEXTURE_2D); 483 | } 484 | 485 | void glfonsDrawText(FONScontext* ctx, fsuint id) { 486 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 487 | GLStash* stash = glctx->stashes->at(id); 488 | unsigned int last = (stash->vbo->nverts / N_GLYPH_VERTS) - 1; 489 | 490 | glfonsDrawText(ctx, id, 0, last); 491 | } 492 | 493 | void glfonsSetColor(FONScontext* ctx, float r, float g, float b, float a) { 494 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 495 | glctx->color = glm::vec4(r, g, b, a); 496 | } 497 | 498 | void glfonsPushMatrix(FONScontext* ctx) { 499 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 500 | glctx->matrixStack.push(glctx->transform); 501 | } 502 | 503 | void glfonsPopMatrix(FONScontext* ctx) { 504 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 505 | 506 | if(glctx->matrixStack.size() > 0) { 507 | glctx->transform = glctx->matrixStack.top(); 508 | glctx->matrixStack.pop(); 509 | } 510 | } 511 | 512 | float glfonsGetGlyphOffset(FONScontext* ctx, fsuint id, int i) { 513 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 514 | GLStash* stash = glctx->stashes->at(id); 515 | 516 | return stash->glyphsXOffset[i]; 517 | } 518 | 519 | void glfonsGetBBox(FONScontext* ctx, fsuint id, float* x0, float* y0, float* x1, float* y1) { 520 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 521 | GLStash* stash = glctx->stashes->at(id); 522 | 523 | *x0 = stash->bbox[0]; *y0 = stash->bbox[1]; 524 | *x1 = stash->bbox[2]; *y1 = stash->bbox[3]; 525 | } 526 | 527 | float glfonsGetLength(FONScontext* ctx, fsuint id) { 528 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 529 | GLStash* stash = glctx->stashes->at(id); 530 | 531 | return stash->length; 532 | } 533 | 534 | void glfonsSetOutlineColor(FONScontext* ctx, float r, float g, float b, float a) { 535 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 536 | glctx->outlineColor = glm::vec4(r, g, b, a); 537 | } 538 | 539 | void glfonsSetSDFProperties(FONScontext* ctx, float minOutlineD, float maxOutlineD, float minInsideD, float maxInsideD, float mixFactor) { 540 | GLFONScontext* glctx = (GLFONScontext*) ctx->params.userPtr; 541 | 542 | glctx->sdfProperties[0] = minOutlineD; glctx->sdfProperties[1] = maxOutlineD; 543 | glctx->sdfProperties[2] = minInsideD; glctx->sdfProperties[3] = maxInsideD; 544 | 545 | glctx->sdfMixFactor = mixFactor; 546 | } 547 | 548 | #endif 549 | -------------------------------------------------------------------------------- /libs/glmFontstash/fontstash/sdf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Mikko Mononen (memon@inside.org) 3 | Copyright (C) 2009-2012 Stefan Gustavson (stefan.gustavson@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #ifndef SDF_H 25 | #define SDF_H 26 | 27 | // Sweep-and-update Euclidean distance transform of an antialised image for contour textures. 28 | // Based on edtaa3func.c by Stefan Gustavson. 29 | // 30 | // White (255) pixels are treated as object pixels, zero pixels are treated as background. 31 | // An attempt is made to treat antialiased edges correctly. The input image must have 32 | // pixels in the range [0,255], and the antialiased image should be a box-filter 33 | // sampling of the ideal, crisp edge. If the antialias region is more than 1 pixel wide, 34 | // the result from this transform will be inaccurate. 35 | // Pixels at image border are not calculated and are set to 0. 36 | // 37 | // The output distance field is encoded as bytes, where 0 = radius (outside) and 255 = -radius (inside). 38 | // Input and output can be the same buffer. 39 | // out - Output of the distance transform, one byte per pixel. 40 | // outstride - Bytes per row on output image. 41 | // radius - The radius of the distance field narrow band in pixels. 42 | // img - Input image, one byte per pixel. 43 | // width - Width if the image. 44 | // height - Height if the image. 45 | // stride - Bytes per row on input image. 46 | int sdfBuildDistanceField(unsigned char* out, int outstride, float radius, 47 | const unsigned char* img, int width, int height, int stride); 48 | 49 | // Same as distXform, but does not allocate any memory. 50 | // The 'temp' array should be enough to fit width * height * sizeof(float) * 3 bytes. 51 | void sdfBuildDistanceFieldNoAlloc(unsigned char* out, int outstride, float radius, 52 | const unsigned char* img, int width, int height, int stride, 53 | unsigned char* temp); 54 | 55 | // This function converts the antialiased image where each pixel represents coverage (box-filter 56 | // sampling of the ideal, crisp edge) to a distance field with narrow band radius of sqrt(2). 57 | // This is the fastest way to turn antialised image to contour texture. This function is good 58 | // if you don't need the distance field for effects (i.e. fat outline or dropshadow). 59 | // Input and output buffers must be different. 60 | // out - Output of the distance transform, one byte per pixel. 61 | // outstride - Bytes per row on output image. 62 | // img - Input image, one byte per pixel. 63 | // width - Width if the image. 64 | // height - Height if the image. 65 | // stride - Bytes per row on input image. 66 | void sdfCoverageToDistanceField(unsigned char* out, int outstride, 67 | const unsigned char* img, int width, int height, int stride); 68 | 69 | #endif //SDF_H 70 | 71 | 72 | #ifdef SDF_IMPLEMENTATION 73 | 74 | #include 75 | #include 76 | 77 | #define SDF_MAX_PASSES 10 // Maximum number of distance transform passes 78 | #define SDF_SLACK 0.001f // Controls how much smaller the neighbour value must be to cosnider, too small slack increse iteration count. 79 | #define SDF_SQRT2 1.4142136f // sqrt(2) 80 | #define SDF_BIG 1e+37f // Big value used to initialize the distance field. 81 | 82 | static float sdf__clamp01(float x) 83 | { 84 | return x < 0.0f ? 0.0f : (x > 1.0f ? 1.0f : x); 85 | } 86 | 87 | void sdfCoverageToDistanceField(unsigned char* out, int outstride, 88 | const unsigned char* img, int width, int height, int stride) 89 | { 90 | int x, y; 91 | 92 | // Zero out borders 93 | for (x = 0; x < width; x++) 94 | out[x] = 0; 95 | for (y = 1; y < height; y++) { 96 | out[y*outstride] = 0; 97 | out[width-1+y*outstride] = 0; 98 | } 99 | for (x = 0; x < width; x++) 100 | out[x+(height-1)*outstride] = 0; 101 | 102 | for (y = 1; y < height-1; y++) { 103 | for (x = 1; x < width-1; x++) { 104 | int k = x + y * stride; 105 | float d, gx, gy, glen, a, a1; 106 | 107 | // Skip flat areas. 108 | if (img[k] == 255) { 109 | out[x+y*outstride] = 255; 110 | continue; 111 | } 112 | if (img[k] == 0) { 113 | // Special handling for cases where full opaque pixels are next to full transparent pixels. 114 | // See: https://github.com/memononen/SDF/issues/2 115 | int he = img[k-1] == 255 || img[k+1] == 255; 116 | int ve = img[k-stride] == 255 || img[k+stride] == 255; 117 | if (!he && !ve) { 118 | out[x+y*outstride] = 0; 119 | continue; 120 | } 121 | } 122 | 123 | gx = -(float)img[k-stride-1] - SDF_SQRT2*(float)img[k-1] - (float)img[k+stride-1] + (float)img[k-stride+1] + SDF_SQRT2*(float)img[k+1] + (float)img[k+stride+1]; 124 | gy = -(float)img[k-stride-1] - SDF_SQRT2*(float)img[k-stride] - (float)img[k-stride+1] + (float)img[k+stride-1] + SDF_SQRT2*(float)img[k+stride] + (float)img[k+stride+1]; 125 | a = (float)img[k]/255.0f; 126 | gx = fabsf(gx); 127 | gy = fabsf(gy); 128 | if (gx < 0.0001f || gy < 0.000f) { 129 | d = (0.5f - a) * SDF_SQRT2; 130 | } else { 131 | glen = gx*gx + gy*gy; 132 | glen = 1.0f / sqrtf(glen); 133 | gx *= glen; 134 | gy *= glen; 135 | if (gx < gy) { 136 | float temp = gx; 137 | gx = gy; 138 | gy = temp; 139 | } 140 | a1 = 0.5f*gy/gx; 141 | if (a < a1) { // 0 <= a < a1 142 | d = 0.5f*(gx + gy) - sqrtf(2.0f*gx*gy*a); 143 | } else if (a < (1.0-a1)) { // a1 <= a <= 1-a1 144 | d = (0.5f-a)*gx; 145 | } else { // 1-a1 < a <= 1 146 | d = -0.5f*(gx + gy) + sqrt(2.0f*gx*gy*(1.0f-a)); 147 | } 148 | } 149 | d *= 1.0f / SDF_SQRT2; 150 | out[x+y*outstride] = (unsigned char)(sdf__clamp01(0.5f - d) * 255.0f); 151 | } 152 | } 153 | } 154 | 155 | static float sdf__edgedf(float gx, float gy, float a) 156 | { 157 | float df, a1; 158 | if ((gx == 0) || (gy == 0)) { 159 | // Either A) gu or gv are zero, or B) both 160 | // Linear approximation is A) correct or B) a fair guess 161 | df = 0.5f - a; 162 | } else { 163 | // Everything is symmetric wrt sign and transposition, 164 | // so move to first octant (gx>=0, gy>=0, gx>=gy) to 165 | // avoid handling all possible edge directions. 166 | gx = fabsf(gx); 167 | gy = fabsf(gy); 168 | if (gx < gy) { 169 | float temp = gx; 170 | gx = gy; 171 | gy = temp; 172 | } 173 | a1 = 0.5f*gy/gx; 174 | if (a < a1) { // 0 <= a < a1 175 | df = 0.5f*(gx + gy) - sqrtf(2.0f*gx*gy*a); 176 | } else if (a < (1.0-a1)) { // a1 <= a <= 1-a1 177 | df = (0.5f-a)*gx; 178 | } else { // 1-a1 < a <= 1 179 | df = -0.5f*(gx + gy) + sqrt(2.0f*gx*gy*(1.0f-a)); 180 | } 181 | } 182 | return df; 183 | } 184 | 185 | struct SDFpoint { 186 | float x,y; 187 | }; 188 | 189 | static float sdf__distsqr(struct SDFpoint* a, struct SDFpoint* b) 190 | { 191 | float dx = b->x - a->x, dy = b->y - a->y; 192 | return dx*dx + dy*dy; 193 | } 194 | 195 | void sdfBuildDistanceFieldNoAlloc(unsigned char* out, int outstride, float radius, 196 | const unsigned char* img, int width, int height, int stride, 197 | unsigned char* temp) 198 | { 199 | int i, x, y, pass; 200 | float scale; 201 | float* tdist = (float*)&temp[0]; 202 | struct SDFpoint* tpt = (struct SDFpoint*)&temp[width * height * sizeof(float)]; 203 | 204 | // Initialize buffers 205 | for (i = 0; i < width*height; i++) { 206 | tpt[i].x = 0; 207 | tpt[i].y = 0; 208 | tdist[i] = SDF_BIG; 209 | } 210 | 211 | // Calculate position of the anti-aliased pixels and distance to the boundary of the shape. 212 | for (y = 1; y < height-1; y++) { 213 | for (x = 1; x < width-1; x++) { 214 | int tk, k = x + y * stride; 215 | struct SDFpoint c = { (float)x, (float)y }; 216 | float d, gx, gy, glen; 217 | 218 | // Skip flat areas. 219 | if (img[k] == 255) continue; 220 | if (img[k] == 0) { 221 | // Special handling for cases where full opaque pixels are next to full transparent pixels. 222 | // See: https://github.com/memononen/SDF/issues/2 223 | int he = img[k-1] == 255 || img[k+1] == 255; 224 | int ve = img[k-stride] == 255 || img[k+stride] == 255; 225 | if (!he && !ve) continue; 226 | } 227 | 228 | // Calculate gradient direction 229 | gx = -(float)img[k-stride-1] - SDF_SQRT2*(float)img[k-1] - (float)img[k+stride-1] + (float)img[k-stride+1] + SDF_SQRT2*(float)img[k+1] + (float)img[k+stride+1]; 230 | gy = -(float)img[k-stride-1] - SDF_SQRT2*(float)img[k-stride] - (float)img[k-stride+1] + (float)img[k+stride-1] + SDF_SQRT2*(float)img[k+stride] + (float)img[k+stride+1]; 231 | if (fabsf(gx) < 0.001f && fabsf(gy) < 0.001f) continue; 232 | glen = gx*gx + gy*gy; 233 | if (glen > 0.0001f) { 234 | glen = 1.0f / sqrtf(glen); 235 | gx *= glen; 236 | gy *= glen; 237 | } 238 | 239 | // Find nearest point on contour. 240 | tk = x + y * width; 241 | d = sdf__edgedf(gx, gy, (float)img[k]/255.0f); 242 | tpt[tk].x = x + gx*d; 243 | tpt[tk].y = y + gy*d; 244 | tdist[tk] = sdf__distsqr(&c, &tpt[tk]); 245 | } 246 | } 247 | 248 | // Calculate distance transform using sweep-and-update. 249 | for (pass = 0; pass < SDF_MAX_PASSES; pass++){ 250 | int changed = 0; 251 | 252 | // Bottom-left to top-right. 253 | for (y = 1; y < height-1; y++) { 254 | for (x = 1; x < width-1; x++) { 255 | int k = x+y*width, kn, ch = 0; 256 | struct SDFpoint c = { (float)x, (float)y }, pt; 257 | float pd = tdist[k], d; 258 | // (-1,-1) 259 | kn = k - 1 - width; 260 | if (tdist[kn] < pd) { 261 | d = sdf__distsqr(&c, &tpt[kn]); 262 | if (d + SDF_SLACK < pd) { 263 | pt = tpt[kn]; 264 | pd = d; 265 | ch = 1; 266 | } 267 | } 268 | // (0,-1) 269 | kn = k - width; 270 | if (tdist[kn] < pd) { 271 | d = sdf__distsqr(&c, &tpt[kn]); 272 | if (d + SDF_SLACK < pd) { 273 | pt = tpt[kn]; 274 | pd = d; 275 | ch = 1; 276 | } 277 | } 278 | // (1,-1) 279 | kn = k + 1 - width; 280 | if (tdist[kn] < pd) { 281 | d = sdf__distsqr(&c, &tpt[kn]); 282 | if (d + SDF_SLACK < pd) { 283 | pt = tpt[kn]; 284 | pd = d; 285 | ch = 1; 286 | } 287 | } 288 | // (-1,0) 289 | kn = k - 1; 290 | if (tdist[kn] < tdist[k]) { 291 | d = sdf__distsqr(&c, &tpt[kn]); 292 | if (d + SDF_SLACK < pd) { 293 | pt = tpt[kn]; 294 | pd = d; 295 | ch = 1; 296 | } 297 | } 298 | if (ch) { 299 | tpt[k] = pt; 300 | tdist[k] = pd; 301 | changed++; 302 | } 303 | } 304 | } 305 | 306 | // Top-right to bottom-left. 307 | for (y = height-2; y > 0 ; y--) { 308 | for (x = width-2; x > 0; x--) { 309 | int k = x+y*width, kn, ch = 0; 310 | struct SDFpoint c = { (float)x, (float)y }, pt; 311 | float pd = tdist[k], d; 312 | // (1,0) 313 | kn = k + 1; 314 | if (tdist[kn] < pd) { 315 | d = sdf__distsqr(&c, &tpt[kn]); 316 | if (d + SDF_SLACK < pd) { 317 | pt = tpt[kn]; 318 | pd = d; 319 | ch = 1; 320 | } 321 | } 322 | // (-1,1) 323 | kn = k - 1 + width; 324 | if (tdist[kn] < pd) { 325 | d = sdf__distsqr(&c, &tpt[kn]); 326 | if (d + SDF_SLACK < pd) { 327 | pt = tpt[kn]; 328 | pd = d; 329 | ch = 1; 330 | } 331 | } 332 | // (0,1) 333 | kn = k + width; 334 | if (tdist[kn] < pd) { 335 | d = sdf__distsqr(&c, &tpt[kn]); 336 | if (d + SDF_SLACK < pd) { 337 | pt = tpt[kn]; 338 | pd = d; 339 | ch = 1; 340 | } 341 | } 342 | // (1,1) 343 | kn = k + 1 + width; 344 | if (tdist[kn] < pd) { 345 | d = sdf__distsqr(&c, &tpt[kn]); 346 | if (d + SDF_SLACK < pd) { 347 | pt = tpt[kn]; 348 | pd = d; 349 | ch = 1; 350 | } 351 | } 352 | if (ch) { 353 | tpt[k] = pt; 354 | tdist[k] = pd; 355 | changed++; 356 | } 357 | } 358 | } 359 | 360 | if (changed == 0) break; 361 | } 362 | 363 | // Map to good range. 364 | scale = 1.0f / radius; 365 | for (y = 0; y < height; y++) { 366 | for (x = 0; x < width; x++) { 367 | float d = sqrtf(tdist[x+y*width]) * scale; 368 | if (img[x+y*stride] > 127) d = -d; 369 | out[x+y*outstride] = (unsigned char)(sdf__clamp01(0.5f - d*0.5f) * 255.0f); 370 | } 371 | } 372 | 373 | } 374 | 375 | int sdfBuildDistanceField(unsigned char* out, int outstride, float radius, 376 | const unsigned char* img, int width, int height, int stride) 377 | { 378 | unsigned char* temp = (unsigned char*)malloc(width*height*sizeof(float)*3); 379 | if (temp == NULL) return 0; 380 | sdfBuildDistanceFieldNoAlloc(out, outstride, radius, img, width, height, stride, temp); 381 | free(temp); 382 | return 1; 383 | } 384 | 385 | #endif //SDF_IMPLEMENTATION -------------------------------------------------------------------------------- /libs/glmFontstash/glmFont.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmFont.cpp 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/8/14. 6 | // 7 | // 8 | 9 | #include "glmFont.h" 10 | 11 | #define GLFONTSTASH_IMPLEMENTATION 12 | #include "glfontstash.h" 13 | 14 | glmFont::glmFont(): m_bLoaded(false) { 15 | m_fs = glfonsCreate(512, 512, FONS_ZERO_TOPLEFT); 16 | } 17 | 18 | glmFont::~glmFont(){ 19 | unload(); 20 | } 21 | 22 | void glmFont::unload(){ 23 | m_bLoaded = false; 24 | 25 | if(m_fs != NULL) { 26 | glfonsDelete(m_fs); 27 | } 28 | } 29 | 30 | bool glmFont::loadFont(std::string _filename, float _fontsize, float _depth, bool _bUsePolygons){ 31 | _fontsize *= 2; 32 | 33 | m_font = fonsAddFont(m_fs, "sans", _filename.c_str()); 34 | if(m_font == FONS_INVALID) { 35 | std::cerr << "Could not add font normal" << std::endl; 36 | glfonsDelete(m_fs); 37 | m_fs = NULL; 38 | 39 | m_bLoaded = false; 40 | } else { 41 | m_effect = FONS_EFFECT_DISTANCE_FIELD; 42 | 43 | fonsSetBlur(m_fs, 4.5); 44 | fonsSetBlurType(m_fs, m_effect); 45 | 46 | fonsSetSize(m_fs, _fontsize); 47 | fonsSetFont(m_fs, m_font); 48 | 49 | glfonsSetSDFProperties(m_fs, 0.25, 0.35, 0.38, 0.55, 0.7); 50 | 51 | fonsVertMetrics(m_fs, &m_ascender, &m_descender, &m_lineh); 52 | 53 | fonsSetErrorCallback(m_fs, glmFont::handleFontstashError, this); 54 | 55 | m_bLoaded = true; 56 | } 57 | 58 | return m_bLoaded; 59 | } 60 | 61 | void glmFont::handleFontstashError(void* uptr, int error, int val) { 62 | glmFont* ref = (glmFont*) uptr; 63 | 64 | switch (error) { 65 | case FONS_ATLAS_FULL: 66 | int width, height; 67 | fonsGetAtlasSize(ref->m_fs, &width, &height); 68 | if(width <= ATLAS_MAX_SIZE && height <= ATLAS_MAX_SIZE) { 69 | fonsExpandAtlas(ref->m_fs, width * 2, height * 2, 0); 70 | } else { 71 | std::cerr << "Atlas couldn't expand more than " << ATLAS_MAX_SIZE << std::endl; 72 | } 73 | break; 74 | default: 75 | break; 76 | } 77 | } 78 | 79 | bool glmFont::isLoaded(){ 80 | return m_bLoaded; 81 | } 82 | 83 | glmRectangle glmFont::getStringBoundingBox(unsigned int id) { 84 | if(m_bLoaded){ 85 | glm::vec4 bbox; 86 | glfonsGetBBox(m_fs, id, &bbox[0], &bbox[1], &bbox[2], &bbox[3]); 87 | return glmRectangle(bbox); 88 | } 89 | return glmRectangle(); 90 | } 91 | 92 | void glmFont::drawString(unsigned int _id, float _alpha) { 93 | glfonsSetColor(m_fs, fontColor.r, fontColor.g, fontColor.b, _alpha); 94 | glfonsSetOutlineColor(m_fs, outlineColor.r, outlineColor.g, outlineColor.b, _alpha); 95 | glfonsScale(m_fs, 1, -1); 96 | glfonsDrawText(m_fs, _id); 97 | } 98 | 99 | void glmFont::drawString(unsigned int _id, const glm::vec3 &_pos, float _alpha) { 100 | glfonsPushMatrix(m_fs); 101 | 102 | glfonsTranslate(m_fs, _pos.x, _pos.y); 103 | 104 | glfonsSetColor(m_fs, fontColor.r, fontColor.g, fontColor.b, _alpha); 105 | glfonsSetOutlineColor(m_fs, outlineColor.r, outlineColor.g, outlineColor.b, _alpha); 106 | glfonsDrawText(m_fs, _id); 107 | 108 | glfonsPopMatrix(m_fs); 109 | } 110 | 111 | void glmFont::drawString(unsigned int _id, const glmRectangle &_rect, float _alpha) { 112 | glm::vec3 p = _rect.getBottomLeft(); 113 | glfonsPushMatrix(m_fs); 114 | 115 | glfonsTranslate(m_fs, p.x, p.y); 116 | 117 | glfonsSetColor(m_fs, fontColor.r, fontColor.g, fontColor.b, _alpha); 118 | glfonsSetOutlineColor(m_fs, outlineColor.r, outlineColor.g, outlineColor.b, _alpha); 119 | glfonsDrawText(m_fs, _id); 120 | 121 | glfonsPopMatrix(m_fs); 122 | } 123 | 124 | void glmFont::drawSubString(unsigned int _id, unsigned int _i, bool _offset, float _alpha) { 125 | if(!_offset) { 126 | float xglyphOffset = glfonsGetGlyphOffset(m_fs, _id, _i); 127 | glfonsTranslate(m_fs, -xglyphOffset, 0.0); 128 | } 129 | drawSubString(_id, _i, _i, _alpha); 130 | } 131 | 132 | void glmFont::drawSubString(unsigned int _id, unsigned int _from, unsigned int _to, float _alpha) { 133 | glfonsScale(m_fs, 1, -1); 134 | 135 | glfonsSetColor(m_fs, fontColor.r, fontColor.g, fontColor.b, _alpha); 136 | glfonsSetOutlineColor(m_fs, outlineColor.r, outlineColor.g, outlineColor.b, _alpha); 137 | 138 | glfonsDrawText(m_fs, _id, _from, _to); 139 | } 140 | 141 | FONScontext* glmFont::getContext() const { 142 | return m_fs; 143 | } 144 | 145 | FONSeffectType glmFont::getEffect() const { 146 | return m_effect; 147 | } 148 | 149 | float glmFont::getAscender() const { 150 | return m_ascender; 151 | } 152 | 153 | float glmFont::getDescender() const { 154 | return m_descender; 155 | } 156 | 157 | float glmFont::getLineH() const { 158 | return m_lineh; 159 | } -------------------------------------------------------------------------------- /libs/glmFontstash/glmFont.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmFont.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 9/8/14. 5 | // 6 | // 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include "glmRectangle.h" 13 | 14 | #include "glm.hpp" 15 | #include "glfontstash.h" 16 | 17 | #define ATLAS_MAX_SIZE 2048 18 | 19 | class glmFont { 20 | public: 21 | 22 | glmFont(); 23 | virtual ~glmFont(); 24 | 25 | void unload(); 26 | bool loadFont(std::string filename, float fontsize, float depth = 0, bool bUsePolygons = false); 27 | bool isLoaded(); 28 | 29 | glmRectangle getStringBoundingBox(unsigned int id); 30 | 31 | void drawString(unsigned int _id, float _alpha); 32 | void drawString(unsigned int _id, const glm::vec3 &_pos, float _alpha); 33 | void drawString(unsigned int _id, const glmRectangle &_rect, float _alpha); 34 | void drawSubString(unsigned int _id, unsigned int _i, bool _offset, float _alpha); 35 | void drawSubString(unsigned int _id, unsigned int _from, unsigned int _to, float _alpha); 36 | 37 | FONScontext* getContext() const; 38 | FONSeffectType getEffect() const; 39 | 40 | float getAscender() const; 41 | float getDescender() const; 42 | float getLineH() const; 43 | 44 | glm::vec3 outlineColor; 45 | glm::vec3 fontColor; 46 | 47 | protected: 48 | bool m_bLoaded; 49 | 50 | FONScontext* m_fs; 51 | int m_font; 52 | FONSeffectType m_effect; 53 | float m_ascender; 54 | float m_descender; 55 | float m_lineh; 56 | 57 | static void handleFontstashError(void* uptr, int error, int val); 58 | }; 59 | 60 | typedef std::tr1::shared_ptr glmFontRef; -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmAnchorLine.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmAnchorLine.cpp 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/26/14. 6 | // 7 | // 8 | 9 | #include "glmAnchorLine.h" 10 | 11 | glmAnchorLine::glmAnchorLine():originalCentroid(0.0,0.0,0.0),bLetterByLetter(false){ 12 | }; 13 | 14 | void glmAnchorLine::clear(){ 15 | glmFastPolyline::clear(); 16 | marks.clear(); 17 | } -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmAnchorLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmAnchorLine.h 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/26/14. 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include "glmFastPolyline.h" 12 | 13 | struct AnchorMark { 14 | AnchorMark():m_pct(0),m_alpha(0.0){}; 15 | AnchorMark(float _pct):m_pct(_pct),m_alpha(1.0){}; 16 | 17 | float m_pct; 18 | float m_alpha; 19 | }; 20 | 21 | class glmAnchorLine : public glmFastPolyline { 22 | public: 23 | 24 | glmAnchorLine(); 25 | 26 | void clear(); 27 | 28 | std::vector marks; 29 | glm::vec3 originalCentroid; 30 | bool bLetterByLetter; 31 | }; -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmFeatureLabel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmFeatureLabel.cpp 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/8/14. 6 | // 7 | // 8 | 9 | #include "glmFeatureLabel.h" 10 | 11 | #include "glmGL.h" 12 | #include "glmGeom.h" 13 | #include "glmString.h" 14 | 15 | glmFeatureLabel::glmFeatureLabel(): m_text("NONE"), m_alpha(0.0), m_cameraPos(NULL), bVisible(false), m_bChanged(true) { 16 | 17 | } 18 | 19 | glmFeatureLabel::glmFeatureLabel(const std::string &_text):m_text(_text), m_alpha(0.0), m_cameraPos(NULL), bVisible(false), m_bChanged(true){ 20 | 21 | } 22 | 23 | glmFeatureLabel::~glmFeatureLabel(){ 24 | FONScontext* ctx = m_font->getContext(); 25 | glfonsUnbufferText(ctx, m_fsid); 26 | }; 27 | 28 | std::string glmFeatureLabel::getText(){ 29 | return m_text; 30 | } 31 | 32 | void glmFeatureLabel::setFont(glmFontRef &_fontRef){ 33 | m_font = _fontRef; 34 | m_bChanged = true; 35 | 36 | if(m_font != NULL && m_font->isLoaded()) { 37 | FONScontext* ctx = m_font->getContext(); 38 | glfonsBufferText(ctx, m_text.c_str(), &m_fsid, m_font->getEffect()); 39 | } 40 | } 41 | 42 | void glmFeatureLabel::setText(const std::string &_text){ 43 | m_text = _text; 44 | stringPurifier(m_text); 45 | m_bChanged = true; 46 | } 47 | 48 | void glmFeatureLabel::setCameraPos(glm::vec3 *_camPos){ 49 | m_cameraPos = _camPos; 50 | } 51 | 52 | unsigned int glmFeatureLabel::getId() const { 53 | return m_fsid; 54 | } -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmFeatureLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmFeatureLabel.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 9/8/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include "glmFeature.h" 11 | #include "glmAnchorLine.h" 12 | #include "glmRectangle.h" 13 | 14 | #include "glmFont.h" 15 | 16 | class glmFeatureLabel : public glmFeature{ 17 | public: 18 | 19 | glmFeatureLabel(); 20 | glmFeatureLabel(const std::string &_text); 21 | virtual ~glmFeatureLabel(); 22 | 23 | void setFont(glmFontRef &_fontRef); 24 | void setCameraPos(glm::vec3 *_camPos); 25 | void setText(const std::string &_text); 26 | 27 | std::string getText(); 28 | virtual void draw2D() = 0; 29 | 30 | std::vector m_anchorLines; // Use to mount the text 31 | glmRectangle m_label; // Containg the text information 32 | 33 | bool bVisible; 34 | 35 | unsigned int getId() const; 36 | 37 | protected: 38 | virtual void updateCached() = 0; 39 | 40 | std::string m_text; 41 | glmFontRef m_font; 42 | 43 | glm::vec3 *m_cameraPos; 44 | 45 | float m_alpha; 46 | bool m_bChanged; 47 | 48 | fsuint m_fsid; 49 | }; 50 | 51 | typedef std::tr1::shared_ptr glmFeatureLabelRef; -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmFeatureLabelLine.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmFeatureLabelLine.cpp 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/8/14. 6 | // 7 | // 8 | 9 | #include "glmFeatureLabelLine.h" 10 | 11 | glmFeatureLabelLine::glmFeatureLabelLine(){ 12 | } 13 | 14 | glmFeatureLabelLine::glmFeatureLabelLine(const std::string &_text){ 15 | setText(_text); 16 | } 17 | 18 | glmFeatureLabelLine::~glmFeatureLabelLine(){ 19 | 20 | } 21 | 22 | void glmFeatureLabelLine::seedAnchorsEvery(glmAnchorLine &_anchorLine, float _minDistance, float _maxDistance){ 23 | 24 | // Update Fonts/Text cached values if something change 25 | // 26 | if(m_bChanged){ 27 | updateCached(); 28 | } 29 | 30 | float segmentLength = _anchorLine.getLength(); 31 | 32 | // How many times? 33 | int nTimes = segmentLength/(m_label.width+_maxDistance); 34 | 35 | // At what distance between each other? 36 | float margin = (segmentLength-m_label.width*(float)nTimes)/((float)nTimes+1.0); 37 | 38 | // Center the Labels 39 | float seed = margin; 40 | 41 | // Add anchor points for seeds every _distance 42 | for (int i = 0; i < nTimes; i++) { 43 | _anchorLine.marks.push_back(AnchorMark(seed/_anchorLine.getLength())); 44 | seed += m_label.width+margin; 45 | } 46 | } 47 | 48 | void glmFeatureLabelLine::seedAnchorOnSegmentsAt(glmAnchorLine &_anchorLine, float _minDistance, float _maxDistance){ 49 | 50 | // Update Fonts/Text cached values if something change 51 | // 52 | if(m_bChanged){ 53 | updateCached(); 54 | } 55 | 56 | float lastSeed = 0.0; 57 | for (int i = 0; i < _anchorLine.size()-1; i++) { 58 | float offset = _anchorLine.getDistances()[i]; 59 | 60 | float segmentLength = _anchorLine.getDistances()[i+1]-_anchorLine.getDistances()[i];//_anchorLine.getPolars()[i].r; 61 | 62 | // Fits? 63 | // 64 | if( segmentLength >= (m_label.width+_maxDistance) ){ 65 | 66 | // How many times? 67 | int nTimes = segmentLength/(m_label.width+_maxDistance); 68 | 69 | // At what distance between each other? 70 | float margin = (segmentLength-m_label.width*(float)nTimes)/((float)nTimes+1.0); 71 | 72 | // Add anchors points for seeds 73 | float seed = margin; 74 | for (int i = 0; i < nTimes; i++) { 75 | float potentialSeed = offset + seed ; 76 | if( potentialSeed-lastSeed > _minDistance ){ 77 | lastSeed = potentialSeed; 78 | _anchorLine.marks.push_back(AnchorMark(lastSeed/_anchorLine.getLength())); 79 | seed += m_label.width+margin; 80 | } 81 | } 82 | 83 | } else if ( segmentLength >= m_label.width+_minDistance){ 84 | 85 | // Only one time 86 | // 87 | float margin = (segmentLength-m_label.width)*0.5; 88 | float potentialSeed = offset + margin ; 89 | if( potentialSeed-lastSeed > _minDistance){ 90 | lastSeed = potentialSeed; 91 | _anchorLine.marks.push_back(AnchorMark(lastSeed/_anchorLine.getLength())); 92 | } 93 | } 94 | } 95 | } 96 | 97 | void glmFeatureLabelLine::updateCached(){ 98 | if(m_font!=NULL&&m_text!="NONE"){ 99 | 100 | m_lettersWidth.clear(); 101 | m_wordsWidth.clear(); 102 | 103 | FONScontext* ctx = m_font->getContext(); 104 | std::string word = ""; 105 | float wordWidth = 0.0f; 106 | 107 | for(int i = 0; i < m_text.size(); ++i) { 108 | float currentOffset = glfonsGetGlyphOffset(ctx, m_fsid, i); 109 | float nextOffset; 110 | float letterWidth; 111 | 112 | if(i < m_text.size() - 1) { 113 | nextOffset = glfonsGetGlyphOffset(ctx, m_fsid, i+1); 114 | } else { 115 | nextOffset = glfonsGetLength(ctx, m_fsid); 116 | } 117 | letterWidth = (nextOffset - currentOffset); 118 | 119 | float wordWidth = 0.0f; 120 | if( m_text[i] == ' '){ 121 | m_lettersWidth.push_back(letterWidth); 122 | m_wordsWidth.push_back(wordWidth); 123 | wordWidth = 0.; 124 | word = ""; 125 | } else { 126 | m_lettersWidth.push_back(letterWidth); 127 | wordWidth += letterWidth; 128 | word += &m_text[i]; 129 | } 130 | } 131 | 132 | m_label = m_font->getStringBoundingBox(m_fsid); 133 | m_bChanged = false; 134 | } else { 135 | bVisible = false; 136 | } 137 | } 138 | 139 | 140 | void glmFeatureLabelLine::draw2D(){ 141 | if(m_font!=NULL&&m_text!="NONE"&&bVisible){ 142 | 143 | // Global m_alpha 144 | // 145 | if(m_cameraPos!=0 && bVisible){ 146 | float angle = glm::dot(glm::normalize( *m_cameraPos - shapes[0].getCentroid()),glm::vec3(0.,0.,1.)); 147 | m_alpha = lerpValue(m_alpha,powf( CLAMP(angle,0.01,1.0), 0.6 ),0.1); 148 | } else { 149 | m_alpha = lerpValue(m_alpha,0.0, 0.1); 150 | } 151 | 152 | if(m_alpha > 0.1){ 153 | for (auto &it: m_anchorLines) { 154 | drawTextOn(it); 155 | } 156 | } 157 | 158 | } 159 | } 160 | 161 | void glmFeatureLabelLine::drawDebug(){ 162 | 163 | glEnable(GL_LINE_STIPPLE); 164 | glLineStipple(1, 0x1111); 165 | for (auto &it: m_anchorLines) { 166 | drawPolyline(it.getVertices()); 167 | } 168 | glDisable(GL_LINE_STIPPLE); 169 | 170 | for (auto &it: m_anchorLines) { 171 | for (int i = 0; i < it.size(); i++) { 172 | if(i == 0 ){ 173 | glLineWidth(2); 174 | drawCross(it[i],5); 175 | } else { 176 | glLineWidth(1); 177 | drawCross(it[i]); 178 | 179 | // Print distances 180 | // 181 | // glPushMatrix(); 182 | // glTranslated(it[i].x, it[i].y, it[i].z); 183 | // glScalef(0.75,-0.75,1); 184 | // glRotated(it.getPolars()[i-1].a*RAD_TO_DEG, 0, 0, -1); 185 | // glTranslated(5.,3.,0.); 186 | // m_font->drawString( toString( (int)it.getDistances()[i]), m_alpha ); 187 | // glPopMatrix(); 188 | } 189 | } 190 | } 191 | } 192 | 193 | void glmFeatureLabelLine::drawTextOn( glmAnchorLine &_anchorLine){ 194 | if(_anchorLine.bLetterByLetter){ 195 | drawLetterByLetter(_anchorLine); 196 | } else { 197 | drawAllTextAtOnce(_anchorLine); 198 | } 199 | } 200 | 201 | void glmFeatureLabelLine::drawAllTextAtOnce( glmAnchorLine &_anchorLine){ 202 | for (auto &mark : _anchorLine.marks){ 203 | glm::ivec4 viewport; 204 | glGetIntegerv(GL_VIEWPORT, &viewport[0]); 205 | glmRectangle screen = glmRectangle(viewport); 206 | 207 | // Orientation 208 | // 209 | float angle = PI; 210 | glm::vec3 diff = _anchorLine[0]-_anchorLine[_anchorLine.size()-1]; 211 | angle = atan2f(-diff.y, diff.x); 212 | float offset = mark.m_pct*_anchorLine.getLength(); 213 | glm::vec3 src = _anchorLine.getPositionAt(offset); 214 | 215 | if(bVisible){ 216 | mark.m_alpha = lerpValue(mark.m_alpha,m_alpha,0.1); 217 | } else { 218 | mark.m_alpha = lerpValue(mark.m_alpha,0.0,0.1); 219 | } 220 | 221 | if(screen.inside(src)){ 222 | double rot = _anchorLine.getAngleAt(offset); 223 | 224 | glmRectangle boundingBox = glmPolyline(m_label,angle).getBoundingBox(); 225 | boundingBox.translate( _anchorLine.getPositionAt( offset + m_label.width*0.5) ); 226 | 227 | // Draw boundign box for debug 228 | // 229 | // boundingBox.drawCorners(); 230 | 231 | bool bOver = false; 232 | 233 | for (int i = 0; i < pointLabels->size(); i++ ){ 234 | if(pointLabels->at(i)->bVisible){ 235 | if( boundingBox.intersects(pointLabels->at(i)->getLabel(0) ) ){ 236 | bOver = true; 237 | break; 238 | } 239 | } 240 | } 241 | 242 | if(!bOver){ 243 | FONScontext* fs = m_font->getContext(); 244 | 245 | glfonsPushMatrix(fs); 246 | glfonsTranslate(fs, src.x, src.y); 247 | 248 | glfonsScale(fs, 1, -1); 249 | glfonsRotate(fs, rot * RAD_TO_DEG); 250 | 251 | if(angle < PI*0.5 && angle > -PI*0.5) { 252 | glfonsScale(fs, -1, -1); 253 | glfonsTranslate(fs, -m_label.width, 0); 254 | } 255 | 256 | glfonsTranslate(fs, 0.0, -m_label.height*0.5); 257 | m_font->drawString(m_fsid, mark.m_alpha); 258 | glfonsPopMatrix(fs); 259 | } 260 | } 261 | 262 | } 263 | } 264 | 265 | void glmFeatureLabelLine::drawLetterByLetter(glmAnchorLine &_anchorLine){ 266 | for (auto &mark : _anchorLine.marks){ 267 | glm::ivec4 viewport; 268 | glGetIntegerv(GL_VIEWPORT, &viewport[0]); 269 | glmRectangle screen = glmRectangle(viewport); 270 | 271 | // Orientation 272 | // 273 | float angle = PI; 274 | glm::vec3 diff = _anchorLine[0]-_anchorLine[_anchorLine.size()-1]; 275 | angle = atan2f(-diff.y, diff.x); 276 | float offset = mark.m_pct*_anchorLine.getLength(); 277 | 278 | if(bVisible){ 279 | mark.m_alpha = lerpValue(mark.m_alpha,m_alpha,0.1); 280 | } else { 281 | mark.m_alpha = lerpValue(mark.m_alpha,0.0,0.1); 282 | } 283 | 284 | if(angle < PI*0.5 && angle > -PI*0.5){ 285 | for (int i = m_text.length()-1; i >=0 ; i--) { 286 | 287 | glm::vec3 src = _anchorLine.getPositionAt(offset); 288 | 289 | if(screen.inside(src)){ 290 | double rot = _anchorLine.getAngleAt(offset); 291 | 292 | FONScontext* ctx = m_font->getContext(); 293 | 294 | glfonsPushMatrix(ctx); 295 | glfonsTranslate(ctx, src.x, src.y); 296 | 297 | glfonsScale(ctx, 1, -1); 298 | glfonsRotate(ctx, rot * RAD_TO_DEG); 299 | 300 | glfonsScale(ctx, -1, -1); 301 | glfonsTranslate(ctx, -m_lettersWidth[i], 0); 302 | 303 | glfonsTranslate(ctx, 0, -m_label.height*0.5); 304 | 305 | m_font->drawSubString(m_fsid, i, false, mark.m_alpha); 306 | glfonsPopMatrix(ctx); 307 | 308 | offset += m_lettersWidth[i]; 309 | } else { 310 | break; 311 | } 312 | 313 | } 314 | } else { 315 | 316 | for (int i = 0; i < m_text.length(); i++) { 317 | glm::vec3 src = _anchorLine.getPositionAt(offset); 318 | if(screen.inside(src)){ 319 | double rot = _anchorLine.getAngleAt(offset); 320 | 321 | FONScontext* ctx = m_font->getContext(); 322 | 323 | glfonsPushMatrix(ctx); 324 | glfonsTranslate(ctx, src.x, src.y); 325 | 326 | glfonsScale(ctx, 1, -1); 327 | glfonsRotate(ctx, rot * RAD_TO_DEG); 328 | 329 | glfonsTranslate(ctx, 0.0, -m_label.height * 0.5); 330 | 331 | m_font->drawSubString(m_fsid, i, false, mark.m_alpha); 332 | 333 | glfonsPopMatrix(ctx); 334 | offset += m_lettersWidth[i]; 335 | } else { 336 | break; 337 | } 338 | } 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmFeatureLabelLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmFeatureLabelLine.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 9/8/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include "glmFeatureLabel.h" 11 | 12 | #include "glmAnchorLine.h" 13 | #include "glmFeatureLabelPoint.h" 14 | 15 | class glmFeatureLabelLine : public glmFeatureLabel{ 16 | public: 17 | 18 | glmFeatureLabelLine(); 19 | glmFeatureLabelLine(const std::string &_text); 20 | virtual ~glmFeatureLabelLine(); 21 | 22 | void update(); 23 | void seedAnchorsEvery(glmAnchorLine &_anchorLine, float _minDistance, float _maxDistance); 24 | void seedAnchorOnSegmentsAt(glmAnchorLine &_anchorLine, float _minDistance, float _maxDistance); 25 | 26 | void draw2D(); 27 | void drawTextOn(glmAnchorLine &_anchorLine); 28 | void drawDebug(); 29 | 30 | std::vector *pointLabels; 31 | 32 | protected: 33 | void updateCached(); 34 | 35 | void drawAllTextAtOnce( glmAnchorLine &_anchorLine); 36 | void drawLetterByLetter( glmAnchorLine &_anchorLine); 37 | 38 | // Text cached data 39 | std::vector m_wordsWidth; 40 | std::vector m_lettersWidth; 41 | }; 42 | 43 | typedef std::tr1::shared_ptr glmFeatureLabelLineRef; -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmFeatureLabelPoint.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmFeatureLabelPoint.cpp 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/8/14. 6 | // 7 | // 8 | 9 | #include "glmFeatureLabelPoint.h" 10 | 11 | 12 | glmFeatureLabelPoint::glmFeatureLabelPoint():m_centroid(0.0,0.0,0.0), m_offset(0.0,0.0,0.0), m_anchorPoint(0.0,0.0,0.0), m_margin(8.0), m_angle(HALF_PI) { 13 | }; 14 | 15 | glmFeatureLabelPoint::glmFeatureLabelPoint(const std::string &_text):m_centroid(0.0,0.0,0.0), m_offset(0.0,0.0,0.0), m_anchorPoint(0.0,0.0,0.0), m_margin(8.0), m_angle(HALF_PI){ 16 | setText(_text); 17 | } 18 | 19 | glmFeatureLabelPoint::~glmFeatureLabelPoint(){ 20 | 21 | }; 22 | 23 | void glmFeatureLabelPoint::setPosition(const glm::vec3 &_pos){ 24 | m_centroid = _pos; 25 | m_bChanged = true; 26 | } 27 | 28 | void glmFeatureLabelPoint::setLabelAngle(const double &_radiant){ 29 | m_angle = _radiant; 30 | m_bChanged = true; 31 | } 32 | 33 | void glmFeatureLabelPoint::setLabelMargin(const float &_margin){ 34 | m_margin = _margin; 35 | m_bChanged = true; 36 | } 37 | 38 | glm::vec3 glmFeatureLabelPoint::getScreenPosition() const{ 39 | return m_anchorPoint; 40 | } 41 | 42 | glmRectangle glmFeatureLabelPoint::getLabel(const float &_marign) const{ 43 | if (_marign == 0.0) { 44 | return m_label; 45 | } else { 46 | return glmRectangle(m_label, _marign); 47 | } 48 | } 49 | 50 | glm::vec3 glmFeatureLabelPoint::getAnchorPoint() const{ 51 | return m_anchorPoint; 52 | } 53 | 54 | bool glmFeatureLabelPoint::isOver(const glmFeatureLabelPoint *_other, float _margin){ 55 | if(m_bChanged){ 56 | updateCached(); 57 | } 58 | return m_label.intersects(_other->getLabel(_margin)) || isInside(_other->getAnchorPoint()); 59 | } 60 | 61 | bool glmFeatureLabelPoint::isInside(const glm::vec3 &_point){ 62 | if(m_bChanged){ 63 | updateCached(); 64 | } 65 | return m_label.inside(_point); 66 | } 67 | 68 | void glmFeatureLabelPoint::updateCached(){ 69 | if(m_font!=NULL&&m_text!="NONE"){ 70 | m_label = m_font->getStringBoundingBox(m_fsid); 71 | m_bChanged = false; 72 | } 73 | } 74 | 75 | void glmFeatureLabelPoint::update(){ 76 | 77 | if(m_font!=NULL&&m_text!="NONE"){ 78 | glm::ivec4 viewport; 79 | glm::mat4x4 mvmatrix, projmatrix; 80 | glGetIntegerv(GL_VIEWPORT, &viewport[0]); 81 | glGetFloatv(GL_MODELVIEW_MATRIX, &mvmatrix[0][0]); 82 | glGetFloatv(GL_PROJECTION_MATRIX, &projmatrix[0][0]); 83 | 84 | if(m_bChanged){ 85 | updateCached(); 86 | } 87 | 88 | m_label.x = m_anchorPoint.x + m_margin * cos(m_angle); 89 | m_label.y = m_anchorPoint.y + m_margin * sin(-m_angle); 90 | 91 | if (m_angle <= QUARTER_PI && m_angle >= -QUARTER_PI){ 92 | // EAST 93 | // 94 | m_label.x += 0.0; 95 | m_label.y += mapValue(m_angle, 96 | QUARTER_PI, -QUARTER_PI, 97 | -m_label.height, 0); 98 | 99 | } else if (m_angle >= QUARTER_PI && m_angle <= QUARTER_PI*3.){ 100 | // NORTH 101 | // 102 | m_label.x += mapValue(m_angle, 103 | QUARTER_PI*3., QUARTER_PI, 104 | -m_label.width, 0); 105 | m_label.y += -m_label.height; 106 | } else if (m_angle <= -QUARTER_PI && m_angle >= -QUARTER_PI*3.){ 107 | // SOUTH 108 | // 109 | m_label.x += mapValue(m_angle, 110 | -QUARTER_PI*3., -QUARTER_PI, 111 | -m_label.width, 0); 112 | m_label.y += 0.0; 113 | } else if (m_angle > QUARTER_PI*3. || m_angle < -QUARTER_PI*3. ){ 114 | // WEST 115 | // 116 | m_label.x -= m_label.width; 117 | 118 | if(m_angle > 0){ 119 | m_label.y += mapValue(m_angle, 120 | QUARTER_PI*3., PI, 121 | -m_label.height, -m_label.height*0.5); 122 | } else { 123 | m_label.y += mapValue(m_angle, 124 | -PI, -QUARTER_PI*3., 125 | -m_label.height*0.5,0.0); 126 | } 127 | } 128 | 129 | bVisible = m_anchorPoint.z >= 0.0 && m_anchorPoint.z <= 1.0; 130 | } else { 131 | bVisible = false; 132 | } 133 | }; 134 | 135 | void glmFeatureLabelPoint::draw2D(){ 136 | 137 | // 2D ancher line 138 | // 139 | // float angle = 0; 140 | // float length = 0; 141 | // 142 | // if(m_cameraPos!=0 ){ 143 | // glm::vec3 dist = *m_cameraPos - m_centroid; 144 | // length = glm::distance(*m_cameraPos, m_centroid)*0.2; 145 | // angle = (1.-glm::dot( glm::normalize( dist ), glm::vec3(0.,0.,1.))); 146 | // } 147 | // 148 | // m_offset.z = lerpValue(m_offset.z,angle*length,0.1); 149 | 150 | if(m_font != NULL){ 151 | if(m_bChanged){ 152 | updateCached(); 153 | } 154 | 155 | if (bVisible) { 156 | m_alpha = lerpValue(m_alpha, powf(m_anchorPoint.z,5), 0.1); 157 | } else { 158 | m_alpha = lerpValue(m_alpha,0.,0.1); 159 | } 160 | 161 | if(m_alpha > 0.0 && m_projectedCentroid.z > 0 && m_anchorPoint.z > 0){ 162 | // drawStippleLine(m_projectedCentroid, m_anchorPoint, 0x1111); 163 | 164 | m_font->drawString(m_fsid, m_label, m_alpha); 165 | } 166 | } 167 | } 168 | 169 | void glmFeatureLabelPoint::draw3D(){ 170 | float angle = 0; 171 | float length = 0; 172 | 173 | if(m_cameraPos!=0 ){ 174 | glm::vec3 dist = *m_cameraPos - m_centroid; 175 | length = glm::distance(*m_cameraPos, m_centroid)*0.2; 176 | angle = (1.-glm::dot( glm::normalize( dist ), glm::vec3(0.,0.,1.))); 177 | } 178 | 179 | m_offset.z = lerpValue(m_offset.z,angle*length,0.1); 180 | 181 | if(m_alpha > 0.1){ 182 | 183 | m_line.clear(); 184 | m_line.setDrawMode(LINES); 185 | m_line.addVertex(m_centroid); 186 | m_line.addVertex(m_centroid+m_offset); 187 | 188 | glColor4f(1., 1., 1., m_alpha); 189 | glEnable(GL_LINE_STIPPLE); 190 | glLineStipple(1, 0x1111); 191 | drawMesh(m_line); 192 | glDisable(GL_LINE_STIPPLE); 193 | 194 | glColor4f(1., 1., 1., 1.); 195 | } 196 | } 197 | 198 | void glmFeatureLabelPoint::drawDebug(){ 199 | 200 | glColor4f(m_font->fontColor.r, m_font->fontColor.g, m_font->fontColor.g, m_alpha); 201 | glEnable(GL_LINE_STIPPLE); 202 | glLineStipple(1, 0x1111); 203 | for (auto &it: m_anchorLines) { 204 | drawPolyline(it.getVertices()); 205 | } 206 | glDisable(GL_LINE_STIPPLE); 207 | drawCross(m_anchorPoint,3.0); 208 | 209 | if(!bVisible){ 210 | // glColor4f(m_font->colorFront.r, m_font->colorFront.g, m_font->colorFront.g,0.2); 211 | // m_label.drawCorners(); 212 | } else { 213 | glColor4f(m_font->fontColor.r, m_font->fontColor.g, m_font->fontColor.g,1.); 214 | drawCorners(getLabel(25)); 215 | } 216 | } 217 | 218 | -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmFeatureLabelPoint.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmFeatureLabelPoint.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 9/8/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include "glmFeatureLabel.h" 11 | 12 | class glmFeatureLabelPoint : public glmFeatureLabel{ 13 | public: 14 | 15 | glmFeatureLabelPoint(); 16 | glmFeatureLabelPoint(const std::string &_text); 17 | virtual ~glmFeatureLabelPoint(); 18 | 19 | void setPosition(const glm::vec3 &_pos); 20 | void setLabelAngle(const double &_radiant); 21 | void setLabelMargin(const float &_margin); 22 | 23 | glm::vec3 getScreenPosition() const; 24 | 25 | glmRectangle getLabel( const float &_marign ) const; 26 | glm::vec3 getAnchorPoint() const; 27 | 28 | bool isOver(const glmFeatureLabelPoint *_other, float _margin); 29 | bool isInside(const glm::vec3 &_point); 30 | 31 | void update(); 32 | void draw2D(); 33 | void draw3D(); 34 | 35 | void drawDebug(); 36 | 37 | glm::vec3 m_offset; 38 | glm::vec3 m_centroid; 39 | glm::vec3 m_anchorPoint; 40 | glm::vec3 m_projectedCentroid; 41 | 42 | protected: 43 | void updateCached(); 44 | 45 | glmMesh m_line; 46 | 47 | double m_angle; 48 | float m_margin; 49 | }; 50 | 51 | typedef std::tr1::shared_ptr glmFeatureLabelPointRef; -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmLabelManager.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmLabelManager.cpp 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/4/14. 6 | // 7 | // 8 | 9 | #include "glmLabelManager.h" 10 | #include 11 | 12 | glmLabelManager::glmLabelManager(): minDistance(50), maxDistance(500), bLines(true), bPoints(true), bDebugLines(false), bUpdateSegments(false), bDebugPoints(false), m_bFontChanged(true), m_bChange(true) { 13 | } 14 | 15 | glmLabelManager::~glmLabelManager(){ 16 | 17 | } 18 | 19 | void glmLabelManager::setFont(glmFont *_font){ 20 | m_font = glmFontRef(_font); 21 | m_bFontChanged = true; 22 | } 23 | 24 | void glmLabelManager::setFont(glmFontRef &_font){ 25 | m_font = _font; 26 | m_bFontChanged = true; 27 | } 28 | 29 | glmFontRef& glmLabelManager::getFont(){ 30 | return m_font; 31 | } 32 | 33 | void glmLabelManager::addLineLabel( glmFeatureLabelLineRef &_lineLabel ){ 34 | if(m_font != NULL){ 35 | _lineLabel->setFont(m_font); 36 | } 37 | _lineLabel->setCameraPos(&m_cameraPos); 38 | _lineLabel->pointLabels = &pointLabels; 39 | 40 | lineLabels.push_back(_lineLabel); 41 | m_bChange = true; 42 | 43 | // TODO: Check duplicates street names 44 | } 45 | 46 | void glmLabelManager::addPointLabel( glmFeatureLabelPointRef &_pointLabel ){ 47 | if(m_font != NULL){ 48 | _pointLabel->setFont(m_font); 49 | } 50 | _pointLabel->setCameraPos(&m_cameraPos); 51 | 52 | bool isPrev = false; 53 | for (int i = 0; i < pointLabels.size(); i++) { 54 | 55 | if(pointLabels[i]->idString == _pointLabel->idString ){ 56 | 57 | mergePointLabels(pointLabels[i],_pointLabel); 58 | 59 | isPrev = true; 60 | break; 61 | } 62 | } 63 | 64 | if(!isPrev){ 65 | pointLabels.push_back(_pointLabel); 66 | } 67 | 68 | m_bChange = true; 69 | } 70 | 71 | void glmLabelManager::mergLineLabels( glmFeatureLabelLineRef &_father, glmFeatureLabelLineRef &_child ){ 72 | 73 | } 74 | 75 | void glmLabelManager::mergePointLabels( glmFeatureLabelPointRef &_father, glmFeatureLabelPointRef &_child){ 76 | 77 | // Move shapes from _child to father 78 | // 79 | for (int i = _child->shapes.size()-1; i >= 0; i--) { 80 | _father->shapes.push_back(_child->shapes[i]); 81 | _child->shapes.erase(_child->shapes.begin()+i); 82 | } 83 | 84 | // Re center father 85 | // 86 | int maxHeight = 0; 87 | glm::vec3 center; 88 | for (auto &it: _father->shapes) { 89 | if (it[0].z > maxHeight) { 90 | maxHeight = it[0].z; 91 | } 92 | center += it.getCentroid(); 93 | } 94 | center = center / (float)_father->shapes.size(); 95 | center.z = maxHeight; 96 | _father->setPosition(center); 97 | 98 | } 99 | 100 | bool glmLabelManager::deleteLabel(const std::string &_idString){ 101 | for (int i = lineLabels.size()-1 ; i >= 0 ; i--) { 102 | if (lineLabels[i]->idString == _idString) { 103 | lineLabels.erase(lineLabels.begin()+i); 104 | break; 105 | } 106 | } 107 | 108 | for (int i = pointLabels.size()-1 ; i >= 0 ; i--) { 109 | if (pointLabels[i]->idString == _idString) { 110 | pointLabels.erase(pointLabels.begin()+i); 111 | break; 112 | } 113 | } 114 | 115 | m_bChange = true; 116 | } 117 | 118 | void glmLabelManager::updateFont(){ 119 | if(m_bFontChanged){ 120 | for (auto &it : pointLabels) { 121 | it->setFont(m_font); 122 | } 123 | 124 | for (auto &it : lineLabels) { 125 | it->setFont(m_font); 126 | } 127 | 128 | m_bFontChanged = false; 129 | } 130 | } 131 | 132 | bool depthSort(const glmFeatureLabelPointRef &_A, const glmFeatureLabelPointRef &_B){ 133 | return _A->getAnchorPoint().z < _B->getAnchorPoint().z; 134 | } 135 | 136 | void glmLabelManager::updateCameraPosition( const glm::vec3 &_pos ){ 137 | if(m_cameraPos != _pos){ 138 | m_cameraPos = _pos; 139 | m_bProjectionChanged = true; 140 | } 141 | } 142 | 143 | void glmLabelManager::updateProjection(){ 144 | 145 | if(m_bFontChanged){ 146 | updateFont(); 147 | } 148 | 149 | // Viewport change? 150 | // 151 | glm::ivec4 viewport; 152 | glGetIntegerv(GL_VIEWPORT, &viewport[0]); 153 | if(m_viewport != viewport){ 154 | m_viewport = viewport; 155 | m_bProjectionChanged = true; 156 | } 157 | 158 | glfonsUpdateViewport(m_font->getContext()); 159 | 160 | // Projection Change? New Labels? 161 | // 162 | if(m_bProjectionChanged || m_bChange ){ 163 | 164 | // Get transformation matrixes 165 | // 166 | glm::mat4x4 mvmatrix, projmatrix; 167 | glGetFloatv(GL_MODELVIEW_MATRIX, &mvmatrix[0][0]); 168 | glGetFloatv(GL_PROJECTION_MATRIX, &projmatrix[0][0]); 169 | 170 | // UPDATE POINTS 171 | // 172 | if(bPoints){ 173 | 174 | // Update Projection 175 | // 176 | for (auto &it : pointLabels) { 177 | 178 | it->m_anchorLines.clear(); 179 | if(bUpdateSegments){ 180 | for (auto &shape: it->shapes) { 181 | glmAnchorLine line; 182 | for (int i = 0; i < shape.size(); i++) { 183 | glm::vec3 v = glm::project(shape[i], mvmatrix, projmatrix, viewport); 184 | if( v.z >= 0.0 && v.z <= 1.0){ 185 | line.add(v); 186 | } 187 | } 188 | it->m_anchorLines.push_back(line); 189 | } 190 | } 191 | 192 | it->m_anchorPoint = glm::project(it->m_centroid+it->m_offset, mvmatrix, projmatrix, viewport); 193 | it->m_projectedCentroid = glm::project(it->m_centroid, mvmatrix, projmatrix, viewport); 194 | 195 | it->update(); 196 | } 197 | 198 | // Depth Sort 199 | // 200 | std::sort(pointLabels.begin(),pointLabels.end(), depthSort); 201 | 202 | // Check for oclussions 203 | // 204 | for (int i = 0; i < pointLabels.size(); i++) { 205 | if(pointLabels[i]->bVisible){ 206 | for (int j = i-1; j >= 0 ; j--) { 207 | if (pointLabels[i]->isOver( pointLabels[j].get(), minDistance ) ){ 208 | pointLabels[i]->bVisible = false; 209 | break; 210 | } 211 | } 212 | } 213 | } 214 | } else { 215 | for (auto &it : pointLabels) { 216 | it->bVisible = false; 217 | } 218 | } 219 | 220 | // LINES 221 | // 222 | if(bLines){ 223 | for (auto &it : lineLabels) { 224 | 225 | // Clear Previus computed values 226 | // 227 | it->m_anchorLines.clear(); 228 | 229 | // Project the road into 2D screen position 230 | // 231 | for (auto &iShape: it->shapes){ 232 | glmAnchorLine line; 233 | for (int i = 0; i < iShape.size(); i++) { 234 | glm::vec3 v = glm::project(iShape[i], mvmatrix, projmatrix, viewport); 235 | if( v.z >= 0.0 && v.z <= 1.0){ 236 | line.add(v); 237 | } 238 | } 239 | 240 | if(line.size()>1 && line.getLength() > 0.0 && it->m_label.width < line.getLength()){ 241 | line.originalCentroid = iShape.getCentroid(); 242 | it->m_anchorLines.push_back(line); 243 | } 244 | } 245 | 246 | // There is something to show?? 247 | // 248 | it->bVisible = it->m_anchorLines.size() > 0.0; 249 | 250 | if (it->bVisible) { 251 | 252 | // Seed the positions for line labels 253 | // 254 | for (auto &lines: it->m_anchorLines) { 255 | 256 | // Place the anchor points for the text labels 257 | // 258 | 259 | // 1. First try to place all the text inside segments 260 | // It will repeat that for each segment that have enought space. 261 | // This works great for blocks 262 | it->seedAnchorOnSegmentsAt(lines,minDistance,maxDistance); 263 | 264 | // 2. If the previus step fail, place as much labels as it can 265 | // This works better on rivers non-streight roads 266 | if (lines.marks.size() == 0) { 267 | it->seedAnchorsEvery(lines,minDistance,maxDistance); 268 | lines.bLetterByLetter = true; 269 | } 270 | } 271 | } 272 | 273 | } 274 | } else { 275 | for (auto &it : lineLabels) { 276 | it->bVisible = false; 277 | } 278 | } 279 | 280 | m_bProjectionChanged = false; 281 | m_bChange = false; 282 | } 283 | } 284 | 285 | void glmLabelManager::updateOcclusions(float *_depthBuffer, int _width, int _height){ 286 | for (auto &it : pointLabels) { 287 | if (it->bVisible) { 288 | glm::vec3 pos = it->getAnchorPoint(); 289 | 290 | if(pos.x>0 && pos.x<_width && pos.y>0 && pos.y<_height){ 291 | 292 | int index = ((int)pos.y) * _width + (int)pos.x; 293 | float depth = _depthBuffer[ index*3 ]; 294 | 295 | if(pos.z == depth){ 296 | it->bVisible = true; 297 | } else { 298 | it->bVisible = false; 299 | } 300 | } 301 | } 302 | } 303 | } 304 | 305 | void glmLabelManager::draw2D(){ 306 | 307 | glColor4f(1.,1.,1.,1.); 308 | 309 | for (auto &it : lineLabels) { 310 | if(bDebugLines){ 311 | it->drawDebug(); 312 | } 313 | it->draw2D(); 314 | } 315 | 316 | glColor4f(1.,1.,1.,1.); 317 | 318 | for (auto &it : pointLabels) { 319 | if(bDebugPoints){ 320 | it->drawDebug(); 321 | } 322 | it->draw2D(); 323 | } 324 | 325 | glColor4f(1.,1.,1.,1.); 326 | } 327 | 328 | void glmLabelManager::draw3D(){ 329 | if(bPoints){ 330 | glColor4f(1.,1.,1.,1.); 331 | for (auto &it : pointLabels) { 332 | it->draw3D(); 333 | } 334 | } 335 | } -------------------------------------------------------------------------------- /libs/glmTile/Labels/glmLabelManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmLabelManager.h 3 | // Labeling 4 | // 5 | // Created by Patricio Gonzalez Vivo on 9/4/14. 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include "glmTile.h" 12 | #include "glmFeatureLabelLine.h" 13 | #include "glmFeatureLabelPoint.h" 14 | 15 | #include "glmFont.h" 16 | class glmLabelManager { 17 | public: 18 | 19 | glmLabelManager(); 20 | virtual ~glmLabelManager(); 21 | 22 | void setFont(glmFont *_font); 23 | void setFont(glmFontRef &_font); 24 | 25 | glmFontRef& getFont(); 26 | 27 | void addLineLabel( glmFeatureLabelLineRef &_lineLabel ); 28 | void addPointLabel( glmFeatureLabelPointRef &_pointLabel ); 29 | 30 | bool deleteLabel(const std::string &_idString); 31 | 32 | void mergLineLabels( glmFeatureLabelLineRef &_father, glmFeatureLabelLineRef &_child ); 33 | void mergePointLabels( glmFeatureLabelPointRef &_father, glmFeatureLabelPointRef &_child); 34 | 35 | void updateFont(); 36 | void updateProjection(); 37 | void updateCameraPosition( const glm::vec3 &_pos ); 38 | void updateOcclusions(float *_depthBuffer, int _width, int _height); 39 | 40 | void draw2D(); 41 | void draw3D(); 42 | 43 | std::vector lineLabels; 44 | std::vector pointLabels; 45 | 46 | float minDistance, maxDistance; 47 | 48 | bool bLines; 49 | bool bPoints; 50 | 51 | bool bUpdateSegments; 52 | 53 | bool bDebugLines; 54 | bool bDebugPoints; 55 | 56 | protected: 57 | 58 | glmFontRef m_font; 59 | 60 | glm::ivec4 m_viewport; 61 | glm::vec3 m_cameraPos; 62 | 63 | bool m_bFontChanged; 64 | bool m_bProjectionChanged; 65 | bool m_bChange; 66 | }; -------------------------------------------------------------------------------- /libs/glmTile/glmFeature.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmTileFeature.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 8/27/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | // TODO: use default one 11 | // 12 | //#include 13 | #include 14 | 15 | #include "glmString.h" 16 | #include "glmPolyline.h" 17 | #include "glmMesh.h" 18 | 19 | class glmFeature : public glmMesh { 20 | public: 21 | 22 | glmFeature(){}; 23 | virtual ~glmFeature(){}; 24 | 25 | std::vector shapes; 26 | std::string idString; 27 | 28 | protected: 29 | 30 | }; 31 | 32 | typedef std::tr1::shared_ptr glmFeatureRef; -------------------------------------------------------------------------------- /libs/glmTile/glmGeometryBuilder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmGeometryBuilder.cpp 3 | // 4 | // Created by Patricio Gonzalez Vivo on 9/4/14. 5 | // 6 | // 7 | 8 | #include "glmGeometryBuilder.h" 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "glmGeo.h" 17 | #include "glmGeom.h" 18 | #include "glmString.h" 19 | #include "glmTesselation.h" 20 | 21 | //write_data call back from CURLOPT_WRITEFUNCTION 22 | //responsible to read and fill "stream" with the data. 23 | size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) { 24 | std::string data((const char*) ptr, (size_t) size*nmemb); 25 | *((std::stringstream*) stream) << data; 26 | return size*nmemb; 27 | } 28 | 29 | std::string getURL(const std::string& url) { 30 | CURL * curl = curl_easy_init(); 31 | 32 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 33 | /* example.com is redirected, so we tell libcurl to follow redirection */ 34 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 35 | curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug 36 | curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate"); 37 | std::stringstream out; 38 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 39 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); 40 | /* Perform the request, res will get the return code */ 41 | CURLcode res = curl_easy_perform(curl); 42 | /* Check for errors */ 43 | if (res != CURLE_OK) { 44 | fprintf(stderr, "curl_easy_perform() failed: %s\n", 45 | curl_easy_strerror(res)); 46 | } 47 | return out.str(); 48 | } 49 | 50 | glmGeometryBuilder::glmGeometryBuilder():m_geometryOffset(0.0,0.0,0.0),lineWidth(5.5),labelManager(NULL),m_bFirst(true){ 51 | LayerColorPalette["earth"] = glm::vec4(0.5,0.5,0.5,1.0); 52 | LayerColorPalette["landuse"] = glm::vec4(0.0,0.7,0.0,1.0); 53 | LayerColorPalette["water"] = glm::vec4(0.0,0.0,0.9,1.0); 54 | LayerColorPalette["buildings"] = glm::vec4(0.9,0.9,0.5,1.0); 55 | LayerColorPalette["places"] = glm::vec4(1.0,0.0,0.0,1.0); 56 | LayerColorPalette["roads"] = glm::vec4(0.1,0.1,0.1,1.0); 57 | LayerColorPalette["pois"] = glm::vec4(1.0,0.1,0.1,1.0); 58 | } 59 | 60 | glmGeometryBuilder::~glmGeometryBuilder(){ 61 | }; 62 | 63 | void glmGeometryBuilder::setLabelManager(glmLabelManager *_lm){ 64 | labelManager = _lm; 65 | } 66 | 67 | void glmGeometryBuilder::setOffset(glm::vec3 _offset){ 68 | m_geometryOffset = _offset; 69 | } 70 | 71 | void glmGeometryBuilder::setOffset(int _tileX, int _tileY, int _zoom){ 72 | m_geometryOffset = tile2xy(_tileX, _tileY, _zoom); 73 | } 74 | 75 | glm::vec3 glmGeometryBuilder::getPointAt(double _lat, double _lon, double _alt){ 76 | return glm::vec3(lon2x(_lon), 77 | lat2y(_lat),_alt)-m_geometryOffset; 78 | } 79 | 80 | void glmGeometryBuilder::load(int _tileX, int _tileY, int _zoom, glmTile &_tile){ 81 | // TODO: get JSON file from the web 82 | // 83 | std::string tmp = getURL("http://vector.mapzen.com/osm/all/"+ getString(_zoom)+"/" + getString(_tileX) + "/" + getString(_tileY)+".json"); 84 | 85 | std::tr1::shared_ptr jsonVal(new Json::Value); 86 | 87 | int length = tmp.size(); 88 | Json::Reader jsonReader; 89 | jsonReader.parse(tmp.c_str(), tmp.c_str() + length, *(jsonVal.get())); 90 | 91 | _tile.tileX = _tileX; 92 | _tile.tileY = _tileY; 93 | _tile.zoom = _zoom; 94 | load( *(jsonVal.get()), _tile ); 95 | 96 | } 97 | 98 | void glmGeometryBuilder::load(Json::Value &_jsonRoot, glmTile & _tile){ 99 | 100 | // Generate the geometries for these layers... 101 | // ... also record those that have labels. 102 | // 103 | buildLayer(_jsonRoot, "earth", _tile, 0.0); 104 | buildLayer(_jsonRoot, "landuse", _tile, .1); 105 | 106 | buildLayer(_jsonRoot, "water", _tile, .2); 107 | buildLayer(_jsonRoot, "buildings", _tile, .3); 108 | 109 | buildLayer(_jsonRoot, "places", _tile, .4); 110 | buildLayer(_jsonRoot, "roads", _tile, .5); 111 | buildLayer(_jsonRoot, "pois", _tile, .6); 112 | 113 | // Until the data from the server provides buildings parts 114 | // merge buildings (both important for have smarter labels) 115 | // 116 | // for (auto &pointLabel: _tile.labeledPoints) { 117 | // 118 | // for(int i = _tile.byLayers["buildings"].size()-1; i >= 0; i-- ){ 119 | // if (pointLabel.get() != NULL 120 | // && _tile.byLayers["buildings"][i].get() != NULL 121 | // && pointLabel.get() != _tile.byLayers["buildings"][i].get() ) { 122 | // 123 | // bool bOverlap = false; 124 | // 125 | // for (auto &it: _tile.byLayers["buildings"][i]->shapes ) { 126 | // glm::vec3 centroid = it.getCentroid(); 127 | // for (auto &jt: pointLabel->shapes){ 128 | // if( jt.isInside(centroid.x, centroid.y) ){ 129 | // bOverlap = true; 130 | // break; 131 | // } 132 | // } 133 | // 134 | // if(bOverlap){ 135 | // break; 136 | // } 137 | // } 138 | // 139 | // if(bOverlap){ 140 | // mergeFeature(pointLabel, _tile.byLayers["buildings"][i]); 141 | // 142 | // // Erase the merged geometry 143 | // // 144 | // deleteFeature(_tile, _tile.byLayers["buildings"][i]->idString); 145 | // } 146 | // 147 | // } 148 | // 149 | // } 150 | // 151 | // int maxHeight = 0; 152 | // glm::vec3 center; 153 | // for (auto &it: pointLabel->shapes) { 154 | // if (it[0].z > maxHeight) { 155 | // maxHeight = it[0].z; 156 | // } 157 | // center += it.getCentroid(); 158 | // } 159 | // center = center / (float)pointLabel->shapes.size(); 160 | // center.z = maxHeight; 161 | // pointLabel->setPosition(center); 162 | // } 163 | } 164 | 165 | glm::vec3 glmGeometryBuilder::getOffset(){ 166 | return m_geometryOffset; 167 | } 168 | 169 | glmTile glmGeometryBuilder::getFromFile(std::string _filename){ 170 | 171 | std::ifstream inputStream(_filename.c_str(),std::ifstream::in); 172 | if(inputStream.bad()){ 173 | return glmTile(); 174 | } 175 | 176 | Json::Reader jsonReader; 177 | Json::Value m_jsonRoot; 178 | 179 | if (!jsonReader.parse(inputStream, m_jsonRoot)) { 180 | return glmTile(); 181 | } 182 | 183 | glmTile newTile; 184 | load(m_jsonRoot, newTile); 185 | return newTile; 186 | } 187 | 188 | void glmGeometryBuilder::mergeFeature(const glmFeatureRef &_father, const glmFeatureRef &_child){ 189 | 190 | if( _father.get() != NULL 191 | && _child.get() != NULL 192 | && _father.get() != _child.get() ){ 193 | 194 | if(_father->idString != _child->idString){ 195 | for (auto &it: _child->shapes) { 196 | _father->shapes.push_back(it); 197 | } 198 | _child->shapes.clear(); 199 | _father->add( *((glmMesh*)_child.get()) ); 200 | } 201 | } 202 | } 203 | 204 | void glmGeometryBuilder::deleteFeature( glmTile &_tile, const std::string &_idString ){ 205 | 206 | for (auto &layer: _tile.byLayers ) { 207 | for (int i = layer.second.size()-1 ; i >= 0 ; i--) { 208 | if (layer.second[i]->idString == _idString) { 209 | layer.second.erase(layer.second.begin()+i); 210 | break; 211 | } 212 | } 213 | } 214 | 215 | for (int i = _tile.labeledFeatures.size()-1 ; i >= 0 ; i--) { 216 | if (_tile.labeledFeatures[i]->idString == _idString) { 217 | _tile.labeledFeatures.erase(_tile.labeledFeatures.begin()+i); 218 | break; 219 | } 220 | } 221 | 222 | for (int i = _tile.labeledLines.size()-1 ; i >= 0 ; i--) { 223 | if (_tile.labeledLines[i]->idString == _idString) { 224 | _tile.labeledLines.erase(_tile.labeledLines.begin()+i); 225 | break; 226 | } 227 | } 228 | 229 | for (int i = _tile.labeledPoints.size()-1 ; i >= 0 ; i--) { 230 | if (_tile.labeledPoints[i]->idString == _idString) { 231 | _tile.labeledPoints.erase(_tile.labeledPoints.begin()+i); 232 | break; 233 | } 234 | } 235 | 236 | if(labelManager!=NULL){ 237 | labelManager->deleteLabel(_idString); 238 | } 239 | } 240 | 241 | glmTile glmGeometryBuilder::getFromWeb(int _tileX, int _tileY, int _zoom){ 242 | 243 | if(m_bFirst){ 244 | setOffset(_tileX,_tileY,_zoom); 245 | m_bFirst = false; 246 | } 247 | 248 | glmTile newTile; 249 | load(_tileX, _tileY,_zoom,newTile); 250 | return newTile; 251 | } 252 | 253 | glmTile glmGeometryBuilder::getFromWeb(double _lat, double _lon, int _zoom){ 254 | int tileX = long2tilex(_lon, _zoom); 255 | int tileY = lat2tiley(_lat, _zoom); 256 | 257 | if(m_bFirst){ 258 | setOffset(tileX,tileY,_zoom); 259 | m_bFirst = false; 260 | } 261 | 262 | glmTile newTile; 263 | glmGeometryBuilder::load(tileX,tileY,_zoom,newTile); 264 | return newTile; 265 | } 266 | 267 | void glmGeometryBuilder::buildLayer(Json::Value &_jsonRoot, const std::string &_layerName, glmTile &_tile, float _minHeight) { 268 | 269 | Json::Value featureListJson = _jsonRoot[_layerName.c_str()]["features"]; 270 | 271 | for (int i = 0; i < featureListJson.size(); i++) { 272 | 273 | // Extract properties 274 | // 275 | Json::Value geometryJson = featureListJson[i]["geometry"]; 276 | std::string geometryType = geometryJson["type"].asString(); 277 | Json::Value propsJson = featureListJson[i]["properties"]; 278 | 279 | float height = _minHeight; 280 | if (propsJson.isMember("height")) 281 | height += propsJson["height"].asFloat(); 282 | 283 | float minHeight = _minHeight; 284 | if (propsJson.isMember("min_height")) 285 | minHeight += propsJson["min_height"].asFloat(); 286 | 287 | 288 | glmFeatureRef feature(new glmFeature()); 289 | glmPolyline polyline; 290 | 291 | // Parse geometry into feature 292 | // 293 | if (geometryType.compare("Point") == 0) { 294 | 295 | // PARSE POINT 296 | // 297 | 298 | if (propsJson.isMember("name") && labelManager != NULL) { 299 | 300 | glmFeatureLabelPointRef labelRef(new glmFeatureLabelPoint( propsJson["name"].asString() )); 301 | labelRef->setFont(labelManager->getFont()); 302 | glm::vec3 pos = glm::vec3(lon2x(geometryJson["coordinates"][0].asFloat()), 303 | lat2y(geometryJson["coordinates"][1].asFloat()), 304 | _minHeight) - m_geometryOffset; 305 | 306 | labelRef->setPosition( pos ); 307 | 308 | _tile.labeledFeatures.push_back(labelRef); 309 | _tile.labeledPoints.push_back(labelRef); 310 | 311 | labelRef->idString = featureListJson[i]["id"].asString(); 312 | 313 | polyline.add(pos); 314 | labelRef->shapes.push_back(polyline); 315 | 316 | if(labelManager!=NULL){ 317 | labelManager->addPointLabel(labelRef); 318 | } 319 | 320 | feature = labelRef; 321 | } else { 322 | feature->shapes.push_back(polyline); 323 | } 324 | 325 | pointJson2Mesh(geometryJson["coordinates"], *feature, 3, 6, minHeight); 326 | 327 | } else if (geometryType.compare("MultiPoint") == 0) { 328 | 329 | // PARSE MULTI-POINT 330 | // 331 | if (propsJson.isMember("name") && labelManager != NULL) { 332 | 333 | glmFeatureLabelPointRef labelRef(new glmFeatureLabelPoint(propsJson["name"].asString())); 334 | 335 | for (int j = 0; j < geometryJson["coordinates"].size(); j++) { 336 | 337 | glm::vec3 pos = glm::vec3(lon2x(geometryJson["coordinates"][j][0].asFloat()), 338 | lat2y(geometryJson["coordinates"][j][1].asFloat()), 339 | _minHeight) - m_geometryOffset; 340 | polyline.add(pos); 341 | } 342 | 343 | labelRef->setPosition( polyline.getCentroid() ); 344 | labelRef->setFont(labelManager->getFont()); 345 | 346 | _tile.labeledFeatures.push_back(labelRef); 347 | _tile.labeledPoints.push_back(labelRef); 348 | 349 | labelRef->idString = featureListJson[i]["id"].asString(); 350 | labelRef->shapes.push_back(polyline); 351 | if(labelManager!=NULL){ 352 | labelManager->addPointLabel(labelRef); 353 | } 354 | 355 | feature = labelRef; 356 | } else { 357 | feature->shapes.push_back(polyline); 358 | } 359 | 360 | for (int j = 0; j < geometryJson["coordinates"].size(); j++) { 361 | pointJson2Mesh(geometryJson["coordinates"][j], *feature, 3.0, 6, minHeight); 362 | } 363 | 364 | } else if (geometryType.compare("LineString") == 0) { 365 | 366 | // PARSE LINE STRING 367 | // 368 | lineJson2Polyline(geometryJson["coordinates"],polyline, minHeight); 369 | 370 | if (propsJson.isMember("name") && labelManager != NULL) { 371 | glmFeatureLabelLineRef labelRef(new glmFeatureLabelLine(propsJson["name"].asString())); 372 | 373 | _tile.labeledFeatures.push_back(labelRef); 374 | _tile.labeledLines.push_back(labelRef); 375 | 376 | labelRef->setFont(labelManager->getFont()); 377 | labelRef->idString = featureListJson[i]["id"].asString(); 378 | labelRef->shapes.push_back(polyline); 379 | if(labelManager!=NULL){ 380 | labelManager->addLineLabel(labelRef); 381 | } 382 | 383 | feature = labelRef; 384 | } else { 385 | feature->shapes.push_back(polyline); 386 | } 387 | 388 | // feature->add(polyline,lineWidth); 389 | flatLine(*feature, polyline, lineWidth); 390 | 391 | } else if (geometryType.compare("MultiLineString") == 0) { 392 | 393 | // PARSE MULTI-LINE STRING 394 | // 395 | if (propsJson.isMember("name") && labelManager != NULL) { 396 | 397 | glmFeatureLabelLineRef labelRef(new glmFeatureLabelLine( propsJson["name"].asString() )); 398 | 399 | _tile.labeledFeatures.push_back(labelRef); 400 | _tile.labeledLines.push_back(labelRef); 401 | 402 | labelRef->setFont(labelManager->getFont()); 403 | labelRef->idString = featureListJson[i]["id"].asString(); 404 | 405 | for (int j = 0; j < geometryJson["coordinates"].size(); j++) { 406 | polyline.clear(); 407 | lineJson2Polyline(geometryJson["coordinates"][j],polyline,minHeight); 408 | labelRef->shapes.push_back(polyline); 409 | } 410 | 411 | if(labelManager!=NULL){ 412 | labelManager->addLineLabel(labelRef); 413 | } 414 | 415 | feature = labelRef; 416 | } else { 417 | for (int j = 0; j < geometryJson["coordinates"].size(); j++) { 418 | polyline.clear(); 419 | lineJson2Polyline(geometryJson["coordinates"][j],polyline,minHeight); 420 | feature->shapes.push_back(polyline); 421 | 422 | } 423 | } 424 | 425 | // feature->add(polyline,lineWidth); 426 | flatLine(*feature, polyline, lineWidth); 427 | 428 | } else if (geometryType.compare("Polygon") == 0) { 429 | 430 | // PARSE POLYGON 431 | // 432 | lineJson2Polyline(geometryJson["coordinates"][0],polyline, height); 433 | 434 | if (propsJson.isMember("name") && labelManager != NULL) { 435 | glmFeatureLabelPointRef labelRef(new glmFeatureLabelPoint(propsJson["name"].asString())); 436 | 437 | labelRef->setFont(labelManager->getFont()); 438 | labelRef->setPosition(polyline.getCentroid()); 439 | 440 | _tile.labeledFeatures.push_back(labelRef); 441 | _tile.labeledPoints.push_back(labelRef); 442 | 443 | labelRef->idString = featureListJson[i]["id"].asString(); 444 | labelRef->shapes.push_back(polyline); 445 | if(labelManager!=NULL){ 446 | labelManager->addPointLabel(labelRef); 447 | } 448 | 449 | feature = labelRef; 450 | } else { 451 | feature->shapes.push_back(polyline); 452 | } 453 | 454 | polygonJson2Mesh(geometryJson["coordinates"], *feature, minHeight, height); 455 | 456 | } else if (geometryType.compare("MultiPolygon") == 0) { 457 | 458 | lineJson2Polyline(geometryJson["coordinates"][0][0], polyline, height); 459 | 460 | if (propsJson.isMember("name") && labelManager != NULL) { 461 | glmFeatureLabelPointRef labelRef(new glmFeatureLabelPoint(propsJson["name"].asString())); 462 | 463 | labelRef->setFont(labelManager->getFont()); 464 | labelRef->setPosition( polyline.getCentroid() ); 465 | 466 | _tile.labeledFeatures.push_back(labelRef); 467 | _tile.labeledPoints.push_back(labelRef); 468 | 469 | labelRef->idString = featureListJson[i]["id"].asString(); 470 | for (int j = 0; j < geometryJson["coordinates"].size(); j++) { 471 | 472 | polyline.clear(); 473 | lineJson2Polyline(geometryJson["coordinates"][j][0], polyline, height); 474 | labelRef->shapes.push_back(polyline); 475 | 476 | polygonJson2Mesh(geometryJson["coordinates"][j], *feature, minHeight, height); 477 | } 478 | 479 | if(labelManager!=NULL){ 480 | labelManager->addPointLabel(labelRef); 481 | } 482 | 483 | feature = labelRef; 484 | } else { 485 | for (int j = 0; j < geometryJson["coordinates"].size(); j++) { 486 | 487 | polyline.clear(); 488 | lineJson2Polyline(geometryJson["coordinates"][j][0], polyline, height); 489 | feature->shapes.push_back(polyline); 490 | 491 | polygonJson2Mesh(geometryJson["coordinates"][j], *feature, minHeight, height); 492 | } 493 | } 494 | 495 | } else if (geometryType.compare("GeometryCollection") == 0) { 496 | 497 | // PARSE GEOMETRY-COLLECTION 498 | // 499 | 500 | // TODO 501 | std::cout << "TODO: GeometryCollection" << std::endl; 502 | } 503 | 504 | // Assign color based on Layer name 505 | // 506 | feature->setColor(LayerColorPalette[_layerName]); 507 | feature->idString = featureListJson[i]["id"].asString(); 508 | 509 | // Save the share pointer into 2 maps organiced by ID and LAYER 510 | // 511 | _tile.byLayers[_layerName].push_back(feature); 512 | } 513 | } 514 | 515 | //--------------------------------------------------------------------------- 516 | 517 | void glmGeometryBuilder::lineJson2Polyline(Json::Value &lineJson, glmPolyline &_poly, float _minHeight){ 518 | for (int i = 0; i < lineJson.size(); i++) { 519 | _poly.add(glm::vec3(lon2x(lineJson[i][0].asFloat()), 520 | lat2y(lineJson[i][1].asFloat()), 521 | _minHeight) - m_geometryOffset); 522 | } 523 | } 524 | 525 | //--------------------------------------------------------------------------- 526 | 527 | void glmGeometryBuilder::pointJson2Mesh(Json::Value &_lineJson, glmMesh &_mesh, float _radius, int _sides, float _minHeight){ 528 | 529 | glm::vec3 p(lon2x(_lineJson[0].asFloat()), 530 | lat2y(_lineJson[1].asFloat()), 531 | _minHeight); 532 | p -= m_geometryOffset; 533 | 534 | // make a circle 535 | // TODO: add this to polyline; 536 | // 537 | float angle = 0.0f; 538 | float jump = TWO_PI/(float)_sides; 539 | glmPolyline polyline; 540 | for(int i = 0; i < _sides; i++){ 541 | polyline.add(glm::vec3(p.x+_radius*cos(angle), 542 | p.y+_radius*sin(angle), 543 | _minHeight)); 544 | angle += jump; 545 | } 546 | _mesh.add( getMesh(polyline) ); 547 | } 548 | 549 | //--------------------------------------------------------------------------- 550 | void glmGeometryBuilder::polygonJson2Mesh(Json::Value &polygonJson, glmMesh &_mesh, float _minHeight, float _height) { 551 | uint16_t indexOffset = (uint16_t)_mesh.getVertices().size(); // track indices 552 | 553 | // Go through the Json polygons making walls and adding it to the tessalator 554 | // 555 | std::vector rings; 556 | 557 | for (int i = 0; i < polygonJson.size(); i++) { 558 | 559 | glmPolyline ringCoords; 560 | lineJson2Polyline(polygonJson[i],ringCoords,_height); 561 | 562 | // Extrude polygon based on height 563 | if (_height != _minHeight){ 564 | 565 | glm::vec3 tan, nor; 566 | 567 | for (int i = 0; i < ringCoords.size() - 1; i++) { 568 | 569 | //For each vertex in the polygon, make two triangles to form a quad 570 | // 571 | glm::vec3 ip0 = ringCoords[i]; 572 | glm::vec3 ip1 = ringCoords[i+1]; 573 | 574 | tan = ringCoords[i+1] - ringCoords[i]; 575 | nor = glm::cross(UP_NORMAL, tan); 576 | nor = nor; 577 | 578 | _mesh.addTexCoord(glm::vec2(1.,0.)); 579 | _mesh.addVertex(ip0); 580 | _mesh.addNormal(nor); 581 | _mesh.addTexCoord(glm::vec2(0.,0.)); 582 | _mesh.addVertex(ip1); 583 | _mesh.addNormal(nor); 584 | 585 | _mesh.addTexCoord(glm::vec2(1.,1.)); 586 | _mesh.addVertex(ip0+glm::vec3(0.,0.,_minHeight - _height - m_geometryOffset.z)); 587 | _mesh.addNormal(nor); 588 | _mesh.addTexCoord(glm::vec2(0.,1.)); 589 | _mesh.addVertex(ip1+glm::vec3(0.,0.,_minHeight - _height - m_geometryOffset.z)); 590 | _mesh.addNormal(nor); 591 | 592 | _mesh.addIndex(indexOffset); 593 | _mesh.addIndex(indexOffset + 2); 594 | _mesh.addIndex(indexOffset + 1); 595 | 596 | _mesh.addIndex(indexOffset + 1); 597 | _mesh.addIndex(indexOffset + 2); 598 | _mesh.addIndex(indexOffset + 3); 599 | indexOffset += 4; 600 | } 601 | } 602 | 603 | rings.push_back(ringCoords); 604 | } 605 | 606 | _mesh.add( getMesh(rings) ); 607 | } 608 | -------------------------------------------------------------------------------- /libs/glmTile/glmGeometryBuilder.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmGeometryBuilder.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 9/4/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | //#include 11 | #include "json/json.h" 12 | 13 | #include "glmTile.h" 14 | #include "glmLabelManager.h" 15 | 16 | class glmGeometryBuilder { 17 | public: 18 | 19 | glmGeometryBuilder(); 20 | virtual ~glmGeometryBuilder(); 21 | 22 | static glmGeometryBuilder* GetInstance() { 23 | static glmGeometryBuilder *instance = new glmGeometryBuilder(); 24 | return instance; 25 | } 26 | 27 | // Setting up 28 | // 29 | void setOffset(glm::vec3 _center); 30 | void setOffset(int _tileX, int _tileY, int _zoom); 31 | void setLabelManager(glmLabelManager *_lm); 32 | 33 | // Loading the data 34 | // 35 | void load(int _tileX, int _tileY, int _zoom, glmTile &_tile); 36 | void load(Json::Value &_jsonRoot, glmTile &_tile); 37 | glmTile getFromFile(std::string _fileName); 38 | glmTile getFromWeb(int _tileX, int _tileY, int _zoom); 39 | glmTile getFromWeb(double _lat, double _lon, int _zoom); 40 | 41 | glm::vec3 getOffset(); 42 | glm::vec3 getPointAt(double _lat, double _lon, double _alt = 0); 43 | 44 | void mergeFeature(const glmFeatureRef &_father, const glmFeatureRef &_child); 45 | void deleteFeature( glmTile &_tile, const std::string &_idString ); 46 | 47 | std::map< std::string, glm::vec4 > LayerColorPalette; 48 | 49 | float lineWidth; 50 | 51 | protected: 52 | 53 | void buildLayer(Json::Value &_jsonRoot, const std::string &_layerName, glmTile &_tile, float _minHeight = 0.); 54 | 55 | // Mesh constructors 56 | // 57 | void lineJson2Polyline(Json::Value &_lineJson, glmPolyline &_poly, float _minHeight = 0.); 58 | void pointJson2Mesh(Json::Value &_lineJson, glmMesh &_mesh, float _radius, int _sides = 6, float _minHeight = 0.); 59 | void polygonJson2Mesh(Json::Value &_polygonJson, glmMesh &_mesh, float _minHeight, float _height); 60 | 61 | glm::vec3 m_geometryOffset; 62 | 63 | glmLabelManager *labelManager; 64 | 65 | bool m_bFirst; 66 | }; -------------------------------------------------------------------------------- /libs/glmTile/glmTile.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // glmTile.cpp 3 | // 4 | // Created by Patricio Gonzalez Vivo on 8/27/14. 5 | // 6 | // 7 | 8 | #include "glmTile.h" 9 | 10 | glmTile::glmTile():tileX(-1), tileY(-1), zoom(-1){ 11 | } 12 | 13 | glmTile::~glmTile(){ 14 | byLayers.clear(); 15 | labeledFeatures.clear(); 16 | labeledLines.clear(); 17 | labeledPoints.clear(); 18 | } 19 | 20 | glmMesh glmTile::getMeshFor(const std::string &_layerName){ 21 | glmMesh mesh; 22 | for (auto &it : byLayers[_layerName]){ 23 | mesh.add( *it ); 24 | } 25 | return mesh; 26 | } 27 | 28 | glmMesh glmTile::getMeshFor(const std::vector< std::string > &_layersNames){ 29 | glmMesh mesh; 30 | for (auto &it : _layersNames ) { 31 | mesh.add(getMeshFor(it)); 32 | } 33 | return mesh; 34 | } 35 | 36 | glmMesh glmTile::getMesh(){ 37 | glmMesh mesh; 38 | for (auto &it : byLayers ){ 39 | mesh.add( getMeshFor(it.first) ); 40 | } 41 | return mesh; 42 | } -------------------------------------------------------------------------------- /libs/glmTile/glmTile.h: -------------------------------------------------------------------------------- 1 | // 2 | // glmTile.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 8/27/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #include "glmFeature.h" 13 | //#include "glmFeatureLabel.h" 14 | #include "glmFeatureLabelLine.h" 15 | #include "glmFeatureLabelPoint.h" 16 | 17 | class glmTile { 18 | public: 19 | 20 | glmTile(); 21 | virtual ~glmTile(); 22 | 23 | glmMesh getMesh(); 24 | glmMesh getMeshFor(const std::string &_layerName); 25 | glmMesh getMeshFor(const std::vector< std::string > &_layersNames); 26 | 27 | std::map< std::string, std::vector > byLayers; 28 | 29 | std::vector labeledFeatures; 30 | std::vector labeledLines; // Usualy Roads 31 | std::vector labeledPoints; 32 | 33 | int tileX, tileY, zoom; 34 | }; -------------------------------------------------------------------------------- /ofxaddons_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangrams/ofxVectorTile/5b38fc6660d932856b30056a5d3960a8464bf005/ofxaddons_thumbnail.png -------------------------------------------------------------------------------- /src/ofxVectorBuilder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorBuilder.cpp 3 | // 4 | // Created by Patricio Gonzalez Vivo on 10/10/14. 5 | // 6 | // 7 | 8 | #include "ofxVectorBuilder.h" 9 | 10 | #include "ofxGlm.h" 11 | #include "ofxGlmTools.h" 12 | 13 | ofxVectorBuilder::ofxVectorBuilder(){ 14 | 15 | } 16 | 17 | ofxVectorBuilder::~ofxVectorBuilder(){ 18 | 19 | } 20 | 21 | ofPoint ofxVectorBuilder::getOffset(){ 22 | return toOf(glmGeometryBuilder::getOffset()); 23 | } 24 | 25 | ofPoint ofxVectorBuilder::getPointAt(double _lat, double _lon, double _alt){ 26 | return toOf(glmGeometryBuilder::getPointAt(_lat, _lon, _alt)); 27 | } 28 | 29 | ofMesh ofxVectorBuilder::getMesh(int _tileX, int _tileY, int _zoom){ 30 | return toOf( getFromWeb(_tileX, _tileY, _zoom).getMesh() ); 31 | } 32 | 33 | ofMesh ofxVectorBuilder::getMesh(double _lat, double _lon, int _zoom){ 34 | return toOf( getFromWeb(_lat,_lon,_zoom).getMesh() ); 35 | } 36 | -------------------------------------------------------------------------------- /src/ofxVectorBuilder.h: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorBuilder.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 10/10/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include "ofMain.h" 11 | #include "glmGeometryBuilder.h" 12 | 13 | class ofxVectorBuilder : public glmGeometryBuilder { 14 | public: 15 | 16 | ofxVectorBuilder(); 17 | virtual ~ofxVectorBuilder(); 18 | 19 | ofPoint getOffset(); 20 | ofPoint getPointAt(double _lat, double _lon, double _alt = 0); 21 | 22 | ofMesh getMesh(int _tileX, int _tileY, int _zoom); 23 | ofMesh getMesh(double _lat, double _lon, int _zoom); 24 | 25 | private: 26 | }; -------------------------------------------------------------------------------- /src/ofxVectorLabels.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorLabel.cpp 3 | // example 4 | // 5 | // Created by Patricio Gonzalez Vivo on 10/10/14. 6 | // 7 | // 8 | 9 | #include "ofxVectorLabels.h" 10 | 11 | #include "ofxGlm.h" 12 | 13 | #include "glmFont.h" 14 | 15 | ofxVectorLabels::ofxVectorLabels(){ 16 | 17 | } 18 | 19 | ofxVectorLabels::~ofxVectorLabels(){ 20 | 21 | } 22 | 23 | void ofxVectorLabels::setFontColor( const ofFloatColor &_front, const ofFloatColor &_back ){ 24 | m_font->outlineColor = glm::vec3(_back.r, _back.g, _back.b); 25 | m_font->fontColor = glm::vec3(_front.r, _front.g, _front.b); 26 | } 27 | 28 | void ofxVectorLabels::updateCameraPosition( const ofPoint &_camPos ){ 29 | glmLabelManager::updateCameraPosition( toGlm(_camPos) ); 30 | } 31 | 32 | void ofxVectorLabels::updateProjection(){ 33 | ofPushMatrix(); 34 | // ofScale(1, -1, 1); 35 | glmLabelManager::updateProjection(); 36 | ofPopMatrix(); 37 | } 38 | 39 | void ofxVectorLabels::loadFont(const string &_font, int _size){ 40 | glmFontRef tmpFont = glmFontRef(new glmFont()); 41 | tmpFont->loadFont(ofToDataPath(_font), _size); 42 | setFont(tmpFont); 43 | } 44 | -------------------------------------------------------------------------------- /src/ofxVectorLabels.h: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorLabel.h 3 | // example 4 | // 5 | // Created by Patricio Gonzalez Vivo on 10/10/14. 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include "ofMain.h" 12 | #include "glmLabelManager.h" 13 | 14 | class ofxVectorLabels: public glmLabelManager { 15 | public: 16 | 17 | ofxVectorLabels(); 18 | virtual ~ofxVectorLabels(); 19 | 20 | void setFontColor( const ofFloatColor &_front, const ofFloatColor &_back ); 21 | void loadFont( const string &_font, int _size); 22 | 23 | void updateCameraPosition( const ofPoint &_camPos ); 24 | void updateProjection(); 25 | }; -------------------------------------------------------------------------------- /src/ofxVectorTile.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorTile.cpp 3 | // example 4 | // 5 | // Created by Patricio Gonzalez Vivo on 11/10/14. 6 | // 7 | // 8 | 9 | #include "ofxVectorTile.h" 10 | 11 | #include "ofxGlm.h" 12 | #include "ofxGlmTools.h" 13 | 14 | ofxVectorTile::ofxVectorTile(){ 15 | 16 | } 17 | 18 | ofxVectorTile::~ofxVectorTile(){ 19 | 20 | } 21 | 22 | ofxVectorTile& ofxVectorTile::operator = (const glmTile &_tile){ 23 | byLayers.clear(); 24 | labeledFeatures.clear(); 25 | labeledLines.clear(); 26 | labeledPoints.clear(); 27 | 28 | byLayers = _tile.byLayers; 29 | labeledFeatures = _tile.labeledFeatures; 30 | labeledLines = _tile.labeledLines; 31 | labeledPoints = _tile.labeledPoints; 32 | } 33 | 34 | ofMesh ofxVectorTile::getMesh(){ 35 | return toOf(glmTile::getMesh()); 36 | } 37 | 38 | ofMesh ofxVectorTile::getMeshFor(const std::string &_layerName){ 39 | return toOf(glmTile::getMeshFor(_layerName)); 40 | } 41 | 42 | ofMesh ofxVectorTile::getMeshFor(const std::vector< std::string > &_layersNames){ 43 | return toOf(glmTile::getMeshFor(_layersNames)); 44 | } 45 | 46 | void ofxVectorTile::draw(){ 47 | for (auto &layer : byLayers ){ 48 | for( auto &feature : layer.second ){ 49 | drawMesh(*feature); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/ofxVectorTile.h: -------------------------------------------------------------------------------- 1 | // 2 | // ofxVectorTile.h 3 | // 4 | // Created by Patricio Gonzalez Vivo on 11/10/14. 5 | // 6 | // 7 | 8 | #pragma once 9 | 10 | #include "ofMain.h" 11 | #include "glmTile.h" 12 | 13 | class ofxVectorTile : public glmTile { 14 | public: 15 | 16 | ofxVectorTile(); 17 | virtual ~ofxVectorTile(); 18 | 19 | ofxVectorTile& operator = (const glmTile &_tile); 20 | 21 | ofMesh getMesh(); 22 | ofMesh getMeshFor(const std::string &_layerName); 23 | ofMesh getMeshFor(const std::vector< std::string > &_layersNames); 24 | 25 | void draw(); 26 | }; --------------------------------------------------------------------------------