framework2

Форк
0
3074 строки · 81.8 Кб
1
#ifndef OF_MESH_H
2
#include "ofMesh.h"
3
#endif
4

5
#include "ofAppRunner.h"
6
#include "ofGraphicsBaseTypes.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
//--------------------------------------------------------------
16
template<class V, class N, class C, class T>
17
ofMesh_<V,N,C,T>::ofMesh_(){
18
	mode = OF_PRIMITIVE_TRIANGLES;
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
//--------------------------------------------------------------
33
template<class V, class N, class C, class T>
34
ofMesh_<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
//--------------------------------------------------------------
48
template<class V, class N, class C, class T>
49
void ofMesh_<V,N,C,T>::clear(){
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
//--------------------------------------------------------------
75
template<class V, class N, class C, class T>
76
bool ofMesh_<V,N,C,T>::haveVertsChanged(){
77
	if(bVertsChanged){
78
		bVertsChanged = false;
79
		return true;
80
	}else{
81
		return false;
82
	}
83
}
84

85

86

87
//--------------------------------------------------------------
88
template<class V, class N, class C, class T>
89
bool ofMesh_<V,N,C,T>::haveColorsChanged(){
90
	if(bColorsChanged){
91
		bColorsChanged = false;
92
		return true;
93
	}else{
94
		return false;
95
	}
96
}
97

98

99

100
//--------------------------------------------------------------
101
template<class V, class N, class C, class T>
102
bool ofMesh_<V,N,C,T>::haveNormalsChanged(){
103
	if(bNormalsChanged){
104
		bNormalsChanged = false;
105
		return true;
106
	}else{
107
		return false;
108
	}
109
}
110

111

112

113
//--------------------------------------------------------------
114
template<class V, class N, class C, class T>
115
bool ofMesh_<V,N,C,T>::haveTexCoordsChanged(){
116
	if(bTexCoordsChanged){
117
		bTexCoordsChanged = false;
118
		return true;
119
	}else{
120
		return false;
121
	}
122
}
123

124

125

126
//--------------------------------------------------------------
127
template<class V, class N, class C, class T>
128
bool ofMesh_<V,N,C,T>::haveIndicesChanged(){
129
	if(bIndicesChanged){
130
		bIndicesChanged = false;
131
		return true;
132
	}else{
133
		return false;
134
	}
135
}
136

137

138

139

140
//--------------------------------------------------------------
141
template<class V, class N, class C, class T>
142
bool ofMesh_<V,N,C,T>::hasVertices() const{
143
	return !vertices.empty();
144
}
145

146

147

148
//--------------------------------------------------------------
149
template<class V, class N, class C, class T>
150
bool ofMesh_<V,N,C,T>::hasColors() const{
151
	return !colors.empty();
152
}
153

154

155

156
//--------------------------------------------------------------
157
template<class V, class N, class C, class T>
158
bool ofMesh_<V,N,C,T>::hasNormals() const{
159
	return !normals.empty();
160
}
161

162

163

164
//--------------------------------------------------------------
165
template<class V, class N, class C, class T>
166
bool ofMesh_<V,N,C,T>::hasTexCoords() const{
167
	return !texCoords.empty();
168
}
169

170

171

172
//--------------------------------------------------------------
173
template<class V, class N, class C, class T>
174
bool ofMesh_<V,N,C,T>::hasIndices() const{
175
	return !indices.empty();
176
}
177

178
//ADDERS
179

180

181

182
//--------------------------------------------------------------
183
template<class V, class N, class C, class T>
184
void ofMesh_<V,N,C,T>::addVertex(const V& v){
185
	vertices.push_back(v);
186
	bVertsChanged = true;
187
	bFacesDirty = true;
188
}
189

190

191

192
//--------------------------------------------------------------
193
template<class V, class N, class C, class T>
194
void 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
}
199

200

201

202
//--------------------------------------------------------------
203
template<class V, class N, class C, class T>
204
void 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
//--------------------------------------------------------------
213
template<class V, class N, class C, class T>
214
void ofMesh_<V,N,C,T>::addColor(const C& c){
215
	colors.push_back(c);
216
	bColorsChanged = true;
217
	bFacesDirty = true;
218
}
219

220

221

222
//--------------------------------------------------------------
223
template<class V, class N, class C, class T>
224
void 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

230

231

232
//--------------------------------------------------------------
233
template<class V, class N, class C, class T>
234
void 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

240

241

242
//--------------------------------------------------------------
243
template<class V, class N, class C, class T>
244
void ofMesh_<V,N,C,T>::addNormal(const N& n){
245
	normals.push_back(n);
246
	bNormalsChanged = true;
247
	bFacesDirty = true;
248
}
249

250

251

252
//--------------------------------------------------------------
253
template<class V, class N, class C, class T>
254
void 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

260

261

262
//--------------------------------------------------------------
263
template<class V, class N, class C, class T>
264
void 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
//--------------------------------------------------------------
273
template<class V, class N, class C, class T>
274
void ofMesh_<V,N,C,T>::addTexCoord(const T& 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

281

282

283
//--------------------------------------------------------------
284
template<class V, class N, class C, class T>
285
void 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

291

292

293
//--------------------------------------------------------------
294
template<class V, class N, class C, class T>
295
void 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
}
300

301

302

303
//--------------------------------------------------------------
304
template<class V, class N, class C, class T>
305
ofIndexType ofMesh_<V,N,C,T>::getIndex(ofIndexType i) const{
306
	return indices[i];
307
}
308

309

310

311
//--------------------------------------------------------------
312
template<class V, class N, class C, class T>
313
void ofMesh_<V,N,C,T>::addIndex(ofIndexType i){
314
	indices.push_back(i);
315
	bIndicesChanged = true;
316
	bFacesDirty = true;
317
}
318

319

320

321
//--------------------------------------------------------------
322
template<class V, class N, class C, class T>
323
void 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
}
328

