├── .gitignore ├── README.md ├── example ├── Makefile ├── Project.xcconfig ├── addons.make ├── bin │ └── data │ │ ├── .gitkeep │ │ ├── .ma │ │ ├── box0.obj │ │ ├── box1.obj │ │ ├── coplanar0.mtl │ │ ├── coplanar0.obj │ │ ├── coplanar1.mtl │ │ ├── coplanar1.obj │ │ ├── plane0.mtl │ │ ├── plane0.obj │ │ ├── plane1.mtl │ │ ├── plane1.obj │ │ ├── sphere0.mtl │ │ ├── sphere0.obj │ │ └── torus1.obj ├── config.make ├── example.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── example Debug.xcscheme │ │ └── example Release.xcscheme ├── openFrameworks-Info.plist └── src │ ├── main.cpp │ ├── ofApp.cpp │ ├── ofApp.h │ └── ofxObjLoader │ ├── .gitignore │ ├── Readme.md │ ├── libs │ └── glm │ │ ├── glm.c │ │ └── glm.h │ └── src │ ├── ofxObjLoader.cpp │ └── ofxObjLoader.h └── src ├── CSG ├── BoundBox.cpp ├── BoundBox.h ├── LineSegment.cpp ├── LineSegment.h ├── Polygon.cpp ├── Polygon.h ├── Triangle.cpp ├── Triangle.h ├── Utils.h └── Vertex.h └── ofxCSG.h /.gitignore: -------------------------------------------------------------------------------- 1 | ######################### 2 | # openFrameworks patterns 3 | ######################### 4 | 5 | # build files 6 | openFrameworks.a 7 | openFrameworksDebug.a 8 | openFrameworksUniversal.a 9 | libs/openFrameworksCompiled/lib/*/* 10 | !libs/openFrameworksCompiled/lib/*/.gitkeep 11 | 12 | # apothecary 13 | scripts/apothecary/build 14 | 15 | # rule to avoid non-official addons going into git 16 | # see addons/.gitignore 17 | addons/* 18 | 19 | # rule to avoid non-official apps going into git 20 | # see apps/.gitignore 21 | apps/* 22 | 23 | # also, see examples/.gitignore 24 | 25 | ######################### 26 | # general 27 | ######################### 28 | 29 | [Bb]uild/ 30 | [Oo]bj/ 31 | *.o 32 | [Dd]ebug*/ 33 | [Rr]elease*/ 34 | *.mode* 35 | *.app/ 36 | *.pyc 37 | .svn/ 38 | *.log 39 | *.cpp.eep 40 | *.cpp.elf 41 | *.cpp.hex 42 | 43 | ######################### 44 | # IDE 45 | ######################### 46 | 47 | # XCode 48 | *.pbxuser 49 | *.perspective 50 | *.perspectivev3 51 | *.mode1v3 52 | *.mode2v3 53 | # XCode 4 54 | xcuserdata 55 | *.xcworkspace 56 | 57 | # Code::Blocks 58 | *.depend 59 | *.layout 60 | 61 | # Visual Studio 62 | *.sdf 63 | *.opensdf 64 | *.suo 65 | *.pdb 66 | *.ilk 67 | *.aps 68 | ipch/ 69 | 70 | # Eclipse 71 | .metadata 72 | local.properties 73 | .externalToolBuilders 74 | 75 | ######################### 76 | # operating system 77 | ######################### 78 | 79 | # Linux 80 | *~ 81 | # KDE 82 | .directory 83 | .AppleDouble 84 | 85 | # OSX 86 | .DS_Store 87 | *.swp 88 | *~.nib 89 | # Thumbnails 90 | ._* 91 | 92 | # Windows 93 | # Windows image file caches 94 | Thumbs.db 95 | # Folder config file 96 | Desktop.ini 97 | 98 | # Android 99 | .csettings 100 | /libs/openFrameworksCompiled/project/android/paths.make 101 | 102 | # Android Studio 103 | *.iml 104 | 105 | ######################### 106 | # miscellaneous 107 | ######################### 108 | 109 | .mailmap 110 | 111 | 112 | *.app -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ofxCSG 2 | ##a constructive solid geometry addon for openframeworks 3 | 4 | WIP! 5 | 6 | This is still in the early stages. My goal here is to create a lightweight constructive solid geometry addon for openframeworks with minimal dependencies. Contributions and advice welcome 7 | 8 | references 9 | ---------- 10 | * http://paulbourke.net/geometry/pointlineplane/ 11 | * http://geomalgorithms.com/algorithms.html, http://geomalgorithms.com/a04-_planes.html 12 | * http://www.blackpawn.com/texts/pointinpoly/ 13 | * http://evanw.github.io/csg.js/ 14 | -------------------------------------------------------------------------------- /example/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/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) $(OF_CORE_FRAMEWORKS) 17 | HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) 18 | -------------------------------------------------------------------------------- /example/addons.make: -------------------------------------------------------------------------------- 1 | ofxCSG 2 | ofxObjLoader 3 | -------------------------------------------------------------------------------- /example/bin/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larsberg/ofxCSG/4c8a2898127b932ed75eb63c2b0184e5d9bd654d/example/bin/data/.gitkeep -------------------------------------------------------------------------------- /example/bin/data/.ma: -------------------------------------------------------------------------------- 1 | //Maya ASCII 2013 scene 2 | //Name: .ma 3 | //Last modified: Wed, Mar 04, 2015 10:34:10 AM 4 | //Codeset: UTF-8 5 | requires maya "2013"; 6 | currentUnit -l centimeter -a degree -t film; 7 | fileInfo "application" "maya"; 8 | fileInfo "product" "Maya 2013"; 9 | fileInfo "version" "2013 x64"; 10 | fileInfo "cutIdentifier" "201202220220-825135"; 11 | fileInfo "osv" "Mac OS X 10.9.2"; 12 | createNode transform -n "pCube2"; 13 | setAttr ".t" -type "double3" 8.7559185028076172 0 0 ; 14 | setAttr ".r" -type "double3" 43.665450620930031 0 0 ; 15 | createNode mesh -n "pCubeShape2" -p "pCube2"; 16 | setAttr -k off ".v"; 17 | setAttr ".vir" yes; 18 | setAttr ".vif" yes; 19 | setAttr ".uvst[0].uvsn" -type "string" "map1"; 20 | setAttr -s 14 ".uvst[0].uvsp[0:13]" -type "float2" 0.375 0 0.625 0 0.375 21 | 0.25 0.625 0.25 0.375 0.5 0.625 0.5 0.375 0.75 0.625 0.75 0.375 1 0.625 1 0.875 0 22 | 0.875 0.25 0.125 0 0.125 0.25; 23 | setAttr ".cuvs" -type "string" "map1"; 24 | setAttr ".dcc" -type "string" "Ambient+Diffuse"; 25 | setAttr ".covm[0]" 0 1 1; 26 | setAttr ".cdvm[0]" 0 1 1; 27 | setAttr -s 8 ".vt[0:7]" -4.37795925 -2.96688199 3.99958348 4.37795925 -2.96688199 3.99958348 28 | -4.37795925 2.96688199 3.99958348 4.37795925 2.96688199 3.99958348 -4.37795925 2.96688199 -3.99958348 29 | 4.37795925 2.96688199 -3.99958348 -4.37795925 -2.96688199 -3.99958348 4.37795925 -2.96688199 -3.99958348; 30 | setAttr -s 12 ".ed[0:11]" 0 1 0 2 3 0 4 5 0 6 7 0 0 2 0 1 3 0 2 4 0 31 | 3 5 0 4 6 0 5 7 0 6 0 0 7 1 0; 32 | setAttr -s 6 -ch 24 ".fc[0:5]" -type "polyFaces" 33 | f 4 0 5 -2 -5 34 | mu 0 4 0 1 3 2 35 | f 4 1 7 -3 -7 36 | mu 0 4 2 3 5 4 37 | f 4 2 9 -4 -9 38 | mu 0 4 4 5 7 6 39 | f 4 3 11 -1 -11 40 | mu 0 4 6 7 9 8 41 | f 4 -12 -10 -8 -6 42 | mu 0 4 1 10 11 3 43 | f 4 10 4 6 8 44 | mu 0 4 12 0 2 13; 45 | setAttr ".cd" -type "dataPolyComponent" Index_Data Edge 0 ; 46 | setAttr ".cvd" -type "dataPolyComponent" Index_Data Vertex 0 ; 47 | setAttr ".hfd" -type "dataPolyComponent" Index_Data Face 0 ; 48 | setAttr ".vs" 2; 49 | setAttr ".ns" 0.1; 50 | select -ne :time1; 51 | setAttr ".o" 1; 52 | setAttr ".unw" 1; 53 | select -ne :renderPartition; 54 | setAttr -s 2 ".st"; 55 | select -ne :initialShadingGroup; 56 | setAttr -s 2 ".dsm"; 57 | setAttr ".ro" yes; 58 | select -ne :initialParticleSE; 59 | setAttr ".ro" yes; 60 | select -ne :defaultShaderList1; 61 | setAttr -s 2 ".s"; 62 | select -ne :postProcessList1; 63 | setAttr -s 2 ".p"; 64 | select -ne :defaultRenderingList1; 65 | select -ne :renderGlobalsList1; 66 | select -ne :hardwareRenderGlobals; 67 | setAttr ".ctrs" 256; 68 | setAttr ".btrs" 512; 69 | select -ne :defaultHardwareRenderGlobals; 70 | setAttr ".fn" -type "string" "im"; 71 | setAttr ".res" -type "string" "ntsc_4d 646 485 1.333"; 72 | connectAttr "pCubeShape2.iog" ":initialShadingGroup.dsm" -na; 73 | // End of .ma 74 | -------------------------------------------------------------------------------- /example/bin/data/box0.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | v -5.000000 -5.000000 5.000000 4 | v 5.000000 -5.000000 5.000000 5 | v -5.000000 5.000000 5.000000 6 | v 5.000000 5.000000 5.000000 7 | v -5.000000 5.000000 -5.000000 8 | v 5.000000 5.000000 -5.000000 9 | v -5.000000 -5.000000 -5.000000 10 | v 5.000000 -5.000000 -5.000000 11 | vt 0.375000 0.000000 12 | vt 0.625000 0.000000 13 | vt 0.375000 0.250000 14 | vt 0.625000 0.250000 15 | vt 0.375000 0.500000 16 | vt 0.625000 0.500000 17 | vt 0.375000 0.750000 18 | vt 0.625000 0.750000 19 | vt 0.375000 1.000000 20 | vt 0.625000 1.000000 21 | vt 0.875000 0.000000 22 | vt 0.875000 0.250000 23 | vt 0.125000 0.000000 24 | vt 0.125000 0.250000 25 | vn 0.000000 0.000000 1.000000 26 | vn 0.000000 0.000000 1.000000 27 | vn 0.000000 0.000000 1.000000 28 | vn 0.000000 0.000000 1.000000 29 | vn 0.000000 1.000000 0.000000 30 | vn 0.000000 1.000000 0.000000 31 | vn 0.000000 1.000000 0.000000 32 | vn 0.000000 1.000000 0.000000 33 | vn 0.000000 0.000000 -1.000000 34 | vn 0.000000 0.000000 -1.000000 35 | vn 0.000000 0.000000 -1.000000 36 | vn 0.000000 0.000000 -1.000000 37 | vn 0.000000 -1.000000 0.000000 38 | vn 0.000000 -1.000000 0.000000 39 | vn 0.000000 -1.000000 0.000000 40 | vn 0.000000 -1.000000 0.000000 41 | vn 1.000000 0.000000 0.000000 42 | vn 1.000000 0.000000 0.000000 43 | vn 1.000000 0.000000 0.000000 44 | vn 1.000000 0.000000 0.000000 45 | vn -1.000000 0.000000 0.000000 46 | vn -1.000000 0.000000 0.000000 47 | vn -1.000000 0.000000 0.000000 48 | vn -1.000000 0.000000 0.000000 49 | f 1/1/1 2/2/2 4/4/3 3/3/4 50 | f 3/3/5 4/4/6 6/6/7 5/5/8 51 | f 5/5/9 6/6/10 8/8/11 7/7/12 52 | f 7/7/13 8/8/14 2/10/15 1/9/16 53 | f 2/2/17 8/11/18 6/12/19 4/4/20 54 | f 7/13/21 1/1/22 3/3/23 5/14/24 55 | -------------------------------------------------------------------------------- /example/bin/data/box1.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | v -13.283423 -0.011168 -0.901256 4 | v -6.407761 -5.791504 3.493399 5 | v -11.402043 7.252540 5.709263 6 | v -4.526382 1.472203 10.103918 7 | v -4.388792 10.970908 -0.372517 8 | v 2.486869 5.190571 4.022137 9 | v -6.270172 3.707200 -6.983036 10 | v 0.605490 -2.073137 -2.588382 11 | vt 0.375000 0.000000 12 | vt 0.625000 0.000000 13 | vt 0.375000 0.250000 14 | vt 0.625000 0.250000 15 | vt 0.375000 0.500000 16 | vt 0.625000 0.500000 17 | vt 0.375000 0.750000 18 | vt 0.625000 0.750000 19 | vt 0.375000 1.000000 20 | vt 0.625000 1.000000 21 | vt 0.875000 0.000000 22 | vt 0.875000 0.250000 23 | vt 0.125000 0.000000 24 | vt 0.125000 0.250000 25 | vn -0.701325 -0.371837 0.608178 26 | vn -0.701325 -0.371837 0.608178 27 | vn -0.701325 -0.371837 0.608178 28 | vn -0.701325 -0.371837 0.608178 29 | vn 0.188138 0.726371 0.661052 30 | vn 0.188138 0.726371 0.661052 31 | vn 0.188138 0.726371 0.661052 32 | vn 0.188138 0.726371 0.661052 33 | vn 0.701325 0.371837 -0.608178 34 | vn 0.701325 0.371837 -0.608178 35 | vn 0.701325 0.371837 -0.608178 36 | vn 0.701325 0.371837 -0.608178 37 | vn -0.188138 -0.726371 -0.661052 38 | vn -0.188138 -0.726371 -0.661052 39 | vn -0.188138 -0.726371 -0.661052 40 | vn -0.188138 -0.726371 -0.661052 41 | vn 0.687566 -0.578034 0.439465 42 | vn 0.687566 -0.578034 0.439465 43 | vn 0.687566 -0.578034 0.439465 44 | vn 0.687566 -0.578034 0.439465 45 | vn -0.687566 0.578034 -0.439465 46 | vn -0.687566 0.578034 -0.439465 47 | vn -0.687566 0.578034 -0.439465 48 | vn -0.687566 0.578034 -0.439465 49 | f 1/1/1 2/2/2 4/4/3 3/3/4 50 | f 3/3/5 4/4/6 6/6/7 5/5/8 51 | f 5/5/9 6/6/10 8/8/11 7/7/12 52 | f 7/7/13 8/8/14 2/10/15 1/9/16 53 | f 2/2/17 8/11/18 6/12/19 4/4/20 54 | f 7/13/21 1/1/22 3/3/23 5/14/24 55 | -------------------------------------------------------------------------------- /example/bin/data/coplanar0.mtl: -------------------------------------------------------------------------------- 1 | newmtl coplanar0_initialShadingGroup 2 | illum 4 3 | Kd 0.50 0.50 0.50 4 | Ka 0.00 0.00 0.00 5 | Tf 1.00 1.00 1.00 6 | Ni 1.00 7 | Ks 0.50 0.50 0.50 8 | Ns 18.00 9 | newmtl coplanar1_initialShadingGroup 10 | illum 4 11 | Kd 0.50 0.50 0.50 12 | Ka 0.00 0.00 0.00 13 | Tf 1.00 1.00 1.00 14 | Ni 1.00 15 | Ks 0.50 0.50 0.50 16 | Ns 18.00 17 | -------------------------------------------------------------------------------- /example/bin/data/coplanar0.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | mtllib coplanar0.mtl 4 | v -20.386112 -0.000001 16.203667 5 | v -2.606901 -0.000001 50.086094 6 | v -20.386112 47.420914 16.203667 7 | v -2.606901 47.420914 50.086094 8 | v 71.192162 47.420914 -31.850430 9 | v 88.971375 47.420914 2.031998 10 | v 71.192162 -0.000001 -31.850430 11 | v 88.971375 -0.000001 2.031998 12 | vt 0.375000 0.000000 13 | vt 0.625000 0.000000 14 | vt 0.375000 0.250000 15 | vt 0.625000 0.250000 16 | vt 0.375000 0.500000 17 | vt 0.625000 0.500000 18 | vt 0.375000 0.750000 19 | vt 0.625000 0.750000 20 | vt 0.375000 1.000000 21 | vt 0.625000 1.000000 22 | vt 0.125000 0.000000 23 | vt 0.125000 0.250000 24 | vn -0.885495 0.000000 0.464648 25 | vn -0.885495 0.000000 0.464648 26 | vn -0.885495 0.000000 0.464648 27 | vn -0.885495 0.000000 0.464648 28 | vn -0.885495 0.000000 0.464648 29 | vn -0.885495 0.000000 0.464648 30 | vn 0.000000 1.000000 0.000000 31 | vn 0.000000 1.000000 0.000000 32 | vn 0.000000 1.000000 0.000000 33 | vn 0.000000 1.000000 0.000000 34 | vn 0.000000 1.000000 0.000000 35 | vn 0.000000 1.000000 0.000000 36 | vn 0.885495 0.000000 -0.464648 37 | vn 0.885495 0.000000 -0.464648 38 | vn 0.885495 0.000000 -0.464648 39 | vn 0.885495 0.000000 -0.464648 40 | vn 0.885495 0.000000 -0.464648 41 | vn 0.885495 0.000000 -0.464648 42 | vn 0.000000 -1.000000 0.000000 43 | vn 0.000000 -1.000000 0.000000 44 | vn 0.000000 -1.000000 0.000000 45 | vn 0.000000 -1.000000 0.000000 46 | vn 0.000000 -1.000000 0.000000 47 | vn 0.000000 -1.000000 0.000000 48 | vn -0.464648 0.000000 -0.885495 49 | vn -0.464648 0.000000 -0.885495 50 | vn -0.464648 0.000000 -0.885495 51 | vn -0.464648 0.000000 -0.885495 52 | vn -0.464648 0.000000 -0.885495 53 | vn -0.464648 0.000000 -0.885495 54 | vn 0.464648 0.000000 0.885495 55 | vn 0.464648 0.000000 0.885495 56 | vn 0.464648 0.000000 0.885495 57 | vn 0.464648 0.000000 0.885495 58 | s off 59 | usemtl coplanar1_initialShadingGroup 60 | f 1/1/1 2/2/2 3/3/3 61 | f 3/3/4 2/2/5 4/4/6 62 | f 3/3/7 4/4/8 5/5/9 63 | f 5/5/10 4/4/11 6/6/12 64 | f 5/5/13 6/6/14 7/7/15 65 | f 7/7/16 6/6/17 8/8/18 66 | f 7/7/19 8/8/20 1/9/21 67 | f 1/9/22 8/8/23 2/10/24 68 | f 7/11/25 1/1/26 5/12/27 69 | f 5/12/28 1/1/29 3/3/30 70 | f 4/4/31 2/10/32 8/8/33 6/6/34 71 | -------------------------------------------------------------------------------- /example/bin/data/coplanar1.mtl: -------------------------------------------------------------------------------- 1 | newmtl coplanar0_initialShadingGroup 2 | illum 4 3 | Kd 0.50 0.50 0.50 4 | Ka 0.00 0.00 0.00 5 | Tf 1.00 1.00 1.00 6 | Ni 1.00 7 | Ks 0.50 0.50 0.50 8 | Ns 18.00 9 | newmtl coplanar1_initialShadingGroup 10 | illum 4 11 | Kd 0.50 0.50 0.50 12 | Ka 0.00 0.00 0.00 13 | Tf 1.00 1.00 1.00 14 | Ni 1.00 15 | Ks 0.50 0.50 0.50 16 | Ns 18.00 17 | -------------------------------------------------------------------------------- /example/bin/data/coplanar1.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | mtllib coplanar1.mtl 4 | v -14.240695 -27.538380 -30.022400 5 | v 3.538518 -27.538380 3.860033 6 | v -41.030712 8.977673 -15.964806 7 | v -23.251501 8.977673 17.917625 8 | v 29.488319 74.959290 -52.968433 9 | v 47.267532 74.959290 -19.086002 10 | v 56.278339 38.443241 -67.026024 11 | v 74.057556 38.443241 -33.143597 12 | vt 0.375000 0.000000 13 | vt 0.625000 0.000000 14 | vt 0.375000 0.250000 15 | vt 0.625000 0.250000 16 | vt 0.375000 0.500000 17 | vt 0.625000 0.500000 18 | vt 0.375000 0.750000 19 | vt 0.625000 0.750000 20 | vt 0.375000 1.000000 21 | vt 0.625000 1.000000 22 | vt 0.875000 0.000000 23 | vt 0.875000 0.250000 24 | vn -0.681868 -0.637994 0.357798 25 | vn -0.681868 -0.637994 0.357798 26 | vn -0.681868 -0.637994 0.357798 27 | vn -0.681868 -0.637994 0.357798 28 | vn -0.681868 -0.637994 0.357798 29 | vn -0.681868 -0.637994 0.357798 30 | vn -0.564941 0.770041 0.296443 31 | vn -0.564941 0.770041 0.296443 32 | vn -0.564941 0.770041 0.296443 33 | vn -0.564941 0.770041 0.296443 34 | vn -0.564941 0.770041 0.296443 35 | vn -0.564941 0.770041 0.296443 36 | vn 0.681868 0.637994 -0.357798 37 | vn 0.681868 0.637994 -0.357798 38 | vn 0.681868 0.637994 -0.357798 39 | vn 0.681868 0.637994 -0.357798 40 | vn 0.681868 0.637994 -0.357798 41 | vn 0.681868 0.637994 -0.357798 42 | vn 0.564941 -0.770041 -0.296443 43 | vn 0.564941 -0.770041 -0.296443 44 | vn 0.564941 -0.770041 -0.296443 45 | vn 0.564941 -0.770041 -0.296443 46 | vn 0.564941 -0.770041 -0.296443 47 | vn 0.564941 -0.770041 -0.296443 48 | vn 0.464648 0.000000 0.885495 49 | vn 0.464648 0.000000 0.885495 50 | vn 0.464648 0.000000 0.885495 51 | vn 0.464648 0.000000 0.885495 52 | vn 0.464648 0.000000 0.885495 53 | vn 0.464648 0.000000 0.885495 54 | vn -0.464648 0.000000 -0.885495 55 | vn -0.464648 0.000000 -0.885495 56 | vn -0.464648 0.000000 -0.885495 57 | vn -0.464648 0.000000 -0.885495 58 | s off 59 | usemtl coplanar0_initialShadingGroup 60 | f 1/1/1 2/2/2 3/3/3 61 | f 3/3/4 2/2/5 4/4/6 62 | f 3/3/7 4/4/8 5/5/9 63 | f 5/5/10 4/4/11 6/6/12 64 | f 5/5/13 6/6/14 7/7/15 65 | f 7/7/16 6/6/17 8/8/18 66 | f 7/7/19 8/8/20 1/9/21 67 | f 1/9/22 8/8/23 2/10/24 68 | f 2/2/25 8/11/26 4/4/27 69 | f 4/4/28 8/11/29 6/12/30 70 | f 1/1/31 3/3/32 5/5/33 7/7/34 71 | -------------------------------------------------------------------------------- /example/bin/data/plane0.mtl: -------------------------------------------------------------------------------- 1 | newmtl plane0_initialShadingGroup 2 | illum 4 3 | Kd 0.50 0.50 0.50 4 | Ka 0.00 0.00 0.00 5 | Tf 1.00 1.00 1.00 6 | Ni 1.00 7 | newmtl plane1_initialShadingGroup 8 | illum 4 9 | Kd 0.50 0.50 0.50 10 | Ka 0.00 0.00 0.00 11 | Tf 1.00 1.00 1.00 12 | Ni 1.00 13 | -------------------------------------------------------------------------------- /example/bin/data/plane0.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | mtllib plane0.mtl 4 | v -22.892697 10.361499 11.927248 5 | v -19.014235 2.029226 13.384997 6 | v -15.135770 -6.303052 14.842748 7 | v -11.257306 -14.635329 16.300498 8 | v -7.378842 -22.967605 17.758248 9 | v -12.851215 13.513025 3.224699 10 | v -8.972752 5.180752 4.682449 11 | v -5.094288 -3.151526 6.140199 12 | v -1.215824 -11.483802 7.597949 13 | v 2.662640 -19.816079 9.055700 14 | v -2.809736 16.664551 -5.477846 15 | v 1.068727 8.332277 -4.020097 16 | v 4.947192 -0.000001 -2.562346 17 | v 8.825656 -8.332277 -1.104596 18 | v 12.704120 -16.664553 0.353154 19 | v 7.231746 19.816077 -14.180395 20 | v 11.110209 11.483803 -12.722646 21 | v 14.988674 3.151525 -11.264895 22 | v 18.867138 -5.180751 -9.807145 23 | v 22.745602 -13.513027 -8.349395 24 | v 17.273225 22.967602 -22.882940 25 | v 21.151687 14.635328 -21.425190 26 | v 25.030152 6.303050 -19.967440 27 | v 28.908616 -2.029226 -18.509690 28 | v 32.787080 -10.361502 -17.051940 29 | vt 0.000000 0.000000 30 | vt 0.170352 0.000000 31 | vt 0.170352 0.250000 32 | vt 0.000000 0.250000 33 | vt 0.340705 0.000000 34 | vt 0.340705 0.250000 35 | vt 0.511057 0.000000 36 | vt 0.511057 0.250000 37 | vt 0.681409 0.000000 38 | vt 0.681409 0.250000 39 | vt 0.170352 0.500000 40 | vt 0.000000 0.500000 41 | vt 0.340705 0.500000 42 | vt 0.511057 0.500000 43 | vt 0.681409 0.500000 44 | vt 0.170352 0.750000 45 | vt 0.000000 0.750000 46 | vt 0.340705 0.750000 47 | vt 0.511057 0.750000 48 | vt 0.681409 0.750000 49 | vt 0.170352 1.000000 50 | vt 0.000000 1.000000 51 | vt 0.340705 1.000000 52 | vt 0.511057 1.000000 53 | vt 0.681409 1.000000 54 | vn 0.534444 0.380784 0.754568 55 | vn 0.534444 0.380784 0.754568 56 | vn 0.534444 0.380784 0.754568 57 | vn 0.534444 0.380784 0.754568 58 | vn 0.534444 0.380784 0.754568 59 | vn 0.534444 0.380784 0.754568 60 | vn 0.534444 0.380784 0.754568 61 | vn 0.534444 0.380784 0.754568 62 | vn 0.534444 0.380784 0.754568 63 | vn 0.534444 0.380784 0.754568 64 | vn 0.534444 0.380784 0.754568 65 | vn 0.534444 0.380784 0.754568 66 | vn 0.534444 0.380784 0.754568 67 | vn 0.534444 0.380784 0.754568 68 | vn 0.534444 0.380784 0.754568 69 | vn 0.534444 0.380784 0.754568 70 | vn 0.534444 0.380784 0.754568 71 | vn 0.534444 0.380784 0.754568 72 | vn 0.534444 0.380784 0.754568 73 | vn 0.534444 0.380784 0.754568 74 | vn 0.534444 0.380784 0.754568 75 | vn 0.534444 0.380784 0.754568 76 | vn 0.534444 0.380784 0.754568 77 | vn 0.534444 0.380784 0.754568 78 | vn 0.534444 0.380784 0.754568 79 | vn 0.534444 0.380784 0.754568 80 | vn 0.534444 0.380784 0.754568 81 | vn 0.534444 0.380784 0.754568 82 | vn 0.534444 0.380784 0.754568 83 | vn 0.534444 0.380784 0.754568 84 | vn 0.534444 0.380784 0.754568 85 | vn 0.534444 0.380784 0.754568 86 | vn 0.534444 0.380784 0.754568 87 | vn 0.534444 0.380784 0.754568 88 | vn 0.534444 0.380784 0.754568 89 | vn 0.534444 0.380784 0.754568 90 | vn 0.534444 0.380784 0.754568 91 | vn 0.534444 0.380784 0.754568 92 | vn 0.534444 0.380784 0.754568 93 | vn 0.534444 0.380784 0.754568 94 | vn 0.534444 0.380784 0.754568 95 | vn 0.534444 0.380784 0.754568 96 | vn 0.534444 0.380784 0.754568 97 | vn 0.534444 0.380784 0.754568 98 | vn 0.534444 0.380784 0.754568 99 | vn 0.534444 0.380784 0.754568 100 | vn 0.534444 0.380784 0.754568 101 | vn 0.534444 0.380784 0.754568 102 | vn 0.534444 0.380784 0.754568 103 | vn 0.534444 0.380784 0.754568 104 | vn 0.534444 0.380784 0.754568 105 | vn 0.534444 0.380784 0.754568 106 | vn 0.534444 0.380784 0.754568 107 | vn 0.534444 0.380784 0.754568 108 | vn 0.534444 0.380784 0.754568 109 | vn 0.534444 0.380784 0.754568 110 | vn 0.534444 0.380784 0.754568 111 | vn 0.534444 0.380784 0.754568 112 | vn 0.534444 0.380784 0.754568 113 | vn 0.534444 0.380784 0.754568 114 | vn 0.534444 0.380784 0.754568 115 | vn 0.534444 0.380784 0.754568 116 | vn 0.534444 0.380784 0.754568 117 | vn 0.534444 0.380784 0.754568 118 | s off 119 | usemtl plane1_initialShadingGroup 120 | f 1/1/1 2/2/2 7/3/3 6/4/4 121 | f 2/2/5 3/5/6 8/6/7 7/3/8 122 | f 3/5/9 4/7/10 9/8/11 8/6/12 123 | f 4/7/13 5/9/14 10/10/15 9/8/16 124 | f 6/4/17 7/3/18 12/11/19 11/12/20 125 | f 7/3/21 8/6/22 13/13/23 12/11/24 126 | f 8/6/25 9/8/26 14/14/27 13/13/28 127 | f 9/8/29 10/10/30 15/15/31 14/14/32 128 | f 11/12/33 12/11/34 17/16/35 16/17/36 129 | f 12/11/37 13/13/38 18/18/39 17/16/40 130 | f 13/13/41 14/14/42 19/19/43 18/18/44 131 | f 14/14/45 15/15/46 20/20/47 19/19/48 132 | f 16/17/49 17/16/50 22/21/51 21/22/52 133 | f 17/16/53 18/18/54 23/23/55 22/21/56 134 | f 18/18/57 19/19/58 24/24/59 23/23/60 135 | f 19/19/61 20/20/62 25/25/63 24/24/64 136 | -------------------------------------------------------------------------------- /example/bin/data/plane1.mtl: -------------------------------------------------------------------------------- 1 | newmtl plane0_initialShadingGroup 2 | illum 4 3 | Kd 0.50 0.50 0.50 4 | Ka 0.00 0.00 0.00 5 | Tf 1.00 1.00 1.00 6 | Ni 1.00 7 | newmtl plane1_initialShadingGroup 8 | illum 4 9 | Kd 0.50 0.50 0.50 10 | Ka 0.00 0.00 0.00 11 | Tf 1.00 1.00 1.00 12 | Ni 1.00 13 | -------------------------------------------------------------------------------- /example/bin/data/plane1.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | mtllib plane1.mtl 4 | v -18.583703 22.605542 2.696468 5 | v -18.355866 14.236400 6.758484 6 | v -18.128029 5.867263 10.820497 7 | v -17.900194 -2.501875 14.882512 8 | v -17.672358 -10.871013 18.944526 9 | v -7.046091 19.671909 -3.994954 10 | v -6.818256 11.302771 0.067061 11 | v -6.590421 2.933633 4.129076 12 | v -6.362581 -5.435508 8.191089 13 | v -6.134747 -13.804646 12.253104 14 | v 4.491522 16.738276 -10.686377 15 | v 4.719357 8.369137 -6.624362 16 | v 4.947192 -0.000001 -2.562346 17 | v 5.175026 -8.369137 1.499668 18 | v 5.402862 -16.738277 5.561684 19 | v 16.029135 13.804643 -17.377800 20 | v 16.256968 5.435505 -13.315784 21 | v 16.484804 -2.933633 -9.253769 22 | v 16.712639 -11.302771 -5.191755 23 | v 16.940476 -19.671907 -1.129742 24 | v 27.566743 10.871012 -24.069220 25 | v 27.794576 2.501875 -20.007205 26 | v 28.022410 -5.867263 -15.945189 27 | v 28.250251 -14.236406 -11.883176 28 | v 28.478086 -22.605542 -7.821162 29 | vt 0.000000 0.000000 30 | vt 0.170352 0.000000 31 | vt 0.170352 0.250000 32 | vt 0.000000 0.250000 33 | vt 0.340705 0.000000 34 | vt 0.340705 0.250000 35 | vt 0.511057 0.000000 36 | vt 0.511057 0.250000 37 | vt 0.681409 0.000000 38 | vt 0.681409 0.250000 39 | vt 0.170352 0.500000 40 | vt 0.000000 0.500000 41 | vt 0.340705 0.500000 42 | vt 0.511057 0.500000 43 | vt 0.681409 0.500000 44 | vt 0.170352 0.750000 45 | vt 0.000000 0.750000 46 | vt 0.340705 0.750000 47 | vt 0.511057 0.750000 48 | vt 0.681409 0.750000 49 | vt 0.170352 1.000000 50 | vt 0.000000 1.000000 51 | vt 0.340705 1.000000 52 | vt 0.511057 1.000000 53 | vt 0.681409 1.000000 54 | vn -0.534444 -0.380784 -0.754568 55 | vn -0.534444 -0.380784 -0.754568 56 | vn -0.534444 -0.380784 -0.754568 57 | vn -0.534444 -0.380784 -0.754568 58 | vn -0.534444 -0.380784 -0.754568 59 | vn -0.534444 -0.380784 -0.754568 60 | vn -0.534444 -0.380784 -0.754568 61 | vn -0.534444 -0.380784 -0.754568 62 | vn -0.534444 -0.380784 -0.754568 63 | vn -0.534444 -0.380784 -0.754568 64 | vn -0.534444 -0.380784 -0.754568 65 | vn -0.534444 -0.380784 -0.754568 66 | vn -0.534444 -0.380784 -0.754568 67 | vn -0.534444 -0.380784 -0.754568 68 | vn -0.534444 -0.380784 -0.754568 69 | vn -0.534444 -0.380784 -0.754568 70 | vn -0.534444 -0.380784 -0.754568 71 | vn -0.534444 -0.380784 -0.754568 72 | vn -0.534444 -0.380784 -0.754568 73 | vn -0.534444 -0.380784 -0.754568 74 | vn -0.534444 -0.380784 -0.754568 75 | vn -0.534444 -0.380784 -0.754568 76 | vn -0.534444 -0.380784 -0.754568 77 | vn -0.534444 -0.380784 -0.754568 78 | vn -0.534444 -0.380784 -0.754568 79 | vn -0.534444 -0.380784 -0.754568 80 | vn -0.534444 -0.380784 -0.754568 81 | vn -0.534444 -0.380784 -0.754568 82 | vn -0.534444 -0.380784 -0.754568 83 | vn -0.534444 -0.380784 -0.754568 84 | vn -0.534444 -0.380784 -0.754568 85 | vn -0.534444 -0.380784 -0.754568 86 | vn -0.534444 -0.380784 -0.754568 87 | vn -0.534444 -0.380784 -0.754568 88 | vn -0.534444 -0.380784 -0.754568 89 | vn -0.534444 -0.380784 -0.754568 90 | vn -0.534444 -0.380784 -0.754568 91 | vn -0.534444 -0.380784 -0.754568 92 | vn -0.534444 -0.380784 -0.754568 93 | vn -0.534444 -0.380784 -0.754568 94 | vn -0.534444 -0.380784 -0.754568 95 | vn -0.534444 -0.380784 -0.754568 96 | vn -0.534444 -0.380784 -0.754568 97 | vn -0.534444 -0.380784 -0.754568 98 | vn -0.534444 -0.380784 -0.754568 99 | vn -0.534444 -0.380784 -0.754568 100 | vn -0.534444 -0.380784 -0.754568 101 | vn -0.534444 -0.380784 -0.754568 102 | vn -0.534444 -0.380784 -0.754568 103 | vn -0.534444 -0.380784 -0.754568 104 | vn -0.534444 -0.380784 -0.754568 105 | vn -0.534444 -0.380784 -0.754568 106 | vn -0.534444 -0.380784 -0.754568 107 | vn -0.534444 -0.380784 -0.754568 108 | vn -0.534444 -0.380784 -0.754568 109 | vn -0.534444 -0.380784 -0.754568 110 | vn -0.534444 -0.380784 -0.754568 111 | vn -0.534444 -0.380784 -0.754568 112 | vn -0.534444 -0.380784 -0.754568 113 | vn -0.534444 -0.380784 -0.754568 114 | vn -0.534444 -0.380784 -0.754568 115 | vn -0.534444 -0.380784 -0.754568 116 | vn -0.534444 -0.380784 -0.754568 117 | vn -0.534444 -0.380784 -0.754568 118 | s off 119 | usemtl plane0_initialShadingGroup 120 | f 1/1/1 6/4/2 7/3/3 2/2/4 121 | f 2/2/5 7/3/6 8/6/7 3/5/8 122 | f 3/5/9 8/6/10 9/8/11 4/7/12 123 | f 4/7/13 9/8/14 10/10/15 5/9/16 124 | f 6/4/17 11/12/18 12/11/19 7/3/20 125 | f 7/3/21 12/11/22 13/13/23 8/6/24 126 | f 8/6/25 13/13/26 14/14/27 9/8/28 127 | f 9/8/29 14/14/30 15/15/31 10/10/32 128 | f 11/12/33 16/17/34 17/16/35 12/11/36 129 | f 12/11/37 17/16/38 18/18/39 13/13/40 130 | f 13/13/41 18/18/42 19/19/43 14/14/44 131 | f 14/14/45 19/19/46 20/20/47 15/15/48 132 | f 16/17/49 21/22/50 22/21/51 17/16/52 133 | f 17/16/53 22/21/54 23/23/55 18/18/56 134 | f 18/18/57 23/23/58 24/24/59 19/19/60 135 | f 19/19/61 24/24/62 25/25/63 20/20/64 136 | -------------------------------------------------------------------------------- /example/bin/data/sphere0.mtl: -------------------------------------------------------------------------------- 1 | newmtl initialShadingGroup 2 | illum 4 3 | Kd 0.50 0.50 0.50 4 | Ka 0.00 0.00 0.00 5 | Tf 1.00 1.00 1.00 6 | Ni 1.00 7 | -------------------------------------------------------------------------------- /example/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/example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5067B44B1AAF4823001557EA /* LineSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5067B44A1AAF4823001557EA /* LineSegment.cpp */; }; 11 | 5067B44D1AAF491D001557EA /* Triangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5067B44C1AAF491D001557EA /* Triangle.cpp */; }; 12 | 5067B44F1AAF4A79001557EA /* Polygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5067B44E1AAF4A79001557EA /* Polygon.cpp */; }; 13 | 5067B4521AAF532D001557EA /* BoundBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5067B4501AAF532D001557EA /* BoundBox.cpp */; }; 14 | 50E08C481AB0E34400762CC9 /* glm.c in Sources */ = {isa = PBXBuildFile; fileRef = 50E08C421AB0E34400762CC9 /* glm.c */; }; 15 | 50E08C491AB0E34400762CC9 /* Readme.md in Sources */ = {isa = PBXBuildFile; fileRef = 50E08C441AB0E34400762CC9 /* Readme.md */; }; 16 | 50E08C4A1AB0E34400762CC9 /* ofxObjLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50E08C461AB0E34400762CC9 /* ofxObjLoader.cpp */; }; 17 | E4328149138ABC9F0047C5CB /* openFrameworksDebug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E4328148138ABC890047C5CB /* openFrameworksDebug.a */; }; 18 | E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B69E1D0A3A1BDC003C02F2 /* main.cpp */; }; 19 | E4B69E210A3A1BDC003C02F2 /* ofApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | E4328147138ABC890047C5CB /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */; 26 | proxyType = 2; 27 | remoteGlobalIDString = E4B27C1510CBEB8E00536013; 28 | remoteInfo = openFrameworks; 29 | }; 30 | E4EEB9AB138B136A00A80321 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */; 33 | proxyType = 1; 34 | remoteGlobalIDString = E4B27C1410CBEB8E00536013; 35 | remoteInfo = openFrameworks; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXCopyFilesBuildPhase section */ 40 | E4C2427710CC5ABF004149E2 /* CopyFiles */ = { 41 | isa = PBXCopyFilesBuildPhase; 42 | buildActionMask = 2147483647; 43 | dstPath = ""; 44 | dstSubfolderSpec = 10; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXCopyFilesBuildPhase section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | 25EB393F641E2D96B4947177 /* Utils.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = Utils.h; path = ../../../addons/ofxCSG/src/CSG/Utils.h; sourceTree = SOURCE_ROOT; }; 53 | 4091601133A9DA1ED8505149 /* ofxCSG.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = ofxCSG.h; path = ../../../addons/ofxCSG/src/ofxCSG.h; sourceTree = SOURCE_ROOT; }; 54 | 5067B44A1AAF4823001557EA /* LineSegment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LineSegment.cpp; path = ../src/CSG/LineSegment.cpp; sourceTree = ""; }; 55 | 5067B44C1AAF491D001557EA /* Triangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Triangle.cpp; path = ../src/CSG/Triangle.cpp; sourceTree = ""; }; 56 | 5067B44E1AAF4A79001557EA /* Polygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Polygon.cpp; path = ../src/CSG/Polygon.cpp; sourceTree = ""; }; 57 | 5067B4501AAF532D001557EA /* BoundBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoundBox.cpp; path = ../src/CSG/BoundBox.cpp; sourceTree = ""; }; 58 | 5067B4511AAF532D001557EA /* BoundBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BoundBox.h; path = ../src/CSG/BoundBox.h; sourceTree = ""; }; 59 | 50E08C3F1AB0E34400762CC9 /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; 60 | 50E08C421AB0E34400762CC9 /* glm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = glm.c; sourceTree = ""; }; 61 | 50E08C431AB0E34400762CC9 /* glm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glm.h; sourceTree = ""; }; 62 | 50E08C441AB0E34400762CC9 /* Readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = ""; }; 63 | 50E08C461AB0E34400762CC9 /* ofxObjLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxObjLoader.cpp; sourceTree = ""; }; 64 | 50E08C471AB0E34400762CC9 /* ofxObjLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxObjLoader.h; sourceTree = ""; }; 65 | 50F347101AA6612300E4B69E /* Triangle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Triangle.h; path = ../src/CSG/Triangle.h; sourceTree = ""; }; 66 | 50F347111AA6621B00E4B69E /* Polygon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Polygon.h; path = ../src/CSG/Polygon.h; sourceTree = ""; }; 67 | 50F347121AA6637F00E4B69E /* LineSegment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LineSegment.h; path = ../src/CSG/LineSegment.h; sourceTree = ""; }; 68 | E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = openFrameworksLib.xcodeproj; path = ../../../libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj; sourceTree = SOURCE_ROOT; }; 69 | E4B69B5B0A3A1756003C02F2 /* exampleDebug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = exampleDebug.app; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | E4B69E1D0A3A1BDC003C02F2 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = src/main.cpp; sourceTree = SOURCE_ROOT; }; 71 | E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = ofApp.cpp; path = src/ofApp.cpp; sourceTree = SOURCE_ROOT; }; 72 | E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ofApp.h; path = src/ofApp.h; sourceTree = SOURCE_ROOT; }; 73 | E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = "openFrameworks-Info.plist"; sourceTree = ""; }; 74 | E4EB691F138AFCF100A09F29 /* CoreOF.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CoreOF.xcconfig; path = ../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig; sourceTree = SOURCE_ROOT; }; 75 | E4EB6923138AFD0F00A09F29 /* Project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Project.xcconfig; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | E4B69B590A3A1756003C02F2 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | E4328149138ABC9F0047C5CB /* openFrameworksDebug.a in Frameworks */, 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 50E08C3E1AB0E34400762CC9 /* ofxObjLoader */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 50E08C3F1AB0E34400762CC9 /* .gitignore */, 94 | 50E08C401AB0E34400762CC9 /* libs */, 95 | 50E08C441AB0E34400762CC9 /* Readme.md */, 96 | 50E08C451AB0E34400762CC9 /* src */, 97 | ); 98 | path = ofxObjLoader; 99 | sourceTree = ""; 100 | }; 101 | 50E08C401AB0E34400762CC9 /* libs */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 50E08C411AB0E34400762CC9 /* glm */, 105 | ); 106 | path = libs; 107 | sourceTree = ""; 108 | }; 109 | 50E08C411AB0E34400762CC9 /* glm */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 50E08C421AB0E34400762CC9 /* glm.c */, 113 | 50E08C431AB0E34400762CC9 /* glm.h */, 114 | ); 115 | path = glm; 116 | sourceTree = ""; 117 | }; 118 | 50E08C451AB0E34400762CC9 /* src */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 50E08C461AB0E34400762CC9 /* ofxObjLoader.cpp */, 122 | 50E08C471AB0E34400762CC9 /* ofxObjLoader.h */, 123 | ); 124 | path = src; 125 | sourceTree = ""; 126 | }; 127 | 78D2F5C708852DFBB8CA1A94 /* CSG */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 25EB393F641E2D96B4947177 /* Utils.h */, 131 | 50F347101AA6612300E4B69E /* Triangle.h */, 132 | 5067B44C1AAF491D001557EA /* Triangle.cpp */, 133 | 50F347111AA6621B00E4B69E /* Polygon.h */, 134 | 5067B44E1AAF4A79001557EA /* Polygon.cpp */, 135 | 50F347121AA6637F00E4B69E /* LineSegment.h */, 136 | 5067B44A1AAF4823001557EA /* LineSegment.cpp */, 137 | 5067B4501AAF532D001557EA /* BoundBox.cpp */, 138 | 5067B4511AAF532D001557EA /* BoundBox.h */, 139 | ); 140 | name = CSG; 141 | sourceTree = ""; 142 | }; 143 | BB4B014C10F69532006C3DED /* addons */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | FA58553341DABCD3FC75DDCD /* ofxCSG */, 147 | ); 148 | name = addons; 149 | sourceTree = ""; 150 | }; 151 | BD45E5EA171EA66D2CCA5547 /* src */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 78D2F5C708852DFBB8CA1A94 /* CSG */, 155 | 4091601133A9DA1ED8505149 /* ofxCSG.h */, 156 | ); 157 | name = src; 158 | sourceTree = ""; 159 | }; 160 | E4328144138ABC890047C5CB /* Products */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | E4328148138ABC890047C5CB /* openFrameworksDebug.a */, 164 | ); 165 | name = Products; 166 | sourceTree = ""; 167 | }; 168 | E4B69B4A0A3A1720003C02F2 = { 169 | isa = PBXGroup; 170 | children = ( 171 | E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */, 172 | E4EB6923138AFD0F00A09F29 /* Project.xcconfig */, 173 | E4B69E1C0A3A1BDC003C02F2 /* src */, 174 | E4EEC9E9138DF44700A80321 /* openFrameworks */, 175 | BB4B014C10F69532006C3DED /* addons */, 176 | E4B69B5B0A3A1756003C02F2 /* exampleDebug.app */, 177 | ); 178 | sourceTree = ""; 179 | }; 180 | E4B69E1C0A3A1BDC003C02F2 /* src */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | E4B69E1D0A3A1BDC003C02F2 /* main.cpp */, 184 | E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */, 185 | E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */, 186 | 50E08C3E1AB0E34400762CC9 /* ofxObjLoader */, 187 | ); 188 | path = src; 189 | sourceTree = SOURCE_ROOT; 190 | }; 191 | E4EEC9E9138DF44700A80321 /* openFrameworks */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | E4EB691F138AFCF100A09F29 /* CoreOF.xcconfig */, 195 | E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */, 196 | ); 197 | name = openFrameworks; 198 | sourceTree = ""; 199 | }; 200 | FA58553341DABCD3FC75DDCD /* ofxCSG */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | BD45E5EA171EA66D2CCA5547 /* src */, 204 | ); 205 | name = ofxCSG; 206 | sourceTree = ""; 207 | }; 208 | /* End PBXGroup section */ 209 | 210 | /* Begin PBXNativeTarget section */ 211 | E4B69B5A0A3A1756003C02F2 /* example */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = E4B69B5F0A3A1757003C02F2 /* Build configuration list for PBXNativeTarget "example" */; 214 | buildPhases = ( 215 | E4B69B580A3A1756003C02F2 /* Sources */, 216 | E4B69B590A3A1756003C02F2 /* Frameworks */, 217 | E4B6FFFD0C3F9AB9008CF71C /* ShellScript */, 218 | E4C2427710CC5ABF004149E2 /* CopyFiles */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | E4EEB9AC138B136A00A80321 /* PBXTargetDependency */, 224 | ); 225 | name = example; 226 | productName = myOFApp; 227 | productReference = E4B69B5B0A3A1756003C02F2 /* exampleDebug.app */; 228 | productType = "com.apple.product-type.application"; 229 | }; 230 | /* End PBXNativeTarget section */ 231 | 232 | /* Begin PBXProject section */ 233 | E4B69B4C0A3A1720003C02F2 /* Project object */ = { 234 | isa = PBXProject; 235 | attributes = { 236 | LastUpgradeCheck = 0600; 237 | }; 238 | buildConfigurationList = E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "example" */; 239 | compatibilityVersion = "Xcode 3.2"; 240 | developmentRegion = English; 241 | hasScannedForEncodings = 0; 242 | knownRegions = ( 243 | English, 244 | Japanese, 245 | French, 246 | German, 247 | ); 248 | mainGroup = E4B69B4A0A3A1720003C02F2; 249 | productRefGroup = E4B69B4A0A3A1720003C02F2; 250 | projectDirPath = ""; 251 | projectReferences = ( 252 | { 253 | ProductGroup = E4328144138ABC890047C5CB /* Products */; 254 | ProjectRef = E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */; 255 | }, 256 | ); 257 | projectRoot = ""; 258 | targets = ( 259 | E4B69B5A0A3A1756003C02F2 /* example */, 260 | ); 261 | }; 262 | /* End PBXProject section */ 263 | 264 | /* Begin PBXReferenceProxy section */ 265 | E4328148138ABC890047C5CB /* openFrameworksDebug.a */ = { 266 | isa = PBXReferenceProxy; 267 | fileType = archive.ar; 268 | path = openFrameworksDebug.a; 269 | remoteRef = E4328147138ABC890047C5CB /* PBXContainerItemProxy */; 270 | sourceTree = BUILT_PRODUCTS_DIR; 271 | }; 272 | /* End PBXReferenceProxy section */ 273 | 274 | /* Begin PBXShellScriptBuildPhase section */ 275 | E4B6FFFD0C3F9AB9008CF71C /* ShellScript */ = { 276 | isa = PBXShellScriptBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | ); 280 | inputPaths = ( 281 | ); 282 | outputPaths = ( 283 | ); 284 | runOnlyForDeploymentPostprocessing = 0; 285 | shellPath = /bin/sh; 286 | shellScript = "cp -f ../../../libs/fmodex/lib/osx/libfmodex.dylib \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/libfmodex.dylib\"; install_name_tool -change ./libfmodex.dylib @executable_path/libfmodex.dylib \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME\";\nmkdir -p \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/\"\ncp -f \"$ICON_FILE\" \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/\"\n"; 287 | }; 288 | /* End PBXShellScriptBuildPhase section */ 289 | 290 | /* Begin PBXSourcesBuildPhase section */ 291 | E4B69B580A3A1756003C02F2 /* Sources */ = { 292 | isa = PBXSourcesBuildPhase; 293 | buildActionMask = 2147483647; 294 | files = ( 295 | 5067B44B1AAF4823001557EA /* LineSegment.cpp in Sources */, 296 | 5067B44F1AAF4A79001557EA /* Polygon.cpp in Sources */, 297 | 5067B44D1AAF491D001557EA /* Triangle.cpp in Sources */, 298 | E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */, 299 | E4B69E210A3A1BDC003C02F2 /* ofApp.cpp in Sources */, 300 | 50E08C4A1AB0E34400762CC9 /* ofxObjLoader.cpp in Sources */, 301 | 50E08C481AB0E34400762CC9 /* glm.c in Sources */, 302 | 50E08C491AB0E34400762CC9 /* Readme.md in Sources */, 303 | 5067B4521AAF532D001557EA /* BoundBox.cpp in Sources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | /* End PBXSourcesBuildPhase section */ 308 | 309 | /* Begin PBXTargetDependency section */ 310 | E4EEB9AC138B136A00A80321 /* PBXTargetDependency */ = { 311 | isa = PBXTargetDependency; 312 | name = openFrameworks; 313 | targetProxy = E4EEB9AB138B136A00A80321 /* PBXContainerItemProxy */; 314 | }; 315 | /* End PBXTargetDependency section */ 316 | 317 | /* Begin XCBuildConfiguration section */ 318 | E4B69B4E0A3A1720003C02F2 /* Debug */ = { 319 | isa = XCBuildConfiguration; 320 | baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */; 321 | buildSettings = { 322 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 323 | CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/"; 324 | COPY_PHASE_STRIP = NO; 325 | DEAD_CODE_STRIPPING = YES; 326 | GCC_AUTO_VECTORIZATION = YES; 327 | GCC_ENABLE_SSE3_EXTENSIONS = YES; 328 | GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES; 329 | GCC_INLINES_ARE_PRIVATE_EXTERN = NO; 330 | GCC_OPTIMIZATION_LEVEL = 0; 331 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 332 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; 333 | GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; 334 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; 335 | GCC_WARN_UNINITIALIZED_AUTOS = NO; 336 | GCC_WARN_UNUSED_VALUE = NO; 337 | GCC_WARN_UNUSED_VARIABLE = NO; 338 | HEADER_SEARCH_PATHS = ( 339 | "$(OF_CORE_HEADERS)", 340 | ../../../addons/ofxCSG/libs, 341 | ../../../addons/ofxCSG/src, 342 | ../../../addons/ofxCSG/src/CSG, 343 | ../../../addons/ofxObjLoader/libs, 344 | ../../../addons/ofxObjLoader/libs/glm, 345 | ../../../addons/ofxObjLoader/src, 346 | ); 347 | MACOSX_DEPLOYMENT_TARGET = 10.6; 348 | ONLY_ACTIVE_ARCH = YES; 349 | OTHER_CPLUSPLUSFLAGS = ( 350 | "-D__MACOSX_CORE__", 351 | "-lpthread", 352 | "-mtune=native", 353 | ); 354 | SDKROOT = macosx; 355 | }; 356 | name = Debug; 357 | }; 358 | E4B69B4F0A3A1720003C02F2 /* Release */ = { 359 | isa = XCBuildConfiguration; 360 | baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */; 361 | buildSettings = { 362 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 363 | CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/"; 364 | COPY_PHASE_STRIP = YES; 365 | DEAD_CODE_STRIPPING = YES; 366 | GCC_AUTO_VECTORIZATION = YES; 367 | GCC_ENABLE_SSE3_EXTENSIONS = YES; 368 | GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES; 369 | GCC_INLINES_ARE_PRIVATE_EXTERN = NO; 370 | GCC_OPTIMIZATION_LEVEL = 3; 371 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 372 | GCC_UNROLL_LOOPS = YES; 373 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; 374 | GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; 375 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; 376 | GCC_WARN_UNINITIALIZED_AUTOS = NO; 377 | GCC_WARN_UNUSED_VALUE = NO; 378 | GCC_WARN_UNUSED_VARIABLE = NO; 379 | HEADER_SEARCH_PATHS = ( 380 | "$(OF_CORE_HEADERS)", 381 | ../../../addons/ofxCSG/libs, 382 | ../../../addons/ofxCSG/src, 383 | ../../../addons/ofxCSG/src/CSG, 384 | ../../../addons/ofxObjLoader/libs, 385 | ../../../addons/ofxObjLoader/libs/glm, 386 | ../../../addons/ofxObjLoader/src, 387 | ); 388 | MACOSX_DEPLOYMENT_TARGET = 10.6; 389 | OTHER_CPLUSPLUSFLAGS = ( 390 | "-D__MACOSX_CORE__", 391 | "-lpthread", 392 | "-mtune=native", 393 | ); 394 | SDKROOT = macosx; 395 | }; 396 | name = Release; 397 | }; 398 | E4B69B600A3A1757003C02F2 /* Debug */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | COMBINE_HIDPI_IMAGES = YES; 402 | COPY_PHASE_STRIP = NO; 403 | FRAMEWORK_SEARCH_PATHS = ( 404 | "$(inherited)", 405 | "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", 406 | ); 407 | FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../../../libs/glut/lib/osx\""; 408 | GCC_DYNAMIC_NO_PIC = NO; 409 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 410 | GCC_MODEL_TUNING = NONE; 411 | ICON = "$(ICON_NAME_DEBUG)"; 412 | ICON_FILE = "$(ICON_FILE_PATH)$(ICON)"; 413 | INFOPLIST_FILE = "openFrameworks-Info.plist"; 414 | INSTALL_PATH = "$(HOME)/Applications"; 415 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 416 | PRODUCT_NAME = "$(TARGET_NAME)Debug"; 417 | WRAPPER_EXTENSION = app; 418 | }; 419 | name = Debug; 420 | }; 421 | E4B69B610A3A1757003C02F2 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | COMBINE_HIDPI_IMAGES = YES; 425 | COPY_PHASE_STRIP = YES; 426 | FRAMEWORK_SEARCH_PATHS = ( 427 | "$(inherited)", 428 | "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", 429 | ); 430 | FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../../../libs/glut/lib/osx\""; 431 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 432 | GCC_MODEL_TUNING = NONE; 433 | ICON = "$(ICON_NAME_RELEASE)"; 434 | ICON_FILE = "$(ICON_FILE_PATH)$(ICON)"; 435 | INFOPLIST_FILE = "openFrameworks-Info.plist"; 436 | INSTALL_PATH = "$(HOME)/Applications"; 437 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | WRAPPER_EXTENSION = app; 440 | }; 441 | name = Release; 442 | }; 443 | /* End XCBuildConfiguration section */ 444 | 445 | /* Begin XCConfigurationList section */ 446 | E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "example" */ = { 447 | isa = XCConfigurationList; 448 | buildConfigurations = ( 449 | E4B69B4E0A3A1720003C02F2 /* Debug */, 450 | E4B69B4F0A3A1720003C02F2 /* Release */, 451 | ); 452 | defaultConfigurationIsVisible = 0; 453 | defaultConfigurationName = Release; 454 | }; 455 | E4B69B5F0A3A1757003C02F2 /* Build configuration list for PBXNativeTarget "example" */ = { 456 | isa = XCConfigurationList; 457 | buildConfigurations = ( 458 | E4B69B600A3A1757003C02F2 /* Debug */, 459 | E4B69B610A3A1757003C02F2 /* Release */, 460 | ); 461 | defaultConfigurationIsVisible = 0; 462 | defaultConfigurationName = Release; 463 | }; 464 | /* End XCConfigurationList section */ 465 | }; 466 | rootObject = E4B69B4C0A3A1720003C02F2 /* Project object */; 467 | } 468 | -------------------------------------------------------------------------------- /example/example.xcodeproj/xcshareddata/xcschemes/example 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/example.xcodeproj/xcshareddata/xcschemes/example 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/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/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/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | //-------------------------------------------------------------- 4 | void ofApp::setup() 5 | { 6 | // ofSetLogLevel( OF_LOG_VERBOSE ); 7 | 8 | ofxObjLoader::load( "box0.obj", m0 ); 9 | ofxObjLoader::load( "box1.obj", m1 ); 10 | } 11 | 12 | //-------------------------------------------------------------- 13 | void ofApp::update() 14 | { 15 | ofMesh mesh0 = m0, mesh1 = m1; 16 | 17 | ofMatrix4x4 transform; 18 | 19 | transform.translate( sin(ofGetElapsedTimef() ) * 10, 0, 0); 20 | transform.rotate( ofGetElapsedTimef() * 10, 0, .1, 1); 21 | 22 | auto& vertices = mesh1.getVertices(); 23 | for(auto& v: vertices) 24 | { 25 | v = v * transform; 26 | } 27 | 28 | ofxCSG::meshUnion( mesh0, mesh1, mesh ); 29 | 30 | } 31 | 32 | //-------------------------------------------------------------- 33 | void ofApp::draw() 34 | { 35 | ofBackground(0,0,0); 36 | ofPushStyle(); 37 | ofDisableDepthTest(); 38 | 39 | ofSetLineWidth( 1 ); 40 | 41 | camera.begin(); 42 | 43 | ofPushMatrix(); 44 | ofScale(10, 10, 10); 45 | 46 | ofSetColor(255, 45); 47 | mesh.draw(); 48 | ofSetColor(255); 49 | mesh.drawWireframe(); 50 | 51 | ofPopMatrix(); 52 | 53 | camera.end(); 54 | 55 | ofPopStyle(); 56 | } 57 | 58 | //-------------------------------------------------------------- 59 | void ofApp::keyPressed(int key){ 60 | 61 | } 62 | -------------------------------------------------------------------------------- /example/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | 5 | #include "ofxObjLoader.h" 6 | 7 | #include "ofxCSG.h" 8 | 9 | class ofApp : public ofBaseApp{ 10 | 11 | public: 12 | void setup(); 13 | void update(); 14 | void draw(); 15 | 16 | void keyPressed(int key); 17 | 18 | ofEasyCam camera; 19 | 20 | ofMesh m0, m1, mesh, otherMesh; 21 | 22 | 23 | ofxCSG::Polygon cp0, cp1; 24 | vector intersectionPoints; 25 | }; 26 | -------------------------------------------------------------------------------- /example/src/ofxObjLoader/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode* 2 | *.pbxuser 3 | *.xcworkspace 4 | xcuserdata/ 5 | 6 | build/ 7 | obj/ 8 | *.o 9 | openFrameworks.a 10 | openFrameworksDebug.a 11 | openFrameworksUniversal.a 12 | *.app 13 | 14 | #rule to avoid non-official addons going into git 15 | #see addons/.gitignore 16 | #addons/** 17 | 18 | #NMM: 19 | apps/*/*/bin/data/img_cache 20 | 21 | #codeblocks files 22 | apps/*/*/*.layout 23 | apps/*/*/*.depend 24 | apps/*/*/bin/clickToLaunch* 25 | apps/*/*/bin/libs 26 | apps/*/*/obj 27 | 28 | #rule to avoid non-official apps going into git 29 | #see apps/.gitignore 30 | #apps 31 | 32 | #codeblocks OF lib files 33 | libs/openFrameworksCompiled/project/*/*.depend 34 | libs/openFrameworksCompiled/project/*/*.layout 35 | 36 | #linux temporary files 37 | *~ 38 | 39 | #eclipse build folders 40 | #Mac OS X 41 | addons/Debug Mac OS X 42 | addons/Release Mac OS X 43 | libs/openFrameworks/Debug Mac OS X 44 | libs/openFrameworks/Release Mac OS X 45 | apps/*/*/Debug Mac OS X 46 | apps/*/*/Release Mac OS X 47 | .DS_Store 48 | 49 | #xcode 50 | *.perspectivev3 51 | *.pbxuser 52 | 53 | 54 | #Linux 55 | addons/Debug Linux 56 | addons/Release Linux 57 | libs/openFrameworks/Debug Linux 58 | libs/openFrameworks/Release Linux 59 | apps/*/*/Debug Linux 60 | apps/*/*/Release Linux 61 | apps/*/*/Debug Linux64 62 | apps/*/*/Release Linux64 63 | 64 | 65 | 66 | apps/nmm/NMMVisualizer/bin/data/journeys/** 67 | apps/nmm/NMMVisualizer/bin/data/img_cache/** 68 | #/apps/nmm/_sharedTestingFiles/SampleLayout/Wave_layout_template_scaleREZ_04_cs3.ai 69 | #/apps/nmm/_sharedTestingFiles/SampleLayout/Wave_layout_template_scaleREZ_04_cs3.svg 70 | /apps/nmm/NMMVisualizer/bin/data/VisualizerSettings.xml 71 | 72 | #Android 73 | addons/Debug Android 74 | addons/Release Android 75 | libs/openFrameworks/Debug Android 76 | libs/openFrameworks/Release Android 77 | libs/openFrameworks/Release 78 | libs/openFrameworks/Debug 79 | libs/openFrameworks/Release_arm7 80 | apps/*/*/Debug Android 81 | apps/*/*/Release Android 82 | apps/*/*/Debug 83 | apps/*/*/Release 84 | apps/*/*/Release_arm7 85 | apps/*/*/test link 86 | apps/*/*/obj 87 | #apps/*/*/bin 88 | 89 | .csettings 90 | 91 | /apps/nmm/NMMPufferfish_DesignPrototype/bin/data/Puffersphere Settings_settings.xml 92 | /apps/nmm/NMMRenderer/bin/data/mpe_config.xml 93 | /apps/nmm/NMMRenderer/NMMRenderer.xcodeproj/focus.perspectivev3 94 | /apps/nmm/NMMRenderer/bin/data/LocalSettings.xml 95 | /apps/nmm/NMMAudioPlayer/bin/data/Test conflict_settings.xml 96 | /apps/nmm/NMMAudioPlayer/bin/data/Test navigation_settings.xml 97 | /apps/nmm/NMMAudioPlayer/bin/data/Test trade_settings.xml -------------------------------------------------------------------------------- /example/src/ofxObjLoader/Readme.md: -------------------------------------------------------------------------------- 1 | # Wavefront OBJ loading and saving for openFrameworks 2 | 3 | This class provides encapsulates the GLM library for to save and load ofMesh in OBJ format. 4 | 5 | It also allows for Normal generation 6 | 7 | GLM library by Nate Robins, 1997 8 | ndr@pobox.com, http://www.pobox.com/~ndr/ 9 | 10 | Addon by Satoru Higa ( http://structor.jp/ ) 11 | Improvements by James George ( http://jamesgeorge.org/ ) 12 | 13 | Example sphere from: http://liszt.stanford.edu/meshes/sphere.obj 14 | -------------------------------------------------------------------------------- /example/src/ofxObjLoader/libs/glm/glm.c: -------------------------------------------------------------------------------- 1 | /* 2 | glm.c 3 | Nate Robins, 1997 4 | ndr@pobox.com, http://www.pobox.com/~ndr/ 5 | 6 | Wavefront OBJ model file format reader/writer/manipulator. 7 | 8 | Includes routines for generating smooth normals with 9 | preservation of edges, welding redundant vertices & texture 10 | coordinate generation (spheremap and planar projections) + more. 11 | 12 | */ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "glm.h" 21 | 22 | 23 | #define T(x) (model->triangles[(x)]) 24 | 25 | 26 | /* _GLMnode: general purpose node 27 | */ 28 | typedef struct _GLMnode { 29 | GLuint index; 30 | GLboolean averaged; 31 | struct _GLMnode* next; 32 | } GLMnode; 33 | 34 | 35 | /* glmMax: returns the maximum of two floats */ 36 | static GLfloat 37 | glmMax(GLfloat a, GLfloat b) 38 | { 39 | if (b > a) 40 | return b; 41 | return a; 42 | } 43 | 44 | /* glmAbs: returns the absolute value of a float */ 45 | static GLfloat 46 | glmAbs(GLfloat f) 47 | { 48 | if (f < 0) 49 | return -f; 50 | return f; 51 | } 52 | 53 | /* glmDot: compute the dot product of two vectors 54 | * 55 | * u - array of 3 GLfloats (GLfloat u[3]) 56 | * v - array of 3 GLfloats (GLfloat v[3]) 57 | */ 58 | static GLfloat 59 | glmDot(GLfloat* u, GLfloat* v) 60 | { 61 | assert(u); assert(v); 62 | 63 | return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; 64 | } 65 | 66 | /* glmCross: compute the cross product of two vectors 67 | * 68 | * u - array of 3 GLfloats (GLfloat u[3]) 69 | * v - array of 3 GLfloats (GLfloat v[3]) 70 | * n - array of 3 GLfloats (GLfloat n[3]) to return the cross product in 71 | */ 72 | static GLvoid 73 | glmCross(GLfloat* u, GLfloat* v, GLfloat* n) 74 | { 75 | assert(u); assert(v); assert(n); 76 | 77 | n[0] = u[1]*v[2] - u[2]*v[1]; 78 | n[1] = u[2]*v[0] - u[0]*v[2]; 79 | n[2] = u[0]*v[1] - u[1]*v[0]; 80 | } 81 | 82 | /* glmNormalize: normalize a vector 83 | * 84 | * v - array of 3 GLfloats (GLfloat v[3]) to be normalized 85 | */ 86 | static GLvoid 87 | glmNormalize(GLfloat* v) 88 | { 89 | GLfloat l; 90 | 91 | assert(v); 92 | 93 | l = (GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); 94 | v[0] /= l; 95 | v[1] /= l; 96 | v[2] /= l; 97 | } 98 | 99 | /* glmEqual: compares two vectors and returns GL_TRUE if they are 100 | * equal (within a certain threshold) or GL_FALSE if not. An epsilon 101 | * that works fairly well is 0.000001. 102 | * 103 | * u - array of 3 GLfloats (GLfloat u[3]) 104 | * v - array of 3 GLfloats (GLfloat v[3]) 105 | */ 106 | static GLboolean 107 | glmEqual(GLfloat* u, GLfloat* v, GLfloat epsilon) 108 | { 109 | if (glmAbs(u[0] - v[0]) < epsilon && 110 | glmAbs(u[1] - v[1]) < epsilon && 111 | glmAbs(u[2] - v[2]) < epsilon) 112 | { 113 | return GL_TRUE; 114 | } 115 | return GL_FALSE; 116 | } 117 | 118 | /* glmWeldVectors: eliminate (weld) vectors that are within an 119 | * epsilon of each other. 120 | * 121 | * vectors - array of GLfloat[3]'s to be welded 122 | * numvectors - number of GLfloat[3]'s in vectors 123 | * epsilon - maximum difference between vectors 124 | * 125 | */ 126 | GLfloat* 127 | glmWeldVectors(GLfloat* vectors, GLuint* numvectors, GLfloat epsilon) 128 | { 129 | GLfloat* copies; 130 | GLuint copied; 131 | GLuint i, j; 132 | 133 | copies = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (*numvectors + 1)); 134 | memcpy(copies, vectors, (sizeof(GLfloat) * 3 * (*numvectors + 1))); 135 | 136 | copied = 1; 137 | for (i = 1; i <= *numvectors; i++) { 138 | for (j = 1; j <= copied; j++) { 139 | if (glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) { 140 | goto duplicate; 141 | } 142 | } 143 | 144 | /* must not be any duplicates -- add to the copies array */ 145 | copies[3 * copied + 0] = vectors[3 * i + 0]; 146 | copies[3 * copied + 1] = vectors[3 * i + 1]; 147 | copies[3 * copied + 2] = vectors[3 * i + 2]; 148 | j = copied; /* pass this along for below */ 149 | copied++; 150 | 151 | duplicate: 152 | /* set the first component of this vector to point at the correct 153 | index into the new copies array */ 154 | vectors[3 * i + 0] = (GLfloat)j; 155 | } 156 | 157 | *numvectors = copied-1; 158 | return copies; 159 | } 160 | 161 | /* glmFindGroup: Find a group in the model 162 | */ 163 | GLMgroup* 164 | glmFindGroup(GLMmodel* model, char* name) 165 | { 166 | GLMgroup* group; 167 | 168 | assert(model); 169 | 170 | group = model->groups; 171 | while(group) { 172 | if (!strcmp(name, group->name)) 173 | break; 174 | group = group->next; 175 | } 176 | 177 | return group; 178 | } 179 | 180 | /* glmAddGroup: Add a group to the model 181 | */ 182 | GLMgroup* 183 | glmAddGroup(GLMmodel* model, char* name) 184 | { 185 | GLMgroup* group; 186 | 187 | group = glmFindGroup(model, name); 188 | if (!group) { 189 | group = (GLMgroup*)malloc(sizeof(GLMgroup)); 190 | group->name = strdup(name); 191 | group->material = 0; 192 | group->numtriangles = 0; 193 | group->triangles = NULL; 194 | group->next = model->groups; 195 | model->groups = group; 196 | model->numgroups++; 197 | } 198 | 199 | return group; 200 | } 201 | 202 | /* glmFindGroup: Find a material in the model 203 | */ 204 | GLuint 205 | glmFindMaterial(GLMmodel* model, char* name) 206 | { 207 | GLuint i; 208 | 209 | /* XXX doing a linear search on a string key'd list is pretty lame, 210 | but it works and is fast enough for now. */ 211 | for (i = 0; i < model->nummaterials; i++) { 212 | if (!strcmp(model->materials[i].name, name)) 213 | goto found; 214 | } 215 | 216 | /* didn't find the name, so print a warning and return the default 217 | material (0). */ 218 | printf("glmFindMaterial(): can't find material \"%s\".\n", name); 219 | i = 0; 220 | 221 | found: 222 | return i; 223 | } 224 | 225 | 226 | /* glmDirName: return the directory given a path 227 | * 228 | * path - filesystem path 229 | * 230 | * NOTE: the return value should be free'd. 231 | */ 232 | static char* 233 | glmDirName(char* path) 234 | { 235 | char* dir; 236 | char* s; 237 | 238 | dir = strdup(path); 239 | 240 | s = strrchr(dir, '/'); 241 | if (s) 242 | s[1] = '\0'; 243 | else 244 | dir[0] = '\0'; 245 | 246 | return dir; 247 | } 248 | 249 | 250 | /* glmReadMTL: read a wavefront material library file 251 | * 252 | * model - properly initialized GLMmodel structure 253 | * name - name of the material library 254 | */ 255 | static GLvoid 256 | glmReadMTL(GLMmodel* model, char* name) 257 | { 258 | FILE* file; 259 | char* dir; 260 | char* filename; 261 | char buf[128]; 262 | GLuint nummaterials, i; 263 | 264 | dir = glmDirName(model->pathname); 265 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1)); 266 | strcpy(filename, dir); 267 | strcat(filename, name); 268 | free(dir); 269 | 270 | file = fopen(filename, "r"); 271 | if (!file) { 272 | fprintf(stderr, "glmReadMTL() failed: can't open material file \"%s\".\n", 273 | filename); 274 | return; 275 | } 276 | free(filename); 277 | 278 | /* count the number of materials in the file */ 279 | nummaterials = 1; 280 | while(fscanf(file, "%s", buf) != EOF) { 281 | switch(buf[0]) { 282 | case '#': /* comment */ 283 | /* eat up rest of line */ 284 | fgets(buf, sizeof(buf), file); 285 | break; 286 | case 'n': /* newmtl */ 287 | fgets(buf, sizeof(buf), file); 288 | nummaterials++; 289 | sscanf(buf, "%s %s", buf, buf); 290 | break; 291 | default: 292 | /* eat up rest of line */ 293 | fgets(buf, sizeof(buf), file); 294 | break; 295 | } 296 | } 297 | 298 | rewind(file); 299 | 300 | model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials); 301 | model->nummaterials = nummaterials; 302 | 303 | /* set the default material */ 304 | for (i = 0; i < nummaterials; i++) { 305 | model->materials[i].name = NULL; 306 | model->materials[i].texture_path = NULL; 307 | model->materials[i].shininess = 65.0; 308 | model->materials[i].diffuse[0] = 0.8; 309 | model->materials[i].diffuse[1] = 0.8; 310 | model->materials[i].diffuse[2] = 0.8; 311 | model->materials[i].diffuse[3] = 1.0; 312 | model->materials[i].ambient[0] = 0.2; 313 | model->materials[i].ambient[1] = 0.2; 314 | model->materials[i].ambient[2] = 0.2; 315 | model->materials[i].ambient[3] = 1.0; 316 | model->materials[i].specular[0] = 0.0; 317 | model->materials[i].specular[1] = 0.0; 318 | model->materials[i].specular[2] = 0.0; 319 | model->materials[i].specular[3] = 1.0; 320 | } 321 | model->materials[0].name = strdup("default"); 322 | 323 | /* now, read in the data */ 324 | nummaterials = 0; 325 | while(fscanf(file, "%s", buf) != EOF) { 326 | switch(buf[0]) { 327 | case '#': /* comment */ 328 | /* eat up rest of line */ 329 | fgets(buf, sizeof(buf), file); 330 | break; 331 | case 'n': /* newmtl */ 332 | fgets(buf, sizeof(buf), file); 333 | sscanf(buf, "%s %s", buf, buf); 334 | nummaterials++; 335 | model->materials[nummaterials].name = strdup(buf); 336 | break; 337 | case 'N': 338 | fscanf(file, "%f", &model->materials[nummaterials].shininess); 339 | /* wavefront shininess is from [0, 1000], so scale for OpenGL */ 340 | model->materials[nummaterials].shininess /= 1000.0; 341 | model->materials[nummaterials].shininess *= 128.0; 342 | break; 343 | case 'K': 344 | switch(buf[1]) { 345 | case 'd': 346 | fscanf(file, "%f %f %f", 347 | &model->materials[nummaterials].diffuse[0], 348 | &model->materials[nummaterials].diffuse[1], 349 | &model->materials[nummaterials].diffuse[2]); 350 | break; 351 | case 's': 352 | fscanf(file, "%f %f %f", 353 | &model->materials[nummaterials].specular[0], 354 | &model->materials[nummaterials].specular[1], 355 | &model->materials[nummaterials].specular[2]); 356 | break; 357 | case 'a': 358 | fscanf(file, "%f %f %f", 359 | &model->materials[nummaterials].ambient[0], 360 | &model->materials[nummaterials].ambient[1], 361 | &model->materials[nummaterials].ambient[2]); 362 | break; 363 | default: 364 | /* eat up rest of line */ 365 | fgets(buf, sizeof(buf), file); 366 | break; 367 | } 368 | break; 369 | default: 370 | /* eat up rest of line */ 371 | fgets(buf, sizeof(buf), file); 372 | break; 373 | } 374 | } 375 | } 376 | 377 | /* glmWriteMTL: write a wavefront material library file 378 | * 379 | * model - properly initialized GLMmodel structure 380 | * modelpath - pathname of the model being written 381 | * mtllibname - name of the material library to be written 382 | */ 383 | static GLvoid 384 | glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname) 385 | { 386 | FILE* file; 387 | char* dir; 388 | char* filename; 389 | GLMmaterial* material; 390 | GLuint i; 391 | 392 | dir = glmDirName(modelpath); 393 | filename = (char*)malloc(sizeof(char) * (strlen(dir)+strlen(mtllibname))); 394 | strcpy(filename, dir); 395 | strcat(filename, mtllibname); 396 | free(dir); 397 | 398 | /* open the file */ 399 | file = fopen(filename, "w"); 400 | if (!file) { 401 | fprintf(stderr, "glmWriteMTL() failed: can't open file \"%s\".\n", 402 | filename); 403 | return; 404 | } 405 | free(filename); 406 | 407 | /* spit out a header */ 408 | fprintf(file, "# \n"); 409 | fprintf(file, "# Wavefront MTL generated by GLM library\n"); 410 | fprintf(file, "# \n"); 411 | fprintf(file, "# GLM library\n"); 412 | fprintf(file, "# Nate Robins\n"); 413 | fprintf(file, "# ndr@pobox.com\n"); 414 | fprintf(file, "# http://www.pobox.com/~ndr\n"); 415 | fprintf(file, "# \n\n"); 416 | 417 | for (i = 0; i < model->nummaterials; i++) { 418 | material = &model->materials[i]; 419 | fprintf(file, "newmtl %s\n", material->name); 420 | fprintf(file, "map_Kd %s\n", material->texture_path); 421 | fprintf(file, "Ka %f %f %f\n", 422 | material->ambient[0], material->ambient[1], material->ambient[2]); 423 | fprintf(file, "Kd %f %f %f\n", 424 | material->diffuse[0], material->diffuse[1], material->diffuse[2]); 425 | fprintf(file, "Ks %f %f %f\n", 426 | material->specular[0],material->specular[1],material->specular[2]); 427 | fprintf(file, "Ns %f\n", material->shininess / 128.0 * 1000.0); 428 | fprintf(file, "\n"); 429 | } 430 | 431 | fflush(file); 432 | } 433 | 434 | 435 | /* glmFirstPass: first pass at a Wavefront OBJ file that gets all the 436 | * statistics of the model (such as #vertices, #normals, etc) 437 | * 438 | * model - properly initialized GLMmodel structure 439 | * file - (fopen'd) file descriptor 440 | */ 441 | static GLvoid 442 | glmFirstPass(GLMmodel* model, FILE* file) 443 | { 444 | GLuint numvertices; /* number of vertices in model */ 445 | GLuint numnormals; /* number of normals in model */ 446 | GLuint numtexcoords; /* number of texcoords in model */ 447 | GLuint numtriangles; /* number of triangles in model */ 448 | GLMgroup* group; /* current group */ 449 | unsigned v, n, t; 450 | char buf[128]; 451 | 452 | /* make a default group */ 453 | group = glmAddGroup(model, "default"); 454 | 455 | numvertices = numnormals = numtexcoords = numtriangles = 0; 456 | while(fscanf(file, "%s", buf) != EOF) { 457 | switch(buf[0]) { 458 | case '#': /* comment */ 459 | /* eat up rest of line */ 460 | fgets(buf, sizeof(buf), file); 461 | break; 462 | case 'v': /* v, vn, vt */ 463 | switch(buf[1]) { 464 | case '\0': /* vertex */ 465 | /* eat up rest of line */ 466 | fgets(buf, sizeof(buf), file); 467 | numvertices++; 468 | break; 469 | case 'n': /* normal */ 470 | /* eat up rest of line */ 471 | fgets(buf, sizeof(buf), file); 472 | numnormals++; 473 | break; 474 | case 't': /* texcoord */ 475 | /* eat up rest of line */ 476 | fgets(buf, sizeof(buf), file); 477 | numtexcoords++; 478 | break; 479 | default: 480 | printf("glmFirstPass(): Unknown token \"%s\".\n", buf); 481 | return; 482 | break; 483 | } 484 | break; 485 | case 'm': 486 | fgets(buf, sizeof(buf), file); 487 | sscanf(buf, "%s %s", buf, buf); 488 | model->mtllibname = strdup(buf); 489 | glmReadMTL(model, buf); 490 | break; 491 | case 'u': 492 | /* eat up rest of line */ 493 | fgets(buf, sizeof(buf), file); 494 | break; 495 | case 'g': /* group */ 496 | /* eat up rest of line */ 497 | fgets(buf, sizeof(buf), file); 498 | #if SINGLE_STRING_GROUP_NAMES 499 | sscanf(buf, "%s", buf); 500 | #else 501 | buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ 502 | #endif 503 | group = glmAddGroup(model, buf); 504 | break; 505 | case 'f': /* face */ 506 | v = n = t = 0; 507 | fscanf(file, "%s", buf); 508 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 509 | if (strstr(buf, "//")) { 510 | /* v//n */ 511 | sscanf(buf, "%d//%d", &v, &n); 512 | fscanf(file, "%d//%d", &v, &n); 513 | fscanf(file, "%d//%d", &v, &n); 514 | numtriangles++; 515 | group->numtriangles++; 516 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 517 | numtriangles++; 518 | group->numtriangles++; 519 | } 520 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 521 | /* v/t/n */ 522 | fscanf(file, "%d/%d/%d", &v, &t, &n); 523 | fscanf(file, "%d/%d/%d", &v, &t, &n); 524 | numtriangles++; 525 | group->numtriangles++; 526 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 527 | numtriangles++; 528 | group->numtriangles++; 529 | } 530 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 531 | /* v/t */ 532 | fscanf(file, "%d/%d", &v, &t); 533 | fscanf(file, "%d/%d", &v, &t); 534 | numtriangles++; 535 | group->numtriangles++; 536 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 537 | numtriangles++; 538 | group->numtriangles++; 539 | } 540 | } else { 541 | /* v */ 542 | fscanf(file, "%d", &v); 543 | fscanf(file, "%d", &v); 544 | numtriangles++; 545 | group->numtriangles++; 546 | while(fscanf(file, "%d", &v) > 0) { 547 | numtriangles++; 548 | group->numtriangles++; 549 | } 550 | } 551 | break; 552 | 553 | default: 554 | /* eat up rest of line */ 555 | fgets(buf, sizeof(buf), file); 556 | break; 557 | } 558 | } 559 | 560 | /* set the stats in the model structure */ 561 | model->numvertices = numvertices; 562 | model->numnormals = numnormals; 563 | model->numtexcoords = numtexcoords; 564 | model->numtriangles = numtriangles; 565 | 566 | /* allocate memory for the triangles in each group */ 567 | group = model->groups; 568 | while(group) { 569 | group->triangles = (GLuint*)malloc(sizeof(GLuint) * group->numtriangles); 570 | group->numtriangles = 0; 571 | group = group->next; 572 | } 573 | } 574 | 575 | /* glmSecondPass: second pass at a Wavefront OBJ file that gets all 576 | * the data. 577 | * 578 | * model - properly initialized GLMmodel structure 579 | * file - (fopen'd) file descriptor 580 | */ 581 | static GLvoid 582 | glmSecondPass(GLMmodel* model, FILE* file) 583 | { 584 | GLuint numvertices; /* number of vertices in model */ 585 | GLuint numnormals; /* number of normals in model */ 586 | GLuint numtexcoords; /* number of texcoords in model */ 587 | GLuint numtriangles; /* number of triangles in model */ 588 | GLfloat* vertices; /* array of vertices */ 589 | GLfloat* colors; /* array of vertices */ 590 | GLfloat* normals; /* array of normals */ 591 | GLfloat* texcoords; /* array of texture coordinates */ 592 | GLMgroup* group; /* current group pointer */ 593 | GLuint material; /* current material */ 594 | GLuint v, n, t; 595 | char buf[128]; 596 | 597 | /* set the pointer shortcuts */ 598 | vertices = model->vertices; 599 | colors = model->colors; 600 | normals = model->normals; 601 | texcoords = model->texcoords; 602 | group = model->groups; 603 | 604 | /* on the second pass through the file, read all the data into the 605 | allocated arrays */ 606 | numvertices = numnormals = numtexcoords = 1; 607 | numtriangles = 0; 608 | material = 0; 609 | 610 | while(fscanf(file, "%s", buf) != EOF) { 611 | switch(buf[0]) { 612 | case '#': /* comment */ 613 | /* eat up rest of line */ 614 | fgets(buf, sizeof(buf), file); 615 | break; 616 | case 'v': /* v, vn, vt */ 617 | switch(buf[1]) { 618 | case '\0': /* vertex */ 619 | model->has_vertex_color = (6 == fscanf(file, "%f %f %f %f %f %f", 620 | &vertices[3 * numvertices + 0], 621 | &vertices[3 * numvertices + 1], 622 | &vertices[3 * numvertices + 2], 623 | &colors[3 * numvertices + 0], 624 | &colors[3 * numvertices + 1], 625 | &colors[3 * numvertices + 2])); 626 | numvertices++; 627 | break; 628 | case 'n': /* normal */ 629 | fscanf(file, "%f %f %f", 630 | &normals[3 * numnormals + 0], 631 | &normals[3 * numnormals + 1], 632 | &normals[3 * numnormals + 2]); 633 | numnormals++; 634 | break; 635 | case 't': /* texcoord */ 636 | fscanf(file, "%f %f", 637 | &texcoords[2 * numtexcoords + 0], 638 | &texcoords[2 * numtexcoords + 1]); 639 | numtexcoords++; 640 | break; 641 | } 642 | break; 643 | case 'u': 644 | fgets(buf, sizeof(buf), file); 645 | sscanf(buf, "%s %s", buf, buf); 646 | group->material = material = glmFindMaterial(model, buf); 647 | break; 648 | case 'g': /* group */ 649 | /* eat up rest of line */ 650 | fgets(buf, sizeof(buf), file); 651 | #if SINGLE_STRING_GROUP_NAMES 652 | sscanf(buf, "%s", buf); 653 | #else 654 | buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ 655 | #endif 656 | group = glmFindGroup(model, buf); 657 | group->material = material; 658 | break; 659 | case 'f': /* face */ 660 | v = n = t = 0; 661 | fscanf(file, "%s", buf); 662 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 663 | if (strstr(buf, "//")) { 664 | /* v//n */ 665 | sscanf(buf, "%d//%d", &v, &n); 666 | T(numtriangles).vindices[0] = v; 667 | T(numtriangles).nindices[0] = n; 668 | fscanf(file, "%d//%d", &v, &n); 669 | T(numtriangles).vindices[1] = v; 670 | T(numtriangles).nindices[1] = n; 671 | fscanf(file, "%d//%d", &v, &n); 672 | T(numtriangles).vindices[2] = v; 673 | T(numtriangles).nindices[2] = n; 674 | group->triangles[group->numtriangles++] = numtriangles; 675 | numtriangles++; 676 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 677 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 678 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 679 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 680 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 681 | T(numtriangles).vindices[2] = v; 682 | T(numtriangles).nindices[2] = n; 683 | group->triangles[group->numtriangles++] = numtriangles; 684 | numtriangles++; 685 | } 686 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 687 | /* v/t/n */ 688 | T(numtriangles).vindices[0] = v; 689 | T(numtriangles).tindices[0] = t; 690 | T(numtriangles).nindices[0] = n; 691 | fscanf(file, "%d/%d/%d", &v, &t, &n); 692 | T(numtriangles).vindices[1] = v; 693 | T(numtriangles).tindices[1] = t; 694 | T(numtriangles).nindices[1] = n; 695 | fscanf(file, "%d/%d/%d", &v, &t, &n); 696 | T(numtriangles).vindices[2] = v; 697 | T(numtriangles).tindices[2] = t; 698 | T(numtriangles).nindices[2] = n; 699 | group->triangles[group->numtriangles++] = numtriangles; 700 | numtriangles++; 701 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 702 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 703 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 704 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 705 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 706 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 707 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 708 | T(numtriangles).vindices[2] = v; 709 | T(numtriangles).tindices[2] = t; 710 | T(numtriangles).nindices[2] = n; 711 | group->triangles[group->numtriangles++] = numtriangles; 712 | numtriangles++; 713 | } 714 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 715 | /* v/t */ 716 | T(numtriangles).vindices[0] = v; 717 | T(numtriangles).tindices[0] = t; 718 | fscanf(file, "%d/%d", &v, &t); 719 | T(numtriangles).vindices[1] = v; 720 | T(numtriangles).tindices[1] = t; 721 | fscanf(file, "%d/%d", &v, &t); 722 | T(numtriangles).vindices[2] = v; 723 | T(numtriangles).tindices[2] = t; 724 | group->triangles[group->numtriangles++] = numtriangles; 725 | numtriangles++; 726 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 727 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 728 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 729 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 730 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 731 | T(numtriangles).vindices[2] = v; 732 | T(numtriangles).tindices[2] = t; 733 | group->triangles[group->numtriangles++] = numtriangles; 734 | numtriangles++; 735 | } 736 | } else { 737 | /* v */ 738 | sscanf(buf, "%d", &v); 739 | T(numtriangles).vindices[0] = v; 740 | fscanf(file, "%d", &v); 741 | T(numtriangles).vindices[1] = v; 742 | fscanf(file, "%d", &v); 743 | T(numtriangles).vindices[2] = v; 744 | group->triangles[group->numtriangles++] = numtriangles; 745 | numtriangles++; 746 | while(fscanf(file, "%d", &v) > 0) { 747 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 748 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 749 | T(numtriangles).vindices[2] = v; 750 | group->triangles[group->numtriangles++] = numtriangles; 751 | numtriangles++; 752 | } 753 | } 754 | break; 755 | 756 | default: 757 | /* eat up rest of line */ 758 | fgets(buf, sizeof(buf), file); 759 | break; 760 | } 761 | } 762 | 763 | #if 0 764 | /* announce the memory requirements */ 765 | printf(" Memory: %d bytes\n", 766 | numvertices * 3*sizeof(GLfloat) + 767 | numnormals * 3*sizeof(GLfloat) * (numnormals ? 1 : 0) + 768 | numtexcoords * 3*sizeof(GLfloat) * (numtexcoords ? 1 : 0) + 769 | numtriangles * sizeof(GLMtriangle)); 770 | #endif 771 | } 772 | 773 | 774 | /* public functions */ 775 | 776 | 777 | /* glmUnitize: "unitize" a model by translating it to the origin and 778 | * scaling it to fit in a unit cube around the origin. Returns the 779 | * scalefactor used. 780 | * 781 | * model - properly initialized GLMmodel structure 782 | */ 783 | GLfloat 784 | glmUnitize(GLMmodel* model) 785 | { 786 | GLuint i; 787 | GLfloat maxx, minx, maxy, miny, maxz, minz; 788 | GLfloat cx, cy, cz, w, h, d; 789 | GLfloat scale; 790 | 791 | assert(model); 792 | assert(model->vertices); 793 | 794 | /* get the max/mins */ 795 | maxx = minx = model->vertices[3 + 0]; 796 | maxy = miny = model->vertices[3 + 1]; 797 | maxz = minz = model->vertices[3 + 2]; 798 | for (i = 1; i <= model->numvertices; i++) { 799 | if (maxx < model->vertices[3 * i + 0]) 800 | maxx = model->vertices[3 * i + 0]; 801 | if (minx > model->vertices[3 * i + 0]) 802 | minx = model->vertices[3 * i + 0]; 803 | 804 | if (maxy < model->vertices[3 * i + 1]) 805 | maxy = model->vertices[3 * i + 1]; 806 | if (miny > model->vertices[3 * i + 1]) 807 | miny = model->vertices[3 * i + 1]; 808 | 809 | if (maxz < model->vertices[3 * i + 2]) 810 | maxz = model->vertices[3 * i + 2]; 811 | if (minz > model->vertices[3 * i + 2]) 812 | minz = model->vertices[3 * i + 2]; 813 | } 814 | 815 | /* calculate model width, height, and depth */ 816 | w = glmAbs(maxx) + glmAbs(minx); 817 | h = glmAbs(maxy) + glmAbs(miny); 818 | d = glmAbs(maxz) + glmAbs(minz); 819 | 820 | /* calculate center of the model */ 821 | cx = (maxx + minx) / 2.0; 822 | cy = (maxy + miny) / 2.0; 823 | cz = (maxz + minz) / 2.0; 824 | 825 | /* calculate unitizing scale factor */ 826 | scale = 2.0 / glmMax(glmMax(w, h), d); 827 | 828 | /* translate around center then scale */ 829 | for (i = 1; i <= model->numvertices; i++) { 830 | model->vertices[3 * i + 0] -= cx; 831 | model->vertices[3 * i + 1] -= cy; 832 | model->vertices[3 * i + 2] -= cz; 833 | model->vertices[3 * i + 0] *= scale; 834 | model->vertices[3 * i + 1] *= scale; 835 | model->vertices[3 * i + 2] *= scale; 836 | } 837 | 838 | return scale; 839 | } 840 | 841 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 842 | * a model. 843 | * 844 | * model - initialized GLMmodel structure 845 | * dimensions - array of 3 GLfloats (GLfloat dimensions[3]) 846 | */ 847 | GLvoid 848 | glmDimensions(GLMmodel* model, GLfloat* dimensions) 849 | { 850 | GLuint i; 851 | GLfloat maxx, minx, maxy, miny, maxz, minz; 852 | 853 | assert(model); 854 | assert(model->vertices); 855 | assert(dimensions); 856 | 857 | /* get the max/mins */ 858 | maxx = minx = model->vertices[3 + 0]; 859 | maxy = miny = model->vertices[3 + 1]; 860 | maxz = minz = model->vertices[3 + 2]; 861 | for (i = 1; i <= model->numvertices; i++) { 862 | if (maxx < model->vertices[3 * i + 0]) 863 | maxx = model->vertices[3 * i + 0]; 864 | if (minx > model->vertices[3 * i + 0]) 865 | minx = model->vertices[3 * i + 0]; 866 | 867 | if (maxy < model->vertices[3 * i + 1]) 868 | maxy = model->vertices[3 * i + 1]; 869 | if (miny > model->vertices[3 * i + 1]) 870 | miny = model->vertices[3 * i + 1]; 871 | 872 | if (maxz < model->vertices[3 * i + 2]) 873 | maxz = model->vertices[3 * i + 2]; 874 | if (minz > model->vertices[3 * i + 2]) 875 | minz = model->vertices[3 * i + 2]; 876 | } 877 | 878 | /* calculate model width, height, and depth */ 879 | dimensions[0] = glmAbs(maxx) + glmAbs(minx); 880 | dimensions[1] = glmAbs(maxy) + glmAbs(miny); 881 | dimensions[2] = glmAbs(maxz) + glmAbs(minz); 882 | } 883 | 884 | /* glmScale: Scales a model by a given amount. 885 | * 886 | * model - properly initialized GLMmodel structure 887 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 888 | */ 889 | GLvoid 890 | glmScale(GLMmodel* model, GLfloat scale) 891 | { 892 | GLuint i; 893 | 894 | for (i = 1; i <= model->numvertices; i++) { 895 | model->vertices[3 * i + 0] *= scale; 896 | model->vertices[3 * i + 1] *= scale; 897 | model->vertices[3 * i + 2] *= scale; 898 | } 899 | } 900 | 901 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 902 | * this model. Default winding is counter-clockwise. Also changes 903 | * the direction of the normals. 904 | * 905 | * model - properly initialized GLMmodel structure 906 | */ 907 | GLvoid 908 | glmReverseWinding(GLMmodel* model) 909 | { 910 | GLuint i, swap; 911 | 912 | assert(model); 913 | 914 | for (i = 0; i < model->numtriangles; i++) { 915 | swap = T(i).vindices[0]; 916 | T(i).vindices[0] = T(i).vindices[2]; 917 | T(i).vindices[2] = swap; 918 | 919 | if (model->numnormals) { 920 | swap = T(i).nindices[0]; 921 | T(i).nindices[0] = T(i).nindices[2]; 922 | T(i).nindices[2] = swap; 923 | } 924 | 925 | if (model->numtexcoords) { 926 | swap = T(i).tindices[0]; 927 | T(i).tindices[0] = T(i).tindices[2]; 928 | T(i).tindices[2] = swap; 929 | } 930 | } 931 | 932 | /* reverse facet normals */ 933 | for (i = 1; i <= model->numfacetnorms; i++) { 934 | model->facetnorms[3 * i + 0] = -model->facetnorms[3 * i + 0]; 935 | model->facetnorms[3 * i + 1] = -model->facetnorms[3 * i + 1]; 936 | model->facetnorms[3 * i + 2] = -model->facetnorms[3 * i + 2]; 937 | } 938 | 939 | /* reverse vertex normals */ 940 | for (i = 1; i <= model->numnormals; i++) { 941 | model->normals[3 * i + 0] = -model->normals[3 * i + 0]; 942 | model->normals[3 * i + 1] = -model->normals[3 * i + 1]; 943 | model->normals[3 * i + 2] = -model->normals[3 * i + 2]; 944 | } 945 | } 946 | 947 | /* glmFacetNormals: Generates facet normals for a model (by taking the 948 | * cross product of the two vectors derived from the sides of each 949 | * triangle). Assumes a counter-clockwise winding. 950 | * 951 | * model - initialized GLMmodel structure 952 | */ 953 | GLvoid 954 | glmFacetNormals(GLMmodel* model) 955 | { 956 | GLuint i; 957 | GLfloat u[3]; 958 | GLfloat v[3]; 959 | 960 | assert(model); 961 | assert(model->vertices); 962 | 963 | /* clobber any old facetnormals */ 964 | if (model->facetnorms) 965 | free(model->facetnorms); 966 | 967 | /* allocate memory for the new facet normals */ 968 | model->numfacetnorms = model->numtriangles; 969 | model->facetnorms = (GLfloat*)malloc(sizeof(GLfloat) * 970 | 3 * (model->numfacetnorms + 1)); 971 | 972 | for (i = 0; i < model->numtriangles; i++) { 973 | model->triangles[i].findex = i+1; 974 | 975 | u[0] = model->vertices[3 * T(i).vindices[1] + 0] - 976 | model->vertices[3 * T(i).vindices[0] + 0]; 977 | u[1] = model->vertices[3 * T(i).vindices[1] + 1] - 978 | model->vertices[3 * T(i).vindices[0] + 1]; 979 | u[2] = model->vertices[3 * T(i).vindices[1] + 2] - 980 | model->vertices[3 * T(i).vindices[0] + 2]; 981 | 982 | v[0] = model->vertices[3 * T(i).vindices[2] + 0] - 983 | model->vertices[3 * T(i).vindices[0] + 0]; 984 | v[1] = model->vertices[3 * T(i).vindices[2] + 1] - 985 | model->vertices[3 * T(i).vindices[0] + 1]; 986 | v[2] = model->vertices[3 * T(i).vindices[2] + 2] - 987 | model->vertices[3 * T(i).vindices[0] + 2]; 988 | 989 | glmCross(u, v, &model->facetnorms[3 * (i+1)]); 990 | glmNormalize(&model->facetnorms[3 * (i+1)]); 991 | } 992 | } 993 | 994 | /* glmVertexNormals: Generates smooth vertex normals for a model. 995 | * First builds a list of all the triangles each vertex is in. Then 996 | * loops through each vertex in the the list averaging all the facet 997 | * normals of the triangles each vertex is in. Finally, sets the 998 | * normal index in the triangle for the vertex to the generated smooth 999 | * normal. If the dot product of a facet normal and the facet normal 1000 | * associated with the first triangle in the list of triangles the 1001 | * current vertex is in is greater than the cosine of the angle 1002 | * parameter to the function, that facet normal is not added into the 1003 | * average normal calculation and the corresponding vertex is given 1004 | * the facet normal. This tends to preserve hard edges. The angle to 1005 | * use depends on the model, but 90 degrees is usually a good start. 1006 | * 1007 | * model - initialized GLMmodel structure 1008 | * angle - maximum angle (in degrees) to smooth across 1009 | */ 1010 | GLvoid 1011 | glmVertexNormals(GLMmodel* model, GLfloat angle) 1012 | { 1013 | GLMnode* node; 1014 | GLMnode* tail; 1015 | GLMnode** members; 1016 | GLfloat* normals; 1017 | GLuint numnormals; 1018 | GLfloat average[3]; 1019 | GLfloat dot, cos_angle; 1020 | GLuint i, avg; 1021 | 1022 | assert(model); 1023 | assert(model->facetnorms); 1024 | 1025 | /* calculate the cosine of the angle (in degrees) */ 1026 | cos_angle = cos(angle * M_PI / 180.0); 1027 | 1028 | /* nuke any previous normals */ 1029 | if (model->normals) 1030 | free(model->normals); 1031 | 1032 | /* allocate space for new normals */ 1033 | model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ 1034 | model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); 1035 | 1036 | /* allocate a structure that will hold a linked list of triangle 1037 | indices for each vertex */ 1038 | members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); 1039 | for (i = 1; i <= model->numvertices; i++) 1040 | members[i] = NULL; 1041 | 1042 | /* for every triangle, create a node for each vertex in it */ 1043 | for (i = 0; i < model->numtriangles; i++) { 1044 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1045 | node->index = i; 1046 | node->next = members[T(i).vindices[0]]; 1047 | members[T(i).vindices[0]] = node; 1048 | 1049 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1050 | node->index = i; 1051 | node->next = members[T(i).vindices[1]]; 1052 | members[T(i).vindices[1]] = node; 1053 | 1054 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1055 | node->index = i; 1056 | node->next = members[T(i).vindices[2]]; 1057 | members[T(i).vindices[2]] = node; 1058 | } 1059 | 1060 | /* calculate the average normal for each vertex */ 1061 | numnormals = 1; 1062 | for (i = 1; i <= model->numvertices; i++) { 1063 | /* calculate an average normal for this vertex by averaging the 1064 | facet normal of every triangle this vertex is in */ 1065 | node = members[i]; 1066 | if (!node) 1067 | fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); 1068 | average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; 1069 | avg = 0; 1070 | while (node) { 1071 | /* only average if the dot product of the angle between the two 1072 | facet normals is greater than the cosine of the threshold 1073 | angle -- or, said another way, the angle between the two 1074 | facet normals is less than (or equal to) the threshold angle */ 1075 | dot = glmDot(&model->facetnorms[3 * T(node->index).findex], 1076 | &model->facetnorms[3 * T(members[i]->index).findex]); 1077 | if (dot > cos_angle) { 1078 | node->averaged = GL_TRUE; 1079 | average[0] += model->facetnorms[3 * T(node->index).findex + 0]; 1080 | average[1] += model->facetnorms[3 * T(node->index).findex + 1]; 1081 | average[2] += model->facetnorms[3 * T(node->index).findex + 2]; 1082 | avg = 1; /* we averaged at least one normal! */ 1083 | } else { 1084 | node->averaged = GL_FALSE; 1085 | } 1086 | node = node->next; 1087 | } 1088 | 1089 | if (avg) { 1090 | /* normalize the averaged normal */ 1091 | glmNormalize(average); 1092 | 1093 | /* add the normal to the vertex normals list */ 1094 | model->normals[3 * numnormals + 0] = average[0]; 1095 | model->normals[3 * numnormals + 1] = average[1]; 1096 | model->normals[3 * numnormals + 2] = average[2]; 1097 | avg = numnormals; 1098 | numnormals++; 1099 | } 1100 | 1101 | /* set the normal of this vertex in each triangle it is in */ 1102 | node = members[i]; 1103 | while (node) { 1104 | if (node->averaged) { 1105 | /* if this node was averaged, use the average normal */ 1106 | if (T(node->index).vindices[0] == i) 1107 | T(node->index).nindices[0] = avg; 1108 | else if (T(node->index).vindices[1] == i) 1109 | T(node->index).nindices[1] = avg; 1110 | else if (T(node->index).vindices[2] == i) 1111 | T(node->index).nindices[2] = avg; 1112 | } else { 1113 | /* if this node wasn't averaged, use the facet normal */ 1114 | model->normals[3 * numnormals + 0] = 1115 | model->facetnorms[3 * T(node->index).findex + 0]; 1116 | model->normals[3 * numnormals + 1] = 1117 | model->facetnorms[3 * T(node->index).findex + 1]; 1118 | model->normals[3 * numnormals + 2] = 1119 | model->facetnorms[3 * T(node->index).findex + 2]; 1120 | if (T(node->index).vindices[0] == i) 1121 | T(node->index).nindices[0] = numnormals; 1122 | else if (T(node->index).vindices[1] == i) 1123 | T(node->index).nindices[1] = numnormals; 1124 | else if (T(node->index).vindices[2] == i) 1125 | T(node->index).nindices[2] = numnormals; 1126 | numnormals++; 1127 | } 1128 | node = node->next; 1129 | } 1130 | } 1131 | 1132 | model->numnormals = numnormals - 1; 1133 | 1134 | /* free the member information */ 1135 | for (i = 1; i <= model->numvertices; i++) { 1136 | node = members[i]; 1137 | while (node) { 1138 | tail = node; 1139 | node = node->next; 1140 | free(tail); 1141 | } 1142 | } 1143 | free(members); 1144 | 1145 | /* pack the normals array (we previously allocated the maximum 1146 | number of normals that could possibly be created (numtriangles * 1147 | 3), so get rid of some of them (usually alot unless none of the 1148 | facet normals were averaged)) */ 1149 | normals = model->normals; 1150 | model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); 1151 | for (i = 1; i <= model->numnormals; i++) { 1152 | model->normals[3 * i + 0] = normals[3 * i + 0]; 1153 | model->normals[3 * i + 1] = normals[3 * i + 1]; 1154 | model->normals[3 * i + 2] = normals[3 * i + 2]; 1155 | } 1156 | free(normals); 1157 | } 1158 | 1159 | 1160 | /* glmLinearTexture: Generates texture coordinates according to a 1161 | * linear projection of the texture map. It generates these by 1162 | * linearly mapping the vertices onto a square. 1163 | * 1164 | * model - pointer to initialized GLMmodel structure 1165 | */ 1166 | GLvoid 1167 | glmLinearTexture(GLMmodel* model) 1168 | { 1169 | GLMgroup *group; 1170 | GLfloat dimensions[3]; 1171 | GLfloat x, y, scalefactor; 1172 | GLuint i; 1173 | 1174 | assert(model); 1175 | 1176 | if (model->texcoords) 1177 | free(model->texcoords); 1178 | model->numtexcoords = model->numvertices; 1179 | model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); 1180 | 1181 | glmDimensions(model, dimensions); 1182 | scalefactor = 2.0 / 1183 | glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2])); 1184 | 1185 | /* do the calculations */ 1186 | for(i = 1; i <= model->numvertices; i++) { 1187 | x = model->vertices[3 * i + 0] * scalefactor; 1188 | y = model->vertices[3 * i + 2] * scalefactor; 1189 | model->texcoords[2 * i + 0] = (x + 1.0) / 2.0; 1190 | model->texcoords[2 * i + 1] = (y + 1.0) / 2.0; 1191 | } 1192 | 1193 | /* go through and put texture coordinate indices in all the triangles */ 1194 | group = model->groups; 1195 | while(group) { 1196 | for(i = 0; i < group->numtriangles; i++) { 1197 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; 1198 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; 1199 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; 1200 | } 1201 | group = group->next; 1202 | } 1203 | 1204 | #if 0 1205 | printf("glmLinearTexture(): generated %d linear texture coordinates\n", 1206 | model->numtexcoords); 1207 | #endif 1208 | } 1209 | 1210 | /* glmSpheremapTexture: Generates texture coordinates according to a 1211 | * spherical projection of the texture map. Sometimes referred to as 1212 | * spheremap, or reflection map texture coordinates. It generates 1213 | * these by using the normal to calculate where that vertex would map 1214 | * onto a sphere. Since it is impossible to map something flat 1215 | * perfectly onto something spherical, there is distortion at the 1216 | * poles. This particular implementation causes the poles along the X 1217 | * axis to be distorted. 1218 | * 1219 | * model - pointer to initialized GLMmodel structure 1220 | */ 1221 | GLvoid 1222 | glmSpheremapTexture(GLMmodel* model) 1223 | { 1224 | GLMgroup* group; 1225 | GLfloat theta, phi, rho, x, y, z, r; 1226 | GLuint i; 1227 | 1228 | assert(model); 1229 | assert(model->normals); 1230 | 1231 | if (model->texcoords) 1232 | free(model->texcoords); 1233 | model->numtexcoords = model->numnormals; 1234 | model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); 1235 | 1236 | for (i = 1; i <= model->numnormals; i++) { 1237 | z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ 1238 | y = model->normals[3 * i + 1]; 1239 | x = model->normals[3 * i + 2]; 1240 | r = sqrt((x * x) + (y * y)); 1241 | rho = sqrt((r * r) + (z * z)); 1242 | 1243 | if(r == 0.0) { 1244 | theta = 0.0; 1245 | phi = 0.0; 1246 | } else { 1247 | if(z == 0.0) 1248 | phi = 3.14159265 / 2.0; 1249 | else 1250 | phi = acos(z / rho); 1251 | 1252 | if(y == 0.0) 1253 | theta = 3.141592365 / 2.0; 1254 | else 1255 | theta = asin(y / r) + (3.14159265 / 2.0); 1256 | } 1257 | 1258 | model->texcoords[2 * i + 0] = theta / 3.14159265; 1259 | model->texcoords[2 * i + 1] = phi / 3.14159265; 1260 | } 1261 | 1262 | /* go through and put texcoord indices in all the triangles */ 1263 | group = model->groups; 1264 | while(group) { 1265 | for (i = 0; i < group->numtriangles; i++) { 1266 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; 1267 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; 1268 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; 1269 | } 1270 | group = group->next; 1271 | } 1272 | } 1273 | 1274 | /* glmDelete: Deletes a GLMmodel structure. 1275 | * 1276 | * model - initialized GLMmodel structure 1277 | */ 1278 | GLvoid 1279 | glmDelete(GLMmodel* model) 1280 | { 1281 | GLMgroup* group; 1282 | GLuint i; 1283 | 1284 | assert(model); 1285 | 1286 | if (model->pathname) free(model->pathname); 1287 | if (model->mtllibname) free(model->mtllibname); 1288 | if (model->vertices) free(model->vertices); 1289 | if (model->normals) free(model->normals); 1290 | if (model->texcoords) free(model->texcoords); 1291 | if (model->facetnorms) free(model->facetnorms); 1292 | if (model->triangles) free(model->triangles); 1293 | if (model->materials) { 1294 | for (i = 0; i < model->nummaterials; i++) 1295 | { 1296 | free(model->materials[i].name); 1297 | if (model->materials[i].texture_path != NULL) 1298 | free(model->materials[i].texture_path); 1299 | } 1300 | } 1301 | free(model->materials); 1302 | while(model->groups) { 1303 | group = model->groups; 1304 | model->groups = model->groups->next; 1305 | free(group->name); 1306 | free(group->triangles); 1307 | free(group); 1308 | } 1309 | 1310 | free(model); 1311 | } 1312 | 1313 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 1314 | * Returns a pointer to the created object which should be free'd with 1315 | * glmDelete(). 1316 | * 1317 | * filename - name of the file containing the Wavefront .OBJ format data. 1318 | */ 1319 | GLMmodel* 1320 | glmReadOBJ(char* filename) 1321 | { 1322 | GLMmodel* model; 1323 | FILE* file; 1324 | 1325 | /* open the file */ 1326 | file = fopen(filename, "r"); 1327 | if (!file) { 1328 | fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n", 1329 | filename); 1330 | return NULL; 1331 | } 1332 | 1333 | /* allocate a new model */ 1334 | model = (GLMmodel*)malloc(sizeof(GLMmodel)); 1335 | model->pathname = strdup(filename); 1336 | model->mtllibname = NULL; 1337 | model->numvertices = 0; 1338 | model->vertices = NULL; 1339 | model->colors = NULL; 1340 | model->numnormals = 0; 1341 | model->normals = NULL; 1342 | model->numtexcoords = 0; 1343 | model->texcoords = NULL; 1344 | model->numfacetnorms = 0; 1345 | model->facetnorms = NULL; 1346 | model->numtriangles = 0; 1347 | model->triangles = NULL; 1348 | model->nummaterials = 0; 1349 | model->materials = NULL; 1350 | model->numgroups = 0; 1351 | model->groups = NULL; 1352 | model->position[0] = 0.0; 1353 | model->position[1] = 0.0; 1354 | model->position[2] = 0.0; 1355 | 1356 | /* make a first pass through the file to get a count of the number 1357 | of vertices, normals, texcoords & triangles */ 1358 | glmFirstPass(model, file); 1359 | 1360 | /* allocate memory */ 1361 | model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * 1362 | 3 * (model->numvertices + 1)); 1363 | model->colors = (GLfloat*)malloc(sizeof(GLfloat) * 1364 | 3 * (model->numvertices + 1)); 1365 | model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * 1366 | model->numtriangles); 1367 | if (model->numnormals) { 1368 | model->normals = (GLfloat*)malloc(sizeof(GLfloat) * 1369 | 3 * (model->numnormals + 1)); 1370 | } 1371 | if (model->numtexcoords) { 1372 | model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 1373 | 2 * (model->numtexcoords + 1)); 1374 | } 1375 | 1376 | /* rewind to beginning of file and read in the data this pass */ 1377 | rewind(file); 1378 | 1379 | glmSecondPass(model, file); 1380 | 1381 | if (!model->has_vertex_color) 1382 | { 1383 | free(model->colors); 1384 | model->colors = NULL; 1385 | } 1386 | 1387 | /* close the file */ 1388 | fclose(file); 1389 | 1390 | return model; 1391 | } 1392 | 1393 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 1394 | * a file. 1395 | * 1396 | * model - initialized GLMmodel structure 1397 | * filename - name of the file to write the Wavefront .OBJ format data to 1398 | * mode - a bitwise or of values describing what is written to the file 1399 | * GLM_NONE - render with only vertices 1400 | * GLM_FLAT - render with facet normals 1401 | * GLM_SMOOTH - render with vertex normals 1402 | * GLM_TEXTURE - render with texture coords 1403 | * GLM_COLOR - render with colors (color material) 1404 | * GLM_MATERIAL - render with materials 1405 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1406 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1407 | */ 1408 | GLvoid 1409 | glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode) 1410 | { 1411 | GLuint i; 1412 | FILE* file; 1413 | GLMgroup* group; 1414 | 1415 | assert(model); 1416 | 1417 | /* do a bit of warning */ 1418 | if (mode & GLM_FLAT && !model->facetnorms) { 1419 | printf("glmWriteOBJ() warning: flat normal output requested " 1420 | "with no facet normals defined.\n"); 1421 | mode &= ~GLM_FLAT; 1422 | } 1423 | if (mode & GLM_SMOOTH && !model->normals) { 1424 | printf("glmWriteOBJ() warning: smooth normal output requested " 1425 | "with no normals defined.\n"); 1426 | mode &= ~GLM_SMOOTH; 1427 | } 1428 | if (mode & GLM_TEXTURE && !model->texcoords) { 1429 | printf("glmWriteOBJ() warning: texture coordinate output requested " 1430 | "with no texture coordinates defined.\n"); 1431 | mode &= ~GLM_TEXTURE; 1432 | } 1433 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1434 | printf("glmWriteOBJ() warning: flat normal output requested " 1435 | "and smooth normal output requested (using smooth).\n"); 1436 | mode &= ~GLM_FLAT; 1437 | } 1438 | if (mode & GLM_COLOR && !model->materials) { 1439 | printf("glmWriteOBJ() warning: color output requested " 1440 | "with no colors (materials) defined.\n"); 1441 | mode &= ~GLM_COLOR; 1442 | } 1443 | if (mode & GLM_MATERIAL && !model->materials) { 1444 | printf("glmWriteOBJ() warning: material output requested " 1445 | "with no materials defined.\n"); 1446 | mode &= ~GLM_MATERIAL; 1447 | } 1448 | if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 1449 | printf("glmWriteOBJ() warning: color and material output requested " 1450 | "outputting only materials.\n"); 1451 | mode &= ~GLM_COLOR; 1452 | } 1453 | 1454 | 1455 | /* open the file */ 1456 | file = fopen(filename, "w"); 1457 | if (!file) { 1458 | fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n", 1459 | filename); 1460 | return; 1461 | } 1462 | 1463 | /* spit out a header */ 1464 | fprintf(file, "# \n"); 1465 | fprintf(file, "# Wavefront OBJ generated by GLM library\n"); 1466 | fprintf(file, "# \n"); 1467 | fprintf(file, "# GLM library\n"); 1468 | fprintf(file, "# Nate Robins\n"); 1469 | fprintf(file, "# ndr@pobox.com\n"); 1470 | fprintf(file, "# http://www.pobox.com/~ndr\n"); 1471 | fprintf(file, "# \n"); 1472 | 1473 | if (mode & GLM_MATERIAL && model->mtllibname) { 1474 | fprintf(file, "\nmtllib %s\n\n", model->mtllibname); 1475 | glmWriteMTL(model, filename, model->mtllibname); 1476 | } 1477 | 1478 | /* spit out the vertices */ 1479 | fprintf(file, "\n"); 1480 | fprintf(file, "# %d vertices\n", model->numvertices); 1481 | for (i = 1; i <= model->numvertices; i++) { 1482 | fprintf(file, "v %f %f %f\n", 1483 | model->vertices[3 * i + 0], 1484 | model->vertices[3 * i + 1], 1485 | model->vertices[3 * i + 2]); 1486 | } 1487 | 1488 | /* spit out the smooth/flat normals */ 1489 | if (mode & GLM_SMOOTH) { 1490 | fprintf(file, "\n"); 1491 | fprintf(file, "# %d normals\n", model->numnormals); 1492 | for (i = 1; i <= model->numnormals; i++) { 1493 | fprintf(file, "vn %f %f %f\n", 1494 | model->normals[3 * i + 0], 1495 | model->normals[3 * i + 1], 1496 | model->normals[3 * i + 2]); 1497 | } 1498 | } else if (mode & GLM_FLAT) { 1499 | fprintf(file, "\n"); 1500 | fprintf(file, "# %d normals\n", model->numfacetnorms); 1501 | for (i = 1; i <= model->numnormals; i++) { 1502 | fprintf(file, "vn %f %f %f\n", 1503 | model->facetnorms[3 * i + 0], 1504 | model->facetnorms[3 * i + 1], 1505 | model->facetnorms[3 * i + 2]); 1506 | } 1507 | } 1508 | 1509 | /* spit out the texture coordinates */ 1510 | if (mode & GLM_TEXTURE) { 1511 | fprintf(file, "\n"); 1512 | fprintf(file, "# %d texcoords\n", model->numtexcoords); 1513 | for (i = 1; i <= model->numtexcoords; i++) { 1514 | fprintf(file, "vt %f %f\n", 1515 | model->texcoords[2 * i + 0], 1516 | model->texcoords[2 * i + 1]); 1517 | } 1518 | } 1519 | 1520 | fprintf(file, "\n"); 1521 | fprintf(file, "# %d groups\n", model->numgroups); 1522 | fprintf(file, "# %d faces (triangles)\n", model->numtriangles); 1523 | fprintf(file, "\n"); 1524 | 1525 | group = model->groups; 1526 | while(group) { 1527 | fprintf(file, "g %s\n", group->name); 1528 | if (mode & GLM_MATERIAL) 1529 | { 1530 | fprintf(file, "usemtl %s\n", model->materials[group->material].name); 1531 | } 1532 | for (i = 0; i < group->numtriangles; i++) { 1533 | if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) { 1534 | fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", 1535 | T(group->triangles[i]).vindices[0], 1536 | T(group->triangles[i]).nindices[0], 1537 | T(group->triangles[i]).tindices[0], 1538 | T(group->triangles[i]).vindices[1], 1539 | T(group->triangles[i]).nindices[1], 1540 | T(group->triangles[i]).tindices[1], 1541 | T(group->triangles[i]).vindices[2], 1542 | T(group->triangles[i]).nindices[2], 1543 | T(group->triangles[i]).tindices[2]); 1544 | } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) { 1545 | fprintf(file, "f %d/%d %d/%d %d/%d\n", 1546 | T(group->triangles[i]).vindices[0], 1547 | T(group->triangles[i]).findex, 1548 | T(group->triangles[i]).vindices[1], 1549 | T(group->triangles[i]).findex, 1550 | T(group->triangles[i]).vindices[2], 1551 | T(group->triangles[i]).findex); 1552 | } else if (mode & GLM_TEXTURE) { 1553 | fprintf(file, "f %d/%d %d/%d %d/%d\n", 1554 | T(group->triangles[i]).vindices[0], 1555 | T(group->triangles[i]).tindices[0], 1556 | T(group->triangles[i]).vindices[1], 1557 | T(group->triangles[i]).tindices[1], 1558 | T(group->triangles[i]).vindices[2], 1559 | T(group->triangles[i]).tindices[2]); 1560 | } else if (mode & GLM_SMOOTH) { 1561 | fprintf(file, "f %d//%d %d//%d %d//%d\n", 1562 | T(group->triangles[i]).vindices[0], 1563 | T(group->triangles[i]).nindices[0], 1564 | T(group->triangles[i]).vindices[1], 1565 | T(group->triangles[i]).nindices[1], 1566 | T(group->triangles[i]).vindices[2], 1567 | T(group->triangles[i]).nindices[2]); 1568 | } else if (mode & GLM_FLAT) { 1569 | fprintf(file, "f %d//%d %d//%d %d//%d\n", 1570 | T(group->triangles[i]).vindices[0], 1571 | T(group->triangles[i]).findex, 1572 | T(group->triangles[i]).vindices[1], 1573 | T(group->triangles[i]).findex, 1574 | T(group->triangles[i]).vindices[2], 1575 | T(group->triangles[i]).findex); 1576 | } else { 1577 | fprintf(file, "f %d %d %d\n", 1578 | T(group->triangles[i]).vindices[0], 1579 | T(group->triangles[i]).vindices[1], 1580 | T(group->triangles[i]).vindices[2]); 1581 | } 1582 | } 1583 | fprintf(file, "\n"); 1584 | group = group->next; 1585 | } 1586 | 1587 | fclose(file); 1588 | } 1589 | 1590 | /* glmDraw: Renders the model to the current OpenGL context using the 1591 | * mode specified. 1592 | * 1593 | * model - initialized GLMmodel structure 1594 | * mode - a bitwise OR of values describing what is to be rendered. 1595 | * GLM_NONE - render with only vertices 1596 | * GLM_FLAT - render with facet normals 1597 | * GLM_SMOOTH - render with vertex normals 1598 | * GLM_TEXTURE - render with texture coords 1599 | * GLM_COLOR - render with colors (color material) 1600 | * GLM_MATERIAL - render with materials 1601 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1602 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1603 | */ 1604 | GLvoid 1605 | glmDraw(GLMmodel* model, GLuint mode) 1606 | { 1607 | static GLuint i; 1608 | static GLMgroup* group; 1609 | static GLMtriangle* triangle; 1610 | static GLMmaterial* material; 1611 | 1612 | assert(model); 1613 | assert(model->vertices); 1614 | 1615 | /* do a bit of warning */ 1616 | if (mode & GLM_FLAT && !model->facetnorms) { 1617 | printf("glmDraw() warning: flat render mode requested " 1618 | "with no facet normals defined.\n"); 1619 | mode &= ~GLM_FLAT; 1620 | } 1621 | if (mode & GLM_SMOOTH && !model->normals) { 1622 | printf("glmDraw() warning: smooth render mode requested " 1623 | "with no normals defined.\n"); 1624 | mode &= ~GLM_SMOOTH; 1625 | } 1626 | if (mode & GLM_TEXTURE && !model->texcoords) { 1627 | printf("glmDraw() warning: texture render mode requested " 1628 | "with no texture coordinates defined.\n"); 1629 | mode &= ~GLM_TEXTURE; 1630 | } 1631 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1632 | printf("glmDraw() warning: flat render mode requested " 1633 | "and smooth render mode requested (using smooth).\n"); 1634 | mode &= ~GLM_FLAT; 1635 | } 1636 | if (mode & GLM_COLOR && !model->materials) { 1637 | printf("glmDraw() warning: color render mode requested " 1638 | "with no materials defined.\n"); 1639 | mode &= ~GLM_COLOR; 1640 | } 1641 | if (mode & GLM_MATERIAL && !model->materials) { 1642 | printf("glmDraw() warning: material render mode requested " 1643 | "with no materials defined.\n"); 1644 | mode &= ~GLM_MATERIAL; 1645 | } 1646 | if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 1647 | printf("glmDraw() warning: color and material render mode requested " 1648 | "using only material mode.\n"); 1649 | mode &= ~GLM_COLOR; 1650 | } 1651 | if (mode & GLM_COLOR) 1652 | glEnable(GL_COLOR_MATERIAL); 1653 | else if (mode & GLM_MATERIAL) 1654 | glDisable(GL_COLOR_MATERIAL); 1655 | 1656 | /* perhaps this loop should be unrolled into material, color, flat, 1657 | smooth, etc. loops? since most cpu's have good branch prediction 1658 | schemes (and these branches will always go one way), probably 1659 | wouldn't gain too much? */ 1660 | 1661 | group = model->groups; 1662 | while (group) { 1663 | if (mode & GLM_MATERIAL) { 1664 | material = &model->materials[group->material]; 1665 | glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient); 1666 | glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse); 1667 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->specular); 1668 | glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess); 1669 | } 1670 | 1671 | if (mode & GLM_COLOR) { 1672 | glColor3fv(material->diffuse); 1673 | } 1674 | 1675 | glBegin(GL_TRIANGLES); 1676 | for (i = 0; i < group->numtriangles; i++) { 1677 | triangle = &T(group->triangles[i]); 1678 | 1679 | if (mode & GLM_FLAT) 1680 | glNormal3fv(&model->facetnorms[3 * triangle->findex]); 1681 | 1682 | if (mode & GLM_SMOOTH) 1683 | glNormal3fv(&model->normals[3 * triangle->nindices[0]]); 1684 | if (mode & GLM_TEXTURE) 1685 | glTexCoord2fv(&model->texcoords[2 * triangle->tindices[0]]); 1686 | glVertex3fv(&model->vertices[3 * triangle->vindices[0]]); 1687 | 1688 | if (mode & GLM_SMOOTH) 1689 | glNormal3fv(&model->normals[3 * triangle->nindices[1]]); 1690 | if (mode & GLM_TEXTURE) 1691 | glTexCoord2fv(&model->texcoords[2 * triangle->tindices[1]]); 1692 | glVertex3fv(&model->vertices[3 * triangle->vindices[1]]); 1693 | 1694 | if (mode & GLM_SMOOTH) 1695 | glNormal3fv(&model->normals[3 * triangle->nindices[2]]); 1696 | if (mode & GLM_TEXTURE) 1697 | glTexCoord2fv(&model->texcoords[2 * triangle->tindices[2]]); 1698 | glVertex3fv(&model->vertices[3 * triangle->vindices[2]]); 1699 | 1700 | } 1701 | glEnd(); 1702 | 1703 | group = group->next; 1704 | } 1705 | } 1706 | 1707 | /* glmList: Generates and returns a display list for the model using 1708 | * the mode specified. 1709 | * 1710 | * model - initialized GLMmodel structure 1711 | * mode - a bitwise OR of values describing what is to be rendered. 1712 | * GLM_NONE - render with only vertices 1713 | * GLM_FLAT - render with facet normals 1714 | * GLM_SMOOTH - render with vertex normals 1715 | * GLM_TEXTURE - render with texture coords 1716 | * GLM_COLOR - render with colors (color material) 1717 | * GLM_MATERIAL - render with materials 1718 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1719 | * GLM_FLAT and GLM_SMOOTH should not both be specified. */ 1720 | GLuint 1721 | glmList(GLMmodel* model, GLuint mode) 1722 | { 1723 | GLuint list; 1724 | 1725 | list = glGenLists(1); 1726 | glNewList(list, GL_COMPILE); 1727 | glmDraw(model, mode); 1728 | glEndList(); 1729 | 1730 | return list; 1731 | } 1732 | 1733 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 1734 | * each other. 1735 | * 1736 | * model - initialized GLMmodel structure 1737 | * epsilon - maximum difference between vertices 1738 | * ( 0.00001 is a good start for a unitized model) 1739 | * 1740 | */ 1741 | GLvoid 1742 | glmWeld(GLMmodel* model, GLfloat epsilon) 1743 | { 1744 | GLfloat* vectors; 1745 | GLfloat* copies; 1746 | GLuint numvectors; 1747 | GLuint i; 1748 | 1749 | /* vertices */ 1750 | numvectors = model->numvertices; 1751 | vectors = model->vertices; 1752 | copies = glmWeldVectors(vectors, &numvectors, epsilon); 1753 | 1754 | #if 0 1755 | printf("glmWeld(): %d redundant vertices.\n", 1756 | model->numvertices - numvectors - 1); 1757 | #endif 1758 | 1759 | for (i = 0; i < model->numtriangles; i++) { 1760 | T(i).vindices[0] = (GLuint)vectors[3 * T(i).vindices[0] + 0]; 1761 | T(i).vindices[1] = (GLuint)vectors[3 * T(i).vindices[1] + 0]; 1762 | T(i).vindices[2] = (GLuint)vectors[3 * T(i).vindices[2] + 0]; 1763 | } 1764 | 1765 | /* free space for old vertices */ 1766 | free(vectors); 1767 | 1768 | /* allocate space for the new vertices */ 1769 | model->numvertices = numvectors; 1770 | model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * 1771 | 3 * (model->numvertices + 1)); 1772 | 1773 | /* copy the optimized vertices into the actual vertex list */ 1774 | for (i = 1; i <= model->numvertices; i++) { 1775 | model->vertices[3 * i + 0] = copies[3 * i + 0]; 1776 | model->vertices[3 * i + 1] = copies[3 * i + 1]; 1777 | model->vertices[3 * i + 2] = copies[3 * i + 2]; 1778 | } 1779 | 1780 | free(copies); 1781 | } 1782 | 1783 | 1784 | #if 0 1785 | /* normals */ 1786 | if (model->numnormals) { 1787 | numvectors = model->numnormals; 1788 | vectors = model->normals; 1789 | copies = glmOptimizeVectors(vectors, &numvectors); 1790 | 1791 | printf("glmOptimize(): %d redundant normals.\n", 1792 | model->numnormals - numvectors); 1793 | 1794 | for (i = 0; i < model->numtriangles; i++) { 1795 | T(i).nindices[0] = (GLuint)vectors[3 * T(i).nindices[0] + 0]; 1796 | T(i).nindices[1] = (GLuint)vectors[3 * T(i).nindices[1] + 0]; 1797 | T(i).nindices[2] = (GLuint)vectors[3 * T(i).nindices[2] + 0]; 1798 | } 1799 | 1800 | /* free space for old normals */ 1801 | free(vectors); 1802 | 1803 | /* allocate space for the new normals */ 1804 | model->numnormals = numvectors; 1805 | model->normals = (GLfloat*)malloc(sizeof(GLfloat) * 1806 | 3 * (model->numnormals + 1)); 1807 | 1808 | /* copy the optimized vertices into the actual vertex list */ 1809 | for (i = 1; i <= model->numnormals; i++) { 1810 | model->normals[3 * i + 0] = copies[3 * i + 0]; 1811 | model->normals[3 * i + 1] = copies[3 * i + 1]; 1812 | model->normals[3 * i + 2] = copies[3 * i + 2]; 1813 | } 1814 | 1815 | free(copies); 1816 | } 1817 | 1818 | /* texcoords */ 1819 | if (model->numtexcoords) { 1820 | numvectors = model->numtexcoords; 1821 | vectors = model->texcoords; 1822 | copies = glmOptimizeVectors(vectors, &numvectors); 1823 | 1824 | printf("glmOptimize(): %d redundant texcoords.\n", 1825 | model->numtexcoords - numvectors); 1826 | 1827 | for (i = 0; i < model->numtriangles; i++) { 1828 | for (j = 0; j < 3; j++) { 1829 | T(i).tindices[j] = (GLuint)vectors[3 * T(i).tindices[j] + 0]; 1830 | } 1831 | } 1832 | 1833 | /* free space for old texcoords */ 1834 | free(vectors); 1835 | 1836 | /* allocate space for the new texcoords */ 1837 | model->numtexcoords = numvectors; 1838 | model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 1839 | 2 * (model->numtexcoords + 1)); 1840 | 1841 | /* copy the optimized vertices into the actual vertex list */ 1842 | for (i = 1; i <= model->numtexcoords; i++) { 1843 | model->texcoords[2 * i + 0] = copies[2 * i + 0]; 1844 | model->texcoords[2 * i + 1] = copies[2 * i + 1]; 1845 | } 1846 | 1847 | free(copies); 1848 | } 1849 | #endif 1850 | 1851 | #if 0 1852 | /* look for unused vertices */ 1853 | /* look for unused normals */ 1854 | /* look for unused texcoords */ 1855 | for (i = 1; i <= model->numvertices; i++) { 1856 | for (j = 0; j < model->numtriangles; i++) { 1857 | if (T(j).vindices[0] == i || 1858 | T(j).vindices[1] == i || 1859 | T(j).vindices[1] == i) 1860 | break; 1861 | } 1862 | } 1863 | #endif 1864 | -------------------------------------------------------------------------------- /example/src/ofxObjLoader/libs/glm/glm.h: -------------------------------------------------------------------------------- 1 | /* 2 | glm.h 3 | Nate Robins, 1997 4 | ndr@pobox.com, http://www.pobox.com/~ndr/ 5 | 6 | Wavefront OBJ model file format reader/writer/manipulator. 7 | 8 | Includes routines for generating smooth normals with 9 | preservation of edges, welding redundant vertices & texture 10 | coordinate generation (spheremap and planar projections) + more. 11 | 12 | */ 13 | //#include "ofMain.h" 14 | #if defined( __WIN32__ ) || defined( _WIN32 ) 15 | #define TARGET_WIN32 16 | #elif defined( __APPLE_CC__) 17 | #include 18 | 19 | #if (TARGET_OS_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE) || (TARGET_IPHONE) 20 | #define TARGET_OF_IPHONE 21 | #define TARGET_OPENGLES 22 | #else 23 | #define TARGET_OSX 24 | #endif 25 | #elif defined (ANDROID) 26 | #define TARGET_ANDROID 27 | #define TARGET_OPENGLES 28 | #else 29 | #define TARGET_LINUX 30 | #endif 31 | 32 | #ifdef TARGET_WIN32 33 | #define GLUT_BUILDING_LIB 34 | #include "glut.h" 35 | #endif 36 | #ifdef TARGET_OSX 37 | #include 38 | #endif 39 | #ifdef TARGET_LINUX 40 | #include 41 | #endif 42 | 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | #ifndef M_PI 49 | #define M_PI 3.14159265 50 | #endif 51 | 52 | #define GLM_NONE (0) /* render with only vertices */ 53 | #define GLM_FLAT (1 << 0) /* render with facet normals */ 54 | #define GLM_SMOOTH (1 << 1) /* render with vertex normals */ 55 | #define GLM_TEXTURE (1 << 2) /* render with texture coords */ 56 | #define GLM_COLOR (1 << 3) /* render with colors */ 57 | #define GLM_MATERIAL (1 << 4) /* render with materials */ 58 | 59 | 60 | /* GLMmaterial: Structure that defines a material in a model. 61 | */ 62 | typedef struct _GLMmaterial 63 | { 64 | char* name; /* name of material */ 65 | char* texture_path; 66 | GLfloat diffuse[4]; /* diffuse component */ 67 | GLfloat ambient[4]; /* ambient component */ 68 | GLfloat specular[4]; /* specular component */ 69 | GLfloat emmissive[4]; /* emmissive component */ 70 | GLfloat shininess; /* specular exponent */ 71 | } GLMmaterial; 72 | 73 | /* GLMtriangle: Structure that defines a triangle in a model. 74 | */ 75 | typedef struct _GLMtriangle { 76 | GLuint vindices[3]; /* array of triangle vertex indices */ 77 | GLuint nindices[3]; /* array of triangle normal indices */ 78 | GLuint tindices[3]; /* array of triangle texcoord indices*/ 79 | GLuint findex; /* index of triangle facet normal */ 80 | } GLMtriangle; 81 | 82 | /* GLMgroup: Structure that defines a group in a model. 83 | */ 84 | typedef struct _GLMgroup { 85 | char* name; /* name of this group */ 86 | GLuint numtriangles; /* number of triangles in this group */ 87 | GLuint* triangles; /* array of triangle indices */ 88 | GLuint material; /* index to material for group */ 89 | struct _GLMgroup* next; /* pointer to next group in model */ 90 | } GLMgroup; 91 | 92 | /* GLMmodel: Structure that defines a model. 93 | */ 94 | typedef struct _GLMmodel { 95 | char* pathname; /* path to this model */ 96 | char* mtllibname; /* name of the material library */ 97 | 98 | GLuint numvertices; /* number of vertices in model */ 99 | GLfloat* vertices; /* array of vertices */ 100 | 101 | GLuint numnormals; /* number of normals in model */ 102 | GLfloat* normals; /* array of normals */ 103 | 104 | GLuint numtexcoords; /* number of texcoords in model */ 105 | GLfloat* texcoords; /* array of texture coordinates */ 106 | 107 | GLuint numfacetnorms; /* number of facetnorms in model */ 108 | GLfloat* facetnorms; /* array of facetnorms */ 109 | 110 | GLuint numtriangles; /* number of triangles in model */ 111 | GLMtriangle* triangles; /* array of triangles */ 112 | 113 | GLuint nummaterials; /* number of materials in model */ 114 | GLMmaterial* materials; /* array of materials */ 115 | 116 | GLuint numgroups; /* number of groups in model */ 117 | GLMgroup* groups; /* linked list of groups */ 118 | 119 | GLfloat position[3]; /* position of the model */ 120 | 121 | GLfloat* colors; 122 | int has_vertex_color; 123 | 124 | } GLMmodel; 125 | 126 | 127 | /* glmUnitize: "unitize" a model by translating it to the origin and 128 | * scaling it to fit in a unit cube around the origin. Returns the 129 | * scalefactor used. 130 | * 131 | * model - properly initialized GLMmodel structure 132 | */ 133 | GLfloat 134 | glmUnitize(GLMmodel* model); 135 | 136 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 137 | * a model. 138 | * 139 | * model - initialized GLMmodel structure 140 | * dimensions - array of 3 GLfloats (GLfloat dimensions[3]) 141 | */ 142 | GLvoid 143 | glmDimensions(GLMmodel* model, GLfloat* dimensions); 144 | 145 | /* glmScale: Scales a model by a given amount. 146 | * 147 | * model - properly initialized GLMmodel structure 148 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 149 | */ 150 | GLvoid 151 | glmScale(GLMmodel* model, GLfloat scale); 152 | 153 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 154 | * this model. Default winding is counter-clockwise. Also changes 155 | * the direction of the normals. 156 | * 157 | * model - properly initialized GLMmodel structure 158 | */ 159 | GLvoid 160 | glmReverseWinding(GLMmodel* model); 161 | 162 | /* glmFacetNormals: Generates facet normals for a model (by taking the 163 | * cross product of the two vectors derived from the sides of each 164 | * triangle). Assumes a counter-clockwise winding. 165 | * 166 | * model - initialized GLMmodel structure 167 | */ 168 | GLvoid 169 | glmFacetNormals(GLMmodel* model); 170 | 171 | /* glmVertexNormals: Generates smooth vertex normals for a model. 172 | * First builds a list of all the triangles each vertex is in. Then 173 | * loops through each vertex in the the list averaging all the facet 174 | * normals of the triangles each vertex is in. Finally, sets the 175 | * normal index in the triangle for the vertex to the generated smooth 176 | * normal. If the dot product of a facet normal and the facet normal 177 | * associated with the first triangle in the list of triangles the 178 | * current vertex is in is greater than the cosine of the angle 179 | * parameter to the function, that facet normal is not added into the 180 | * average normal calculation and the corresponding vertex is given 181 | * the facet normal. This tends to preserve hard edges. The angle to 182 | * use depends on the model, but 90 degrees is usually a good start. 183 | * 184 | * model - initialized GLMmodel structure 185 | * angle - maximum angle (in degrees) to smooth across 186 | */ 187 | GLvoid 188 | glmVertexNormals(GLMmodel* model, GLfloat angle); 189 | 190 | /* glmLinearTexture: Generates texture coordinates according to a 191 | * linear projection of the texture map. It generates these by 192 | * linearly mapping the vertices onto a square. 193 | * 194 | * model - pointer to initialized GLMmodel structure 195 | */ 196 | GLvoid 197 | glmLinearTexture(GLMmodel* model); 198 | 199 | /* glmSpheremapTexture: Generates texture coordinates according to a 200 | * spherical projection of the texture map. Sometimes referred to as 201 | * spheremap, or reflection map texture coordinates. It generates 202 | * these by using the normal to calculate where that vertex would map 203 | * onto a sphere. Since it is impossible to map something flat 204 | * perfectly onto something spherical, there is distortion at the 205 | * poles. This particular implementation causes the poles along the X 206 | * axis to be distorted. 207 | * 208 | * model - pointer to initialized GLMmodel structure 209 | */ 210 | GLvoid 211 | glmSpheremapTexture(GLMmodel* model); 212 | 213 | /* glmDelete: Deletes a GLMmodel structure. 214 | * 215 | * model - initialized GLMmodel structure 216 | */ 217 | GLvoid 218 | glmDelete(GLMmodel* model); 219 | 220 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 221 | * Returns a pointer to the created object which should be free'd with 222 | * glmDelete(). 223 | * 224 | * filename - name of the file containing the Wavefront .OBJ format data. 225 | */ 226 | GLMmodel* 227 | glmReadOBJ(char* filename); 228 | 229 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 230 | * a file. 231 | * 232 | * model - initialized GLMmodel structure 233 | * filename - name of the file to write the Wavefront .OBJ format data to 234 | * mode - a bitwise or of values describing what is written to the file 235 | * GLM_NONE - write only vertices 236 | * GLM_FLAT - write facet normals 237 | * GLM_SMOOTH - write vertex normals 238 | * GLM_TEXTURE - write texture coords 239 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 240 | */ 241 | GLvoid 242 | glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode); 243 | 244 | /* glmDraw: Renders the model to the current OpenGL context using the 245 | * mode specified. 246 | * 247 | * model - initialized GLMmodel structure 248 | * mode - a bitwise OR of values describing what is to be rendered. 249 | * GLM_NONE - render with only vertices 250 | * GLM_FLAT - render with facet normals 251 | * GLM_SMOOTH - render with vertex normals 252 | * GLM_TEXTURE - render with texture coords 253 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 254 | */ 255 | GLvoid 256 | glmDraw(GLMmodel* model, GLuint mode); 257 | 258 | /* glmList: Generates and returns a display list for the model using 259 | * the mode specified. 260 | * 261 | * model - initialized GLMmodel structure 262 | * mode - a bitwise OR of values describing what is to be rendered. 263 | * GLM_NONE - render with only vertices 264 | * GLM_FLAT - render with facet normals 265 | * GLM_SMOOTH - render with vertex normals 266 | * GLM_TEXTURE - render with texture coords 267 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 268 | */ 269 | GLuint 270 | glmList(GLMmodel* model, GLuint mode); 271 | 272 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 273 | * each other. 274 | * 275 | * model - initialized GLMmodel structure 276 | * epsilon - maximum difference between vertices 277 | * ( 0.00001 is a good start for a unitized model) 278 | * 279 | */ 280 | GLvoid 281 | glmWeld(GLMmodel* model, GLfloat epsilon); 282 | 283 | 284 | #ifdef __cplusplus 285 | } 286 | #endif 287 | -------------------------------------------------------------------------------- /example/src/ofxObjLoader/src/ofxObjLoader.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 5 | * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | * 8 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 12 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | * 14 | * Wavefront OBJ model file format reader/writer/manipulator for openFrameworks 15 | * 16 | * GLM library by Nate Robins, 1997 17 | * ndr@pobox.com, http://www.pobox.com/~ndr/ 18 | * 19 | * Addon by Satoru Higa ( http://structor.jp/ ) 20 | * Improvements by James George ( http://jamesgeorge.org/ ) at YCAM InterLab ( http://interlab.ycam.jp/ ) 21 | * 22 | * Example sphere from: http://liszt.stanford.edu/meshes/sphere.obj 23 | */ 24 | 25 | #include "ofxObjLoader.h" 26 | #include "glm.h" 27 | 28 | OFX_OBJLOADER_BEGIN_NAMESPACE 29 | 30 | void load(string path, ofMesh& mesh, bool generateNormals, bool flipFace) 31 | { 32 | path = ofToDataPath(path); 33 | 34 | mesh.clear(); 35 | 36 | GLMmodel* m; 37 | 38 | m = glmReadOBJ((char*)path.c_str()); 39 | 40 | if (generateNormals) 41 | { 42 | glmFacetNormals(m); 43 | glmVertexNormals(m, 90); 44 | } 45 | 46 | if (flipFace) 47 | { 48 | glmReverseWinding(m); 49 | } 50 | 51 | for (int j = 0; j < m->numtriangles; j++) 52 | { 53 | const GLMtriangle &tri = m->triangles[j]; 54 | 55 | for (int k = 0; k < 3; k++) 56 | { 57 | GLfloat *v = m->vertices + (tri.vindices[k] * 3); 58 | mesh.addVertex(ofVec3f(v[0], v[1], v[2])); 59 | 60 | if (m->colors) 61 | { 62 | GLfloat *c = m->colors + (tri.vindices[k] * 3); 63 | mesh.addColor(ofFloatColor(c[0], c[1], c[2])); 64 | } 65 | 66 | if (m->normals && ofInRange(tri.nindices[k], 0, m->numnormals)) 67 | { 68 | GLfloat *n = m->normals + (tri.nindices[k] * 3); 69 | mesh.addNormal(ofVec3f(n[0], n[1], n[2])); 70 | } 71 | 72 | if (m->texcoords && ofInRange(tri.tindices[k], 0, m->numtexcoords)) 73 | { 74 | GLfloat *c = m->texcoords + (tri.tindices[k] * 2); 75 | mesh.addTexCoord(ofVec2f(c[0], c[1])); 76 | } 77 | } 78 | } 79 | 80 | glmDelete(m); 81 | } 82 | 83 | void loadGroup(string path, map& groups, bool generateNormals) 84 | { 85 | path = ofToDataPath(path); 86 | 87 | groups.clear(); 88 | 89 | GLMmodel* m; 90 | 91 | m = glmReadOBJ((char*)path.c_str()); 92 | 93 | if (generateNormals) 94 | { 95 | glmFacetNormals(m); 96 | } 97 | 98 | glmReverseWinding(m); 99 | 100 | GLMgroup *g = m->groups; 101 | 102 | while (g) 103 | { 104 | string name = g->name; 105 | 106 | ofMesh t; 107 | GLMtriangle *p = m->triangles; 108 | 109 | for (int j = 0; j < g->numtriangles; j++) 110 | { 111 | GLMtriangle tri = p[g->triangles[j]]; 112 | 113 | for (int k = 0; k < 3; k++) 114 | { 115 | GLfloat *v = m->vertices + (tri.vindices[k] * 3); 116 | t.addVertex(ofVec3f(v[0], v[1], v[2])); 117 | 118 | if (m->colors) 119 | { 120 | GLfloat *c = m->colors + (tri.vindices[k] * 3); 121 | t.addColor(ofFloatColor(c[0], c[1], c[2])); 122 | } 123 | 124 | if (m->normals && ofInRange(tri.nindices[k], 0, m->numnormals)) 125 | { 126 | GLfloat *n = m->normals + (tri.nindices[k] * 3); 127 | t.addNormal(ofVec3f(n[0], n[1], n[2])); 128 | } 129 | 130 | if (m->texcoords && ofInRange(tri.tindices[k], 0, m->numtexcoords)) 131 | { 132 | GLfloat *c = m->texcoords + (tri.tindices[k] * 2); 133 | t.addTexCoord(ofVec2f(c[0], c[1])); 134 | } 135 | } 136 | } 137 | 138 | groups[name] = t; 139 | g = g->next; 140 | } 141 | 142 | glmDelete(m); 143 | } 144 | 145 | void save(string path, const ofMesh& mesh_, bool flipFace, bool flipNormals, bool export_vertexcolor_to_texture) 146 | { 147 | ofMesh mesh = mesh_; 148 | 149 | path = ofToDataPath(path); 150 | 151 | // ofFilePath::createEnclosingDirectory(path); 152 | 153 | GLuint writeMode = GLM_NONE; 154 | GLMmodel* m = new GLMmodel(); 155 | 156 | if (export_vertexcolor_to_texture) 157 | { 158 | if (mesh.getMode() != OF_PRIMITIVE_TRIANGLES) 159 | { 160 | ofLogError("ofxObjLoader::save") << "vertex color to texture supported only triangle primitive"; 161 | } 162 | else 163 | { 164 | ofImage image; 165 | 166 | vertexColorToFaceColor(mesh); 167 | faceColorToTexture(mesh, image); 168 | 169 | ofFile file(path); 170 | string base_path = file.getEnclosingDirectory(); 171 | string material_name = file.getBaseName(); 172 | 173 | string image_name = material_name + ".png"; 174 | ofPixels pix = image.getPixelsRef(); 175 | 176 | // flip save texture 177 | pix.mirror(true, false); 178 | ofSaveImage(pix, ofFilePath::join(base_path, image_name)); 179 | 180 | string mtl_filename = material_name + ".mtl"; 181 | 182 | writeMode |= GLM_MATERIAL; 183 | m->mtllibname = (char*)malloc(mtl_filename.size()); 184 | strcpy(m->mtllibname, mtl_filename.c_str()); 185 | 186 | m->nummaterials = 1; 187 | m->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial)); 188 | GLMmaterial *mat = &m->materials[0]; 189 | memset(mat, 0, sizeof(GLMmaterial)); 190 | 191 | for (int i = 0; i < 4; i++) 192 | { 193 | mat->diffuse[i] = 1; 194 | mat->ambient[i] = 1; 195 | mat->specular[i] = 1; 196 | mat->emmissive[i] = 1; 197 | } 198 | mat->shininess = 1; 199 | 200 | mat->name = (char*)malloc(material_name.size()); 201 | strcpy(mat->name, material_name.c_str()); 202 | 203 | mat->texture_path = (char*)malloc(image_name.size()); 204 | strcpy(mat->texture_path, image_name.c_str()); 205 | } 206 | } 207 | 208 | if (mesh.getNumVertices() > 0) 209 | { 210 | m->numvertices = mesh.getNumVertices(); 211 | m->vertices = new GLfloat[(m->numvertices + 1) * 3]; 212 | memcpy(&m->vertices[3], &mesh.getVertices()[0].x, sizeof(ofVec3f) * mesh.getNumVertices()); 213 | } 214 | else 215 | { 216 | ofLogError("ofxObjLoader::save -- No vertices to save!"); 217 | return; 218 | } 219 | 220 | if (mesh.getNumNormals() > 0) 221 | { 222 | m->numnormals = mesh.getNumNormals(); 223 | m->normals = new GLfloat[(m->numnormals + 1) * 3]; 224 | vector normals = mesh.getNormals(); 225 | 226 | if (flipNormals) 227 | for (int i = 0; i < normals.size(); i++) 228 | normals[i] *= -1; 229 | 230 | memcpy(&m->normals[3], &normals[0].x, sizeof(ofVec3f) * normals.size()); 231 | writeMode |= GLM_SMOOTH; 232 | } 233 | 234 | if (mesh.getNumTexCoords() > 0) 235 | { 236 | m->numtexcoords = mesh.getNumTexCoords(); 237 | m->texcoords = new GLfloat[(m->numtexcoords + 1) * 2]; 238 | memcpy(&m->texcoords[2], &mesh.getTexCoords()[0].x, sizeof(ofVec2f) * mesh.getNumTexCoords()); 239 | writeMode |= GLM_TEXTURE; 240 | } 241 | 242 | if (mesh.getNumIndices() > 0) 243 | { 244 | m->numtriangles = mesh.getNumIndices() / 3; 245 | m->triangles = new GLMtriangle[m->numtriangles]; 246 | 247 | m->groups = new GLMgroup(); 248 | m->groups->next = NULL; 249 | m->groups->material = NULL; 250 | 251 | string name = "ofMesh"; 252 | m->groups->name = (char*)malloc(sizeof(char) * name.length() + 1); 253 | strcpy(m->groups->name, name.c_str()); 254 | 255 | m->groups->numtriangles = mesh.getNumIndices() / 3; 256 | m->groups->triangles = new GLuint[m->groups->numtriangles]; 257 | m->numgroups = 1; 258 | 259 | for (int i = 0; i < mesh.getNumIndices(); i += 3) 260 | { 261 | int idx = i / 3; 262 | for (int j = 0; j < 3; j++) 263 | { 264 | m->triangles[idx].vindices[j] = mesh.getIndices()[i + j] + 1; 265 | m->triangles[idx].nindices[j] = mesh.getIndices()[i + j] + 1; 266 | m->triangles[idx].tindices[j] = mesh.getIndices()[i + j] + 1; 267 | } 268 | m->groups->triangles[idx] = idx; 269 | } 270 | } 271 | else 272 | { 273 | m->numtriangles = mesh.getNumVertices() / 3; 274 | m->triangles = new GLMtriangle[m->numtriangles]; 275 | 276 | m->groups = new GLMgroup(); 277 | m->groups->next = NULL; 278 | m->groups->material = NULL; 279 | 280 | string name = "ofMesh"; 281 | m->groups->name = (char*)malloc(sizeof(char) * name.length() + 1); 282 | strcpy(m->groups->name, name.c_str()); 283 | 284 | m->groups->numtriangles = mesh.getNumVertices() / 3; 285 | m->groups->triangles = new GLuint[m->groups->numtriangles]; 286 | m->numgroups = 1; 287 | 288 | for (int i = 0; i < mesh.getNumVertices(); i += 3) 289 | { 290 | int idx = i / 3; 291 | for (int j = 0; j < 3; j++) 292 | { 293 | m->triangles[idx].vindices[j] = i + j + 1; 294 | m->triangles[idx].nindices[j] = i + j + 1; 295 | m->triangles[idx].tindices[j] = i + j + 1; 296 | } 297 | m->groups->triangles[idx] = idx; 298 | } 299 | } 300 | 301 | if (flipFace) 302 | glmReverseWinding(m); 303 | 304 | glmWriteOBJ(m, (char*)path.c_str(), writeMode); 305 | glmDelete(m); 306 | } 307 | 308 | void vertexColorToFaceColor(ofMesh& mesh) 309 | { 310 | vector face_color; 311 | vector &color = mesh.getColors(); 312 | 313 | for (int i = 0; i < color.size(); i += 3) 314 | { 315 | ofFloatColor c0 = color[i + 0]; 316 | ofFloatColor c1 = color[i + 1]; 317 | ofFloatColor c2 = color[i + 2]; 318 | 319 | float r = (c0.r + c1.r + c2.r) / 3; 320 | float g = (c0.g + c1.g + c2.g) / 3; 321 | float b = (c0.b + c1.b + c2.b) / 3; 322 | ofFloatColor c(r, g, b, 1); 323 | 324 | face_color.push_back(c); 325 | face_color.push_back(c); 326 | face_color.push_back(c); 327 | } 328 | 329 | mesh.getColors() = face_color; 330 | } 331 | 332 | void faceColorToTexture(ofMesh& mesh, ofImage& image) 333 | { 334 | vector &color = mesh.getColors(); 335 | int num_face = color.size() / 3; 336 | 337 | int tex_size = ofNextPow2(ceil(sqrt(num_face))); 338 | 339 | bool arb = ofGetUsingArbTex(); 340 | ofDisableArbTex(); 341 | image.allocate(tex_size, tex_size, OF_IMAGE_COLOR); 342 | if (arb) ofEnableArbTex(); 343 | 344 | mesh.clearTexCoords(); 345 | 346 | image.getPixelsRef().set(0); 347 | 348 | float texel_size = (1. / image.getWidth()) * 0.5; 349 | 350 | for (int i = 0; i < num_face; i++) 351 | { 352 | int u = (i % tex_size); 353 | int v = (i / tex_size); 354 | 355 | ofColor c = color[i * 3]; 356 | 357 | image.setColor(u, v, c); 358 | 359 | float uu = (float)u / image.getWidth() + texel_size; 360 | float vv = (float)v / image.getHeight() + texel_size; 361 | 362 | mesh.addTexCoord(ofVec2f(uu, vv)); 363 | mesh.addTexCoord(ofVec2f(uu, vv)); 364 | mesh.addTexCoord(ofVec2f(uu, vv)); 365 | } 366 | 367 | image.update(); 368 | mesh.clearColors(); 369 | } 370 | 371 | OFX_OBJLOADER_END_NAMESPACE -------------------------------------------------------------------------------- /example/src/ofxObjLoader/src/ofxObjLoader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 5 | * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | * 8 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 12 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | * 14 | * Wavefront OBJ model file format reader/writer/manipulator for openFrameworks 15 | * 16 | * GLM library by Nate Robins, 1997 17 | * ndr@pobox.com, http://www.pobox.com/~ndr/ 18 | * 19 | * Addon by Satoru Higa ( http://structor.jp/ ) 20 | * Improvements by James George ( http://jamesgeorge.org/ ) at YCAM InterLab ( http://interlab.ycam.jp/ ) 21 | * 22 | * Example sphere from: http://liszt.stanford.edu/meshes/sphere.obj 23 | */ 24 | 25 | #pragma once 26 | 27 | #include "ofMain.h" 28 | 29 | #define OFX_OBJLOADER_BEGIN_NAMESPACE namespace ofx { namespace ObjLoader { 30 | #define OFX_OBJLOADER_END_NAMESPACE } } 31 | 32 | OFX_OBJLOADER_BEGIN_NAMESPACE 33 | 34 | void load(string path, ofMesh& mesh, bool generateNormals = true, bool flipFace = false); 35 | void save(string path, const ofMesh& mesh, bool flipFace = false, bool flipNormals = false, bool export_vertexcolor_to_texture = false); 36 | 37 | void loadGroup(string path, map& groups, bool generateNormals = true); 38 | 39 | // utils 40 | void vertexColorToFaceColor(ofMesh& mesh); 41 | void faceColorToTexture(ofMesh& mesh, ofImage& image); 42 | 43 | OFX_OBJLOADER_END_NAMESPACE 44 | 45 | namespace ofxObjLoader = ofx::ObjLoader; -------------------------------------------------------------------------------- /src/CSG/BoundBox.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BoundBox.cpp 3 | // example 4 | // 5 | // Created by lars berg on 3/10/15. 6 | // 7 | // 8 | 9 | #include "BoundBox.h" 10 | -------------------------------------------------------------------------------- /src/CSG/BoundBox.h: -------------------------------------------------------------------------------- 1 | // 2 | // BoundBox.h 3 | // 4 | // Created by lars berg on 3/3/15. 5 | // 6 | 7 | #pragma once 8 | 9 | #include "ofMain.h" 10 | 11 | namespace ofxCSG 12 | { 13 | class BoundBox 14 | { 15 | public: 16 | BoundBox() : 17 | initialized( false ), 18 | minBound( ofVec3f() ), 19 | maxBound( ofVec3f() ) 20 | {} 21 | 22 | ~BoundBox() 23 | {} 24 | 25 | void addPoint( ofVec3f p ) 26 | { 27 | if(!initialized) 28 | { 29 | initialized = true; 30 | 31 | minBound = maxBound = p; 32 | } 33 | else 34 | { 35 | for(int i=0; i<3; i++) 36 | { 37 | minBound[i] = min( p[i], minBound[i] ); 38 | maxBound[i] = max( p[i], maxBound[i] ); 39 | } 40 | 41 | if(minBound.x > maxBound.x || minBound.y > maxBound.y || minBound.z > maxBound.z ) 42 | { 43 | cout << "minBound: " << minBound << endl; 44 | cout << "maxBound: " << maxBound << endl << endl; 45 | } 46 | } 47 | } 48 | 49 | void addPoints( vector points ) 50 | { 51 | for(auto& p: points) addPoint( p ); 52 | } 53 | 54 | void addPoints( ofVec3f a, ofVec3f b, ofVec3f c ) 55 | { 56 | addPoint( a ); 57 | addPoint( b ); 58 | addPoint( c ); 59 | } 60 | 61 | void clear() 62 | { 63 | initialized = false; 64 | } 65 | 66 | bool overlap( float minA, float maxA, float minB, float maxB ) 67 | { 68 | if( maxA < minB || maxB < minA ) 69 | { 70 | return false; 71 | } 72 | else if( minB <= minA && minA <= maxB ) 73 | { 74 | return true; 75 | } 76 | else if( minA <= minB && minB <= maxA ) 77 | { 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | bool isPointInside( ofVec3f p ) 85 | { 86 | return minBound.x <= p.x && p.x <= maxBound.x && minBound.y <= p.y && p.y <= maxBound.y && minBound.z <= p.z && p.z <= maxBound.z; 87 | // if( minBound.x <= p.x && p.x <= maxBound.x ) 88 | // { 89 | // if( minBound.y <= p.y && p.y <= maxBound.y ) 90 | // { 91 | // if( minBound.z <= p.z && p.z <= maxBound.z ) 92 | // { 93 | // return true; 94 | // } 95 | // return false; 96 | // } 97 | // return false; 98 | // } 99 | // return false; 100 | } 101 | 102 | bool intersects( BoundBox& bb ) 103 | { 104 | if( overlap( minBound.x, maxBound.x, bb.minBound.x, bb.maxBound.x) ) 105 | { 106 | if( overlap( minBound.y, maxBound.y, bb.minBound.y, bb.maxBound.y) ) 107 | { 108 | return overlap( minBound.z, maxBound.z, bb.minBound.z, bb.maxBound.z); 109 | } 110 | return false; 111 | } 112 | return false; 113 | } 114 | 115 | static bool intersectBoxes( BoundBox& a, BoundBox& b) 116 | { 117 | return a.intersects( b ); 118 | } 119 | 120 | bool initialized; 121 | ofVec3f minBound, maxBound; 122 | }; 123 | } 124 | -------------------------------------------------------------------------------- /src/CSG/LineSegment.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // LineSegment.cpp 3 | // example 4 | // 5 | // Created by lars berg on 3/10/15. 6 | // 7 | // 8 | 9 | #include 10 | 11 | 12 | 13 | namespace ofxCSG 14 | { 15 | LineSegment::LineSegment( ofVec3f a, ofVec3f b) : 16 | a(a), b(b) 17 | {} 18 | 19 | LineSegment::LineSegment() 20 | {} 21 | 22 | void LineSegment::set( ofVec3f p0, ofVec3f p1 ) 23 | { 24 | a = p0, b = p1; 25 | } 26 | 27 | void LineSegment::expandToPoint( ofVec3f p ) 28 | { 29 | if(a == b) 30 | { 31 | b = p; 32 | return; 33 | } 34 | 35 | float u = getLineSegmentUValue(a, b, p); 36 | if(u < 0) a = p; 37 | else if(u > 1) b = p; 38 | } 39 | 40 | float LineSegment::lengthSquared() 41 | { 42 | return a.squareDistance( b ); 43 | } 44 | 45 | bool LineSegment::subtract( LineSegment segment ) 46 | { 47 | return subtract( segment.a, segment.b ); 48 | } 49 | 50 | bool LineSegment::subtract( ofVec3f p0, ofVec3f p1 ) 51 | { 52 | if(!isPointInLineSegment( a, b, p0 ) && !isPointInLineSegment( a, b, p1 )) 53 | { 54 | // cout << "!isPointInLineSegment( a, b, p0 ) && !isPointInLineSegment( a, b, p1 )" << endl; 55 | return false; 56 | } 57 | 58 | float uP0 = getLineSegmentUValue( a, b, p0 ); 59 | float uP1 = getLineSegmentUValue( a, b, p1 ); 60 | 61 | if( uP1 < uP0 ) 62 | { 63 | swap(p0, p1); 64 | swap(uP0, uP1); 65 | } 66 | 67 | if(uP1 == uP0) 68 | { 69 | cout << "SHIT!" << p0 << ", " << p1 << endl << endl; 70 | } 71 | 72 | a = uP0 > 0 ? p0 : a; 73 | b = uP1 < 1 ? p1 : b; 74 | 75 | return true; 76 | } 77 | 78 | bool LineSegment::trimToTriangle( ofVec3f ta, ofVec3f tb, ofVec3f tc) 79 | { 80 | //get the intersections 81 | vector intersections; 82 | ofVec3f intersection; 83 | ofVec3f normal = normalFromPoints( ta, tb, tc); 84 | 85 | //if the points are inside let's keep them 86 | if( isPointInTriangle( a, ta, tb, tc, normal, NEG_EPSILON )) 87 | { 88 | intersections.push_back( a ); 89 | } 90 | if( isPointInTriangle( b, ta, tb, tc, normal, NEG_EPSILON )) 91 | { 92 | intersections.push_back( b ); 93 | } 94 | 95 | // if there both inside we're done 96 | if(intersections.size() == 2) return true; 97 | 98 | 99 | // otherwise let's intersect with the triangle edges 100 | if(intersectLineSegments(a, b, ta, tb, &intersection)) 101 | { 102 | intersections.push_back( intersection ); 103 | } 104 | if(intersectLineSegments(a, b, tb, tc, &intersection)) 105 | { 106 | intersections.push_back( intersection ); 107 | } 108 | if(intersectLineSegments(a, b, tc, ta, &intersection)) 109 | { 110 | intersections.push_back( intersection ); 111 | } 112 | 113 | //rebuild a ine segment if there's enough intersections 114 | if( intersections.size() > 1 ) 115 | { 116 | LineSegment trimmedLine(intersections[0], intersections[1]); 117 | 118 | for(int i=2; i 10 | 11 | namespace ofxCSG 12 | { 13 | class LineSegment 14 | { 15 | public: 16 | LineSegment( ofVec3f a, ofVec3f b); 17 | 18 | LineSegment(); 19 | 20 | void set( ofVec3f p0, ofVec3f p1 ); 21 | 22 | void expandToPoint( ofVec3f p ); 23 | 24 | float lengthSquared(); 25 | 26 | bool subtract( LineSegment segment ); 27 | 28 | bool subtract( ofVec3f p0, ofVec3f p1 ); 29 | 30 | bool trimToTriangle( ofVec3f ta, ofVec3f tb, ofVec3f tc); 31 | 32 | ofVec3f* getPtr(); 33 | 34 | ofVec3f& operator[]( int n ); 35 | 36 | ofVec3f a, b, normal; 37 | }; 38 | } -------------------------------------------------------------------------------- /src/CSG/Polygon.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Polygon.cpp 3 | // example 4 | // 5 | // Created by lars berg on 3/10/15. 6 | // 7 | // 8 | 9 | #include 10 | 11 | namespace ofxCSG 12 | { 13 | Polygon::Polygon() : 14 | rayIntersectionCount( 0 ) 15 | {} 16 | 17 | Polygon::Polygon( ofVec3f a, ofVec3f b, ofVec3f c ) : 18 | rayIntersectionCount( 0 ) 19 | { 20 | addTriangle(a, b, c); 21 | } 22 | 23 | Polygon::~Polygon() 24 | {} 25 | 26 | void Polygon::addTriangle( ofVec3f a, ofVec3f b, ofVec3f c ) 27 | { 28 | bb.addPoints( a, b, c ); 29 | triangles.push_back( Triangle( a, b, c ) ); 30 | } 31 | 32 | void Polygon::addTriangle( Triangle t ) 33 | { 34 | bb.addPoints( t.a, t.b, t.c ); 35 | triangles.push_back( t ); 36 | } 37 | 38 | void Polygon::set( ofVec3f a, ofVec3f b, ofVec3f c ) 39 | { 40 | clear(); 41 | addTriangle( Triangle( a, b, c ) ); 42 | } 43 | 44 | void Polygon::setClassification( Classification classification ) 45 | { 46 | for(auto& t: triangles) 47 | { 48 | t.classification = classification; 49 | } 50 | } 51 | 52 | ofVec3f Polygon::getNormal() 53 | { 54 | return triangles[0].normal; 55 | } 56 | 57 | float Polygon::getW() 58 | { 59 | return triangles[0].w; 60 | } 61 | 62 | void Polygon::clear() 63 | { 64 | bb.clear(); 65 | triangles.clear(); 66 | } 67 | 68 | void Polygon::flip() 69 | { 70 | for(auto& t: triangles) t.flip(); 71 | } 72 | 73 | vector Polygon::toPolylines() 74 | { 75 | vector polylines; 76 | 77 | for(auto& t: triangles) 78 | { 79 | ofPolyline p; 80 | p.addVertex( t.a ); 81 | p.addVertex( t.b ); 82 | p.addVertex( t.c ); 83 | 84 | p.setClosed(true); 85 | 86 | polylines.push_back( p ); 87 | } 88 | 89 | return polylines; 90 | } 91 | 92 | void Polygon::split( Triangle& t ) 93 | { 94 | vector splitTriangles; 95 | for(auto& tri: triangles) 96 | { 97 | auto subd = tri.split( t ); 98 | splitTriangles.insert( splitTriangles.end(), subd.begin(), subd.end() ); 99 | } 100 | 101 | triangles = splitTriangles; 102 | } 103 | 104 | void Polygon::split( Polygon& p ) 105 | { 106 | ////TODO: if they're coplanar we should split them differnetly 107 | //float nDot = getNormal().dot( p.getNormal() ); 108 | //if( false && abs(nDot) >= 1 - EPSILON ) 109 | //{ 110 | // cout << "CSG::Polygon::split() - we should create a coplanar split method." << endl; 111 | //} 112 | //else 113 | //{ 114 | //otherwise split the triangles individually 115 | for( auto& t: p.triangles ) 116 | { 117 | split( t ); 118 | } 119 | //} 120 | } 121 | 122 | void Polygon::split( ofVec3f t0, ofVec3f t1, ofVec3f t2 ) 123 | { 124 | Polygon p( t0, t1, t2 ); 125 | 126 | split( p ); 127 | } 128 | 129 | bool Polygon::intersectRay( ofVec3f rayOrigin, ofVec3f rayDir, float epsilon, ofVec3f* intersection ) 130 | { 131 | for(auto& t: triangles) 132 | { 133 | if( t.intersectRay( rayOrigin, rayDir, epsilon, intersection ) ) 134 | { 135 | return true; 136 | } 137 | } 138 | 139 | return false; 140 | } 141 | 142 | void Polygon::classifyRay( Polygon& p, int& intersectionCount ) 143 | { 144 | ofVec3f rayDir = getNormal(); 145 | for(auto& t: triangles) 146 | { 147 | ofVec3f rayOrigin = t.getCenter(); 148 | 149 | if( p.intersectRay( rayOrigin, rayDir, EPSILON, NULL ) ) 150 | { 151 | intersectionCount++; 152 | } 153 | } 154 | } 155 | 156 | void Polygon::classify( vector& polygons ) 157 | { 158 | ofVec3f rayDir = getNormal(); 159 | for(auto& t: triangles) 160 | { 161 | ofVec3f rayOrigin = t.getCenter(); 162 | 163 | int intersectionCount = 0; 164 | 165 | for( auto& p: polygons ) 166 | { 167 | if( p.intersectRay( rayOrigin, rayDir, EPSILON, NULL ) ) 168 | { 169 | intersectionCount++; 170 | } 171 | } 172 | 173 | t.classification = intersectionCount % 2 ? ofxCSG::BACK : ofxCSG::FRONT; 174 | } 175 | } 176 | 177 | void Polygon::draw(bool useNormalForColor ) 178 | { 179 | for(auto& t: triangles) 180 | { 181 | t.draw(useNormalForColor); 182 | } 183 | } 184 | 185 | } 186 | -------------------------------------------------------------------------------- /src/CSG/Polygon.h: -------------------------------------------------------------------------------- 1 | // 2 | // Polygon.h 3 | // 4 | // Created by lars berg on 3/3/15. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace ofxCSG 13 | { 14 | class Polygon 15 | { 16 | public: 17 | Polygon(); 18 | 19 | Polygon( ofVec3f a, ofVec3f b, ofVec3f c ); 20 | 21 | ~Polygon(); 22 | 23 | void addTriangle( ofVec3f a, ofVec3f b, ofVec3f c ); 24 | 25 | void addTriangle( Triangle t ); 26 | 27 | void set( ofVec3f a, ofVec3f b, ofVec3f c ); 28 | 29 | void setClassification( Classification classification ); 30 | 31 | ofVec3f getNormal(); 32 | 33 | float getW(); 34 | 35 | void clear(); 36 | 37 | void flip(); 38 | 39 | vector toPolylines(); 40 | 41 | void split( Triangle& t ); 42 | 43 | void split( Polygon& p ); 44 | 45 | void split( ofVec3f t0, ofVec3f t1, ofVec3f t2 ); 46 | 47 | bool intersectRay( ofVec3f rayOrigin, ofVec3f rayDir, float epsilon, ofVec3f* intersection = NULL ); 48 | 49 | void classifyRay( Polygon& p, int& intersectionCount ); 50 | 51 | void classify( vector& polygons ); 52 | 53 | void draw(bool useNormalForColor = true); 54 | 55 | 56 | // 57 | vector triangles; 58 | BoundBox bb; 59 | 60 | vector< Polygon* > splitters; 61 | 62 | bool wasSplit; 63 | 64 | int rayIntersectionCount; 65 | 66 | 67 | //for coplanar splitting 68 | // vector polylines; 69 | // vector lineSegments; 70 | }; 71 | } -------------------------------------------------------------------------------- /src/CSG/Triangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Triangle.cpp 3 | // example 4 | // 5 | // Created by lars berg on 3/10/15. 6 | // 7 | // 8 | 9 | #include 10 | 11 | namespace ofxCSG 12 | { 13 | Triangle::Triangle(ofVec3f a, ofVec3f b, ofVec3f c) : 14 | a( a ), 15 | b( b ), 16 | c( c ), 17 | centroid( (a+b+c) / 3 ), 18 | classification( UNDEFINED ), 19 | normal( normalFromPoints(a, b, c) ), 20 | w( normal.dot(a) ) 21 | {} 22 | 23 | Triangle::Triangle() : 24 | classification( UNDEFINED ) 25 | {} 26 | 27 | Triangle::~Triangle() 28 | {} 29 | 30 | ofVec3f* Triangle::getPtr() 31 | { 32 | return &a; 33 | } 34 | 35 | ofVec3f& Triangle::operator[]( int n ) 36 | { 37 | return getPtr()[n]; 38 | } 39 | 40 | void Triangle::set( ofVec3f _a, ofVec3f _b, ofVec3f _c ) 41 | { 42 | a = _a; 43 | b = _b; 44 | c = _c; 45 | centroid = (a+b+c) / 3; 46 | calcNormal(); 47 | } 48 | 49 | void Triangle::flip() 50 | { 51 | swap(b, c); 52 | normal *= -1; 53 | w = -w; 54 | 55 | if(classification == FRONT) classification = BACK; 56 | else if(classification == BACK) classification = FRONT; 57 | } 58 | 59 | void Triangle::calcNormal() 60 | { 61 | normal = normalFromPoints( a, b, c ); 62 | w = normal.dot( a ); 63 | } 64 | 65 | float Triangle::getArea() 66 | { 67 | return areaOfTriangle( a, b, c ); 68 | } 69 | 70 | float Triangle::getAreaSquared() 71 | { 72 | return areaOfTriangleSquared( a, b, c ); 73 | } 74 | 75 | //derived from Akira-Hayasaka's ofxRayTriangleIntersection 76 | // https://github.com/Akira-Hayasaka/ofxRayTriangleIntersection/blob/master/src/ofxRayTriangleIntersection.h 77 | // assume ray direction is normalized 78 | bool Triangle::intersectRay( ofVec3f rayOrigin, ofVec3f rayDir, ofVec3f* intersection ) 79 | { 80 | float vn = rayDir.dot(normal); 81 | 82 | ofVec3f diff = rayOrigin - a; 83 | float xpn = diff.dot( normal ); 84 | float distance = -xpn / vn; 85 | 86 | if (distance < NEG_EPSILON) return false; // behind ray origin. fail 87 | 88 | ofVec3f hitPos = rayDir * distance + rayOrigin; 89 | 90 | if( isPointInTriangle( hitPos, a, b, c, normal ) ) 91 | { 92 | //it's a hit 93 | if(intersection!= NULL) 94 | { 95 | *intersection = hitPos; 96 | } 97 | return true; 98 | } 99 | 100 | //nada 101 | return false; 102 | } 103 | 104 | bool Triangle::rayIntersect( ofVec3f rayOrigin, ofVec3f rayDir ) 105 | { 106 | ofVec3f diff, edge1, edge2, norm; 107 | 108 | bool backfaceCulling = true; 109 | 110 | edge1 = b-a; 111 | edge2 = c-a; 112 | norm = edge1.cross( edge2 ); 113 | 114 | float sign = 1; 115 | 116 | float DdN = rayDir.dot( normal ); 117 | if ( DdN > 0 ) 118 | { 119 | // if ( backfaceCulling ) return false; 120 | sign = 1; 121 | } 122 | else if ( DdN < 0 ) 123 | { 124 | sign = - 1; 125 | DdN = - DdN; 126 | } 127 | else 128 | { 129 | return false; 130 | } 131 | 132 | diff = rayOrigin - a; 133 | auto DdQxE2 = sign * rayDir.dot( diff.cross( edge2 ) ); 134 | 135 | // b1 < 0, no intersection 136 | if ( DdQxE2 < 0 ) 137 | { 138 | return false; 139 | } 140 | 141 | auto DdE1xQ = sign * rayDir.dot( edge1.cross( diff ) ); 142 | 143 | // b2 < 0, no intersection 144 | if ( DdE1xQ < 0 ) 145 | { 146 | return false; 147 | } 148 | 149 | // b1+b2 > 1, no intersection 150 | if ( DdQxE2 + DdE1xQ > DdN ) 151 | { 152 | return false; 153 | } 154 | 155 | // Line intersects triangle, check if ray does. 156 | auto QdN = - sign * diff.dot( normal ); 157 | 158 | // t < 0, no intersection 159 | if ( QdN < 0 ) 160 | { 161 | return false; 162 | } 163 | 164 | // Ray intersects triangle. 165 | return true;// this.at( QdN / DdN, optionalTarget ); 166 | } 167 | 168 | 169 | 170 | //derived from Akira-Hayasaka's ofxRayTriangleIntersection 171 | // https://github.com/Akira-Hayasaka/ofxRayTriangleIntersection/blob/master/src/ofxRayTriangleIntersection.h 172 | // assume ray direction is normalized 173 | bool Triangle::intersectRay( ofVec3f rayOrigin, ofVec3f rayDir, float epsilon, ofVec3f* intersection ) 174 | { 175 | float vn = rayDir.dot(normal); 176 | 177 | ofVec3f diff = rayOrigin - a; 178 | float xpn = diff.dot( normal ); 179 | float distance = -xpn / vn; 180 | 181 | if (distance < NEG_EPSILON) return false; // behind ray origin. fail 182 | 183 | ofVec3f hitPos = rayDir * distance + rayOrigin; 184 | 185 | if( isPointInTriangle( hitPos, a, b, c, normal, epsilon ) ) 186 | { 187 | //it's a hit 188 | if(intersection!= NULL) 189 | { 190 | *intersection = hitPos; 191 | } 192 | return true; 193 | } 194 | 195 | //nada 196 | return false; 197 | } 198 | 199 | ofVec3f Triangle::getCenter() 200 | { 201 | return centroid;//(a + b + c) / 3.; 202 | } 203 | 204 | void Triangle::draw(bool useNormalForColor ) 205 | { 206 | if(classification == BACK) 207 | { 208 | return; 209 | } 210 | 211 | if(useNormalForColor) ofSetColor( ofFloatColor(normal.x * .5 + .5, normal.y * .5 + .5, normal.z * .5 + .5) ); 212 | ofDrawTriangle( a, b, c ); 213 | } 214 | 215 | ofPolyline Triangle::toPolyline() 216 | { 217 | ofPolyline p; 218 | p.addVertices( getPtr(), 3); 219 | p.setClosed(true); 220 | 221 | return p; 222 | } 223 | 224 | Classification Triangle::getClassification( ofVec3f planeNormal, float planeW ) 225 | { 226 | int frontCount = 0, backCount = 0; 227 | Classification classyFries; 228 | for(int i=0; i<3; i++) 229 | { 230 | classyFries = classifyPointWithPlane( (*this)[i], planeNormal, planeW); 231 | if( classyFries == FRONT) frontCount++; 232 | else if( classyFries == BACK) backCount++; 233 | } 234 | 235 | if(frontCount && backCount) return SPANNING; 236 | else if( backCount ) return BACK; 237 | else if( frontCount ) return FRONT; 238 | else return COPLANAR; 239 | } 240 | 241 | void Triangle::classifyWithPlane( ofVec3f planeNormal, float planeW ) 242 | { 243 | classification = getClassification( planeNormal, planeW ); 244 | } 245 | 246 | vector Triangle::intersectWithPlane( ofVec3f planeNormal, float planeW ) 247 | { 248 | vector intersections; 249 | 250 | ofVec3f intersection; 251 | 252 | for(int i=0, j=1; i<3; i++, j++) 253 | { 254 | if( splitLineSegmentWithPlane( (*this)[i], (*this)[j%3], planeNormal, planeW, &intersection) ) 255 | { 256 | intersections.push_back( intersection ); 257 | } 258 | } 259 | 260 | return intersections; 261 | } 262 | 263 | bool Triangle::getIntersection( Triangle t, LineSegment* overlap ) 264 | { 265 | //TODO:: have intersect with plane return a LineSegment 266 | auto i0 = intersectWithPlane( t.normal, t.w ); 267 | auto i1 = t.intersectWithPlane( normal, w ); 268 | 269 | 270 | if(i0.size() < 2 || i1.size() < 2) 271 | { 272 | // cout << "ofxCSG::Triangle::getIntersection() - does this ever happen?" << endl; 273 | return false; 274 | } 275 | 276 | LineSegment l0( i0[0], i0[1] ); 277 | LineSegment l1( i1[0], i1[1] ); 278 | 279 | for(int i=2;i Triangle::insert( ofVec3f v ) 298 | { 299 | vector triangles; 300 | 301 | if( abs(distanceToPlaneSigned( v, a, normal) ) > EPSILON) 302 | { 303 | triangles.push_back( *this ); 304 | return triangles; 305 | } 306 | 307 | //make three triangles 308 | for(int i=0; i<3; i++) 309 | { 310 | Triangle t( (*this)[i], (*this)[(i+1)%3], v); 311 | t.classification - classification; 312 | if(t.getAreaSquared() > EPSILON) 313 | { 314 | triangles.push_back(t); 315 | } 316 | } 317 | 318 | return triangles; 319 | } 320 | 321 | vector Triangle::splitWithCoplanarSegment(ofVec3f a, ofVec3f b) 322 | { 323 | return splitWithCoplanarSegment( LineSegment(a, b) ); 324 | } 325 | 326 | vector Triangle::splitWithCoplanarSegment(LineSegment segment) 327 | { 328 | vector triangles; 329 | 330 | if(segment.trimToTriangle(a, b, c)) 331 | { 332 | //they intersect, let's split using the overlap segment 333 | auto firstPass = insert( segment.a ); 334 | 335 | // we need to trim the line segment for each triangle because we're inserting the end points 336 | // into each triangle to subdivide. 337 | for(auto& tri: firstPass) 338 | { 339 | auto trimedSegment = segment; 340 | if(trimedSegment.trimToTriangle( tri.a, tri.b, tri.c )) 341 | { 342 | 343 | auto subd = tri.insert( trimedSegment.b ); 344 | if(subd.size() == 1) 345 | { 346 | subd = tri.insert( trimedSegment.a ); 347 | } 348 | 349 | triangles.insert( triangles.end(), subd.begin(), subd.end() ); 350 | } 351 | else 352 | { 353 | triangles.push_back( tri ); 354 | } 355 | } 356 | 357 | return triangles; 358 | } 359 | 360 | triangles.push_back( *this ); 361 | return triangles; 362 | } 363 | 364 | vector Triangle::split( Triangle t ) 365 | { 366 | vector triangles; 367 | 368 | auto cl = getClassification( t.normal, t.w ); 369 | 370 | if( cl == SPANNING ) 371 | { 372 | //otherwise check if the other triangle spans this one 373 | cl = t.getClassification(normal, w); 374 | 375 | //if they both span then they might intersect. so we'll find the line segment where they overlap 376 | // and split it with that segment 377 | LineSegment overlap; 378 | if( cl == SPANNING && getIntersection( t, &overlap ) ) 379 | { 380 | return splitWithCoplanarSegment( overlap ); 381 | } 382 | else 383 | { 384 | //no intersection 385 | triangles.push_back( *this ); 386 | } 387 | } 388 | else if( cl == COPLANAR ) 389 | { 390 | //shit... 391 | triangles.push_back( *this ); 392 | } 393 | else 394 | { 395 | //no intersection 396 | triangles.push_back( *this ); 397 | } 398 | 399 | return triangles; 400 | } 401 | 402 | vector Triangle::meshToTriangles(ofMesh& m) 403 | { 404 | vector triangles; 405 | 406 | auto indices = m.getIndices(); 407 | auto v = m.getVertices(); 408 | 409 | if(indices.size()) 410 | { 411 | for(int i=0; i 10 | 11 | namespace ofxCSG 12 | { 13 | class Triangle 14 | { 15 | public: 16 | Triangle(ofVec3f a, ofVec3f b, ofVec3f c); 17 | 18 | Triangle(); 19 | ~Triangle(); 20 | 21 | ofVec3f* getPtr(); 22 | 23 | ofVec3f& operator[]( int n ); 24 | 25 | void set( ofVec3f _a, ofVec3f _b, ofVec3f _c ); 26 | 27 | void flip(); 28 | 29 | void calcNormal(); 30 | 31 | float getArea(); 32 | 33 | float getAreaSquared(); 34 | 35 | bool rayIntersect( ofVec3f rayOrigin, ofVec3f rayDir ); 36 | 37 | bool intersectRay( ofVec3f rayOrigin, ofVec3f rayDir, ofVec3f* intersection = NULL ); 38 | 39 | bool intersectRay( ofVec3f rayOrigin, ofVec3f rayDir, float epsilon, ofVec3f* intersection = NULL ); 40 | 41 | ofVec3f getCenter(); 42 | 43 | void draw(bool useNormalForColor = true); 44 | 45 | ofPolyline toPolyline(); 46 | 47 | Classification getClassification( ofVec3f planeNormal, float planeW ); 48 | 49 | void classifyWithPlane( ofVec3f planeNormal, float planeW ); 50 | 51 | vector intersectWithPlane( ofVec3f planeNormal, float planeW ); 52 | 53 | bool getIntersection( Triangle t, LineSegment* overlap ); 54 | 55 | vector insert( ofVec3f v ); 56 | 57 | vector splitWithCoplanarSegment(ofVec3f a, ofVec3f b); 58 | 59 | vector splitWithCoplanarSegment(LineSegment segment); 60 | 61 | vector split( Triangle t ); 62 | 63 | vector meshToTriangles(ofMesh& m); 64 | 65 | ofVec3f a, b, c, centroid; 66 | ofVec3f normal; 67 | float w; 68 | Classification classification; 69 | }; 70 | 71 | 72 | //STATIC METHODS 73 | static vector meshToTriangles(ofMesh& m) 74 | { 75 | vector triangles; 76 | 77 | auto indices = m.getIndices(); 78 | auto v = m.getVertices(); 79 | 80 | if(indices.size()) 81 | { 82 | for(int i=0; i 30 | static T lerp(T a, T b, float k) 31 | { 32 | return a + (b - a) * k; 33 | } 34 | 35 | template 36 | static void appendVectors( vector& a, vector& b ) 37 | { 38 | //a.reserve( a.size() + b.size() ); 39 | a.insert( a.end(), b.begin(), b.end() ); 40 | } 41 | 42 | static ofVec3f normalFromPoints(ofVec3f p0, ofVec3f p1, ofVec3f p2) 43 | { 44 | return (p2 - p1).cross( p0 - p1).normalize(); 45 | } 46 | 47 | static float areaOfTriangle(ofVec3f p0, ofVec3f p1, ofVec3f p2) 48 | { 49 | return (p2 - p1).cross(p0 - p1).length() * .5; 50 | } 51 | 52 | static float areaOfTriangleSquared(ofVec3f p0, ofVec3f p1, ofVec3f p2) 53 | { 54 | return (p2 - p1).cross(p0 - p1).lengthSquared() * .5; 55 | } 56 | 57 | static float signedDistanceToPlane(ofVec3f point, ofVec3f planePos, ofVec3f planeNormal) 58 | { 59 | float dist = planeNormal.dot(point - planePos); 60 | return dist; 61 | } 62 | 63 | //http://geomalgorithms.com/a04-_planes.html 64 | static float distanceToPlane(ofVec3f point, ofVec3f planePos, ofVec3f planeNormal) 65 | { 66 | float sb, sn, sd; 67 | 68 | sn = -( planeNormal.dot(point - planePos) ); 69 | sd = planeNormal.dot(planeNormal); 70 | sb = sn / sd; 71 | 72 | ofVec3f B = point + sb * planeNormal; 73 | 74 | return point.distance(B); 75 | } 76 | 77 | static float distanceToPlaneSigned(ofVec3f point, ofVec3f planePos, ofVec3f planeNormal) 78 | { 79 | //assumes planeNormal is a unit vector 80 | return -( planeNormal.dot( point - planePos ) ); 81 | // return -( doubleDot( planeNormal, point - planePos ) ); 82 | } 83 | 84 | static Classification classifyPointWithPlane( ofVec3f point, ofVec3f planeNormal, float w ) 85 | { 86 | float t = planeNormal.dot( point ) - w; 87 | return ( t < NEG_EPSILON ) ? BACK : (t > EPSILON) ? FRONT : SPANNING; 88 | } 89 | 90 | static Classification classifyPointWithPlane( ofVec3f point, ofVec3f planePos, ofVec3f planeNormal) 91 | { 92 | auto d = distanceToPlaneSigned( point, planePos, planeNormal ); 93 | 94 | if( d > EPSILON ) return BACK; 95 | else if( d < NEG_EPSILON ) return FRONT; 96 | 97 | return SPANNING; 98 | } 99 | 100 | //barycentric coords 101 | //http://www.blackpawn.com/texts/pointinpoly/ 102 | static bool getBaryCentricCoords(ofVec3f p, ofVec3f t0, ofVec3f t1, ofVec3f t2, float &u, float &v, float& w) 103 | { 104 | // Compute vectors 105 | ofVec3f v0 = t2 - t0; 106 | ofVec3f v1 = t1 - t0; 107 | ofVec3f v2 = p - t0; 108 | 109 | // Compute dot products 110 | float dot00 = v0.dot( v0 ); 111 | float dot01 = v0.dot( v1 ); 112 | float dot02 = v0.dot( v2 ); 113 | float dot11 = v1.dot( v1 ); 114 | float dot12 = v1.dot( v2 ); 115 | 116 | float denom = (dot00 * dot11 - dot01 * dot01); 117 | 118 | if ( denom == 0 ) 119 | { 120 | //TODO: what's the right thing to do here? 121 | u = v = w = 0; 122 | return false; 123 | } 124 | 125 | // Compute barycentric coordinates 126 | float invDenom = 1.f / denom; 127 | u = (dot11 * dot02 - dot01 * dot12) * invDenom; 128 | v = (dot00 * dot12 - dot01 * dot02) * invDenom; 129 | w = 1. - u - v; 130 | 131 | return true; 132 | } 133 | 134 | static bool getBaryCentricCoords(ofVec3f p, ofVec3f t0, ofVec3f t1, ofVec3f t2, float &u, float &v) 135 | { 136 | float w; 137 | return getBaryCentricCoords(p, t0, t1, t2, u, v, w); 138 | } 139 | 140 | static ofVec3f closestPointOnLineSegment(ofVec3f p, ofVec3f l0, ofVec3f l1) 141 | { 142 | ofVec3f diff = p - l0; 143 | ofVec3f dir = l1 - l0; 144 | float u = diff.dot( dir ) / dir.dot( dir ); 145 | 146 | if ( u < 0. ) return l0; 147 | else if( u > 1. ) return l1; 148 | 149 | return l0 + dir * u; 150 | } 151 | 152 | 153 | //http://paulbourke.net/geometry/pointlineplane/lineline.c 154 | static bool LineLineIntersect( ofVec3f p1,ofVec3f p2,ofVec3f p3,ofVec3f p4, ofVec3f *pa = NULL, ofVec3f *pb = NULL ) 155 | { 156 | ofVec3f p13, p43, p21; 157 | double d1343,d4321,d1321,d4343,d2121; 158 | double numer,denom; 159 | 160 | p13 = p1 - p3; 161 | p43 = p4 - p3; 162 | 163 | if (abs(p43.x) < EPSILON && abs(p43.y) < EPSILON && abs(p43.z) < EPSILON) return false; 164 | 165 | p21 = p2 - p1; 166 | 167 | if (abs(p21.x) < EPSILON && abs(p21.y) < EPSILON && abs(p21.z) < EPSILON) return false; 168 | 169 | d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z; 170 | d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z; 171 | d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z; 172 | d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z; 173 | d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z; 174 | 175 | denom = d2121 * d4343 - d4321 * d4321; 176 | if (abs(denom) < EPSILON) return false; 177 | 178 | numer = d1343 * d4321 - d1321 * d4343; 179 | 180 | double mua = numer / denom; 181 | double mub = (d1343 + d4321 * mua) / d4343; 182 | 183 | if( pa != NULL) 184 | { 185 | *pa = p1 + mua * p21; 186 | } 187 | if( pb != NULL ) 188 | { 189 | *pb = p3 + mub * p43; 190 | } 191 | 192 | return true; 193 | } 194 | 195 | static float getLineSegmentUValue(ofVec3f l0, ofVec3f l1, ofVec3f p) 196 | { 197 | ofVec3f diff = p - l0; 198 | ofVec3f dir = l1 - l0; 199 | 200 | if(l0 == l1) 201 | { 202 | return 0; 203 | } 204 | 205 | return diff.dot( dir ) / dir.dot( dir ); 206 | } 207 | 208 | static bool isPointInLineSegment(ofVec3f l0, ofVec3f l1, ofVec3f p) 209 | { 210 | float u = getLineSegmentUValue( l0, l1, p ); 211 | return u >= NEG_EPSILON && u <= ONE_PLUS_EPSILON; 212 | } 213 | 214 | static bool intersectLineSegments(ofVec3f a0, ofVec3f a1, ofVec3f b0, ofVec3f b1, ofVec3f* intersection=NULL) 215 | { 216 | ofVec3f p; 217 | 218 | LineLineIntersect(a0, a1, b0, b1, &p); 219 | 220 | if( isPointInLineSegment(a0, a1, p) ) 221 | { 222 | *intersection = p; 223 | return true; 224 | } 225 | 226 | return false; 227 | } 228 | 229 | static bool splitLineSegmentWithPlane( ofVec3f l0, ofVec3f l1, ofVec3f planeNormal, float w, ofVec3f* intersection) 230 | { 231 | auto c0 = classifyPointWithPlane( l0, planeNormal, w); 232 | auto c1 = classifyPointWithPlane( l1, planeNormal, w); 233 | 234 | if( c0 != c1 ) 235 | { 236 | float k = (w - planeNormal.dot(l0)) / planeNormal.dot( l1 - l0 ); 237 | 238 | *intersection = lerp( l0, l1, CLAMP(k, 0, 1) ); // the clamp fixed some errors where k > 1 239 | 240 | return true; 241 | } 242 | 243 | return false; 244 | } 245 | 246 | static int intersectLineSegmentPlane(ofVec3f p0, ofVec3f p1, ofVec3f planePos, ofVec3f planeNormal, ofVec3f* intersection = NULL) 247 | { 248 | auto d0 = distanceToPlaneSigned( p0, planePos, planeNormal ); 249 | auto d1 = distanceToPlaneSigned( p1, planePos, planeNormal ); 250 | 251 | if( (d0 >= EPSILON && d1 >= EPSILON) || ( d0 <= NEG_EPSILON && d1 <= NEG_EPSILON ) ) 252 | // if( (d0 > 0 && d1 > 0) || ( d0 < 0 && d1 < 0 ) ) 253 | { 254 | //no intersection 255 | return 0; 256 | } 257 | if( d0 == 0 && d1 == 0 ) 258 | { 259 | //it's coplanar 260 | if( intersection != NULL ) 261 | { 262 | *intersection = p0; 263 | } 264 | return 2; 265 | } 266 | 267 | //it's a hit 268 | if( intersection != NULL ) 269 | { 270 | //lerp using the distance to plane values 271 | *intersection = lerp( p0, p1, d0 / (d0 - d1) ); 272 | } 273 | return 1; 274 | } 275 | 276 | 277 | static bool isPointInTriangle(ofVec3f p, ofVec3f a, ofVec3f b, ofVec3f c, ofVec3f normal ) 278 | { 279 | if( fabs( distanceToPlaneSigned( p, a, normal ) ) > EPSILON ) return false; 280 | 281 | float u, v, w, epsilon = NEG_EPSILON; // 0; // EPSILON; // 282 | 283 | if( getBaryCentricCoords( p, a, b, c, u, v, w ) ) 284 | { 285 | return u > epsilon && v > epsilon && w > epsilon; 286 | } 287 | 288 | return false; 289 | } 290 | 291 | static bool isPointOnPlane( ofVec3f p, ofVec3f planeNormal, float w, float epsilon = EPSILON) 292 | { 293 | float t = planeNormal.dot(p) - w; 294 | return abs(t) > epsilon; 295 | } 296 | 297 | static bool isPointInTriangle(ofVec3f p, ofVec3f a, ofVec3f b, ofVec3f c, ofVec3f normal, float epsilon ) 298 | { 299 | float u, v, w; 300 | 301 | if( getBaryCentricCoords( p, a, b, c, u, v, w ) ) 302 | { 303 | return u > epsilon && v > epsilon && w > epsilon; 304 | } 305 | 306 | return false; 307 | } 308 | 309 | static bool isPointInTriangle(ofVec3f p, ofVec3f a, ofVec3f b, ofVec3f c) 310 | { 311 | return isPointInTriangle( p, a, b, c, normalFromPoints(a, b, c) ); 312 | } 313 | 314 | 315 | //derived from Akira-Hayasaka's ofxRayTriangleIntersection 316 | // https://github.com/Akira-Hayasaka/ofxRayTriangleIntersection/blob/master/src/ofxRayTriangleIntersection.h 317 | // assume ray direction is normalized 318 | static bool intersectRayTriangle(ofVec3f rayOrigin, ofVec3f rayDir, ofVec3f t0, ofVec3f t1, ofVec3f t2, ofVec3f* intersection=NULL) 319 | { 320 | ofVec3f normal = (t2 - t1).cross( t0 - t1).normalize(); 321 | float vn = rayDir.dot(normal); 322 | 323 | ofVec3f diff = rayOrigin - t0; 324 | float xpn = diff.dot(normal); 325 | float distance = -xpn / vn; 326 | 327 | if (distance < 0) return false; // behind ray origin. fail 328 | 329 | ofVec3f hitPos = rayDir * distance + rayOrigin; 330 | 331 | if(isPointInTriangle(hitPos, t0, t1, t2)) 332 | { 333 | //it's a hit 334 | if(intersection!= NULL) 335 | { 336 | *intersection = hitPos; 337 | } 338 | return true; 339 | } 340 | 341 | //nada 342 | return false; 343 | } 344 | } -------------------------------------------------------------------------------- /src/CSG/Vertex.h: -------------------------------------------------------------------------------- 1 | // 2 | // Vertex.h 3 | // 4 | // Created by lars berg on 3/3/15. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace ofxCSG 12 | { 13 | class Vertex : public ofVec3f 14 | { 15 | public: 16 | Vertex( float x=0, float y=0, float z=0) : 17 | ofVec3f(x, y, z), 18 | classification(UNDEFINED) 19 | {} 20 | 21 | Vertex( ofVec3f v3 ) : 22 | ofVec3f( v3 ), 23 | classification(UNDEFINED) 24 | {} 25 | 26 | ~Vertex() 27 | {} 28 | 29 | Classification classification; 30 | }; 31 | } -------------------------------------------------------------------------------- /src/ofxCSG.h: -------------------------------------------------------------------------------- 1 | // 2 | // ofxCSG.h 3 | // 4 | // Created by lars berg on 3/3/15. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | 12 | namespace ofxCSG 13 | { 14 | static void addPolygonsToMesh(ofMesh& m, vector& polygons) 15 | { 16 | for(auto& p: polygons) 17 | { 18 | for(auto& t: p.triangles) 19 | { 20 | if(t.classification == FRONT) 21 | { 22 | m.addVertex( t.a ); 23 | m.addVertex( t.b ); 24 | m.addVertex( t.c ); 25 | } 26 | } 27 | } 28 | } 29 | 30 | static vector meshToPolygons(ofMesh& m) 31 | { 32 | vector polygons; 33 | 34 | auto indices = m.getIndices(); 35 | auto v = m.getVertices(); 36 | 37 | if(indices.size()) 38 | { 39 | for(int i=0; i polygonsToPolylines( vector& polygons ) 57 | { 58 | vector polylines; 59 | for(auto& p: polygons) 60 | { 61 | auto pl = p.toPolylines(); 62 | 63 | polylines.insert(polylines.end(), pl.begin(), pl.end() ); 64 | } 65 | 66 | return polylines; 67 | } 68 | 69 | 70 | static void meshBoolean( ofMesh& a, ofMesh& b, ofMesh& m, bool flipA, bool flipB) 71 | { 72 | 73 | // get our polygons 74 | auto polygonsA = meshToPolygons( a ); 75 | auto polygonsB = meshToPolygons( b ); 76 | 77 | auto orig_polygonsA = polygonsA; 78 | auto orig_polygonsB = polygonsB; 79 | 80 | auto startTime = ofGetElapsedTimeMillis(); 81 | 82 | //split the polygons with eachother 83 | int rayIntersectionCount = 0; 84 | for(int i=0; ibb.intersects( pb.bb )) 114 | { 115 | pb.split( *pa ); 116 | } 117 | } 118 | 119 | pb.wasSplit = pb.triangles.size() > 1; 120 | } 121 | 122 | ofLogVerbose( "ofxCSG::meshBoolean", "split time: " + ofToString((ofGetElapsedTimeMillis() - startTime)) ); 123 | 124 | //classy the triangles 125 | startTime = ofGetElapsedTimeMillis(); 126 | ofVec3f rayDir(0,1,0); 127 | for(auto& p: polygonsA) 128 | { 129 | if(p.triangles.size() > 1) 130 | { 131 | p.classify( orig_polygonsB ); 132 | } 133 | else 134 | { 135 | p.setClassification( p.rayIntersectionCount % 2 ? BACK : FRONT ); 136 | } 137 | } 138 | 139 | for(auto& p: polygonsB) 140 | { 141 | if(p.triangles.size() > 1) 142 | { 143 | p.classify( orig_polygonsA ); 144 | } 145 | else 146 | { 147 | p.setClassification( p.rayIntersectionCount % 2 ? BACK : FRONT ); 148 | } 149 | } 150 | ofLogVerbose( "ofxCSG::meshBoolean", "classify time: " + ofToString((ofGetElapsedTimeMillis() - startTime)) ); 151 | 152 | //flip em 153 | if(flipA) 154 | { 155 | for(auto& p: polygonsA) p.flip(); 156 | } 157 | 158 | if(flipB) 159 | { 160 | for(auto& p: polygonsB) p.flip(); 161 | } 162 | 163 | startTime = ofGetElapsedTimeMillis(); 164 | //add the polygons to out outMesh 165 | m.clear(); 166 | addPolygonsToMesh( m, polygonsA ); 167 | addPolygonsToMesh( m, polygonsB ); 168 | ofLogVerbose( "ofxCSG::meshBoolean", "create mesh time: " + ofToString((ofGetElapsedTimeMillis() - startTime)) ); 169 | } 170 | 171 | static void meshUnion( ofMesh& a, ofMesh& b, ofMesh& outMesh ) 172 | { 173 | meshBoolean( a, b, outMesh, false, false ); 174 | } 175 | 176 | static void meshIntersection( ofMesh& a, ofMesh& b, ofMesh& outMesh ) 177 | { 178 | meshBoolean( a, b, outMesh, true, true ); 179 | } 180 | 181 | static void meshDifference( ofMesh& a, ofMesh& b, ofMesh& outMesh ) 182 | { 183 | meshBoolean( a, b, outMesh, false, true ); 184 | } 185 | } --------------------------------------------------------------------------------