reference

This documentation is automatically generated from the openFrameworks source code using doxygen and refers to the most recent release, version 0.12.0.

ofMesh.inl
Go to the documentation of this file.
1#ifndef OF_MESH_H
2#include "ofMesh.h"
3#endif
4
5#include "ofAppRunner.h"
7#include "ofVectorMath.h"
8#include "ofMath.h"
9#include "ofMathConstants.h"
10#include "ofLog.h"
11#include "ofColor.h"
12
13#include <unordered_map>
14
15//--------------------------------------------------------------
16template<class V, class N, class C, class T>
19 bVertsChanged = false;
20 bColorsChanged = false;
21 bNormalsChanged = false;
22 bTexCoordsChanged = false;
23 bIndicesChanged = false;
24 bFacesDirty = false;
25 useColors = true;
26 useTextures = true;
27 useNormals = true;
28 useIndices = true;
29}
30
31
32//--------------------------------------------------------------
33template<class V, class N, class C, class T>
34ofMesh_<V,N,C,T>::ofMesh_(ofPrimitiveMode mode, const std::vector<V>& verts){
35 bColorsChanged = false;
36 bNormalsChanged = false;
37 bTexCoordsChanged = false;
38 useColors = true;
39 useTextures = true;
40 useNormals = true;
41 useIndices = true;
42 setMode(mode);
43 addVertices(verts);
44}
45
46
47//--------------------------------------------------------------
48template<class V, class N, class C, class T>
50 if(!vertices.empty()){
51 bVertsChanged = true;
52 vertices.clear();
53 }
54 if(!colors.empty()){
55 bColorsChanged = true;
56 colors.clear();
57 }
58 if(!normals.empty()){
59 bNormalsChanged = true;
60 normals.clear();
61 }
62 if(!texCoords.empty()){
63 bTexCoordsChanged = true;
64 texCoords.clear();
65 }
66 if(!indices.empty()){
67 bIndicesChanged = true;
68 indices.clear();
69 }
70 bFacesDirty = true;
71}
72
73
74//--------------------------------------------------------------
75template<class V, class N, class C, class T>
77 if(bVertsChanged){
78 bVertsChanged = false;
79 return true;
80 }else{
81 return false;
82 }
83}
84
85
86
87//--------------------------------------------------------------
88template<class V, class N, class C, class T>
90 if(bColorsChanged){
91 bColorsChanged = false;
92 return true;
93 }else{
94 return false;
95 }
97
98
99
100//--------------------------------------------------------------
101template<class V, class N, class C, class T>
103 if(bNormalsChanged){
104 bNormalsChanged = false;
105 return true;
106 }else{
107 return false;
108 }
109}
110
112
113//--------------------------------------------------------------
114template<class V, class N, class C, class T>
116 if(bTexCoordsChanged){
117 bTexCoordsChanged = false;
118 return true;
119 }else{
120 return false;
122}
125
126//--------------------------------------------------------------
127template<class V, class N, class C, class T>
129 if(bIndicesChanged){
130 bIndicesChanged = false;
131 return true;
132 }else{
133 return false;
134 }
135}
136
137
138
140//--------------------------------------------------------------
141template<class V, class N, class C, class T>
143 return !vertices.empty();
144}
145
146
147
148//--------------------------------------------------------------
149template<class V, class N, class C, class T>
151 return !colors.empty();
152}
153
155
156//--------------------------------------------------------------
157template<class V, class N, class C, class T>
159 return !normals.empty();
160}
161
162
163
164//--------------------------------------------------------------
165template<class V, class N, class C, class T>
167 return !texCoords.empty();
168}
169
170
172//--------------------------------------------------------------
173template<class V, class N, class C, class T>
175 return !indices.empty();
176}
177
178//ADDERS
179
180
181
182//--------------------------------------------------------------
183template<class V, class N, class C, class T>
185 vertices.push_back(v);
186 bVertsChanged = true;
187 bFacesDirty = true;
188}
189
190
191
192//--------------------------------------------------------------
193template<class V, class N, class C, class T>
194void ofMesh_<V,N,C,T>::addVertices(const std::vector<V>& verts){
195 vertices.insert(vertices.end(),verts.begin(),verts.end());
196 bVertsChanged = true;
197 bFacesDirty = true;
198}
200
202//--------------------------------------------------------------
203template<class V, class N, class C, class T>
204void ofMesh_<V,N,C,T>::addVertices(const V* verts, std::size_t amt){
205 vertices.insert(vertices.end(),verts,verts+amt);
206 bVertsChanged = true;
207 bFacesDirty = true;
208}
209
210
211
212//--------------------------------------------------------------
213template<class V, class N, class C, class T>
215 colors.push_back(c);
216 bColorsChanged = true;
217 bFacesDirty = true;
219
220
222//--------------------------------------------------------------
223template<class V, class N, class C, class T>
224void ofMesh_<V,N,C,T>::addColors(const std::vector<C>& cols){
225 colors.insert(colors.end(),cols.begin(),cols.end());
226 bColorsChanged = true;
227 bFacesDirty = true;
228}
229
231
232//--------------------------------------------------------------
233template<class V, class N, class C, class T>
234void ofMesh_<V,N,C,T>::addColors(const C* cols, std::size_t amt){
235 colors.insert(colors.end(),cols,cols+amt);
236 bColorsChanged = true;
237 bFacesDirty = true;
238}
239
241
242//--------------------------------------------------------------
243template<class V, class N, class C, class T>
245 normals.push_back(n);
246 bNormalsChanged = true;
247 bFacesDirty = true;
248}
250
251
252//--------------------------------------------------------------
253template<class V, class N, class C, class T>
254void ofMesh_<V,N,C,T>::addNormals(const std::vector<N>& norms){
255 normals.insert(normals.end(),norms.begin(),norms.end());
256 bNormalsChanged = true;
257 bFacesDirty = true;
258}
259
261
262//--------------------------------------------------------------
263template<class V, class N, class C, class T>
264void ofMesh_<V,N,C,T>::addNormals(const N* norms, std::size_t amt){
265 normals.insert(normals.end(),norms,norms+amt);
266 bNormalsChanged = true;
267 bFacesDirty = true;
268}
269
270
271
272//--------------------------------------------------------------
273template<class V, class N, class C, class T>
275 //TODO: figure out if we add to all other arrays to match
276 texCoords.push_back(t);
277 bTexCoordsChanged = true;
278 bFacesDirty = true;
279}
280
282
283//--------------------------------------------------------------
284template<class V, class N, class C, class T>
285void ofMesh_<V,N,C,T>::addTexCoords(const std::vector<T>& tCoords){
286 texCoords.insert(texCoords.end(),tCoords.begin(),tCoords.end());
287 bTexCoordsChanged = true;
288 bFacesDirty = true;
289}
290
292
293//--------------------------------------------------------------
294template<class V, class N, class C, class T>
295void ofMesh_<V,N,C,T>::addTexCoords(const T* tCoords, std::size_t amt){
296 texCoords.insert(texCoords.end(),tCoords,tCoords+amt);
297 bTexCoordsChanged = true;
298 bFacesDirty = true;
299}
301
302
303//--------------------------------------------------------------
304template<class V, class N, class C, class T>
308
309
310
311//--------------------------------------------------------------
312template<class V, class N, class C, class T>
314 indices.push_back(i);
315 bIndicesChanged = true;
316 bFacesDirty = true;
317}
319
320
321//--------------------------------------------------------------
322template<class V, class N, class C, class T>
323void ofMesh_<V,N,C,T>::addIndices(const std::vector<ofIndexType>& inds){
324 indices.insert(indices.end(),inds.begin(),inds.end());
325 bIndicesChanged = true;
326 bFacesDirty = true;
327}
329
330
331//--------------------------------------------------------------
332template<class V, class N, class C, class T>
333void ofMesh_<V,N,C,T>::addIndices(const ofIndexType* inds, std::size_t amt){
334 indices.insert(indices.end(),inds,inds+amt);
335 bIndicesChanged = true;
336 bFacesDirty = true;
337}
338
340
341//--------------------------------------------------------------
342template<class V, class N, class C, class T>
344 addIndex(index1);
345 addIndex(index2);
346 addIndex(index3);
348
349//REMOVERS
350
352//--------------------------------------------------------------
353template<class V, class N, class C, class T>
355 if(index >= vertices.size()){
356 ofLogError("ofMesh") << "removeVertex(): ignoring out of range index " << index << ", number of vertices is" << vertices.size();
357 }else{
358 vertices.erase(vertices.begin() + index);
359 bVertsChanged = true;
360 bFacesDirty = true;
362}
363
364template<class V, class N, class C, class T>
366 if(startIndex >= vertices.size() || endIndex > vertices.size()){
367 ofLogError("ofMesh") << "removeVertex(): ignoring out of range startIndex " << startIndex << " endIndex " << endIndex << ", number of vertices is" << vertices.size();
368 }else{
369 vertices.erase(vertices.begin() + startIndex, vertices.begin() + endIndex);
370 bVertsChanged = true;
371 bFacesDirty = true;
372 }
373}
375
376
377//--------------------------------------------------------------
378template<class V, class N, class C, class T>
380 if(index >= normals.size()){
381 ofLogError("ofMesh") << "removeNormal(): ignoring out of range index " << index << ", number of normals is" << normals.size();
382 }else{
383 normals.erase(normals.begin() + index);
384 bNormalsChanged = true;
385 bFacesDirty = true;
386 }
387}
389template<class V, class N, class C, class T>
391 if(startIndex >= normals.size() || endIndex > normals.size()){
392 ofLogError("ofMesh") << "removeNormal(): ignoring out of range beginIndex " << startIndex << " endIndex " << endIndex << ", number of normals is" << normals.size();
393 }else{
394 normals.erase(normals.begin() + startIndex, normals.begin() + endIndex);
395 bNormalsChanged = true;
396 bFacesDirty = true;
397 }
398}
399
401//--------------------------------------------------------------
402template<class V, class N, class C, class T>
404 if(index >= colors.size()){
405 ofLogError("ofMesh") << "removeColor(): ignoring out of range index " << index << ", number of colors is" << colors.size();
406 }else{
407 colors.erase(colors.begin() + index);
408 bColorsChanged = true;
409 bFacesDirty = true;
410 }
411}
413template<class V, class N, class C, class T>
415 if(startIndex >= colors.size() || endIndex > colors.size()){
416 ofLogError("ofMesh") << "removeColor(): ignoring out of range startIndex " << startIndex << " endIndex " << endIndex << ", number of colors is" << colors.size();
417 }else{
418 colors.erase(colors.begin() + startIndex, colors.begin() + endIndex);
419 bColorsChanged = true;
420 bFacesDirty = true;
421 }
422}
424
425
426//--------------------------------------------------------------
427template<class V, class N, class C, class T>
429 if(index >= texCoords.size()){
430 ofLogError("ofMesh") << "removeTexCoord(): ignoring out of range index " << index << ", number of tex coords is" << texCoords.size();
431 }else{
432 texCoords.erase(texCoords.begin() + index);
433 bTexCoordsChanged = true;
434 bFacesDirty = true;
436}
438template<class V, class N, class C, class T>
440 if(startIndex >= texCoords.size() || endIndex >= texCoords.size()){
441 ofLogError("ofMesh") << "removeTexCoord(): ignoring out of range startIndex " << startIndex << " endIndex " << endIndex << ", number of tex coords is" << texCoords.size();
442 }else{
443 texCoords.erase(texCoords.begin() + startIndex, texCoords.begin() + endIndex);
444 bTexCoordsChanged = true;
445 bFacesDirty = true;
446 }
448
449
451
452//--------------------------------------------------------------
453template<class V, class N, class C, class T>
455 if(index >= indices.size()){
456 ofLogError("ofMesh") << "removeIndex(): ignoring out of range index " << index << ", number of indices is" << indices.size();
457 }else{
458 indices.erase(indices.begin() + index);
459 bIndicesChanged = true;
460 bFacesDirty = true;
462}
463
464template<class V, class N, class C, class T>
466 if(startIndex >= indices.size() || endIndex > indices.size()){
467 ofLogError("ofMesh") << "removeIndex(): ignoring out of range startIndex " << startIndex << " endIndex " << endIndex << ", number of indices is" << indices.size();;
468 }else{
469 indices.erase(indices.begin() + startIndex, indices.begin() + endIndex);
470 bIndicesChanged = true;
471 bFacesDirty = true;
472 }
475
476
477//GETTERS
478
479
480//--------------------------------------------------------------
481template<class V, class N, class C, class T>
483 return mode;
484}
485
486
487
488//--------------------------------------------------------------
489template<class V, class N, class C, class T>
491 return vertices[i];
493
494
495
496//--------------------------------------------------------------
497template<class V, class N, class C, class T>
499 return normals[i];
500}
501
502
503
504//--------------------------------------------------------------
505template<class V, class N, class C, class T>
507 return colors[i];
508}
509
510
511
512//--------------------------------------------------------------
513template<class V, class N, class C, class T>
515 return texCoords[i];
516}
518
519
520//--------------------------------------------------------------
521template<class V, class N, class C, class T>
523 return vertices.size();
525
526
528//--------------------------------------------------------------
529template<class V, class N, class C, class T>
531 return colors.size();
532}
533
534
536//--------------------------------------------------------------
537template<class V, class N, class C, class T>
539 return normals.size();
540}
541
543
544//--------------------------------------------------------------
545template<class V, class N, class C, class T>
547 return texCoords.size();
548}
550
551
552//--------------------------------------------------------------
553template<class V, class N, class C, class T>
555 return indices.size();
557
558/*
559
560
561//--------------------------------------------------------------
562template<class V, class N, class C, class T>
563int ofPrimitive::getNumIndicesSolid(){
564 return indicesSolid.size();
567
569//--------------------------------------------------------------
570template<class V, class N, class C, class T>
571int ofPrimitive::getNumIndicesWire(){
572 return indicesWire.size();
574 */
575
576
577
578//--------------------------------------------------------------
579template<class V, class N, class C, class T>
581 return vertices.data();
582}
583
585
586//--------------------------------------------------------------
587template<class V, class N, class C, class T>
589 return colors.data();
590}
592
593
594//--------------------------------------------------------------
595template<class V, class N, class C, class T>
597 return normals.data();
598}
599
600
601
602//--------------------------------------------------------------
603template<class V, class N, class C, class T>
605 return texCoords.data();
607
608
609
610//--------------------------------------------------------------
611template<class V, class N, class C, class T>
613 return indices.data();
614}
615
616
618
619//--------------------------------------------------------------
620template<class V, class N, class C, class T>
622 return vertices.data();
623}
625
626
627//--------------------------------------------------------------
628template<class V, class N, class C, class T>
630 return colors.data();
631}
632
634
635//--------------------------------------------------------------
636template<class V, class N, class C, class T>
638 return normals.data();
639}
640
641
642
643//--------------------------------------------------------------
644template<class V, class N, class C, class T>
646 return texCoords.data();
647}
648
649
650
651//--------------------------------------------------------------
652template<class V, class N, class C, class T>
654 return indices.data();
655}
656
657//--------------------------------------------------------------
658template<class V, class N, class C, class T>
660 bVertsChanged = true;
661 bFacesDirty = true;
662 return vertices;
663}
664
665//--------------------------------------------------------------
666template<class V, class N, class C, class T>
668 bColorsChanged = true;
669 bFacesDirty = true;
670 return colors;
671}
672
673//--------------------------------------------------------------
674template<class V, class N, class C, class T>
676 bNormalsChanged = true;
677 bFacesDirty = true;
678 return normals;
679}
680
681//--------------------------------------------------------------
682template<class V, class N, class C, class T>
684 bTexCoordsChanged = true;
685 bFacesDirty = true;
686 return texCoords;
687}
688
689//--------------------------------------------------------------
690template<class V, class N, class C, class T>
691std::vector<ofIndexType> & ofMesh_<V,N,C,T>::getIndices(){
692 bIndicesChanged = true;
693 bFacesDirty = true;
694 return indices;
695}
696
697//--------------------------------------------------------------
698template<class V, class N, class C, class T>
699const std::vector<V> & ofMesh_<V,N,C,T>::getVertices() const{
700 return vertices;
701}
702
703//--------------------------------------------------------------
704template<class V, class N, class C, class T>
705const std::vector<C> & ofMesh_<V,N,C,T>::getColors() const{
706 return colors;
707}
708
709//--------------------------------------------------------------
710template<class V, class N, class C, class T>
711const std::vector<N> & ofMesh_<V,N,C,T>::getNormals() const{
712 return normals;
713}
714
715//--------------------------------------------------------------
716template<class V, class N, class C, class T>
717const std::vector<T> & ofMesh_<V,N,C,T>::getTexCoords() const{
718 return texCoords;
719}
720
721//--------------------------------------------------------------
722template<class V, class N, class C, class T>
723const std::vector<ofIndexType> & ofMesh_<V,N,C,T>::getIndices() const{
724 return indices;
725}
726
727/*
728
729
730//--------------------------------------------------------------
731template<class V, class N, class C, class T>
732GLuint* ofPrimitive::getSolidIndexPointer(){
733 return &indicesSolid[0];
734}
735
736
737
738//--------------------------------------------------------------
739template<class V, class N, class C, class T>
740GLuint* ofPrimitive::getWireIndexPointer(){
741 return &indicesWire[0];
742}
743 */
744
745/*
746
747
748//--------------------------------------------------------------
749template<class V, class N, class C, class T>
750std::vector<int>& ofPrimitive::getFace(int faceNum){
751 switch(mode){
752 //GL_QUADS
753 indices[faceNum*4+0];
754 indices[faceNum*4+1];
755 indices[faceNum*4+2];
756 indices[faceNum*4+3];
757
758 //GL_TRIANGLES
759 indices[faceNum*3+0];
760 indices[faceNum*3+1];
761 indices[faceNum*3+2];
762
763 //GL_TRIANGLE_FAN
764 // 1 element per fan
765 indices[0];
766 indices[faceNum+1];
767 indices[faceNum+2];
768
769 //GL_TRIANGLE_STRIP
770 // 1 element per strip
771 indices[faceNum+0];
772 indices[faceNum+1];
773 indices[faceNum+2];
774 default:break;
775 }
776}
777 */
778
779
780
781
782//--------------------------------------------------------------
783template<class V, class N, class C, class T>
785 if(vertices.size() == 0) {
786 ofLogWarning("ofMesh") << "getCentroid(): mesh has no vertices, returning glm::vec3(0, 0, 0)";
787 return glm::vec3(0, 0, 0);
788 }
789
790 V sum;
791 for(ofIndexType i = 0; i < vertices.size(); i++) {
792 sum += vertices[i];
793 }
794 sum /= vertices.size();
795 return sum;
796}
797
798//SETTERS
799
800
801//--------------------------------------------------------------
802template<class V, class N, class C, class T>
804 bIndicesChanged = true;
805 mode = m;
806}
807
808
809
810//--------------------------------------------------------------
811template<class V, class N, class C, class T>
813 vertices[index] = v;
814 bVertsChanged = true;
815 bIndicesChanged = true;
816 bFacesDirty = true;
817}
818
819
820
821//--------------------------------------------------------------
822template<class V, class N, class C, class T>
824 normals[index] = n;
825 bNormalsChanged = true;
826 bFacesDirty = true;
827}
828
829
830
831//--------------------------------------------------------------
832template<class V, class N, class C, class T>
834 colors[index] = c;
835 bColorsChanged = true;
836 bFacesDirty = true;
837}
838
839
840
841//--------------------------------------------------------------
842template<class V, class N, class C, class T>
844 texCoords[index] = t;
845 bTexCoordsChanged = true;
846 bFacesDirty = true;
847}
848
849
850
851//--------------------------------------------------------------
852template<class V, class N, class C, class T>
854 indices[index] = val;
855 bIndicesChanged = true;
856 bFacesDirty = true;
857}
858
859
860
861//--------------------------------------------------------------
862template<class V, class N, class C, class T>
864 bIndicesChanged = true;
865 bFacesDirty = true;
866 indices.resize(vertices.size());
867 for(ofIndexType i = 0; i < vertices.size();i++){
868 indices[i]=i;
869 }
870}
871
872
873
874
875
876//--------------------------------------------------------------
877template<class V, class N, class C, class T>
879 vertices.clear();
880 bVertsChanged=true;
881}
882
883
884
885//--------------------------------------------------------------
886template<class V, class N, class C, class T>
888 normals.clear();
889 bNormalsChanged=true;
890 bFacesDirty = true;
891}
892
893
894
895//--------------------------------------------------------------
896template<class V, class N, class C, class T>
898 colors.clear();
899 bColorsChanged=true;
900 bFacesDirty = true;
901}
902
903
904
905//--------------------------------------------------------------
906template<class V, class N, class C, class T>
908 texCoords.clear();
909 bTexCoordsChanged=true;
910 bFacesDirty = true;
911}
912
913
914
915//--------------------------------------------------------------
916template<class V, class N, class C, class T>
918 indices.clear();
919 bIndicesChanged = true;
920 bFacesDirty = true;
921}
922
923
924
925//--------------------------------------------------------------
926template<class V, class N, class C, class T>
928 draw(OF_MESH_POINTS);
929}
930
931
932
933//--------------------------------------------------------------
934template<class V, class N, class C, class T>
938
939
940
941//--------------------------------------------------------------
942template<class V, class N, class C, class T>
944 draw(OF_MESH_FILL);
945}
946
947
948
949//--------------------------------------------------------------
950template<class V, class N, class C, class T>
952 draw(OF_MESH_FILL);
953}
954
955
956
957//--------------------------------------------------------------
958template<class V, class N, class C, class T>
960 if(getNumVertices()==0) return;
961 ofGetCurrentRenderer()->draw(*this,renderType,useColors,useTextures,useNormals);
962}
963
964
965
966//--------------------------------------------------------------
967template<class V, class N, class C, class T>
969 useColors = true;
970}
971
972
973
974//--------------------------------------------------------------
975template<class V, class N, class C, class T>
977 useTextures = true;
978}
979
980
981
982//--------------------------------------------------------------
983template<class V, class N, class C, class T>
985 useNormals = true;
986}
987
988
989
990//--------------------------------------------------------------
991template<class V, class N, class C, class T>
993 useIndices = true;
994}
995
996
997
998//--------------------------------------------------------------
999template<class V, class N, class C, class T>
1001 useColors = false;
1002}
1003
1004
1005
1006//--------------------------------------------------------------
1007template<class V, class N, class C, class T>
1009 useTextures = false;
1010}
1011
1012
1013
1014//--------------------------------------------------------------
1015template<class V, class N, class C, class T>
1017 useNormals = false;
1018}
1019
1020
1021
1022//--------------------------------------------------------------
1023template<class V, class N, class C, class T>
1025 useIndices = false;
1026}
1027
1028
1029
1030//--------------------------------------------------------------
1031template<class V, class N, class C, class T>
1033 return useColors;
1034}
1035
1036
1037
1038//--------------------------------------------------------------
1039template<class V, class N, class C, class T>
1041 return useTextures;
1042}
1043
1044
1045
1046//--------------------------------------------------------------
1047template<class V, class N, class C, class T>
1049 return useNormals;
1050}
1051
1052
1053
1054//--------------------------------------------------------------
1055template<class V, class N, class C, class T>
1057 return useIndices;
1058}
1059
1060
1061
1062
1063//--------------------------------------------------------------
1064template<class V, class N, class C, class T>
1066 ofIndexType prevNumVertices = static_cast<ofIndexType>(vertices.size());
1067 if(mesh.getNumVertices()){
1068 vertices.insert(vertices.end(),mesh.getVertices().begin(),mesh.getVertices().end());
1069 }
1070 if(mesh.getNumTexCoords()){
1071 texCoords.insert(texCoords.end(),mesh.getTexCoords().begin(),mesh.getTexCoords().end());
1072 }
1073 if(mesh.getNumColors()){
1074 colors.insert(colors.end(),mesh.getColors().begin(),mesh.getColors().end());
1075 }
1076 if(mesh.getNumNormals()){
1077 normals.insert(normals.end(),mesh.getNormals().begin(),mesh.getNormals().end());
1078 }
1079 if(mesh.getNumIndices()){
1080 for(auto index: mesh.getIndices()){
1081 indices.push_back(index+prevNumVertices);
1082 }
1083 }
1084}
1085
1086
1087
1088
1089//--------------------------------------------------------------
1090template<class V, class N, class C, class T>
1091void ofMesh_<V,N,C,T>::load(const of::filesystem::path& path){
1092 ofFile is = {path, ofFile::ReadOnly};
1093 auto & data = *this;
1094
1095 std::string error;
1096 ofBuffer buffer(is);
1097 auto backup = data;
1098
1099 int orderVertices=-1;
1100 int orderIndices=-1;
1101
1102 ofIndexType vertexCoordsFound=0;
1103 ofIndexType colorCompsFound=0;
1104 ofIndexType texCoordsFound=0;
1105 ofIndexType normalsCoordsFound=0;
1106
1107 ofIndexType currentVertex = 0;
1108 ofIndexType currentFace = 0;
1109
1110 bool colorTypeIsUChar = false;
1111
1112 enum State{
1113 Header,
1114 VertexDef,
1115 FaceDef,
1116 Vertices,
1117 Normals,
1118 Faces
1119 };
1120
1121
1122 enum Attribute {
1123 Position,
1124 Color,
1125 Normal,
1126 TexCoord,
1127 };
1128
1129 std::vector<Attribute> meshDefinition;
1130
1131 data.clear();
1132 State state = Header;
1133
1134 int lineNum = 0;
1135 ofBuffer::Lines lines = buffer.getLines();
1136 ofBuffer::Line line = lines.begin();
1137 lineNum++;
1138 if(*line!="ply"){
1139 error = "wrong format, expecting 'ply'";
1140 goto clean;
1141 }
1142
1143 line++;
1144 lineNum++;
1145 if(*line!="format ascii 1.0"){
1146 error = "wrong format, expecting 'format ascii 1.0'";
1147 goto clean;
1148 }
1149
1150 for(;line != lines.end(); ++line){
1151 lineNum++;
1152 std::string lineStr = *line;
1153 if(lineStr.find("comment")==0 || lineStr.empty()){
1154 continue;
1155 }
1156
1157 if((state==Header || state==FaceDef) && lineStr.find("element vertex")==0){
1158 state = VertexDef;
1159 orderVertices = std::max(orderIndices, 0)+1;
1160 data.getVertices().resize(ofTo<size_t>(lineStr.substr(15)));
1161 continue;
1162 }
1163
1164 if((state==Header || state==VertexDef) && lineStr.find("element face")==0){
1165 state = FaceDef;
1166 orderIndices = std::max(orderVertices, 0)+1;
1167 data.getIndices().resize(ofTo<size_t>(lineStr.substr(13))*3);
1168 continue;
1169 }
1170
1171 if(state==VertexDef && (lineStr.find("property float x")==0 || lineStr.find("property float y")==0 || lineStr.find("property float z")==0
1172 || lineStr.find("property double x")==0 || lineStr.find("property double y")==0 || lineStr.find("property double z")==0)){
1173 meshDefinition.push_back(Position);
1174 vertexCoordsFound++;
1175 continue;
1176 }
1177
1178 if(state==VertexDef && (lineStr.find("property float r")==0 || lineStr.find("property float g")==0 || lineStr.find("property float b")==0 || lineStr.find("property float a")==0)){
1179 colorCompsFound++;
1180 meshDefinition.push_back(Color);
1181 data.getColors().resize(data.getVertices().size());
1182 continue;
1183 }
1184
1185 if(state==VertexDef && (lineStr.find("property uchar red")==0 || lineStr.find("property uchar green")==0 || lineStr.find("property uchar blue")==0 || lineStr.find("property uchar alpha")==0)){
1186 colorTypeIsUChar = true;
1187 colorCompsFound++;
1188 meshDefinition.push_back(Color);
1189 data.getColors().resize(data.getVertices().size());
1190 continue;
1191 }
1192
1193 if(state==VertexDef && (lineStr.find("property float u")==0 || lineStr.find("property float v")==0|| lineStr.find("property float s")==0 || lineStr.find("property float t")==0)){
1194 texCoordsFound++;
1195 meshDefinition.push_back(TexCoord);
1196 data.getTexCoords().resize(data.getVertices().size());
1197 continue;
1198 }
1199
1200 if(state==VertexDef && (lineStr.find("property float nx")==0 || lineStr.find("property float ny")==0 || lineStr.find("property float nz")==0)){
1201 normalsCoordsFound++;
1202 meshDefinition.push_back(Normal);
1203 if (normalsCoordsFound==3) data.getNormals().resize(data.getVertices().size());
1204 continue;
1205 }
1206
1207 if(state==FaceDef && lineStr.find("property list")!=0 && lineStr!="end_header"){
1208 error = "wrong face definition";
1209 goto clean;
1210 }
1211
1212 if(lineStr=="end_header"){
1213 if(data.hasColors() && colorCompsFound!=3 && colorCompsFound!=4){
1214 error = "data has color coordiantes but not correct number of components. Found " + ofToString(colorCompsFound) + " expecting 3 or 4";
1215 goto clean;
1216 }
1217 if(data.hasNormals() && normalsCoordsFound!=3){
1218 error = "data has normal coordiantes but not correct number of components. Found " + ofToString(normalsCoordsFound) + " expecting 3";
1219 goto clean;
1220 }
1221 if(!data.hasVertices()){
1222 ofLogWarning("ofMesh") << "load(): mesh loaded from \"" << path << "\" has no vertices";
1223 }
1224 if(orderVertices==-1) orderVertices=9999;
1225 if(orderIndices==-1) orderIndices=9999;
1226
1227 if(orderVertices < orderIndices){
1228 state = Vertices;
1229 }else {
1230 state = Faces;
1231 }
1232 continue;
1233 }
1234
1235 if(state==Vertices){
1236 if(data.getNumVertices()<=currentVertex){
1237 error = "found more vertices: " + ofToString(currentVertex+1) + " than specified in header: " + ofToString(data.getNumVertices());
1238 goto clean;
1239 }
1240 std::stringstream sline(lineStr);
1241
1242 // read in a line of vertex elements
1243 // and split it into attributes,
1244 // based attribute order specified in file header
1245 ofIndexType vAttr = 0;
1246 ofIndexType nAttr = 0;
1247 ofIndexType tAttr = 0;
1248 ofIndexType cAttr = 0;
1249 for(auto s:meshDefinition){
1250 switch (s) {
1251 case Position:
1252 sline >> *(&data.getVertices()[currentVertex].x + (vAttr++)%vertexCoordsFound);
1253 break;
1254 case Color:
1255 if (colorTypeIsUChar){
1256 int c = 0;
1257 sline >> c;
1258 *(&data.getColors()[currentVertex].r + (cAttr++)%colorCompsFound) = c/255.f;
1259 } else {
1260 sline >> *(&data.getColors()[currentVertex].r + (cAttr++)%colorCompsFound);
1261 }
1262 break;
1263 case Normal:
1264 sline >> *(&data.getNormals()[currentVertex].x + (nAttr++)%normalsCoordsFound);
1265 break;
1266 case TexCoord:
1267 sline >> *(&data.getTexCoords()[currentVertex].x + (tAttr++)%texCoordsFound);
1268 break;
1269 default:
1270 break;
1271 }
1272 }
1273 if (vAttr != vertexCoordsFound || cAttr!= colorCompsFound || nAttr!=normalsCoordsFound || tAttr!=texCoordsFound){
1274 error = "attribute data does not match definition in header";
1275 goto clean;
1276 }
1277
1278 currentVertex++;
1279 if(currentVertex==data.getNumVertices()){
1280 if(orderVertices<orderIndices){
1281 state = Faces;
1282 }else{
1283 state = Vertices;
1284 }
1285 }
1286 continue;
1287 }
1288
1289 if(state==Faces){
1290 if(data.getNumIndices()/3<currentFace){
1291 error = "found more faces than specified in header";
1292 goto clean;
1293 }
1294 std::stringstream sline(lineStr);
1295 int numV;
1296 sline >> numV;
1297 if(numV!=3){
1298 error = "face not a triangle";
1299 goto clean;
1300 }
1301 ofIndexType i;
1302 sline >> i;
1303 data.getIndices()[currentFace*3] = i;
1304 sline >> i;
1305 data.getIndices()[currentFace*3+1] = i;
1306 sline >> i;
1307 data.getIndices()[currentFace*3+2] = i;
1308
1309 currentFace++;
1310 if(currentFace==data.getNumIndices()/3){
1311 if(orderVertices<orderIndices){
1312 state = Vertices;
1313 }else{
1314 state = Faces;
1315 }
1316 }
1317 continue;
1318 }
1319 }
1320
1321
1322 return;
1323 clean:
1324 ofLogError("ofMesh") << "load(): " << lineNum << ":" << error;
1325 ofLogError("ofMesh") << "load(): \"" << *line << "\"";
1326 data = backup;
1327}
1328
1329//--------------------------------------------------------------
1330template<class V, class N, class C, class T>
1331void ofMesh_<V,N,C,T>::save(const of::filesystem::path& path, bool useBinary) const{
1332 ofFile os(path, ofFile::WriteOnly);
1333 const auto & data = *this;
1334
1335 os << "ply" << std::endl;
1336 if(useBinary) {
1337 os << "format binary_little_endian 1.0" << std::endl;
1338 } else {
1339 os << "format ascii 1.0" << std::endl;
1340 }
1341
1342 if(data.getNumVertices()){
1343 os << "element vertex " << data.getNumVertices() << std::endl;
1344 os << "property float x" << std::endl;
1345 os << "property float y" << std::endl;
1346 os << "property float z" << std::endl;
1347 if(data.getNumColors()){
1348 os << "property uchar red" << std::endl;
1349 os << "property uchar green" << std::endl;
1350 os << "property uchar blue" << std::endl;
1351 os << "property uchar alpha" << std::endl;
1352 }
1353 if(data.getNumTexCoords()){
1354 os << "property float u" << std::endl;
1355 os << "property float v" << std::endl;
1356 }
1357 if(data.getNumNormals()){
1358 os << "property float nx" << std::endl;
1359 os << "property float ny" << std::endl;
1360 os << "property float nz" << std::endl;
1361 }
1362 }
1363
1364 uint8_t faceSize = 3;
1365 if(data.getNumIndices()){
1366 os << "element face " << data.getNumIndices() / faceSize << std::endl;
1367 os << "property list uchar int vertex_indices" << std::endl;
1368 } else if(data.getMode() == OF_PRIMITIVE_TRIANGLES) {
1369 os << "element face " << data.getNumVertices() / faceSize << std::endl;
1370 os << "property list uchar int vertex_indices" << std::endl;
1371 } else if(data.getMode() == OF_PRIMITIVE_TRIANGLE_STRIP && data.getNumVertices() >= 4) {
1372 os << "element face " << data.getNumVertices() - 2 << std::endl;
1373 os << "property list uchar int vertex_indices" << std::endl;
1374 }
1375
1376 os << "end_header" << std::endl;
1377
1378 for(std::size_t i = 0; i < data.getNumVertices(); i++){
1379 if(useBinary) {
1380 os.write((char*) &data.getVertices()[i], sizeof(V));
1381 } else {
1382 os << data.getVertex(i).x << " " << data.getVertex(i).y << " " << data.getVertex(i).z;
1383 }
1384 if(data.getNumColors()){
1385 // VCG lib / MeshLab don't support float colors, so we have to cast
1386 ofColor cur = data.getColors()[i];
1387 if(useBinary) {
1388 os.write((char*) &cur, sizeof(ofColor));
1389 } else {
1390 os << " " << (int) cur.r << " " << (int) cur.g << " " << (int) cur.b << " " << (int) cur.a;
1391 }
1392 }
1393 if(data.getNumTexCoords()){
1394 if(useBinary) {
1395 os.write((char*) &data.getTexCoords()[i], sizeof(T));
1396 } else {
1397 os << " " << data.getTexCoord(i).x << " " << data.getTexCoord(i).y;
1398 }
1399 }
1400 if(data.getNumNormals()){
1401 if(useBinary) {
1402 os.write((char*) &data.getNormals()[i], sizeof(V));
1403 } else {
1404 os << " " << data.getNormal(i).x << " " << data.getNormal(i).y << " " << data.getNormal(i).z;
1405 }
1406 }
1407 if(!useBinary) {
1408 os << std::endl;
1409 }
1410 }
1411
1412 if(data.getNumIndices()) {
1413 for(uint32_t i = 0; i < data.getNumIndices(); i += faceSize) {
1414 if(useBinary) {
1415 os.write((char*) &faceSize, sizeof(unsigned char));
1416 os.write((char*)&data.getIndices()[i], faceSize);
1417 } else {
1418 os << (std::size_t) faceSize << " " << data.getIndex(i) << " " << data.getIndex(i+1) << " " << data.getIndex(i+2) << std::endl;
1419 }
1420 }
1421 } else if(data.getMode() == OF_PRIMITIVE_TRIANGLES) {
1422 for(uint32_t i = 0; i < data.getNumVertices(); i += faceSize) {
1423 uint32_t indices[] = {i, i + 1, i + 2};
1424 if(useBinary) {
1425 os.write((char*) &faceSize, sizeof(unsigned char));
1426 os.write((char*) indices, sizeof(indices));
1427 } else {
1428 os << (std::size_t) faceSize << " " << indices[0] << " " << indices[1] << " " << indices[2] << std::endl;
1429 }
1430 }
1431 } else if(data.getMode() == OF_PRIMITIVE_TRIANGLE_STRIP && data.getNumVertices() >= 4) {
1432 for(uint32_t i = 0; i < data.getNumVertices() - 2; i += 2) {
1433 uint32_t indices1[] = {i, i + 1, i + 2};
1434 uint32_t indices2[] = {i + 1, i + 3, i + 2};
1435 if(useBinary) {
1436 os.write((char*) &faceSize, sizeof(unsigned char));
1437 os.write((char*) indices1, sizeof(indices1));
1438 os.write((char*) &faceSize, sizeof(unsigned char));
1439 os.write((char*) indices2, sizeof(indices2));
1440 } else {
1441 os << (std::size_t) faceSize << " " << indices1[0] << " " << indices1[1] << " " << indices1[2] << std::endl;
1442 os << (std::size_t) faceSize << " " << indices2[0] << " " << indices2[1] << " " << indices2[2] << std::endl;
1443 }
1444 }
1445 }
1446
1447 //TODO: add index generation for other OF_PRIMITIVE cases
1448}
1449
1450
1451//--------------------------------------------------------------
1452template<class V, class N, class C, class T>
1453void ofMesh_<V,N,C,T>::setColorForIndices( ofIndexType startIndex, ofIndexType endIndex, C color ) {
1454 if(!hasColors()) {
1455 // no colors for vertices, so we must set them here //
1456 getColors().resize( getNumVertices() );
1457 }
1458
1459 for(ofIndexType i = startIndex; i < endIndex; i++) {
1460 setColor( getIndex(i), color);
1461 }
1462}
1463
1464
1465//--------------------------------------------------------------
1466template<class V, class N, class C, class T>
1468 ofIndexType startVertIndex = 0;
1469 ofIndexType endVertIndex = 0;
1470
1471 if(startIndex >= getNumIndices() ) {
1472 startVertIndex = 0;
1473 } else {
1474 startVertIndex = getIndex( startIndex );
1475 }
1476
1477 if(endIndex >= getNumIndices() ) {
1478 // set to the total, because the vector assign does not include the last element //
1479 endVertIndex = getNumVertices();
1480 } else {
1481 endVertIndex = getIndex( endIndex );
1482 }
1483 return getMeshForIndices(startIndex, endIndex, startVertIndex, endVertIndex );
1484}
1485
1486
1487//--------------------------------------------------------------
1488template<class V, class N, class C, class T>
1490
1491 ofMesh_<V,N,C,T> mesh;
1492 mesh.setMode( getMode() );
1493
1494 mesh.getVertices().assign( getVertices().begin()+startVertIndex, getVertices().begin()+endVertIndex );
1495
1496 if( hasColors() ) {
1497 std::vector<ofFloatColor> colors;
1498 mesh.getColors().assign( getColors().begin()+startVertIndex, getColors().begin()+endVertIndex );
1499 if( usingColors()) mesh.enableColors();
1500 else mesh.disableColors();
1501 }
1502
1503 if( hasTexCoords() ) {
1504 mesh.getTexCoords().assign( getTexCoords().begin()+startVertIndex, getTexCoords().begin()+endVertIndex );
1505 if( usingTextures() ) mesh.enableTextures();
1506 else mesh.disableTextures();
1507 }
1508
1509 if( hasNormals() ) {
1510 mesh.getNormals().assign( getNormals().begin()+startVertIndex, getNormals().begin()+endVertIndex );
1511 if( usingNormals() ) mesh.enableNormals();
1512 else mesh.disableNormals();
1513 }
1514
1515 ofIndexType offsetIndex = getIndex(startIndex);
1516 bool bFoundLessThanZero = false;
1517 for(ofIndexType i = startIndex; i < endIndex; i++) {
1518 ofIndexType index;
1519 if(getIndex(i)<offsetIndex){
1520 index = 0;
1521 bFoundLessThanZero = true;
1522 }else{
1523 index = getIndex(i) - offsetIndex;
1524 }
1525 mesh.addIndex( index );
1526 }
1527
1528 if(bFoundLessThanZero) {
1529 ofLogWarning( "ofMesh :: getMeshForIndices : found some indices less than 0, setting them to 0" );
1530 }
1531
1532 return mesh;
1533}
1534
1535
1536//--------------------------------------------------------------
1537template<class V, class N, class C, class T>
1539
1540 std::vector<V> verts = getVertices();
1541 std::vector<ofIndexType> indices = getIndices();
1542
1543 //get indexes to share single point - TODO: try j < i
1544 for(ofIndexType i = 0; i < indices.size(); i++) {
1545 for(ofIndexType j = 0; j < indices.size(); j++ ) {
1546 if(i==j) continue;
1547
1548 ofIndexType i1 = indices[i];
1549 ofIndexType i2 = indices[j];
1550 const V & v1 = verts[ i1 ];
1551 const V & v2 = verts[ i2 ];
1552
1553 if( v1 == v2 && i1 != i2) {
1554 indices[j] = i1;
1555 break;
1556 }
1557 }
1558 }
1559
1560 //indices array now has list of unique points we need
1561 //but we need to delete the old points we're not using and that means the index values will change
1562 //so we are going to create a new list of points and new indexes - we will use a map to map old index values to the new ones
1563 std::vector <V> newPoints;
1564 std::vector <ofIndexType> newIndexes;
1565 std::unordered_map <ofIndexType, bool> ptCreated;
1566 std::unordered_map <ofIndexType, ofIndexType> oldIndexNewIndex;
1567
1568 std::vector<ofFloatColor> newColors;
1569 std::vector<ofFloatColor>& colors = getColors();
1570 std::vector<T> newTCoords;
1571 std::vector<T>& tcoords = getTexCoords();
1572 std::vector<N> newNormals;
1573 std::vector<N>& normals = getNormals();
1574
1575 for(ofIndexType i = 0; i < indices.size(); i++){
1576 ptCreated[i] = false;
1577 }
1578
1579 for(ofIndexType i = 0; i < indices.size(); i++){
1580 ofIndexType index = indices[i];
1581 const auto & p = verts[ index ];
1582
1583 if( ptCreated[index] == false ){
1584 oldIndexNewIndex[index] = newPoints.size();
1585 newPoints.push_back( p );
1586 if(hasColors()) {
1587 newColors.push_back(colors[index]);
1588 }
1589 if(hasTexCoords()) {
1590 newTCoords.push_back(tcoords[index]);
1591 }
1592 if(hasNormals()) {
1593 newNormals.push_back(normals[index]);
1594 }
1595
1596 ptCreated[index] = true;
1597 }
1598
1599 //ofLogNotice("ofMesh") << "[" << i << "]: old " << index << " --> " << oldIndexNewIndex[index];
1600 newIndexes.push_back( oldIndexNewIndex[index] );
1601 }
1602
1603 verts.clear();
1604 verts = newPoints;
1605
1606 indices.clear();
1607 indices = newIndexes;
1608
1609 clearIndices();
1610 addIndices(indices);
1611 clearVertices();
1612 addVertices( verts );
1613
1614 if(hasColors()) {
1615 clearColors();
1616 addColors( newColors );
1617 }
1618
1619 if(hasTexCoords()) {
1620 clearTexCoords();
1621 addTexCoords( newTCoords );
1622 }
1623
1624 if(hasNormals()) {
1625 clearNormals();
1626 addNormals( newNormals );
1627 }
1628
1629}
1630
1631
1632//--------------------------------------------------------------
1633template<class V, class N, class C, class T>
1635 const std::vector<ofMeshFace_<V,N,C,T>> & faces = getUniqueFaces();
1636 if(faces.size()>faceId){
1637 return faces[faceId];
1638 }else{
1639 ofLogError() << "couldn't find face " << faceId;
1640 return ofMeshFace_<V,N,C,T>();
1641 }
1642}
1643
1644
1645//--------------------------------------------------------------
1646template<class V, class N, class C, class T>
1647const std::vector<ofMeshFace_<V,N,C,T>> & ofMesh_<V,N,C,T>::getUniqueFaces() const{
1648 if(bFacesDirty){
1649 // if we are doing triangles, we have to use a vert and normal for each triangle
1650 // that way we can calculate face normals and use getFaceNormal();
1651 faces.resize( indices.size()/3 );
1652
1653 int index = 0;
1654 int triindex = 0;
1655
1656 bool bHasColors = hasColors();
1657 bool bHasNormals = hasNormals();
1658 bool bHasTexcoords = hasTexCoords();
1659
1660 if( getMode() == OF_PRIMITIVE_TRIANGLES) {
1661 for(std::size_t j = 0; j < indices.size(); j += 3) {
1662 ofMeshFace_<V,N,C,T> & tri = faces[triindex];
1663 for(std::size_t k = 0; k < 3; k++) {
1664 index = indices[j+k];
1665 tri.setVertex( k, vertices[index] );
1666 if(bHasNormals)
1667 tri.setNormal(k, normals[index] );
1668 if(bHasTexcoords)
1669 tri.setTexCoord(k, texCoords[index] );
1670 if(bHasColors)
1671 tri.setColor(k, colors[index] );
1672 }
1673 triindex++;
1674 }
1675
1676 } else {
1677 ofLogWarning("ofMesh") << "getUniqueFaces(): only works with primitive mode OF_PRIMITIVE_TRIANGLES";
1678 }
1679
1680 bFacesDirty = false;
1681 }
1682
1683 return faces;
1684
1685}
1686
1687
1688//--------------------------------------------------------------
1689template<class V, class N, class C, class T>
1690std::vector<N> ofMesh_<V,N,C,T>::getFaceNormals( bool perVertex ) const{
1691 // default for ofPrimitiveBase is vertex normals //
1692 std::vector<N> faceNormals;
1693
1694 if( hasVertices() ) {
1695 if(vertices.size() > 3 && indices.size() > 3) {
1696 if(perVertex){
1697 faceNormals.resize(indices.size()*3);
1698 }else{
1699 faceNormals.resize(indices.size());
1700 }
1702 N n;
1703 for(ofIndexType i = 0; i < indices.size(); i+=3) {
1704 face.setVertex( 0, vertices[indices[i+0]] );
1705 face.setVertex( 1, vertices[indices[i+1]] );
1706 face.setVertex( 2, vertices[indices[i+2]] );
1707
1708 n = face.getFaceNormal();
1709
1710 faceNormals[i]=n;
1711 if(perVertex) {
1712 faceNormals[i+1]=n;
1713 faceNormals[i+2]=n;
1714 }
1715 }
1716 }
1717 }
1718
1719 return faceNormals;
1720}
1721
1722
1723//--------------------------------------------------------------
1724template<class V, class N, class C, class T>
1725void ofMesh_<V,N,C,T>::setFromTriangles( const std::vector<ofMeshFace_<V,N,C,T>>& tris, bool bUseFaceNormal ) {
1726 if(tris.empty()) {
1727 ofLogWarning("ofMesh") << "setFromTriangles(): ignoring empty tris vector";
1728 return;
1729 }
1730
1731 typename std::vector<ofMeshFace_<V,N,C,T>>::const_iterator it;
1732
1733 vertices.resize(tris.size()*3 );
1734 it = tris.begin();
1735 // if the first tri has data, assume the rest do as well //
1736 if(it->hasNormals()){
1737 normals.resize(tris.size()*3);
1738 }else{
1739 normals.clear();
1740 }
1741 if(it->hasColors()){
1742 colors.resize(tris.size()*3);
1743 }else{
1744 colors.clear();
1745 }
1746 if(it->hasTexcoords()){
1747 texCoords.resize(tris.size()*3);
1748 }else{
1749 texCoords.clear();
1750 }
1751
1752 int i = 0;
1753 for(it = tris.begin(); it != tris.end(); it++) {
1754 for(std::size_t k = 0; k < 3; k++) {
1755 vertices[i] = it->getVertex(k);
1756 if(it->hasTexcoords())
1757 texCoords[i] = it->getTexCoord(k);
1758 if(it->hasColors())
1759 colors[i] = it->getColor(k);
1760 if(bUseFaceNormal)
1761 normals[i] = it->getFaceNormal();
1762 else if(it->hasNormals())
1763 normals[i] = it->getNormal(k);
1764 i++;
1765 }
1766 }
1767
1768 setupIndicesAuto();
1769 bVertsChanged = true;
1770 bIndicesChanged = true;
1771 bNormalsChanged = true;
1772 bColorsChanged = true;
1773 bTexCoordsChanged = true;
1774
1775 bFacesDirty = false;
1776 faces = tris;
1777}
1778
1779
1780//--------------------------------------------------------------
1781template<class V, class N, class C, class T>
1783
1784 if( getMode() == OF_PRIMITIVE_TRIANGLES) {
1785 std::vector<ofMeshFace_<V,N,C,T>> triangles = getUniqueFaces();
1786 std::vector<V> verts;
1787 for(ofIndexType i = 0; i < triangles.size(); i++) {
1788 for(ofIndexType j = 0; j < 3; j++) {
1789 verts.push_back( triangles[i].getVertex(j) );
1790 }
1791 }
1792
1793 std::unordered_map<int, int> removeIds;
1794
1795 float epsilon = .01f;
1796 for(ofIndexType i = 0; i < verts.size()-1; i++) {
1797 for(ofIndexType j = i+1; j < verts.size(); j++) {
1798 if(i != j) {
1799 const auto& v1 = toGlm(verts[i]);
1800 const auto& v2 = toGlm(verts[j]);
1801 if( glm::distance(v1, v2) <= epsilon ) {
1802 // average the location //
1803 verts[i] = (v1+v2)/2.f;
1804 verts[j] = verts[i];
1805 removeIds[j] = 1;
1806 }
1807 }
1808 }
1809 }
1810
1811 // string of vertex in 3d space to triangle index //
1812 std::unordered_map<std::string, std::vector<int> > vertHash;
1813
1814 //ofLogNotice("ofMesh") << "smoothNormals(): num verts = " << verts.size() << " tris size = " << triangles.size();
1815
1816 std::string xStr, yStr, zStr;
1817
1818 for(ofIndexType i = 0; i < verts.size(); i++ ) {
1819 xStr = "x"+ofToString(verts[i].x==-0?0:verts[i].x);
1820 yStr = "y"+ofToString(verts[i].y==-0?0:verts[i].y);
1821 zStr = "z"+ofToString(verts[i].z==-0?0:verts[i].z);
1822 std::string vstring = xStr+yStr+zStr;
1823 if(vertHash.find(vstring) == vertHash.end()) {
1824 for(ofIndexType j = 0; j < triangles.size(); j++) {
1825 for(ofIndexType k = 0; k < 3; k++) {
1826 if(verts[i].x == triangles[j].getVertex(k).x) {
1827 if(verts[i].y == triangles[j].getVertex(k).y) {
1828 if(verts[i].z == triangles[j].getVertex(k).z) {
1829 vertHash[vstring].push_back( j );
1830 }
1831 }
1832 }
1833 }
1834 }
1835 }
1836 }
1837
1838// for( std::unordered_map<std::string, std::vector<int> >::iterator it = vertHash.begin(); it != vertHash.end(); ++it) {
1839// //for( std::unordered_map<std::string, int >::iterator it = vertHash.begin(); it != vertHash.end(); ++it) {
1840// ofLogNotice("ofMesh") << "smoothNormals(): " << it->first << " num = " << it->second.size();
1841// }
1842
1843 V vert;
1844 N normal;
1845 float angleCos = cos(ofDegToRad(angle));
1846 float numNormals=0;
1847
1848 for(ofIndexType j = 0; j < triangles.size(); j++) {
1849 for(ofIndexType k = 0; k < 3; k++) {
1850 vert = triangles[j].getVertex(k);
1851 xStr = "x"+ofToString(vert.x==-0?0:vert.x);
1852 yStr = "y"+ofToString(vert.y==-0?0:vert.y);
1853 zStr = "z"+ofToString(vert.z==-0?0:vert.z);
1854
1855 std::string vstring = xStr+yStr+zStr;
1856 numNormals=0;
1857 normal = {0.f,0.f,0.f};
1858 if(vertHash.find(vstring) != vertHash.end()) {
1859 for(ofIndexType i = 0; i < vertHash[vstring].size(); i++) {
1860 auto f1 = triangles[j].getFaceNormal();
1861 auto f2 = triangles[vertHash[vstring][i]].getFaceNormal();
1862 if(glm::dot(toGlm(f1), toGlm(f2)) >= angleCos ) {
1863 normal += f2;
1864 numNormals+=1.f;
1865 }
1866 }
1867 //normal /= (float)vertHash[vstring].size();
1868 normal /= numNormals;
1869
1870 triangles[j].setNormal(k, normal);
1871 }
1872 }
1873 }
1874
1875 //ofLogNotice("ofMesh") << "smoothNormals(): setting from triangles ";
1876 setFromTriangles( triangles );
1877
1878 }
1879}
1880
1881//--------------------------------------------------------------
1882template<class V, class N, class C, class T>
1884 if( getMode() == OF_PRIMITIVE_TRIANGLES) {
1885
1886 // get copy original mesh data
1887 auto indices = getIndices();
1888 auto verts = getVertices();
1889 auto texCoords = getTexCoords();
1890 auto colors = getColors();
1891
1892 // remove all data to start from scratch
1893 clear();
1894
1895 // add mesh data back, duplicating vertices and recalculating normals
1896 N normal;
1897 for(ofIndexType i = 0; i < indices.size(); i++) {
1898 ofIndexType indexCurr = indices[i];
1899
1900 if(i % 3 == 0) {
1901 ofIndexType indexNext1 = indices[i + 1];
1902 ofIndexType indexNext2 = indices[i + 2];
1903 auto e1 = verts[indexCurr] - verts[indexNext1];
1904 auto e2 = verts[indexNext2] - verts[indexNext1];
1905 normal = glm::normalize(glm::cross(e1, e2));
1906 }
1907
1908 addIndex(i);
1909 addNormal(normal);
1910
1911 if(indexCurr < texCoords.size()) {
1912 addTexCoord(texCoords[indexCurr]);
1913 }
1914
1915 if(indexCurr < verts.size()) {
1916 addVertex(verts[indexCurr]);
1917 }
1918
1919 if(indexCurr < colors.size()) {
1920 addColor(colors[indexCurr]);
1921 }
1922 }
1923 }
1924}
1925
1926// PLANE MESH //
1927
1928
1929//--------------------------------------------------------------
1930template<class V, class N, class C, class T>
1931ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::plane(float width, float height, int columns, int rows, ofPrimitiveMode mode ) {
1932 ofMesh_<V,N,C,T> mesh;
1933
1935 ofLogWarning("ofMesh") << "ofGetPlaneMesh(): primtive mode " << mode << " not supported, setting to OF_PRIMITIVE_TRIANGLES";
1937 }
1938
1939 mesh.setMode(mode);
1940
1941 V vert;
1942 N normal(0, 0, 1); // always facing forward //
1943 T texcoord;
1944
1945 // the origin of the plane is at the center //
1946 float halfW = width * 0.5f;
1947 float halfH = height * 0.5f;
1948
1949 // add the vertexes //
1950 for(int iy = 0; iy != rows; iy++) {
1951 for(int ix = 0; ix != columns; ix++) {
1952
1953 // normalized tex coords //
1954 texcoord.x = ((float)ix/((float)columns-1));
1955 texcoord.y = 1.f - ((float)iy/((float)rows-1));
1956
1957 vert.x = texcoord.x * width - halfW;
1958 vert.y = -(texcoord.y-1) * height - halfH;
1959
1960 mesh.addVertex(vert);
1961 mesh.addTexCoord(texcoord);
1962 mesh.addNormal(normal);
1963 }
1964 }
1965 if(mode == OF_PRIMITIVE_TRIANGLE_STRIP) {
1966 for(int y = 0; y < rows-1; y++) {
1967 // even rows //
1968 if((y&1)==0) {
1969 for(int x = 0; x < columns; x++) {
1970 mesh.addIndex( (y) * columns + x );
1971 mesh.addIndex( (y+1) * columns + x);
1972 }
1973 } else {
1974 for(int x = columns-1; x >0; x--) {
1975 mesh.addIndex( (y+1) * columns + x );
1976 mesh.addIndex( y * columns + x-1 );
1977 }
1978 }
1979 }
1980
1981 if(rows%2!=0) mesh.addIndex(mesh.getNumVertices()-columns);
1982 } else {
1983 // Triangles //
1984 for(int y = 0; y < rows-1; y++) {
1985 for(int x = 0; x < columns-1; x++) {
1986 // first triangle //
1987 mesh.addIndex((y)*columns + x);
1988 mesh.addIndex((y)*columns + x+1);
1989 mesh.addIndex((y+1)*columns + x);
1990
1991 // second triangle //
1992 mesh.addIndex((y)*columns + x+1);
1993 mesh.addIndex((y+1)*columns + x+1);
1994 mesh.addIndex((y+1)*columns + x);
1995 }
1996 }
1997 }
1998
1999 return mesh;
2000}
2001
2002
2003
2004//--------------------------------------------------------------
2005template<class V, class N, class C, class T>
2007
2008 ofMesh_<V,N,C,T> mesh;
2009
2010 float doubleRes = res*2.f;
2011 float polarInc = glm::pi<float>()/(res); // ringAngle
2012 float azimInc = glm::two_pi<float>()/(doubleRes); // segAngle //
2013
2016 }
2017 mesh.setMode(mode);
2018
2019 V vert;
2020 T tcoord;
2021
2022 for(float i = 0; i < res+1; i++) {
2023
2024 float tr = sin( glm::pi<float>()-i * polarInc );
2025 float ny = cos( glm::pi<float>()-i * polarInc );
2026
2027 tcoord.y = 1.f - (i / res);
2028
2029 for(float j = 0; j <= doubleRes; j++) {
2030
2031 float nx = tr * sin(j * azimInc);
2032 float nz = tr * cos(j * azimInc);
2033
2034 tcoord.x = j / (doubleRes);
2035
2036 vert = {nx, ny, nz};
2037 mesh.addNormal(vert);
2038 vert *= radius;
2039 mesh.addVertex(vert);
2040 mesh.addTexCoord(tcoord);
2041 }
2042 }
2043
2044 int nr = doubleRes+1;
2045 if(mode == OF_PRIMITIVE_TRIANGLES) {
2046
2047 ofIndexType index1, index2, index3;
2048
2049 for(float iy = 0; iy < res; iy++) {
2050 for(float ix = 0; ix < doubleRes; ix++) {
2051
2052 // first tri //
2053 if(iy > 0) {
2054 index1 = (iy+0) * (nr) + (ix+0);
2055 index2 = (iy+0) * (nr) + (ix+1);
2056 index3 = (iy+1) * (nr) + (ix+0);
2057
2058 mesh.addIndex(index1);
2059 mesh.addIndex(index3);
2060 mesh.addIndex(index2);
2061 }
2062
2063 if(iy < res-1 ) {
2064 // second tri //
2065 index1 = (iy+0) * (nr) + (ix+1);
2066 index2 = (iy+1) * (nr) + (ix+1);
2067 index3 = (iy+1) * (nr) + (ix+0);
2068
2069 mesh.addIndex(index1);
2070 mesh.addIndex(index3);
2071 mesh.addIndex(index2);
2072
2073 }
2074 }
2075 }
2076
2077 } else {
2078 for(int y = 0; y < res; y++) {
2079 for(int x = 0; x <= doubleRes; x++) {
2080 mesh.addIndex( (y)*nr + x );
2081 mesh.addIndex( (y+1)*nr + x );
2082 }
2083 }
2084 }
2085
2086
2087 return mesh;
2088}
2089
2090/*
2091 -----------------------------------------------------------------------------
2092 This source file is part of ogre-procedural
2093
2094 For the latest info, see http://code.google.com/p/ogre-procedural/
2095
2096 Copyright (c) 2010 Michael Broutin
2097
2098 Permission is hereby granted, free of charge, to any person obtaining a copy
2099 of this software and associated documentation files (the "Software"), to deal
2100 in the Software without restriction, including without limitation the rights
2101 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2102 copies of the Software, and to permit persons to whom the Software is
2103 furnished to do so, subject to the following conditions:
2104
2105 The above copyright notice and this permission notice shall be included in
2106 all copies or substantial portions of the Software.
2107
2108 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2109 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2110 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2111 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2112 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2113 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2114 THE SOFTWARE.
2115 -----------------------------------------------------------------------------
2116 */
2117// http://code.google.com/p/ogre-procedural/source/browse/library/src/ProceduralIcoSphereGenerator.cpp
2118
2119
2120//--------------------------------------------------------------
2121template<class V, class N, class C, class T>
2123 auto mesh = icosphere(radius, 0);
2124 mesh.flatNormals();
2125 return mesh;
2126}
2127
2128// based on code by Michael Broutin for the ogre-procedural library //
2129// http://code.google.com/p/ogre-procedural/source/browse/library/src/ProceduralIcoSphereGenerator.cpp
2130// For the latest info, see http://code.google.com/p/ogre-procedural/ //
2131
2132//--------------------------------------------------------------
2133template<class V, class N, class C, class T>
2134ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::icosphere(float radius, std::size_t iterations) {
2135 ofMesh_<V,N,C,T> sphere;
2136
2138 const float sqrt5 = sqrt(5.0f);
2139 const float phi = (1.0f + sqrt5) * 0.5f;
2140 const float invnorm = 1/sqrt(phi*phi+1);
2141
2142 sphere.addVertex(invnorm * V(-1, phi, 0));//0
2143 sphere.addVertex(invnorm * V( 1, phi, 0));//1
2144 sphere.addVertex(invnorm * V(0, 1, -phi));//2
2145 sphere.addVertex(invnorm * V(0, 1, phi));//3
2146 sphere.addVertex(invnorm * V(-phi,0, -1));//4
2147 sphere.addVertex(invnorm * V(-phi,0, 1));//5
2148 sphere.addVertex(invnorm * V( phi,0, -1));//6
2149 sphere.addVertex(invnorm * V( phi,0, 1));//7
2150 sphere.addVertex(invnorm * V(0, -1, -phi));//8
2151 sphere.addVertex(invnorm * V(0, -1, phi));//9
2152 sphere.addVertex(invnorm * V(-1, -phi,0));//10
2153 sphere.addVertex(invnorm * V( 1, -phi,0));//11
2154
2155 ofIndexType firstFaces[] = {
2156 0,1,2,
2157 0,3,1,
2158 0,4,5,
2159 1,7,6,
2160 1,6,2,
2161 1,3,7,
2162 0,2,4,
2163 0,5,3,
2164 2,6,8,
2165 2,8,4,
2166 3,5,9,
2167 3,9,7,
2168 11,6,7,
2169 10,5,4,
2170 10,4,8,
2171 10,9,5,
2172 11,8,6,
2173 11,7,9,
2174 10,8,11,
2175 10,11,9
2176 };
2177
2178 for(ofIndexType i = 0; i < 60; i+=3) {
2179 sphere.addTriangle(firstFaces[i], firstFaces[i+1], firstFaces[i+2]);
2180 }
2181
2182 auto& vertices = sphere.getVertices();
2183 auto& faces = sphere.getIndices();
2184
2185 ofIndexType size = faces.size();
2186
2188 for (ofIndexType iteration = 0; iteration < iterations; iteration++)
2189 {
2190 size*=4;
2191 std::vector<ofIndexType> newFaces;
2192 for (ofIndexType i=0; i<size/12; i++)
2193 {
2194 auto i1 = faces[i*3];
2195 auto i2 = faces[i*3+1];
2196 auto i3 = faces[i*3+2];
2197 auto i12 = vertices.size();
2198 auto i23 = i12+1;
2199 auto i13 = i12+2;
2200 auto v1 = vertices[i1];
2201 auto v2 = vertices[i2];
2202 auto v3 = vertices[i3];
2203 //make 1 vertice at the center of each edge and project it onto the sphere
2204 vertices.push_back(glm::normalize(toGlm(v1+v2)));
2205 vertices.push_back(glm::normalize(toGlm(v2+v3)));
2206 vertices.push_back(glm::normalize(toGlm(v1+v3)));
2207 //now recreate indices
2208 newFaces.push_back(i1);
2209 newFaces.push_back(i12);
2210 newFaces.push_back(i13);
2211 newFaces.push_back(i2);
2212 newFaces.push_back(i23);
2213 newFaces.push_back(i12);
2214 newFaces.push_back(i3);
2215 newFaces.push_back(i13);
2216 newFaces.push_back(i23);
2217 newFaces.push_back(i12);
2218 newFaces.push_back(i23);
2219 newFaces.push_back(i13);
2220 }
2221 faces.swap(newFaces);
2222 }
2223
2225 std::vector<T> texCoords;
2226 for (ofIndexType i=0;i<vertices.size();i++)
2227 {
2228 const auto& vec = vertices[i];
2229 float u, v;
2230 float r0 = sqrtf(vec.x*vec.x+vec.z*vec.z);
2231 float alpha;
2232 alpha = atan2f(vec.z,vec.x);
2233 u = alpha/glm::two_pi<float>()+.5f;
2234 v = atan2f(vec.y, r0)/glm::pi<float>() + .5f;
2235 // reverse the u coord, so the default is texture mapped left to
2236 // right on the outside of a sphere
2237 // reverse the v coord, so that texture origin is at top left
2238 texCoords.push_back(T(1.0-u,1.f-v));
2239 }
2240
2242 // find vertices to split
2243 std::vector<ofIndexType> indexToSplit;
2244
2245 for (ofIndexType i=0;i<faces.size()/3;i++)
2246 {
2247 T& t0 = texCoords[faces[i*3+0]];
2248 T& t1 = texCoords[faces[i*3+1]];
2249 T& t2 = texCoords[faces[i*3+2]];
2250
2251 if (std::abs(t2.x-t0.x)>0.5)
2252 {
2253 if (t0.x<0.5)
2254 indexToSplit.push_back(faces[i*3]);
2255 else
2256 indexToSplit.push_back(faces[i*3+2]);
2257 }
2258 if (std::abs(t1.x-t0.x)>0.5)
2259 {
2260 if (t0.x<0.5)
2261 indexToSplit.push_back(faces[i*3]);
2262 else
2263 indexToSplit.push_back(faces[i*3+1]);
2264 }
2265 if (std::abs(t2.x-t1.x)>0.5)
2266 {
2267 if (t1.x<0.5)
2268 indexToSplit.push_back(faces[i*3+1]);
2269 else
2270 indexToSplit.push_back(faces[i*3+2]);
2271 }
2272 }
2273
2274 //split vertices
2275 for (ofIndexType i=0;i<indexToSplit.size();i++)
2276 {
2277 ofIndexType index = indexToSplit[i];
2278 //duplicate vertex
2279 V v = vertices[index];
2280 T t = texCoords[index] + T(1.f, 0.f);
2281 vertices.push_back(v);
2282 texCoords.push_back(t);
2283 ofIndexType newIndex = vertices.size()-1;
2284 //reassign indices
2285 for (ofIndexType j=0;j<faces.size();j++)
2286 {
2287 if (faces[j]==index)
2288 {
2289 ofIndexType index1 = faces[(j+1)%3+(j/3)*3];
2290 ofIndexType index2 = faces[(j+2)%3+(j/3)*3];
2291 if ((texCoords[index1].x>0.5) || (texCoords[index2].x>0.5))
2292 {
2293 faces[j] = newIndex;
2294 }
2295 }
2296 }
2297 }
2298
2299 // tig: flip face(=triangle) winding order, so that we are consistent with all other ofPrimitives.
2300 // i wish there was a more elegant way to do this, but anything happening before "split vertices"
2301 // makes things very, very complicated.
2302
2303 for (ofIndexType i = 0; i < faces.size(); i+=3) {
2304 std::swap(faces[i+1], faces[i+2]);
2305 }
2306
2307 sphere.addNormals( vertices );
2308 sphere.addTexCoords( texCoords );
2309
2310 for(ofIndexType i = 0; i < vertices.size(); i++ ) {
2311 vertices[i] *= radius;
2312 }
2313
2314 return sphere;
2315}
2316/*
2317 -----------------------------------------------------------------------------
2318 // END OGRE
2319 -----------------------------------------------------------------------------
2320 */
2321
2322
2323
2324// Cylinder Mesh
2325
2326//--------------------------------------------------------------
2327template<class V, class N, class C, class T>
2328ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::cylinder( float radius, float height, int radiusSegments, int heightSegments, int numCapSegments, bool bCapped, ofPrimitiveMode mode ) {
2329 ofMesh_<V,N,C,T> mesh;
2332 }
2333 mesh.setMode(mode);
2334
2335 radiusSegments = radiusSegments+1;
2336 int capSegs = numCapSegments;
2337 capSegs = capSegs+1;
2338 heightSegments = heightSegments+1;
2339 if(heightSegments < 2) heightSegments = 2;
2340 if( capSegs < 2 ) bCapped = false;
2341 if(!bCapped) capSegs=1;
2342
2343 float angleIncRadius = -1 * (glm::two_pi<float>()/((float)radiusSegments-1.f));
2344 float heightInc = height/((float)heightSegments-1.f);
2345 float halfH = height*.5f;
2346
2347 float newRad;
2348 V vert;
2349 T tcoord;
2350 N normal;
2351 glm::vec3 up(0,1,0);
2352
2353 std::size_t vertOffset = 0;
2354
2355 float maxTexY = heightSegments-1.f;
2356 if(capSegs > 0) {
2357 maxTexY += (capSegs*2)-2.f;
2358 }
2359 float maxTexYNormalized = (capSegs-1.f) / maxTexY;
2360
2361 // add the top cap //
2362 if(bCapped && capSegs > 0) {
2363 normal = {0.f, -1.f, 0.f};
2364 for(int iy = 0; iy < capSegs; iy++) {
2365 for(int ix = 0; ix < radiusSegments; ix++) {
2366 newRad = ofMap((float)iy, 0, capSegs-1, 0.0, radius);
2367 vert.x = cos((float)ix*angleIncRadius) * newRad;
2368 vert.z = sin((float)ix*angleIncRadius) * newRad;
2369 vert.y = -halfH;
2370
2371 tcoord.x = (float)ix/((float)radiusSegments-1.f);
2372 tcoord.y = 1.f - ofMap(iy, 0, capSegs-1, 0, maxTexYNormalized);
2373
2374 mesh.addTexCoord( tcoord );
2375 mesh.addVertex( vert );
2376 mesh.addNormal( normal );
2377 }
2378 }
2379
2380 if(mode == OF_PRIMITIVE_TRIANGLES) {
2381 for(int y = 0; y < capSegs-1; y++) {
2382 for(int x = 0; x < radiusSegments-1; x++) {
2383 if(y > 0) {
2384 // first triangle //
2385 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2386 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset);
2387 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2388 }
2389
2390 // second triangle //
2391 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset);
2392 mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset);
2393 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2394 }
2395 }
2396 } else {
2397 for(int y = 0; y < capSegs-1; y++) {
2398 for(int x = 0; x < radiusSegments; x++) {
2399 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2400 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2401 }
2402 }
2403 }
2404
2405 vertOffset = mesh.getNumVertices();
2406
2407 }
2408
2409 //maxTexY = heightSegments-1.f + capSegs-1.f;
2410 float minTexYNormalized = 0;
2411 if(bCapped) minTexYNormalized = maxTexYNormalized;
2412 maxTexYNormalized = 1.f;
2413 if(bCapped) maxTexYNormalized = (heightSegments) / maxTexY;
2414
2415 // cylinder vertices //
2416 for(int iy = 0; iy < heightSegments; iy++) {
2417 normal = {1.f, 0.f, 0.f};
2418 for(int ix = 0; ix < radiusSegments; ix++) {
2419
2420 //newRad = ofMap((float)iy, 0, heightSegments-1, 0.0, radius);
2421 vert.x = cos(ix*angleIncRadius) * radius;
2422 vert.y = heightInc*float(iy) - halfH;
2423 vert.z = sin(ix*angleIncRadius) * radius;
2424
2425 tcoord.x = float(ix)/(float(radiusSegments)-1.f);
2426 tcoord.y = 1.f - ofMap(iy, 0, heightSegments-1, minTexYNormalized, maxTexYNormalized );
2427
2428 mesh.addTexCoord( tcoord );
2429 mesh.addVertex( vert );
2430 mesh.addNormal( normal );
2431
2432 normal = glm::rotate(toGlm(normal), -angleIncRadius, up);
2433
2434 }
2435 }
2436
2437 if(mode == OF_PRIMITIVE_TRIANGLES) {
2438 for(int y = 0; y < heightSegments-1; y++) {
2439 for(int x = 0; x < radiusSegments-1; x++) {
2440 // first triangle //
2441 mesh.addIndex( (y)*radiusSegments + x + vertOffset);
2442 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset );
2443 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset );
2444
2445 // second triangle //
2446 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset );
2447 mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset );
2448 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset );
2449 }
2450 }
2451 } else {
2452 for(int y = 0; y < heightSegments-1; y++) {
2453 for(int x = 0; x < radiusSegments; x++) {
2454 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2455 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset );
2456 }
2457 }
2458 }
2459
2460 vertOffset = mesh.getNumVertices();
2461
2462 // add the bottom cap
2463 if(bCapped && capSegs > 0) {
2464 minTexYNormalized = maxTexYNormalized;
2465 maxTexYNormalized = 1.f;
2466
2467 normal = {0.f, 1.f, 0.f};
2468 for(int iy = 0; iy < capSegs; iy++) {
2469 for(int ix = 0; ix < radiusSegments; ix++) {
2470 newRad = ofMap((float)iy, 0, capSegs-1, radius, 0.0);
2471 vert.x = cos((float)ix*angleIncRadius) * newRad;
2472 vert.z = sin((float)ix*angleIncRadius) * newRad;
2473 vert.y = halfH;
2474
2475 tcoord.x = (float)ix/((float)radiusSegments-1.f);
2476 tcoord.y = 1.f - ofMap(iy, 0, capSegs-1, minTexYNormalized, maxTexYNormalized);
2477
2478 mesh.addTexCoord( tcoord );
2479 mesh.addVertex( vert );
2480 mesh.addNormal( normal );
2481 }
2482 }
2483
2484 if(mode == OF_PRIMITIVE_TRIANGLES) {
2485 for(int y = 0; y < capSegs-1; y++) {
2486 for(int x = 0; x < radiusSegments-1; x++) {
2487 // first triangle //
2488 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2489 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset);
2490 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2491
2492 if(y < capSegs -1 && capSegs > 2) {
2493 // second triangle //
2494 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset);
2495 mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset);
2496 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2497 }
2498 }
2499 }
2500 } else {
2501 for(int y = 0; y < capSegs-1; y++) {
2502 for(int x = 0; x < radiusSegments; x++) {
2503 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2504 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2505 }
2506 }
2507 }
2508
2509 vertOffset = mesh.getNumVertices();
2510
2511 }
2512
2513 return mesh;
2514}
2515
2516// Cone Mesh //
2517
2518
2519//--------------------------------------------------------------
2520template<class V, class N, class C, class T>
2521ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::cone( float radius, float height, int radiusSegments, int heightSegments, int capSegments, ofPrimitiveMode mode ) {
2522 ofMesh_<V,N,C,T> mesh;
2525 }
2526 mesh.setMode(mode);
2527
2528 radiusSegments = radiusSegments+1;
2529 capSegments = capSegments+1;
2530 heightSegments = heightSegments+1;
2531 if(heightSegments < 2) heightSegments = 2;
2532 int capSegs = capSegments;
2533 if( capSegs < 2 ) {
2534 capSegs = 0;
2535 }
2536
2537
2538 float angleIncRadius = -1.f * ((glm::two_pi<float>()/((float)radiusSegments-1.f)));
2539 float heightInc = height/((float)heightSegments-1);
2540 float halfH = height*.5f;
2541
2542 float newRad;
2543 V vert;
2544 N normal;
2545 T tcoord;
2546 glm::vec3 up(0,1,0);
2547
2548 std::size_t vertOffset = 0;
2549
2550 float maxTexY = heightSegments-1.f;
2551 if(capSegs > 0) {
2552 maxTexY += capSegs-1.f;
2553 }
2554
2555 V startVec(0, -halfH-1.f, 0);
2556
2557 // cone vertices //
2558 for(int iy = 0; iy < heightSegments; iy++) {
2559 for(int ix = 0; ix < radiusSegments; ix++) {
2560
2561 newRad = ofMap((float)iy, 0, heightSegments-1, 0.0, radius);
2562 vert.x = cos((float)ix*angleIncRadius) * newRad;
2563 vert.y = heightInc*((float)iy) - halfH;
2564 vert.z = sin((float)ix*angleIncRadius) * newRad;
2565
2566 tcoord.x = (float)ix/((float)radiusSegments-1.f);
2567 tcoord.y = 1.f - (float)iy/((float)maxTexY);
2568
2569 mesh.addTexCoord( tcoord );
2570 mesh.addVertex( vert );
2571
2572 if(iy == 0) {
2573 newRad = 1.f;
2574 vert.x = cos((float)ix*angleIncRadius) * newRad;
2575 vert.y = heightInc*((float)iy) - halfH;
2576 vert.z = sin((float)ix*angleIncRadius) * newRad;
2577 }
2578
2579 auto diff = toGlm(vert - startVec);
2580 auto crossed = glm::cross(up, toGlm(vert));
2581 normal = glm::cross(crossed, diff);
2582 mesh.addNormal( glm::normalize(toGlm(normal)) );
2583
2584 }
2585 }
2586
2587 if(mode == OF_PRIMITIVE_TRIANGLES) {
2588 for(int y = 0; y < heightSegments-1; y++) {
2589 for(int x = 0; x < radiusSegments-1; x++) {
2590 if(y > 0){
2591 // first triangle //
2592 mesh.addIndex( (y)*radiusSegments + x );
2593 mesh.addIndex( (y)*radiusSegments + x+1 );
2594 mesh.addIndex( (y+1)*radiusSegments + x );
2595 }
2596
2597 // second triangle //
2598 mesh.addIndex( (y)*radiusSegments + x+1 );
2599 mesh.addIndex( (y+1)*radiusSegments + x+1 );
2600 mesh.addIndex( (y+1)*radiusSegments + x );
2601 }
2602 }
2603 } else {
2604 for(int y = 0; y < heightSegments-1; y++) {
2605 for(int x = 0; x < radiusSegments; x++) {
2606 mesh.addIndex( (y)*radiusSegments + x );
2607 mesh.addIndex( (y+1)*radiusSegments + x );
2608 }
2609 }
2610 }
2611
2612 vertOffset = mesh.getNumVertices();
2613 float maxTexYNormalized = (heightSegments-1.f) / maxTexY;
2614
2615 // add the cap //
2616 normal= {0.f,1.f,0.f};
2617 for(int iy = 0; iy < capSegs; iy++) {
2618 for(int ix = 0; ix < radiusSegments; ix++) {
2619 newRad = ofMap((float)iy, 0, capSegs-1, radius, 0.0);
2620 vert.x = cos((float)ix*angleIncRadius) * newRad;
2621 vert.z = sin((float)ix*angleIncRadius) * newRad;
2622 vert.y = halfH;
2623
2624 tcoord.x = (float)ix/((float)radiusSegments-1.f);
2625 tcoord.y = 1.f - ofMap(iy, 0, capSegs-1, maxTexYNormalized, 1.f);
2626
2627 mesh.addTexCoord( tcoord );
2628 mesh.addVertex( vert );
2629 mesh.addNormal( normal );
2630 }
2631 }
2632
2633 if(mode == OF_PRIMITIVE_TRIANGLES) {
2634 if( capSegs > 0 ) {
2635 for(int y = 0; y < capSegs-1; y++) {
2636 for(int x = 0; x < radiusSegments-1; x++) {
2637 // first triangle //
2638 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2639 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset);
2640 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2641
2642 if(y < capSegs-1) {
2643 // second triangle //
2644 mesh.addIndex( (y)*radiusSegments + x+1 + vertOffset);
2645 mesh.addIndex( (y+1)*radiusSegments + x+1 + vertOffset);
2646 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2647 }
2648 }
2649 }
2650 }
2651 } else {
2652 if(capSegs > 0 ) {
2653 for(int y = 0; y < capSegs-1; y++) {
2654 for(int x = 0; x < radiusSegments; x++) {
2655 mesh.addIndex( (y)*radiusSegments + x + vertOffset );
2656 mesh.addIndex( (y+1)*radiusSegments + x + vertOffset);
2657 }
2658 }
2659 }
2660 }
2661
2662 return mesh;
2663}
2664
2665
2666// Box Mesh //
2667
2668
2669//--------------------------------------------------------------
2670template<class V, class N, class C, class T>
2671ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::box( float width, float height, float depth, int resX, int resY, int resZ ) {
2672 // mesh only available as triangles //
2673 ofMesh_<V,N,C,T> mesh;
2675
2676 resX = resX + 1;
2677 resY = resY + 1;
2678 resZ = resZ + 1;
2679
2680 if( resX < 2 ) resX = 0;
2681 if( resY < 2 ) resY = 0;
2682 if( resZ < 2 ) resZ = 0;
2683
2684 // halves //
2685 float halfW = width * .5f;
2686 float halfH = height * .5f;
2687 float halfD = depth * .5f;
2688
2689 V vert;
2690 T texcoord;
2691 N normal;
2692 std::size_t vertOffset = 0;
2693
2694 // TRIANGLES //
2695
2696 // Front Face //
2697 normal = {0.f, 0.f, 1.f};
2698 // add the vertexes //
2699 for(int iy = 0; iy < resY; iy++) {
2700 for(int ix = 0; ix < resX; ix++) {
2701
2702 // normalized tex coords //
2703 texcoord.x = ((float)ix/((float)resX-1.f));
2704 texcoord.y = 1.f - ((float)iy/((float)resY-1.f));
2705
2706 vert.x = texcoord.x * width - halfW;
2707 vert.y = -(texcoord.y-1.f) * height - halfH;
2708 vert.z = halfD;
2709
2710 mesh.addVertex(vert);
2711 mesh.addTexCoord(texcoord);
2712 mesh.addNormal(normal);
2713 }
2714 }
2715
2716 for(int y = 0; y < resY-1; y++) {
2717 for(int x = 0; x < resX-1; x++) {
2718 // first triangle //
2719 mesh.addIndex((y)*resX + x + vertOffset);
2720 mesh.addIndex((y+1)*resX + x + vertOffset);
2721 mesh.addIndex((y)*resX + x+1 + vertOffset);
2722
2723 // second triangle //
2724 mesh.addIndex((y)*resX + x+1 + vertOffset);
2725 mesh.addIndex((y+1)*resX + x + vertOffset);
2726 mesh.addIndex((y+1)*resX + x+1 + vertOffset);
2727 }
2728 }
2729
2730 vertOffset = mesh.getNumVertices();
2731
2732
2733 // Right Side Face //
2734 normal = {1.f, 0.f, 0.f};
2735 // add the vertexes //
2736 for(int iy = 0; iy < resY; iy++) {
2737 for(int ix = 0; ix < resZ; ix++) {
2738
2739 // normalized tex coords //
2740 texcoord.x = ((float)ix/((float)resZ-1.f));
2741 texcoord.y = 1.f - ((float)iy/((float)resY-1.f));
2742
2743 //vert.x = texcoord.x * width - halfW;
2744 vert.x = halfW;
2745 vert.y = -(texcoord.y-1.f) * height - halfH;
2746 vert.z = texcoord.x * -depth + halfD;
2747
2748 mesh.addVertex(vert);
2749 mesh.addTexCoord(texcoord);
2750 mesh.addNormal(normal);
2751 }
2752 }
2753
2754 for(int y = 0; y < resY-1; y++) {
2755 for(int x = 0; x < resZ-1; x++) {
2756 // first triangle //
2757 mesh.addIndex((y)*resZ + x + vertOffset);
2758 mesh.addIndex((y+1)*resZ + x + vertOffset);
2759 mesh.addIndex((y)*resZ + x+1 + vertOffset);
2760
2761 // second triangle //
2762 mesh.addIndex((y)*resZ + x+1 + vertOffset);
2763 mesh.addIndex((y+1)*resZ + x + vertOffset);
2764 mesh.addIndex((y+1)*resZ + x+1 + vertOffset);
2765 }
2766 }
2767
2768 vertOffset = mesh.getNumVertices();
2769
2770 // Left Side Face //
2771 normal = {-1.f, 0.f, 0.f};
2772 // add the vertexes //
2773 for(int iy = 0; iy < resY; iy++) {
2774 for(int ix = 0; ix < resZ; ix++) {
2775
2776 // normalized tex coords //
2777 texcoord.x = ((float)ix/((float)resZ-1.f));
2778 texcoord.y = 1.f-((float)iy/((float)resY-1.f));
2779
2780 //vert.x = texcoord.x * width - halfW;
2781 vert.x = -halfW;
2782 vert.y = -(texcoord.y-1.f) * height - halfH;
2783 vert.z = texcoord.x * depth - halfD;
2784
2785 mesh.addVertex(vert);
2786 mesh.addTexCoord(texcoord);
2787 mesh.addNormal(normal);
2788 }
2789 }
2790
2791 for(int y = 0; y < resY-1; y++) {
2792 for(int x = 0; x < resZ-1; x++) {
2793 // first triangle //
2794 mesh.addIndex((y)*resZ + x + vertOffset);
2795 mesh.addIndex((y+1)*resZ + x + vertOffset);
2796 mesh.addIndex((y)*resZ + x+1 + vertOffset);
2797
2798 // second triangle //
2799 mesh.addIndex((y)*resZ + x+1 + vertOffset);
2800 mesh.addIndex((y+1)*resZ + x + vertOffset);
2801 mesh.addIndex((y+1)*resZ + x+1 + vertOffset);
2802 }
2803 }
2804
2805 vertOffset = mesh.getNumVertices();
2806
2807
2808 // Back Face //
2809 normal = {0.f, 0.f, -1.f};
2810 // add the vertexes //
2811 for(int iy = 0; iy < resY; iy++) {
2812 for(int ix = 0; ix < resX; ix++) {
2813
2814 // normalized tex coords //
2815 texcoord.x = ((float)ix/((float)resX-1.f));
2816 texcoord.y = 1.f-((float)iy/((float)resY-1.f));
2817
2818 vert.x = texcoord.x * -width + halfW;
2819 vert.y = -(texcoord.y-1.f) * height - halfH;
2820 vert.z = -halfD;
2821
2822 mesh.addVertex(vert);
2823 mesh.addTexCoord(texcoord);
2824 mesh.addNormal(normal);
2825 }
2826 }
2827
2828 for(int y = 0; y < resY-1; y++) {
2829 for(int x = 0; x < resX-1; x++) {
2830 // first triangle //
2831 mesh.addIndex((y)*resX + x + vertOffset);
2832 mesh.addIndex((y+1)*resX + x + vertOffset);
2833 mesh.addIndex((y)*resX + x+1 + vertOffset);
2834
2835 // second triangle //
2836 mesh.addIndex((y)*resX + x+1 + vertOffset);
2837 mesh.addIndex((y+1)*resX + x + vertOffset);
2838 mesh.addIndex((y+1)*resX + x+1 + vertOffset);
2839 }
2840 }
2841
2842 vertOffset = mesh.getNumVertices();
2843
2844
2845 // Top Face //
2846 normal = {0.f, -1.f, 0.f};
2847 // add the vertexes //
2848 for(int iy = 0; iy < resZ; iy++) {
2849 for(int ix = 0; ix < resX; ix++) {
2850
2851 // normalized tex coords //
2852 texcoord.x = ((float)ix/((float)resX-1.f));
2853 texcoord.y = 1.f-((float)iy/((float)resZ-1.f));
2854
2855 vert.x = texcoord.x * width - halfW;
2856 //vert.y = -(texcoord.y-1.f) * height - halfH;
2857 vert.y = -halfH;
2858 vert.z = texcoord.y * depth - halfD;
2859
2860 mesh.addVertex(vert);
2861 mesh.addTexCoord(texcoord);
2862 mesh.addNormal(normal);
2863 }
2864 }
2865
2866 for(int y = 0; y < resZ-1; y++) {
2867 for(int x = 0; x < resX-1; x++) {
2868 // first triangle //
2869 mesh.addIndex((y)*resX + x + vertOffset);
2870 mesh.addIndex((y)*resX + x+1 + vertOffset);
2871 mesh.addIndex((y+1)*resX + x + vertOffset);
2872
2873 // second triangle //
2874 mesh.addIndex((y)*resX + x+1 + vertOffset);
2875 mesh.addIndex((y+1)*resX + x+1 + vertOffset);
2876 mesh.addIndex((y+1)*resX + x + vertOffset);
2877 }
2878 }
2879
2880 vertOffset = mesh.getNumVertices();
2881
2882
2883 // Bottom Face //
2884 normal = {0.f, 1.f, 0.f};
2885 // add the vertexes //
2886 for(int iy = 0; iy < resZ; iy++) {
2887 for(int ix = 0; ix < resX; ix++) {
2888
2889 // normalized tex coords //
2890 texcoord.x = ((float)ix/((float)resX-1.f));
2891 texcoord.y = 1.f-((float)iy/((float)resZ-1.f));
2892
2893 vert.x = texcoord.x * width - halfW;
2894 //vert.y = -(texcoord.y-1.f) * height - halfH;
2895 vert.y = halfH;
2896 vert.z = texcoord.y * -depth + halfD;
2897
2898 mesh.addVertex(vert);
2899 mesh.addTexCoord(texcoord);
2900 mesh.addNormal(normal);
2901 }
2902 }
2903
2904 for(int y = 0; y < resZ-1; y++) {
2905 for(int x = 0; x < resX-1; x++) {
2906 // first triangle //
2907 mesh.addIndex((y)*resX + x + vertOffset);
2908 mesh.addIndex((y)*resX + x+1 + vertOffset);
2909 mesh.addIndex((y+1)*resX + x + vertOffset);
2910
2911 // second triangle //
2912 mesh.addIndex((y)*resX + x+1 + vertOffset);
2913 mesh.addIndex((y+1)*resX + x+1 + vertOffset);
2914 mesh.addIndex((y+1)*resX + x + vertOffset);
2915 }
2916 }
2917
2918 return mesh;
2919}
2920
2921
2922
2923
2924//--------------------------------------------------------------
2926template<class V, class N, class C, class T>
2928 ofMesh_<V,N,C,T> mesh;
2929
2930 // mesh only available as wireframe //
2932
2933 V vertices[6] = {
2934 V(0,0,0),
2935 V(size,0,0),
2936 V(0,0,0),
2937 V(0,size,0),
2938 V(0,0,0),
2939 V(0,0,size),
2940 };
2941 C colors[6] = {
2942 C::red,
2943 C::red,
2944 C::green,
2945 C::green,
2946 C::blue,
2947 C::blue,
2948 };
2949
2950 mesh.addVertices(vertices, 6);
2951 mesh.addColors(colors, 6);
2952
2953 return mesh;
2954}
2955
2956
2957
2958//--------------------------------------------------------------
2959template<class V, class N, class C, class T>
2961:bHasNormals(false)
2962,bHasColors(false)
2963,bHasTexcoords(false)
2964,bFaceNormalDirty(false)
2965{
2966}
2967
2968//--------------------------------------------------------------
2969template<class V, class N, class C, class T>
2971 if(bFaceNormalDirty) calculateFaceNormal();
2972 return faceNormal;
2973}
2974
2975//--------------------------------------------------------------
2976template<class V, class N, class C, class T>
2978 glm::vec3 u, v;
2979
2980 u = toGlm(vertices[1]-vertices[0]);
2981 v = toGlm(vertices[2]-vertices[0]);
2982
2983 faceNormal = glm::cross(u, v);
2984 faceNormal = glm::normalize(toGlm(faceNormal));
2985 bFaceNormalDirty = false;
2986}
2987
2988//--------------------------------------------------------------
2989template<class V, class N, class C, class T>
2991 vertices[index] = v;
2992 bFaceNormalDirty = true;
2993}
2994
2995//--------------------------------------------------------------
2996template<class V, class N, class C, class T>
2998 return vertices[index];
2999}
3000
3001//--------------------------------------------------------------
3002template<class V, class N, class C, class T>
3004 normals[index] = n;
3005 bHasNormals = true;
3006}
3007
3008//--------------------------------------------------------------
3009template<class V, class N, class C, class T>
3011 return normals[ index ];
3012}
3013
3014//--------------------------------------------------------------
3015template<class V, class N, class C, class T>
3016void ofMeshFace_<V,N,C,T>::setColor( ofIndexType index, const C& color ) {
3017 colors[index] = color;
3018 bHasColors = true;
3019}
3020
3021//--------------------------------------------------------------
3022template<class V, class N, class C, class T>
3024 return colors[index];
3025}
3026
3027//--------------------------------------------------------------
3028template<class V, class N, class C, class T>
3029void ofMeshFace_<V,N,C,T>::setTexCoord( ofIndexType index, const T& tCoord ) {
3030 texCoords[index] = tCoord;
3031 bHasTexcoords = true;
3032}
3033
3034//--------------------------------------------------------------
3035template<class V, class N, class C, class T>
3037 return texCoords[index];
3038}
3039
3040//--------------------------------------------------------------
3041template<class V, class N, class C, class T>
3043 bHasColors = bColors;
3044}
3045
3046//--------------------------------------------------------------
3047template<class V, class N, class C, class T>
3049 bHasNormals = bNormals;
3050}
3051
3052//--------------------------------------------------------------
3053template<class V, class N, class C, class T>
3055 bHasTexcoords = bTexcoords;
3056}
3057
3058//--------------------------------------------------------------
3059template<class V, class N, class C, class T>
3061 return bHasColors;
3062}
3063
3064//--------------------------------------------------------------
3065template<class V, class N, class C, class T>
3067 return bHasNormals;
3068}
3069
3070//--------------------------------------------------------------
3071template<class V, class N, class C, class T>
3073 return bHasTexcoords;
3074}
Definition ofFileUtils.h:15
Lines getLines()
Definition ofFileUtils.cpp:432
PixelType g
The green color component.
Definition ofColor.h:90
PixelType r
The red color component.
Definition ofColor.h:89
PixelType a
The alpha color component.
Definition ofColor.h:92
PixelType b
The blue color component.
Definition ofColor.h:91
Definition ofFileUtils.h:472
@ ReadOnly
Definition ofFileUtils.h:479
@ WriteOnly
Definition ofFileUtils.h:480
Derived log class for easy error logging.
Definition ofLog.h:606
Derived log class for easy warning logging.
Definition ofLog.h:585
Represents a set of vertices in 3D spaces with normals, colors, and texture coordinates at those poin...
Definition ofMesh.h:78
void setColorForIndices(ofIndexType startIndex, ofIndexType endIndex, C color)
Definition ofMesh.inl:1453
std::size_t getNumVertices() const
Definition ofMesh.inl:522
virtual void enableIndices()
Enable mesh indices. Use disableIndices() to turn indices off. Indices are enabled by default when th...
Definition ofMesh.inl:992
void clearNormals()
Remove all the normals.
Definition ofMesh.inl:887
void removeVertices(ofIndexType startIndex, ofIndexType endIndex)
Removes the vertices at the startIndex in the vector and the endindex specified.
Definition ofMesh.inl:365
void setMode(ofPrimitiveMode mode)
Allows you to set the ofPrimitiveMode. The available modes are OF_PRIMITIVE_TRIANGLES,...
Definition ofMesh.inl:803
void addTriangle(ofIndexType index1, ofIndexType index2, ofIndexType index3)
Adding a triangle means using three of the vertices that have already been added to create a triangle...
Definition ofMesh.inl:343
virtual void enableTextures()
Enable mesh textures. Use disableTextures() to turn textures off. Textures are enabled by default whe...
Definition ofMesh.inl:976
N getNormal(ofIndexType i) const
\returns the normal at the index in the normals vector.
Definition ofMesh.inl:498
T * getTexCoordsPointer()
Definition ofMesh.inl:604
void removeIndices(ofIndexType startIndex, ofIndexType endIndex)
Definition ofMesh.inl:465
static ofMesh_ sphere(float radius, int res=12, ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP)
Definition ofMesh.inl:2006
virtual void enableNormals()
Enable mesh normals. Use disableNormals() to turn normals off. Normals are enabled by default when th...
Definition ofMesh.inl:984
void addIndex(ofIndexType i)
Definition ofMesh.inl:313
void drawFaces() const
This draws the mesh as faces, meaning that you'll have a collection of faces.
Definition ofMesh.inl:943
bool hasIndices() const
/returns Whether the mesh has any indices assigned to it.
Definition ofMesh.inl:174
void removeNormal(ofIndexType index)
Remove a normal.
Definition ofMesh.inl:379
bool hasTexCoords() const
/returns Whether the mesh has any textures assigned to it.
Definition ofMesh.inl:166
virtual bool usingNormals() const
Definition ofMesh.inl:1048
void addColors(const std::vector< C > &cols)
This adds colors using a reference to a vector of ofColors. For each color in the vector,...
Definition ofMesh.inl:224
bool haveColorsChanged()
Definition ofMesh.inl:89
void setIndex(ofIndexType index, ofIndexType val)
This sets the index at i.
Definition ofMesh.inl:853
static ofMesh_ plane(float width, float height, int columns=2, int rows=2, ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP)
Definition ofMesh.inl:1931
std::size_t getNumNormals() const
This will tell you how many normals are contained in the mesh.
Definition ofMesh.inl:538
ofIndexType getIndex(ofIndexType i) const
Definition ofMesh.inl:305
virtual void enableColors()
Enable mesh colors. Use disableColors() to turn colors off. Colors are enabled by default when they a...
Definition ofMesh.inl:968
static ofMesh_ cone(float radius, float height, int radiusSegments=12, int heightSegments=6, int capSegments=2, ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP)
A helper method that returns a cone made of triangles. The resolution settings for the radius,...
Definition ofMesh.inl:2521
bool haveVertsChanged()
Definition ofMesh.inl:76
void addNormal(const N &n)
Add a normal to the mesh as a 3D vector, typically perpendicular to the plane of the face....
Definition ofMesh.inl:244
void clearTexCoords()
Clear all the texture coordinates.
Definition ofMesh.inl:907
ofMesh_()
This creates the mesh, using OF_PRIMITIVE_TRIANGLES without any initial vertices.
Definition ofMesh.inl:17
bool hasNormals() const
/returnsWhether the mesh has any normals.
Definition ofMesh.inl:158
void clearVertices()
Removes all the vertices.
Definition ofMesh.inl:878
void draw() const
This draws the mesh using its primitive type, meaning that if you set them up to be triangles,...
Definition ofMesh.inl:951
bool hasColors() const
/returns Whether the mesh has any colors.
Definition ofMesh.inl:150
void mergeDuplicateVertices()
Definition ofMesh.inl:1538
void setupIndicesAuto()
Allow you to set up the indices automatically when you add a vertex.
Definition ofMesh.inl:863
void load(const of::filesystem::path &path)
Loads a mesh from a file located at the provided path into the mesh. This will replace any existing d...
Definition ofMesh.inl:1091
void append(const ofMesh_ &mesh)
Add the vertices, normals, texture coordinates and indices of one mesh onto another mesh....
Definition ofMesh.inl:1065
void removeNormals(ofIndexType startIndex, ofIndexType endIndex)
Remove normal's from index to end index from normals vector.
Definition ofMesh.inl:390
void addTexCoords(const std::vector< T > &tCoords)
Add a vector of texture coordinates to a mesh, allowing you to push out many at once rather than addi...
Definition ofMesh.inl:285
std::vector< ofIndexType > & getIndices()
Use this if you plan to change the indices as part of this call as it will force a reset of the cache...
Definition ofMesh.inl:691
V * getVerticesPointer()
Definition ofMesh.inl:580
bool haveTexCoordsChanged()
Definition ofMesh.inl:115
std::vector< C > & getColors()
Definition ofMesh.inl:667
virtual void disableNormals()
Disable mesh normals. Use enableNormals() to turn normals back on.
Definition ofMesh.inl:1016
std::size_t getNumTexCoords() const
This will tell you how many texture coordinates are contained in the mesh.
Definition ofMesh.inl:546
void setColor(ofIndexType index, const C &c)
Set the color at the index in the colors vector.
Definition ofMesh.inl:833
void removeColors(ofIndexType startIndex, ofIndexType endIndex)
Remove colors at the index to the end index of the colors vector.
Definition ofMesh.inl:414
const std::vector< ofMeshFace_< V, N, C, T > > & getUniqueFaces() const
Definition ofMesh.inl:1647
void smoothNormals(float angle)
Definition ofMesh.inl:1782
void removeTexCoord(ofIndexType index)
Remove a Vec2f representing the texture coordinate.
Definition ofMesh.inl:428
static ofMesh_ cylinder(float radius, float height, int radiusSegments=12, int heightSegments=6, int numCapSegments=2, bool bCapped=true, ofPrimitiveMode mode=OF_PRIMITIVE_TRIANGLE_STRIP)
A helper method that returns a cylinder made of triangles. The resolution settings for the radius,...
Definition ofMesh.inl:2328
void flatNormals()
Duplicates vertices and updates normals to get a low-poly look.
Definition ofMesh.inl:1883
void removeVertex(ofIndexType index)
Removes the vertex at the index in the vector.
Definition ofMesh.inl:354
virtual void disableIndices()
Disable mesh indices. Use enableIndices() to turn indices back on.
Definition ofMesh.inl:1024
std::size_t getNumIndices() const
This will tell you how many indices are contained in the mesh.
Definition ofMesh.inl:554
V getVertex(ofIndexType i) const
Definition ofMesh.inl:490
ofMeshFace_< V, N, C, T > getFace(ofIndexType faceId) const
Definition ofMesh.inl:1634
virtual bool usingTextures() const
Definition ofMesh.inl:1040
virtual bool usingColors() const
Definition ofMesh.inl:1032
std::vector< V > & getVertices()
Definition ofMesh.inl:659
void clear()
Removes all the vertices, colors, and indices from the mesh.
Definition ofMesh.inl:49
bool hasVertices() const
Definition ofMesh.inl:142
void addTexCoord(const T &t)
Add a Vec2f representing the texture coordinate. Because OF uses ARB textures these are in pixels rat...
Definition ofMesh.inl:274
std::size_t getNumColors() const
Definition ofMesh.inl:530
static ofMesh_ icosahedron(float radius)
Definition ofMesh.inl:2122
void addIndices(const std::vector< ofIndexType > &inds)
This adds a vector of indices.
Definition ofMesh.inl:323
T getTexCoord(ofIndexType i) const
Definition ofMesh.inl:514
virtual void disableTextures()
Disable mesh textures. Use enableTextures() to turn textures back on.
Definition ofMesh.inl:1008
virtual void disableColors()
Disable mesh colors. Use enableColors() to turn colors back on.
Definition ofMesh.inl:1000
void removeColor(ofIndexType index)
Remove a color at the index in the colors vector.
Definition ofMesh.inl:403
void addVertex(const V &v)
Add a new vertex at the end of the current list of vertices. It is important to remember that the ord...
Definition ofMesh.inl:184
void setVertex(ofIndexType index, const V &v)
Definition ofMesh.inl:812
std::vector< N > & getNormals()
Definition ofMesh.inl:675
std::vector< N > getFaceNormals(bool perVetex=false) const
Get normals for each face As a default it only calculates the normal for the face as a whole but by s...
Definition ofMesh.inl:1690
void removeIndex(ofIndexType index)
Removes an index.
Definition ofMesh.inl:454
N * getNormalsPointer()
Definition ofMesh.inl:596
ofPrimitiveMode getMode() const
\returns the primitive mode that the mesh is using.
Definition ofMesh.inl:482
bool haveNormalsChanged()
Definition ofMesh.inl:102
void save(const of::filesystem::path &path, bool useBinary=false) const
Saves the mesh at the passed path in the PLY Format.
Definition ofMesh.inl:1331
ofIndexType * getIndexPointer()
Definition ofMesh.inl:612
void setTexCoord(ofIndexType index, const T &t)
Definition ofMesh.inl:843
void removeTexCoords(ofIndexType startIndex, ofIndexType endIndex)
Definition ofMesh.inl:439
static ofMesh_ icosphere(float radius, std::size_t iterations=2)
Definition ofMesh.inl:2134
C getColor(ofIndexType i) const
Get the color at the index in the colors vector.
Definition ofMesh.inl:506
void addNormals(const std::vector< N > &norms)
Add a vector of normals to a mesh, allowing you to push out many normals at once rather than adding o...
Definition ofMesh.inl:254
void setNormal(ofIndexType index, const N &n)
Definition ofMesh.inl:823
C * getColorsPointer()
Definition ofMesh.inl:588
void clearIndices()
Remove all the indices of the mesh. This means that your mesh will be a point cloud.
Definition ofMesh.inl:917
void addColor(const C &c)
This adds a color to the mesh, the color will be associated with the vertex in the same position.
Definition ofMesh.inl:214
bool haveIndicesChanged()
Definition ofMesh.inl:128
std::vector< T > & getTexCoords()
Get a vector representing the texture coordinates of the mesh Because OF uses ARB textures these are ...
Definition ofMesh.inl:683
V getCentroid() const
Definition ofMesh.inl:784
void setFromTriangles(const std::vector< ofMeshFace_< V, N, C, T > > &tris, bool bUseFaceNormal=false)
Definition ofMesh.inl:1725
void drawWireframe() const
This draws the mesh as GL_LINES, meaning that you'll have a wireframe.
Definition ofMesh.inl:935
virtual bool usingIndices() const
Definition ofMesh.inl:1056
void addVertices(const std::vector< V > &verts)
Add a vector of vertices to a mesh, allowing you to push out many at once rather than adding one at a...
Definition ofMesh.inl:194
ofMesh_< V, N, C, T > getMeshForIndices(ofIndexType startIndex, ofIndexType endIndex) const
Definition ofMesh.inl:1467
void clearColors()
Clear all the colors.
Definition ofMesh.inl:897
static ofMesh_ axis(float size=1.0)
Returns an ofMesh representing an XYZ coordinate system.
Definition ofMesh.inl:2927
void drawVertices() const
This allows you draw just the vertices, meaning that you'll have a point cloud.
Definition ofMesh.inl:927
static ofMesh_ box(float width, float height, float depth, int resX=2, int resY=2, int resZ=2)
A helper method that returns a box made of triangles. The resolution settings for the width and heigh...
Definition ofMesh.inl:2671
An ofMeshFace_ is a face on one of the ofPrimitive instances. In the ofPrimitive a face consists of 3...
Definition ofMesh.h:680
const V & getVertex(ofIndexType index) const
Definition ofMesh.inl:2997
const N & getFaceNormal() const
Definition ofMesh.inl:2970
bool hasTexcoords() const
Definition ofMesh.inl:3072
const T & getTexCoord(ofIndexType index) const
Definition ofMesh.inl:3036
void setColor(ofIndexType index, const C &color)
Definition ofMesh.inl:3016
void setHasColors(bool bColors)
Definition ofMesh.inl:3042
const C & getColor(ofIndexType index) const
Definition ofMesh.inl:3023
bool hasColors() const
Definition ofMesh.inl:3060
ofMeshFace_()
Definition ofMesh.inl:2960
void setHasNormals(bool bNormals)
Definition ofMesh.inl:3048
void setNormal(ofIndexType index, const N &n)
Definition ofMesh.inl:3003
bool hasNormals() const
Definition ofMesh.inl:3066
void setHasTexcoords(bool bTexcoords)
Definition ofMesh.inl:3054
void setVertex(ofIndexType index, const V &v)
Definition ofMesh.inl:2990
void setTexCoord(ofIndexType index, const T &tCoord)
Definition ofMesh.inl:3029
const N & getNormal(ofIndexType index) const
Definition ofMesh.inl:3010
unsigned int height
Definition ofAppEGLWindow.cpp:125
unsigned int width
Definition ofAppEGLWindow.cpp:124
shared_ptr< ofBaseRenderer > & ofGetCurrentRenderer()
Definition ofAppRunner.cpp:317
TESSindex ofIndexType
Definition ofConstants.h:290
std::string ofToString(const T &)
Convert a value to a string.
Definition ofUtils.h:657
ofPrimitiveMode
Definition ofGraphicsConstants.h:20
@ OF_PRIMITIVE_TRIANGLES
Definition ofGraphicsConstants.h:21
@ OF_PRIMITIVE_TRIANGLE_STRIP
Definition ofGraphicsConstants.h:22
@ OF_PRIMITIVE_LINES
Definition ofGraphicsConstants.h:24
ofPolyRenderMode
Definition ofGraphicsConstants.h:13
@ OF_MESH_WIREFRAME
Definition ofGraphicsConstants.h:15
@ OF_MESH_POINTS
Definition ofGraphicsConstants.h:14
@ OF_MESH_FILL
Definition ofGraphicsConstants.h:16
float ofDegToRad(float degrees)
Convert degrees to radians.
Definition ofMath.cpp:142
float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp)
Given a value and an input range, map the value to an output range.
Definition ofMath.cpp:78
#define c
const glm::vec2 & toGlm(const ofVec2f &v)
Definition ofVectorMath.h:72
Definition ofFileUtils.h:149
Definition ofFileUtils.h:211
Line end()
Get the last line in the buffer.
Definition ofFileUtils.cpp:411
Line begin()
Get the first line in the buffer.
Definition ofFileUtils.cpp:406