File indexing completed on 2026-04-09 07:49:39
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <ostream>
0023 #include <glm/glm.hpp>
0024 #include <glm/gtx/string_cast.hpp>
0025
0026 #include "stra.h"
0027 #include "s_bb.h"
0028 #include "NPFold.h"
0029
0030 struct SMesh
0031 {
0032 static SMesh* Concatenate(std::vector<const SMesh*>& submesh, int ridx );
0033
0034 static constexpr const bool DUMP = false ;
0035 static constexpr const int LIMIT = 50 ;
0036 static constexpr const char* NAME = "SMesh" ;
0037 static constexpr const char* VTX_SPEC = "3,GL_FLOAT,GL_FALSE,12,0,false" ;
0038 static constexpr const char* NRM_SPEC = "3,GL_FLOAT,GL_FALSE,12,0,false" ;
0039 static constexpr const char* MATROW_SPEC = "4,GL_FLOAT,GL_FALSE,64,0,false" ;
0040
0041 static constexpr const bool NRM_SMOOTH = true ;
0042
0043
0044 const char* name ;
0045 const char* loaddir ;
0046 glm::tmat4x4<double> tr0 = {} ;
0047 int nidx = -1 ;
0048
0049 std::vector<std::string> names ;
0050 int lvid = -1 ;
0051
0052 const NP* tri ;
0053 const NP* vtx ;
0054 const NP* nrm ;
0055
0056 glm::tvec3<float> mn = {} ;
0057 glm::tvec3<float> mx = {} ;
0058 glm::tvec4<float> ce = {} ;
0059
0060 struct zmax_functor {
0061 float operator()(const SMesh& mesh) const { return mesh.mx.z ; }
0062 };
0063
0064 struct extent_functor {
0065 float operator()(const SMesh& mesh) const { return mesh.ce.w ; }
0066 };
0067
0068
0069 static SMesh* Load(const char* dir, const char* rel );
0070 static SMesh* Load(const char* dir );
0071 static SMesh* LoadTransformed(const char* dir, const char* rel, const glm::tmat4x4<double>* tr );
0072 static SMesh* LoadTransformed(const char* dir, const glm::tmat4x4<double>* tr );
0073
0074 static SMesh* Import(const NPFold* fold, const glm::tmat4x4<double>* tr=nullptr, int nidx=-1 );
0075 static SMesh* MakeCopy( const SMesh* src );
0076 SMesh* copy() const ;
0077
0078 static bool IsConcat( const NPFold* fold );
0079 void import_( const NPFold* fold, const glm::tmat4x4<double>* tr );
0080 void import_concat( const NPFold* fold, const glm::tmat4x4<double>* tr );
0081 void import_original( const NPFold* fold, const glm::tmat4x4<double>* tr );
0082
0083 NPFold* serialize() const ;
0084 void save(const char* dir) const ;
0085
0086 SMesh();
0087
0088 const float* get_mn() const ;
0089 const float* get_mx() const ;
0090 const float* get_ce() const ;
0091
0092 void set_tri( const NP* _tri );
0093 int indices_num() const ;
0094 int indices_offset() const ;
0095 static const char* FormName(int ridx);
0096 void set_name(int ridx);
0097
0098 void set_vtx( const NP* wvtx, const glm::tmat4x4<double>* tr, std::ostream* out );
0099 void set_vtx_range();
0100
0101 template<typename T>
0102 static T Extent( const glm::tvec3<T>& low, const glm::tvec3<T>& high );
0103
0104 template<typename T>
0105 static glm::tvec4<T> CenterExtent( const glm::tvec3<T>& low, const glm::tvec3<T>& high );
0106
0107 template<typename T>
0108 static void FindCenterExtent(const NP* vtx, glm::tvec3<T>& mn, glm::tvec3<T>& mx, glm::tvec4<T>& ce );
0109
0110 template<typename T>
0111 static std::string Desc2D(const NP* a, int limit=200, const char* label=nullptr) ;
0112
0113 template<typename T, typename S>
0114 static std::string Desc2D(const NP* a, const NP* b, int limit=200, const char* label=nullptr);
0115
0116 std::string descTransform() const ;
0117
0118 std::string brief() const ;
0119 std::string desc() const ;
0120 std::string descTri() const ;
0121 std::string descVtx() const ;
0122 std::string descTriVtx() const ;
0123 std::string descVtxNrm() const ;
0124 std::string descName() const ;
0125 std::string descShape() const ;
0126 std::string descRange() const ;
0127 std::string descRangeNumPy() const ;
0128
0129
0130 static std::string Desc2D_Ref_2D_int_float(const NP* a, const NP* b, int limit, const char* label);
0131
0132
0133
0134 template<typename T> static void SmoothNormals(
0135 std::vector<glm::tvec3<T>>& nrm,
0136 const std::vector<glm::tvec3<T>>& vtx,
0137 const std::vector<glm::tvec3<int>>& tri,
0138 std::ostream* out );
0139
0140 template<typename T> static void FlatNormals(
0141 std::vector<glm::tvec3<T>>& nrm,
0142 const std::vector<glm::tvec3<T>>& vtx,
0143 const std::vector<glm::tvec3<int>>& tri,
0144 std::ostream* out );
0145
0146
0147 static NP* MakeNormals( const NP* a_vtx, const NP* a_tri, bool smooth, std::ostream* out );
0148 };
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 inline SMesh* SMesh::Concatenate(std::vector<const SMesh*>& submesh, int ridx )
0162 {
0163 SMesh* com = new SMesh ;
0164 com->set_name(ridx);
0165
0166 std::vector<const NP*> subtri ;
0167 std::vector<const NP*> subvtx ;
0168 std::vector<const NP*> subnrm ;
0169
0170 int tot_vtx = 0 ;
0171 for(int i=0 ; i < int(submesh.size()) ; i++)
0172 {
0173 const SMesh* sub = submesh[i] ;
0174 com->names.push_back(sub->name ? sub->name : "-" );
0175
0176 const NP* _tri = sub->tri ;
0177 const NP* _vtx = sub->vtx ;
0178 const NP* _nrm = sub->nrm ;
0179
0180 int num_vtx = _vtx->num_items() ;
0181 [[maybe_unused]] int num_nrm = _nrm->num_items() ;
0182 assert( num_vtx == num_nrm );
0183
0184 subtri.push_back(NP::Incremented(_tri, tot_vtx)) ;
0185 subvtx.push_back(_vtx) ;
0186 subnrm.push_back(_nrm) ;
0187
0188 tot_vtx += num_vtx ;
0189 }
0190 com->tri = NP::Concatenate(subtri) ;
0191 com->vtx = NP::Concatenate(subvtx) ;
0192 com->nrm = NP::Concatenate(subnrm) ;
0193 com->set_vtx_range();
0194
0195 return com ;
0196 }
0197
0198 inline SMesh* SMesh::Load(const char* dir, const char* rel )
0199 {
0200 if(DUMP) std::cout << "SMesh::Load dir " << ( dir ? dir : "-" ) << " rel " << ( rel ? rel : "-" ) << "\n" ;
0201 NPFold* fold = NPFold::Load(dir, rel) ;
0202 return Import(fold, nullptr);
0203 }
0204 inline SMesh* SMesh::Load(const char* dir)
0205 {
0206 if(DUMP) std::cout << "SMesh::Load dir " << ( dir ? dir : "-" ) << "\n" ;
0207 NPFold* fold = NPFold::Load(dir) ;
0208 return Import(fold, nullptr);
0209 }
0210
0211 inline SMesh* SMesh::LoadTransformed(const char* dir, const char* rel, const glm::tmat4x4<double>* tr)
0212 {
0213 NPFold* fold = NPFold::Load(dir, rel) ;
0214 return Import(fold, tr);
0215 }
0216 inline SMesh* SMesh::LoadTransformed(const char* dir, const glm::tmat4x4<double>* tr)
0217 {
0218 NPFold* fold = NPFold::Load(dir) ;
0219 return Import(fold, tr);
0220 }
0221
0222
0223 inline SMesh* SMesh::Import(const NPFold* fold, const glm::tmat4x4<double>* tr, int nidx)
0224 {
0225
0226
0227 SMesh* mesh = new SMesh ;
0228 mesh->import_(fold, tr);
0229 mesh->nidx = nidx ;
0230 mesh->loaddir = fold->loaddir ? strdup(fold->loaddir) : nullptr ;
0231 return mesh ;
0232 }
0233
0234 inline SMesh* SMesh::MakeCopy( const SMesh* src )
0235 {
0236 SMesh* dst = new SMesh ;
0237
0238 dst->name = src->name ? strdup(src->name) : nullptr ;
0239 dst->tr0 = src->tr0 ;
0240 dst->nidx = src->nidx ;
0241 dst->loaddir = src->loaddir ? strdup(src->loaddir) : nullptr ;
0242 dst->names = src->names ;
0243 dst->lvid = src->lvid ;
0244
0245 dst->tri = src->tri->copy() ;
0246 dst->vtx = src->vtx->copy() ;
0247 dst->nrm = src->nrm->copy() ;
0248
0249 dst->mn = src->mn ;
0250 dst->mx = src->mx ;
0251 dst->ce = src->ce ;
0252
0253 return dst ;
0254 }
0255
0256 inline SMesh* SMesh::copy() const
0257 {
0258 return MakeCopy(this);
0259 }
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 inline bool SMesh::IsConcat( const NPFold* fold )
0276 {
0277 const NP* vertices = fold->get("vtx") ;
0278 const NP* normals = fold->get("nrm") ;
0279 return vertices && vertices->ebyte == 4 && normals ;
0280 }
0281
0282 inline void SMesh::import_(const NPFold* fold, const glm::tmat4x4<double>* tr )
0283 {
0284 lvid = fold->get_meta<int>("lvid", -1);
0285 bool is_concat = IsConcat( fold );
0286 if(DUMP) std::cout << "SMesh::import lvid " << lvid << " is_concat " << is_concat << "\n" ;
0287
0288 if( is_concat )
0289 {
0290 import_concat( fold, tr ) ;
0291 }
0292 else
0293 {
0294 import_original( fold, tr );
0295 }
0296
0297
0298 }
0299
0300 inline void SMesh::import_concat(const NPFold* fold, const glm::tmat4x4<double>* tr )
0301 {
0302 assert( tr == nullptr );
0303
0304 const NP* triangles = fold->get("tri");
0305 const NP* vertices = fold->get("vtx") ;
0306 const NP* normals = fold->get("nrm") ;
0307
0308 tri = triangles ;
0309 vtx = vertices ;
0310 nrm = normals ;
0311
0312 assert( tri );
0313 assert( vtx );
0314 assert( nrm );
0315
0316 set_vtx_range();
0317 }
0318
0319 inline void SMesh::import_original(const NPFold* fold, const glm::tmat4x4<double>* tr )
0320 {
0321 name = fold->loaddir ? strdup(fold->loaddir) : nullptr ;
0322
0323 const NP* triangles = fold->get("tri");
0324 const NP* vertices = fold->get("vtx") ;
0325 const NP* normals = fold->get("nrm") ;
0326
0327 bool valid_import_original = lvid > -1 && triangles != nullptr && vertices != nullptr && normals == nullptr ;
0328 if(!valid_import_original) std::cerr
0329 << "SMesh::import_original\n"
0330 << " FATAL : FAILED IMPORT \n"
0331 << " valid_import_original " << ( valid_import_original ? "YES" : "NO ") << "\n"
0332 << " triangles " << ( triangles ? "YES" : "NO " ) << "\n"
0333 << " vertices " << ( vertices ? "YES" : "NO " ) << "\n"
0334 << " normals " << ( normals ? "YES" : "NO " ) << " (not execting normals in originals)\n"
0335 << " name " << ( name ? name : "-" ) << "\n"
0336 << " lvid " << lvid
0337 << "\n"
0338 ;
0339
0340 assert(valid_import_original);
0341 assert( normals == nullptr );
0342
0343 bool dump = false ;
0344 std::stringstream ss ;
0345 std::ostream* out = dump ? &ss : nullptr ;
0346
0347 if(out) *out << "[SMesh::import_original" << std::endl ;
0348
0349 set_tri( triangles );
0350 set_vtx( vertices, tr, out );
0351 set_vtx_range();
0352
0353 if(out) *out << "]SMesh::import_original" << std::endl ;
0354 if(dump) std::cout << ss.str() ;
0355 }
0356
0357
0358 inline NPFold* SMesh::serialize() const
0359 {
0360 NPFold* fold = new NPFold ;
0361 fold->add("tri", tri);
0362 fold->add("vtx", vtx);
0363 fold->add("nrm", nrm);
0364 fold->names = names ;
0365 fold->set_meta<int>("lvid", lvid) ;
0366 return fold ;
0367 }
0368 inline void SMesh::save(const char* dir) const
0369 {
0370 NPFold* fold = serialize();
0371 fold->save(dir);
0372 }
0373
0374
0375 inline SMesh::SMesh()
0376 :
0377 name(nullptr),
0378 tr0(1.),
0379 tri(nullptr),
0380 vtx(nullptr),
0381 nrm(nullptr),
0382 mn(0.f),
0383 mx(0.f),
0384 ce(0.f)
0385 {
0386 }
0387
0388 inline const float* SMesh::get_mn() const { return glm::value_ptr(mn); }
0389 inline const float* SMesh::get_mx() const { return glm::value_ptr(mx); }
0390 inline const float* SMesh::get_ce() const { return glm::value_ptr(ce); }
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401 inline void SMesh::set_tri( const NP* _tri )
0402 {
0403 tri = _tri ;
0404 assert( tri->uifc == 'i' );
0405 assert( tri->ebyte == 4 );
0406 }
0407
0408 inline int SMesh::indices_num() const
0409 {
0410 if(tri == nullptr) return 0 ;
0411 assert( tri->shape.size() == 2 );
0412 return tri->num_values() ;
0413 }
0414 inline int SMesh::indices_offset() const
0415 {
0416 return 0 ;
0417 }
0418
0419 inline const char* SMesh::FormName(int ridx)
0420 {
0421 std::stringstream ss ;
0422 ss << ridx ;
0423 std::string str = ss.str();
0424 return strdup( str.c_str() );
0425 }
0426 inline void SMesh::set_name( int ridx )
0427 {
0428 name = FormName(ridx);
0429 }
0430
0431
0432
0433 inline void SMesh::set_vtx( const NP* _vtx, const glm::tmat4x4<double>* tr, std::ostream* out )
0434 {
0435 assert( tri );
0436
0437 assert( _vtx->uifc == 'f' );
0438 assert( _vtx->ebyte == 8 );
0439
0440 assert( _vtx->shape.size() == 2 );
0441 assert( _vtx->shape[0] > 2 );
0442 assert( _vtx->shape[1] == 3 );
0443
0444 if(tr) memcpy( glm::value_ptr(tr0), glm::value_ptr(*tr), sizeof(tr0) );
0445 NP* wvtx = stra<double>::MakeTransformedArray( _vtx, tr );
0446 NP* wnrm = MakeNormals( wvtx, tri, NRM_SMOOTH, out );
0447
0448 vtx = NP::MakeNarrowIfWide(wvtx);
0449 nrm = NP::MakeNarrowIfWide(wnrm);
0450 }
0451
0452 inline void SMesh::set_vtx_range()
0453 {
0454 FindCenterExtent(vtx, mn, mx, ce);
0455 }
0456
0457 template<typename T>
0458 inline std::string SMesh::Desc2D(const NP* a, int limit, const char* label)
0459 {
0460 std::stringstream ss ;
0461 if(label) ss << "[ " << label << std::endl ;
0462 if(a == nullptr)
0463 {
0464 ss << " (null) " << std::endl ;
0465 }
0466 else
0467 {
0468 const T* vv = a->cvalues<T>();
0469 int ni = a->shape[0] ;
0470 int nj = a->shape[1] ;
0471
0472 for(int i=0 ; i < ni ; i++)
0473 {
0474 bool emit = i < limit || i > ni - limit ;
0475 if(!emit) continue ;
0476
0477 ss << std::setw(3) << i << " : " ;
0478 for(int j=0 ; j < nj ; j++)
0479 {
0480 int idx = i*nj + j ;
0481 if( a->uifc == 'i' || a->uifc == 'u' )
0482 {
0483 ss << std::setw(3) << vv[idx] << " " ;
0484 }
0485 else
0486 {
0487 ss << std::setw(7) << std::fixed << std::setprecision(2) << vv[idx] << " " ;
0488 }
0489 }
0490 ss << std::endl ;
0491 }
0492 }
0493 if(label) ss << "] " << label << std::endl ;
0494 std::string str = ss.str() ;
0495 return str ;
0496 }
0497
0498
0499
0500 template<typename T, typename S>
0501 inline std::string SMesh::Desc2D(const NP* a, const NP* b, int limit, const char* label)
0502 {
0503
0504 std::stringstream ss ;
0505 if(label) ss << "[" << label << std::endl ;
0506
0507 if( a == nullptr || b == nullptr )
0508 {
0509 ss << " missing a or b " << std::endl ;
0510 }
0511 else
0512 {
0513
0514 const T* a_vv = a->cvalues<T>();
0515 int a_ni = a->shape[0] ;
0516 int a_nj = a->shape[1] ;
0517
0518 const S* b_vv = b->cvalues<T>();
0519 [[maybe_unused]] int b_ni = b->shape[0] ;
0520 int b_nj = b->shape[1] ;
0521
0522 assert( a_ni == b_ni );
0523 int ni = a_ni ;
0524
0525 for(int i=0 ; i < ni ; i++)
0526 {
0527 bool emit = i < limit || i > (ni - limit) ;
0528 if(!emit) continue ;
0529
0530 ss << std::setw(3) << i << " : " ;
0531
0532 for(int j=0 ; j < a_nj ; j++)
0533 {
0534 int idx = i*a_nj + j ;
0535 if( a->uifc == 'i' || a->uifc == 'u' )
0536 {
0537 ss << std::setw(3) << a_vv[idx] << " " ;
0538 }
0539 else
0540 {
0541 ss << std::setw(7) << std::fixed << std::setprecision(2) << a_vv[idx] << " " ;
0542 }
0543 }
0544
0545 for(int j=0 ; j < b_nj ; j++)
0546 {
0547 int idx = i*b_nj + j ;
0548 if( b->uifc == 'i' || b->uifc == 'u' )
0549 {
0550 ss << std::setw(3) << b_vv[idx] << " " ;
0551 }
0552 else
0553 {
0554 ss << std::setw(7) << std::fixed << std::setprecision(2) << b_vv[idx] << " " ;
0555 }
0556 }
0557 ss << std::endl ;
0558
0559 }
0560 }
0561 if(label) ss << "]" << label << std::endl ;
0562 std::string str = ss.str() ;
0563 return str ;
0564 }
0565
0566 inline std::string SMesh::descTransform() const
0567 {
0568 return stra<double>::Desc(tr0);
0569 }
0570
0571 inline std::string SMesh::brief() const
0572 {
0573 std::stringstream ss ;
0574 ss << "SMesh::brief " ;
0575
0576 ss << " tri " << tri->sstr() ;
0577 ss << " vtx " << vtx->sstr() ;
0578 ss << " nrm " << nrm->sstr() ;
0579
0580 std::string str = ss.str() ;
0581 return str ;
0582 }
0583
0584
0585 inline std::string SMesh::descTri() const
0586 {
0587 return Desc2D<int>(tri,LIMIT, "SMesh::descTri") ;
0588 }
0589 inline std::string SMesh::descVtx() const
0590 {
0591 return Desc2D<float>(vtx,LIMIT,"SMesh::descVtx") ;
0592 }
0593
0594 inline std::string SMesh::descTriVtx() const
0595 {
0596 return Desc2D_Ref_2D_int_float(tri,vtx,LIMIT/3,"SMesh::descTriVtx") ;
0597 }
0598 inline std::string SMesh::descVtxNrm() const
0599 {
0600 return Desc2D<float,float>(vtx,nrm,LIMIT,"SMesh::descVtxNrm") ;
0601 }
0602
0603
0604
0605 inline std::string SMesh::Desc2D_Ref_2D_int_float(const NP* a, const NP* b, int limit, const char* label)
0606 {
0607 std::stringstream ss ;
0608 if(label) ss << "[ " << label << std::endl ;
0609 if( a == nullptr || b == nullptr )
0610 {
0611 ss << " a or b missing " << std::endl ;
0612 }
0613 else
0614 {
0615 const int* a_vv = a->cvalues<int>();
0616 int a_ni = a->shape[0] ;
0617 int a_nj = a->shape[1] ;
0618
0619 const float* b_vv = b->cvalues<float>();
0620 [[maybe_unused]] int b_ni = b->shape[0] ;
0621 int b_nj = b->shape[1] ;
0622
0623 for(int i=0 ; i < a_ni ; i++)
0624 {
0625 bool emit = i < limit || i > (a_ni - limit) ;
0626 if(!emit) continue ;
0627
0628 for(int j=0 ; j < a_nj ; j++)
0629 {
0630 int a_idx = i*a_nj + j ;
0631 int v = a_vv[a_idx] ;
0632 assert( v < b_ni );
0633
0634 ss << std::setw(3) << v << " : " ;
0635 for(int bj=0 ; bj < b_nj ; bj++)
0636 {
0637 int b_idx = v*b_nj + bj ;
0638 ss << std::setw(7) << std::fixed << std::setprecision(2) << b_vv[b_idx] << " " ;
0639 }
0640 ss << std::endl ;
0641
0642 }
0643 ss << std::endl ;
0644 }
0645 }
0646 if(label) ss << "] " << label << std::endl ;
0647 std::string str = ss.str() ;
0648 return str ;
0649 }
0650
0651 inline std::string SMesh::desc() const
0652 {
0653 std::stringstream ss ;
0654 ss
0655 << "[SMesh::desc"
0656 << std::endl
0657 << descName()
0658 << descShape()
0659 << std::endl
0660 << descRange()
0661 << std::endl
0662 << descTri()
0663 << std::endl
0664 << descVtx()
0665 << std::endl
0666 << descTriVtx()
0667 << std::endl
0668 << descVtxNrm()
0669 << std::endl
0670 << "]SMesh::desc"
0671 << std::endl
0672 ;
0673
0674 std::string str = ss.str();
0675 return str ;
0676 }
0677
0678 inline std::string SMesh::descName() const
0679 {
0680 static const char * SPACER = "ridx 0 pidx 36 " ;
0681
0682 std::stringstream ss ;
0683 ss
0684 << " lvid " << std::setw(3) << lvid
0685 << std::setw(strlen(SPACER)) << " "
0686 ;
0687 std::string str = ss.str();
0688 return str ;
0689 }
0690
0691 inline std::string SMesh::descShape() const
0692 {
0693 std::stringstream ss ;
0694 ss
0695 << "SMesh::descShape" << std::endl
0696 << " tri " << ( tri ? tri->sstr() : "-" )
0697 << " vtx " << ( vtx ? vtx->sstr() : "-" )
0698 << " indices_num " << indices_num()
0699 << " indices_offset " << indices_offset()
0700 ;
0701 std::string str = ss.str();
0702 return str ;
0703 }
0704
0705 inline std::string SMesh::descRange() const
0706 {
0707 std::array<float,6> bb = {mn[0],mn[1],mn[2],mx[0],mx[1],mx[2]} ;
0708
0709 const float* _bb = bb.data();
0710 const float* _ce = glm::value_ptr(ce);
0711
0712 std::stringstream ss ;
0713 ss << "SMesh::descRange " ;
0714 ss << " ce " << s_bb::Desc_<float,4>( _ce ) ;
0715 ss << " bb " << s_bb::Desc_<float,6>( _bb) ;
0716 ss << descName() ;
0717 std::string str = ss.str();
0718 return str ;
0719 }
0720
0721 inline std::string SMesh::descRangeNumPy() const
0722 {
0723 std::array<float,6> bb = {mn[0],mn[1],mn[2],mx[0],mx[1],mx[2]} ;
0724 const float* _ce = glm::value_ptr(ce);
0725 const float* _bb = bb.data();
0726
0727 std::stringstream ss ;
0728 ss << s_bb::DescNumPy_<float,4>( _ce, "ce", false ) ;
0729 ss << s_bb::DescNumPy_<float,6>( _bb, "bb", false ) ;
0730 ss << " # SMesh::descRangeNumPy " << descName() ;
0731 std::string str = ss.str();
0732 return str ;
0733 }
0734
0735
0736
0737
0738
0739
0740
0741 template<typename T>
0742 inline T SMesh::Extent( const glm::tvec3<T>& low, const glm::tvec3<T>& high )
0743 {
0744 glm::tvec3<T> dim(high.x - low.x, high.y - low.y, high.z - low.z );
0745 T _extent(0) ;
0746 _extent = std::max( dim.x , _extent );
0747 _extent = std::max( dim.y , _extent );
0748 _extent = std::max( dim.z , _extent );
0749 _extent = _extent / T(2) ;
0750 return _extent ;
0751 }
0752
0753
0754 template<typename T>
0755 inline glm::tvec4<T> SMesh::CenterExtent( const glm::tvec3<T>& low, const glm::tvec3<T>& high )
0756 {
0757 glm::tvec3<T> center = (low + high)/T(2) ;
0758 glm::tvec4<T> _ce ;
0759 _ce.x = center.x ;
0760 _ce.y = center.y ;
0761 _ce.z = center.z ;
0762 _ce.w = Extent<T>( low, high );
0763 return _ce ;
0764 }
0765
0766
0767 template<typename T>
0768 inline void SMesh::FindCenterExtent(const NP* vtx, glm::tvec3<T>& mn, glm::tvec3<T>& mx, glm::tvec4<T>& ce )
0769 {
0770 assert( vtx->ebyte == sizeof(T) );
0771 int item_stride = 1 ;
0772 int item_offset = 0 ;
0773 const_cast<NP*>(vtx)->minmax2D_reshaped<3,T>(&mn.x, &mx.x, item_stride, item_offset );
0774 ce = CenterExtent<T>( mn, mx );
0775 }
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820
0821
0822
0823
0824
0825
0826
0827
0828 template<typename T>
0829 inline void SMesh::SmoothNormals(
0830 std::vector<glm::tvec3<T>>& nrm,
0831 const std::vector<glm::tvec3<T>>& vtx,
0832 const std::vector<glm::tvec3<int>>& tri,
0833 std::ostream* out )
0834 {
0835 int num_vtx = vtx.size();
0836 int num_tri = tri.size();
0837
0838 typedef glm::tvec3<T> R3 ;
0839 typedef glm::tvec3<int> I3 ;
0840
0841 nrm.resize(num_vtx);
0842 for(int i=0 ; i < num_vtx ; i++) nrm[i] = R3{} ;
0843
0844 for(int i=0 ; i < num_tri ; i++)
0845 {
0846 const I3& t = tri[i] ;
0847 if(out) *out << " tri[" << i << "] " << glm::to_string(t) << std::endl ;
0848
0849 bool x_expected = t.x > -1 && t.x < num_vtx ;
0850 bool y_expected = t.y > -1 && t.y < num_vtx ;
0851 bool z_expected = t.z > -1 && t.z < num_vtx ;
0852
0853 bool expected = x_expected && y_expected && z_expected ;
0854
0855 if(!expected ) std::cout
0856 << "SMesh::SmoothNormals"
0857 << " FATAL NOT expected "
0858 << " i [" << i << "] "
0859 << " t [" << glm::to_string(t) << "]"
0860 << " num_vtx " << num_vtx
0861 << " num_tri " << num_tri
0862 << std::endl
0863 ;
0864
0865 assert( x_expected );
0866 assert( y_expected );
0867 assert( z_expected );
0868
0869 const R3& v0 = vtx[t.x] ;
0870 const R3& v1 = vtx[t.y] ;
0871 const R3& v2 = vtx[t.z] ;
0872
0873 R3 n = glm::cross(v1-v0, v2-v0) ;
0874
0875 nrm[t.x] += n ;
0876 nrm[t.y] += n ;
0877 nrm[t.z] += n ;
0878 }
0879 for(int i=0 ; i < num_vtx ; i++) nrm[i] = glm::normalize( nrm[i] );
0880 }
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890
0891 template<typename T>
0892 inline void SMesh::FlatNormals(
0893 std::vector<glm::tvec3<T>>& nrm,
0894 const std::vector<glm::tvec3<T>>& vtx,
0895 const std::vector<glm::tvec3<int>>& tri,
0896 std::ostream* out )
0897 {
0898 int num_vtx = vtx.size();
0899 int num_tri = tri.size();
0900
0901 typedef glm::tvec3<T> R3 ;
0902 typedef glm::tvec3<int> I3 ;
0903
0904 nrm.resize(num_vtx);
0905
0906 for(int i=0 ; i < num_tri ; i++)
0907 {
0908 const I3& t = tri[i] ;
0909 assert( t.x > -1 && t.x < num_vtx );
0910 assert( t.y > -1 && t.y < num_vtx );
0911 assert( t.z > -1 && t.z < num_vtx );
0912
0913 const R3& v0 = vtx[t.x] ;
0914 const R3& v1 = vtx[t.y] ;
0915 const R3& v2 = vtx[t.z] ;
0916
0917 R3 n = glm::cross(v1-v0, v2-v0) ;
0918
0919 nrm[t.x] = n ;
0920 nrm[t.y] = n ;
0921 nrm[t.z] = n ;
0922 }
0923 }
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933 inline NP* SMesh::MakeNormals( const NP* a_vtx, const NP* a_tri, bool smooth, std::ostream* out )
0934 {
0935 int num_vtx = a_vtx ? a_vtx->shape[0] : 0 ;
0936 int num_tri = a_tri ? a_tri->shape[0] : 0 ;
0937
0938 if(out) *out
0939 << "[ SMesh::MakeNormals "
0940 << " num_vtx " << num_vtx
0941 << " num_tri " << num_tri
0942 << std::endl
0943 ;
0944
0945 typedef glm::tvec3<double> D3 ;
0946 typedef glm::tvec3<float> F3 ;
0947 typedef glm::tvec3<int> I3 ;
0948
0949 assert( sizeof(D3) == sizeof(double)*3 );
0950 assert( sizeof(F3) == sizeof(float)*3 );
0951 assert( sizeof(I3) == sizeof(int)*3 );
0952
0953 std::vector<I3> tri(num_tri) ;
0954 assert( NP::INT(sizeof(I3)*tri.size()) == a_tri->arr_bytes() );
0955 memcpy( tri.data(), a_tri->bytes(), a_tri->arr_bytes() );
0956
0957 NP* a_nrm = nullptr ;
0958 if( a_vtx->ebyte == 8 )
0959 {
0960 std::vector<D3> vtx(num_vtx) ;
0961 std::vector<D3> nrm(num_vtx, {0,0,0}) ;
0962 assert( NP::INT(sizeof(D3)*vtx.size()) == a_vtx->arr_bytes() );
0963 memcpy( vtx.data(), a_vtx->bytes(), a_vtx->arr_bytes() );
0964
0965 if(smooth)
0966 {
0967 SmoothNormals<double>( nrm, vtx, tri, out );
0968 }
0969 else
0970 {
0971 FlatNormals<double>( nrm, vtx, tri, out );
0972 }
0973
0974 a_nrm = NP::Make<double>( num_vtx, 3 );
0975 memcpy( a_nrm->bytes(), nrm.data(), a_nrm->arr_bytes() );
0976 }
0977 else if( a_vtx->ebyte == 4 )
0978 {
0979 std::vector<F3> vtx(num_vtx) ;
0980 std::vector<F3> nrm(num_vtx, {0.f,0.f,0.f}) ;
0981 assert( NP::INT(sizeof(F3)*vtx.size()) == a_vtx->arr_bytes() );
0982 memcpy( vtx.data(), a_vtx->bytes(), a_vtx->arr_bytes() );
0983
0984 if(smooth)
0985 {
0986 SmoothNormals<float>( nrm, vtx, tri, out );
0987 }
0988 else
0989 {
0990 FlatNormals<float>( nrm, vtx, tri, out );
0991 }
0992
0993 a_nrm = NP::Make<float>( num_vtx, 3 );
0994 memcpy( a_nrm->bytes(), nrm.data(), a_nrm->arr_bytes() );
0995 }
0996
0997 if(out) *out
0998 << "] SMesh::MakeNormals "
0999 << " a_vtx " << ( a_vtx ? a_vtx->sstr() : "-" )
1000 << " a_tri " << ( a_tri ? a_tri->sstr() : "-" )
1001 << " a_nrm " << ( a_nrm ? a_nrm->sstr() : "-" )
1002 << " num_vtx " << num_vtx
1003 << " num_tri " << num_tri
1004 << std::endl
1005 ;
1006
1007 return a_nrm ;
1008 }
1009
1010