329

330

331
//--------------------------------------------------------------
332
template<class V, class N, class C, class T>
333
void 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

339

340

341
//--------------------------------------------------------------
342
template<class V, class N, class C, class T>
343
void ofMesh_<V,N,C,T>::addTriangle(ofIndexType index1, ofIndexType index2, ofIndexType index3) {
344
	addIndex(index1);
345
	addIndex(index2);
346
	addIndex(index3);
347
}
348

349
//REMOVERS
350

351

352
//--------------------------------------------------------------
353
template<class V, class N, class C, class T>
354
void ofMesh_<V,N,C,T>::removeVertex(ofIndexType index){
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;
361
  }
362
}
363

364
template<class V, class N, class C, class T>
365
void ofMesh_<V,N,C,T>::removeVertices(ofIndexType startIndex, ofIndexType endIndex){
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
}
374

375

376

377
//--------------------------------------------------------------
378
template<class V, class N, class C, class T>
379
void ofMesh_<V,N,C,T>::removeNormal(ofIndexType index){
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
}
388

389
template<class V, class N, class C, class T>
390
void ofMesh_<V,N,C,T>::removeNormals(ofIndexType startIndex, ofIndexType endIndex){
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

400

401
//--------------------------------------------------------------
402
template<class V, class N, class C, class T>
403
void ofMesh_<V,N,C,T>::removeColor(ofIndexType index){
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
}
412

413
template<class V, class N, class C, class T>
414
void ofMesh_<V,N,C,T>::removeColors(ofIndexType startIndex, ofIndexType endIndex){
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
}
423

424

425

426
//--------------------------------------------------------------
427
template<class V, class N, class C, class T>
428
void ofMesh_<V,N,C,T>::removeTexCoord(ofIndexType index){
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;
435
  }
436
}
437

438
template<class V, class N, class C, class T>
439
void ofMesh_<V,N,C,T>::removeTexCoords(ofIndexType startIndex, ofIndexType endIndex){
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
	}
447
}
448

449

450

451

452
//--------------------------------------------------------------
453
template<class V, class N, class C, class T>
454
void ofMesh_<V,N,C,T>::removeIndex(ofIndexType index){
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;
461
  }
462
}
463

464
template<class V, class N, class C, class T>
465
void ofMesh_<V,N,C,T>::removeIndices(ofIndexType startIndex, ofIndexType endIndex){
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
	}
473
}
474

475

476

477
//GETTERS
478

479

480
//--------------------------------------------------------------
481
template<class V, class N, class C, class T>
482
ofPrimitiveMode ofMesh_<V,N,C,T>::getMode() const{
483
	return mode;
484
}
485

486

487

488
//--------------------------------------------------------------
489
template<class V, class N, class C, class T>
490
V ofMesh_<V,N,C,T>::getVertex(ofIndexType i) const{
491
	return vertices[i];
492
}
493

494

495

496
//--------------------------------------------------------------
497
template<class V, class N, class C, class T>
498
N ofMesh_<V,N,C,T>::getNormal(ofIndexType i) const{
499
	return normals[i];
500
}
501

502

503

504
//--------------------------------------------------------------
505
template<class V, class N, class C, class T>
506
C ofMesh_<V,N,C,T>::getColor(ofIndexType i) const{
507
	return colors[i];
508
}
509

510

511

512
//--------------------------------------------------------------
513
template<class V, class N, class C, class T>
514
T ofMesh_<V,N,C,T>::getTexCoord(ofIndexType i) const{
515
	return texCoords[i];
516
}
517

518

519

520
//--------------------------------------------------------------
521
template<class V, class N, class C, class T>
522
std::size_t ofMesh_<V,N,C,T>::getNumVertices() const{
523
	return vertices.size();
524
}
525

526

527

528
//--------------------------------------------------------------
529
template<class V, class N, class C, class T>
530
std::size_t ofMesh_<V,N,C,T>::getNumColors() const{
531
	return colors.size();
532
}
533

534

535

536
//--------------------------------------------------------------
537
template<class V, class N, class C, class T>
538
std::size_t ofMesh_<V,N,C,T>::getNumNormals() const{
539
	return normals.size();
540
}
541

542

543

544
//--------------------------------------------------------------
545
template<class V, class N, class C, class T>
546
std::size_t ofMesh_<V,N,C,T>::getNumTexCoords() const{
547
	return texCoords.size();
548
}
549

550

551

552
//--------------------------------------------------------------
553
template<class V, class N, class C, class T>
554
std::size_t ofMesh_<V,N,C,T>::getNumIndices() const{
555
	return indices.size();
556
}
557

558
/*
559

560

561
//--------------------------------------------------------------
562
template<class V, class N, class C, class T>
563
int ofPrimitive::getNumIndicesSolid(){
564
	return indicesSolid.size();
565
}
566

567

568

569
//--------------------------------------------------------------
570
template<class V, class N, class C, class T>
571
int ofPrimitive::getNumIndicesWire(){
572
	return indicesWire.size();
573
}
574
 */
575

576

577

578
//--------------------------------------------------------------
579
template<class V, class N, class C, class T>
580
V* ofMesh_<V,N,C,T>::getVerticesPointer(){
581
	return vertices.data();
582
}
583

584

585

586
//--------------------------------------------------------------
587
template<class V, class N, class C, class T>
588
C* ofMesh_<V,N,C,T>::getColorsPointer(){
589
	return colors.data();
590
}
591

592

593

594
//--------------------------------------------------------------
595
template<class V, class N, class C, class T>
596
N* ofMesh_<V,N,C,T>::getNormalsPointer(){
597
	return normals.data();
598
}
599

600

601

602
//--------------------------------------------------------------
603
template<class V, class N, class C, class T>
604
T* ofMesh_<V,N,C,T>::getTexCoordsPointer(){
605
	return texCoords.data();
606
}
607

608

609

610
//--------------------------------------------------------------
611
template<class V, class N, class C, class T>
612
ofIndexType* ofMesh_<V,N,C,T>::getIndexPointer(){
613
	return indices.data();
614
}
615

616

617

618

619
//--------------------------------------------------------------
620
template<class V, class N, class C, class T>
621
const V* ofMesh_<V,N,C,T>::getVerticesPointer() const{
622
	return vertices.data();
623
}
624

625

626

627
//--------------------------------------------------------------
628
template<class V, class N, class C, class T>
629
const C* ofMesh_<V,N,C,T>::getColorsPointer() const{
630
	return colors.data();
631
}
632

633

634

635
//--------------------------------------------------------------
636
template<class V, class N, class C, class T>
637
const N* ofMesh_<V,N,C,T>::getNormalsPointer() const{
638
	return normals.data();
639
}
640

641

642

643
//--------------------------------------------------------------
644
template<class V, class N, class C, class T>
645
const T* ofMesh_<V,N,C,T>::getTexCoordsPointer() const{
646
	return texCoords.data();
647
}
648

649

650

651
//--------------------------------------------------------------
652
template<class V, class N, class C, class T>
653
const ofIndexType * ofMesh_<V,N,C,T>::getIndexPointer() const{
654
	return indices.data();
655
}
656

657
//--------------------------------------------------------------
658
template<class V, class N, class C, class T>
659
std::vector<V> & ofMesh_<V,N,C,T>::getVertices(){
660
	bVertsChanged = true;
661
	bFacesDirty = true;
662
	return vertices;
663
}
664

665
//--------------------------------------------------------------
666
template<class V, class N, class C, class T>
667
std::vector<C> & ofMesh_<V,N,C,T>::getColors(){
668
	bColorsChanged = true;
669
	bFacesDirty = true;
670
	return colors;
671
}
672

673
//--------------------------------------------------------------
674
template<class V, class N, class C, class T>
675
std::vector<N> & ofMesh_<V,N,C,T>::getNormals(){
676
	bNormalsChanged = true;
677
	bFacesDirty = true;
678
	return normals;
679
}
680

681
//--------------------------------------------------------------
682
template<class V, class N, class C, class T>
683
std::vector<T> & ofMesh_<V,N,C,T>::getTexCoords(){
684
	bTexCoordsChanged = true;
685
	bFacesDirty = true;
686
	return texCoords;
687
}
688

689
//--------------------------------------------------------------
690
template<class V, class N, class C, class T>
691
std::vector<ofIndexType> & ofMesh_<V,N,C,T>::getIndices(){
692
	bIndicesChanged = true;
693
	bFacesDirty = true;
694
	return indices;
695
}
696

697
//--------------------------------------------------------------
698
template<class V, class N, class C, class T>
699
const std::vector<V> & ofMesh_<V,N,C,T>::getVertices() const{
700
	return vertices;
701
}
702

703
//--------------------------------------------------------------
704
template<class V, class N, class C, class T>
705
const std::vector<C> & ofMesh_<V,N,C,T>::getColors() const{
706
	return colors;
707
}
708

709
//--------------------------------------------------------------
710
template<class V, class N, class C, class T>
711
const std::vector<N> & ofMesh_<V,N,C,T>::getNormals() const{
712
	return normals;
713
}
714

715
//--------------------------------------------------------------
716
template<class V, class N, class C, class T>
717
const std::vector<T> & ofMesh_<V,N,C,T>::getTexCoords() const{
718
	return texCoords;
719
}
720

721
//--------------------------------------------------------------
722
template<class V, class N, class C, class T>
723
const std::vector<ofIndexType> & ofMesh_<V,N,C,T>::getIndices() const{
724
	return indices;
725
}
726

727
/*
728

729

730
//--------------------------------------------------------------
731
template<class V, class N, class C, class T>
732
GLuint* ofPrimitive::getSolidIndexPointer(){
733
	return &indicesSolid[0];
734
}
735

736

737

738
//--------------------------------------------------------------
739
template<class V, class N, class C, class T>
740
GLuint* ofPrimitive::getWireIndexPointer(){
741
	return &indicesWire[0];
742
}
743
 */
744

745
/*
746

747

748
//--------------------------------------------------------------
749
template<class V, class N, class C, class T>
750
std::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
//--------------------------------------------------------------
783
template<class V, class N, class C, class T>
784
V ofMesh_<V,N,C,T>::getCentroid() const {
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
//--------------------------------------------------------------
802
template<class V, class N, class C, class T>
803
void ofMesh_<V,N,C,T>::setMode(ofPrimitiveMode m){
804
	bIndicesChanged = true;
805
	mode = m;
806
}
807

808

809

810
//--------------------------------------------------------------
811
template<class V, class N, class C, class T>
812
void ofMesh_<V,N,C,T>::setVertex(ofIndexType index, const V& v){
813
	vertices[index] = v;
814
	bVertsChanged = true;
815
	bIndicesChanged = true;
816
	bFacesDirty = true;
817
}
818

819

820

821
//--------------------------------------------------------------
822
template<class V, class N, class C, class T>
823
void ofMesh_<V,N,C,T>::setNormal(ofIndexType index, const N& n){
824
	normals[index] = n;
825
	bNormalsChanged = true;
826
	bFacesDirty = true;
827
}
828

829

830

831
//--------------------------------------------------------------
832
template<class V, class N, class C, class T>
833
void ofMesh_<V,N,C,T>::setColor(ofIndexType index, const C& c){
834
	colors[index] = c;
835
	bColorsChanged = true;
836
	bFacesDirty = true;
837
}
838

839

840

841
//--------------------------------------------------------------
842
template<class V, class N, class C, class T>
843
void ofMesh_<V,N,C,T>::setTexCoord(ofIndexType index, const T& t){
844
	texCoords[index] = t;
845
	bTexCoordsChanged = true;
846
	bFacesDirty = true;
847
}
848

849

850

851
//--------------------------------------------------------------
852
template<class V, class N, class C, class T>
853
void ofMesh_<V,N,C,T>::setIndex(ofIndexType index, ofIndexType  val){
854
	indices[index] = val;
855
	bIndicesChanged = true;
856
	bFacesDirty = true;
857
}
858

859

860

861
//--------------------------------------------------------------
862
template<class V, class N, class C, class T>
863
void ofMesh_<V,N,C,T>::setupIndicesAuto(){
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
//--------------------------------------------------------------
877
template<class V, class N, class C, class T>
878
void ofMesh_<V,N,C,T>::clearVertices(){
879
	vertices.clear();
880
	bVertsChanged=true;
881
}
882

883

884

885
//--------------------------------------------------------------
886
template<class V, class N, class C, class T>
887
void ofMesh_<V,N,C,T>::clearNormals(){
888
	normals.clear();
889
	bNormalsChanged=true;
890
	bFacesDirty = true;
891
}
892

893

894

895
//--------------------------------------------------------------
896
template<class V, class N, class C, class T>
897
void ofMesh_<V,N,C,T>::clearColors(){
898
	colors.clear();
899
	bColorsChanged=true;
900
	bFacesDirty = true;
901
}
902

903

904

905
//--------------------------------------------------------------
906
template<class V, class N, class C, class T>
907
void ofMesh_<V,N,C,T>::clearTexCoords(){
908
	texCoords.clear();
909
	bTexCoordsChanged=true;
910
	bFacesDirty = true;
911
}
912

913

914

915
//--------------------------------------------------------------
916
template<class V, class N, class C, class T>
917
void ofMesh_<V,N,C,T>::clearIndices(){
918
	indices.clear();
919
	bIndicesChanged = true;
920
	bFacesDirty = true;
921
}
922

923

924

925
//--------------------------------------------------------------
926
template<class V, class N, class C, class T>
927
void ofMesh_<V,N,C,T>::drawVertices() const{
928
	draw(OF_MESH_POINTS);
929
}
930

931

932

933
//--------------------------------------------------------------
934
template<class V, class N, class C, class T>
935
void ofMesh_<V,N,C,T>::drawWireframe() const{
936
	draw(OF_MESH_WIREFRAME);
937
}
938

939

940

941
//--------------------------------------------------------------
942
template<class V, class N, class C, class T>
943
void ofMesh_<V,N,C,T>::drawFaces() const{
944
	draw(OF_MESH_FILL);
945
}
946

947

948

949
//--------------------------------------------------------------
950
template<class V, class N, class C, class T>
951
void ofMesh_<V,N,C,T>::draw() const{
952
	draw(OF_MESH_FILL);
953
}
954

955

956

957
//--------------------------------------------------------------
958
template<class V, class N, class C, class T>
959
void ofMesh_<V,N,C,T>::draw(ofPolyRenderMode renderType) const{
960
	if(getNumVertices()==0) return;
961
	ofGetCurrentRenderer()->draw(*this,renderType,useColors,useTextures,useNormals);
962
}
963

964

965

966
//--------------------------------------------------------------
967
template<class V, class N, class C, class T>
968
void ofMesh_<V,N,C,T>::enableColors(){
969
	useColors = true;
970
}
971

972

973

974
//--------------------------------------------------------------
975
template<class V, class N, class C, class T>
976
void ofMesh_<V,N,C,T>::enableTextures(){
977
	useTextures = true;
978
}
979

980

981

982
//--------------------------------------------------------------
983
template<class V, class N, class C, class T>
984
void ofMesh_<V,N,C,T>::enableNormals(){
985
	useNormals = true;
986
}
987

988

989

990
//--------------------------------------------------------------
991
template<class V, class N, class C, class T>
992
void ofMesh_<V,N,C,T>::enableIndices(){
993
	useIndices = true;
994
}
995

996

997

998
//--------------------------------------------------------------
999
template<class V, class N, class C, class T>
1000
void ofMesh_<V,N,C,T>::disableColors(){
1001
	useColors = false;
1002
}
1003

1004

1005

1006
//--------------------------------------------------------------
1007
template<class V, class N, class C, class T>
1008
void ofMesh_<V,N,C,T>::disableTextures(){
1009
	useTextures = false;
1010
}
1011

1012

1013

1014
//--------------------------------------------------------------
1015
template<class V, class N, class C, class T>
1016
void ofMesh_<V,N,C,T>::disableNormals(){
1017
	useNormals = false;
1018
}
1019

1020

1021

1022
//--------------------------------------------------------------
1023
template<class V, class N, class C, class T>
1024
void ofMesh_<V,N,C,T>::disableIndices(){
1025
	useIndices = false;
1026
}
1027

1028

1029

1030
//--------------------------------------------------------------
1031
template<class V, class N, class C, class T>
1032
bool ofMesh_<V,N,C,T>::usingColors() const{
1033
	return useColors;
1034
}
1035

1036

1037

1038
//--------------------------------------------------------------
1039
template<class V, class N, class C, class T>
1040
bool ofMesh_<V,N,C,T>::usingTextures() const{
1041
	return useTextures;
1042
}
1043

1044

1045

1046
//--------------------------------------------------------------
1047
template<class V, class N, class C, class T>
1048
bool ofMesh_<V,N,C,T>::usingNormals() const{
1049
	return useNormals;
1050
}
1051

1052

1053

1054
//--------------------------------------------------------------
1055
template<class V, class N, class C, class T>
1056
bool ofMesh_<V,N,C,T>::usingIndices() const{
1057
	return useIndices;
1058
}
1059

1060

1061

1062

1063
//--------------------------------------------------------------
1064
template<class V, class N, class C, class T>
1065
void ofMesh_<V,N,C,T>::append(const ofMesh_<V,N,C,T> & mesh){
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
//--------------------------------------------------------------
1090
template<class V, class N, class C, class T>
1091
void 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; /// flag to distinguish between uchar (more common) and float (less common) color format in ply file
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
//--------------------------------------------------------------
1330
template<class V, class N, class C, class T>
1331
void 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
//--------------------------------------------------------------
1452
template<class V, class N, class C, class T>
1453
void 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
//--------------------------------------------------------------
1466
template<class V, class N, class C, class T>
1467
ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex ) const {
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
//--------------------------------------------------------------
1488
template<class V, class N, class C, class T>
1489
ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::getMeshForIndices( ofIndexType startIndex, ofIndexType endIndex, ofIndexType startVertIndex, ofIndexType endVertIndex ) const{
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
//--------------------------------------------------------------
1537
template<class V, class N, class C, class T>
1538
void ofMesh_<V,N,C,T>::mergeDuplicateVertices() {
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
//--------------------------------------------------------------
1633
template<class V, class N, class C, class T>
1634
ofMeshFace_<V,N,C,T> ofMesh_<V,N,C,T>::getFace(ofIndexType faceId) const{
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
//--------------------------------------------------------------
1646
template<class V, class N, class C, class T>
1647
const 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
//--------------------------------------------------------------
1689
template<class V, class N, class C, class T>
1690
std::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
			}
1701
			ofMeshFace_<V,N,C,T> face;
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
//--------------------------------------------------------------
1724
template<class V, class N, class C, class T>
1725
void 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
//--------------------------------------------------------------
1781
template<class V, class N, class C, class T>
1782
void ofMesh_<V,N,C,T>::smoothNormals( float angle ) {
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
//--------------------------------------------------------------
1882
template<class V, class N, class C, class T>
1883
void ofMesh_<V,N,C,T>::flatNormals() {
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
//--------------------------------------------------------------
1930
template<class V, class N, class C, class T>
1931
ofMesh_<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

1934
	if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) {
1935
		ofLogWarning("ofMesh") << "ofGetPlaneMesh(): primtive mode " << mode << " not supported, setting to OF_PRIMITIVE_TRIANGLES";
1936
		mode = 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
//--------------------------------------------------------------
2005
template<class V, class N, class C, class T>
2006
ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::sphere( float radius, int res, ofPrimitiveMode mode ) {
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

2014
	if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) {
2015
		mode = OF_PRIMITIVE_TRIANGLE_STRIP;
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
//--------------------------------------------------------------
2121
template<class V, class N, class C, class T>
2122
ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::icosahedron(float radius) {
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
//--------------------------------------------------------------
2133
template<class V, class N, class C, class T>
2134
ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::icosphere(float radius, std::size_t iterations) {
2135
	ofMesh_<V,N,C,T> sphere;
2136

2137
	/// Step 1 : Generate icosahedron
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

2187
	/// Step 2 : tessellate
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

2224
	/// Step 3 : generate texcoords
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

2241
	/// Step 4 : fix texcoords
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
//--------------------------------------------------------------
2327
template<class V, class N, class C, class T>
2328
ofMesh_<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;
2330
	if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) {
2331
		mode = OF_PRIMITIVE_TRIANGLE_STRIP;
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
//--------------------------------------------------------------
2520
template<class V, class N, class C, class T>
2521
ofMesh_<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;
2523
	if(mode != OF_PRIMITIVE_TRIANGLE_STRIP && mode != OF_PRIMITIVE_TRIANGLES) {
2524
		mode = OF_PRIMITIVE_TRIANGLE_STRIP;
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
//--------------------------------------------------------------
2670
template<class V, class N, class C, class T>
2671
ofMesh_<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;
2674
	mesh.setMode( OF_PRIMITIVE_TRIANGLES );
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
//--------------------------------------------------------------
2925
/// Returns an ofMesh representing an XYZ coordinate system.
2926
template<class V, class N, class C, class T>
2927
ofMesh_<V,N,C,T> ofMesh_<V,N,C,T>::axis( float size ) {
2928
	ofMesh_<V,N,C,T> mesh;
2929

2930
	// mesh only available as wireframe //
2931
	mesh.setMode(OF_PRIMITIVE_LINES);
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
//--------------------------------------------------------------
2959
template<class V, class N, class C, class T>
2960
ofMeshFace_<V,N,C,T>::ofMeshFace_()
2961
:bHasNormals(false)
2962
,bHasColors(false)
2963
,bHasTexcoords(false)
2964
,bFaceNormalDirty(false)
2965
{
2966
}
2967

2968
//--------------------------------------------------------------
2969
template<class V, class N, class C, class T>
2970
const N & ofMeshFace_<V,N,C,T>::getFaceNormal() const{
2971
	if(bFaceNormalDirty) calculateFaceNormal();
2972
	return faceNormal;
2973
}
2974

2975
//--------------------------------------------------------------
2976
template<class V, class N, class C, class T>
2977
void ofMeshFace_<V,N,C,T>::calculateFaceNormal() const{
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
//--------------------------------------------------------------
2989
template<class V, class N, class C, class T>
2990
void ofMeshFace_<V,N,C,T>::setVertex( ofIndexType index, const V& v ) {
2991
	vertices[index] = v;
2992
	bFaceNormalDirty = true;
2993
}
2994

2995
//--------------------------------------------------------------
2996
template<class V, class N, class C, class T>
2997
const V& ofMeshFace_<V,N,C,T>::getVertex( ofIndexType index ) const{
2998
	return vertices[index];
2999
}
3000

3001
//--------------------------------------------------------------
3002
template<class V, class N, class C, class T>
3003
void ofMeshFace_<V,N,C,T>::setNormal( ofIndexType index, const N& n ) {
3004
	normals[index] = n;
3005
	bHasNormals = true;
3006
}
3007

3008
//--------------------------------------------------------------
3009
template<class V, class N, class C, class T>
3010
const N& ofMeshFace_<V,N,C,T>::getNormal( ofIndexType index ) const{
3011
	return normals[ index ];
3012
}
3013

3014
//--------------------------------------------------------------
3015
template<class V, class N, class C, class T>
3016
void ofMeshFace_<V,N,C,T>::setColor( ofIndexType index, const C& color ) {
3017
	colors[index] = color;
3018
	bHasColors = true;
3019
}
3020

3021
//--------------------------------------------------------------
3022
template<class V, class N, class C, class T>
3023
const C& ofMeshFace_<V,N,C,T>::getColor( ofIndexType index) const{
3024
	return colors[index];
3025
}
3026

3027
//--------------------------------------------------------------
3028
template<class V, class N, class C, class T>
3029
void ofMeshFace_<V,N,C,T>::setTexCoord( ofIndexType index, const T& tCoord ) {
3030
	texCoords[index] = tCoord;
3031
	bHasTexcoords = true;
3032
}
3033

3034
//--------------------------------------------------------------
3035
template<class V, class N, class C, class T>
3036
const T& ofMeshFace_<V,N,C,T>::getTexCoord( ofIndexType index ) const{
3037
	return texCoords[index];
3038
}
3039

3040
//--------------------------------------------------------------
3041
template<class V, class N, class C, class T>
3042
void ofMeshFace_<V,N,C,T>::setHasColors( bool bColors ) {
3043
	bHasColors = bColors;
3044
}
3045

3046
//--------------------------------------------------------------
3047
template<class V, class N, class C, class T>
3048
void ofMeshFace_<V,N,C,T>::setHasNormals( bool bNormals ) {
3049
	bHasNormals = bNormals;
3050
}
3051

3052
//--------------------------------------------------------------
3053
template<class V, class N, class C, class T>
3054
void ofMeshFace_<V,N,C,T>::setHasTexcoords( bool bTexcoords ) {
3055
	bHasTexcoords = bTexcoords;
3056
}
3057

3058
//--------------------------------------------------------------
3059
template<class V, class N, class C, class T>
3060
bool ofMeshFace_<V,N,C,T>::hasColors() const{
3061
	return bHasColors;
3062
}
3063

3064
//--------------------------------------------------------------
3065
template<class V, class N, class C, class T>
3066
bool ofMeshFace_<V,N,C,T>::hasNormals() const{
3067
	return bHasNormals;
3068
}
3069

3070
//--------------------------------------------------------------
3071
template<class V, class N, class C, class T>
3072
bool ofMeshFace_<V,N,C,T>::hasTexcoords() const{
3073
	return bHasTexcoords;
3074
}
3075

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.