You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

783 lines
19 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <iostream>
  25. #include <sstream>
  26. #include <wx/log.h>
  27. #include "3d_cache/sg/sg_shape.h"
  28. #include "3d_cache/sg/sg_faceset.h"
  29. #include "3d_cache/sg/sg_appearance.h"
  30. #include "3d_cache/sg/sg_helpers.h"
  31. #include "3d_cache/sg/sg_coordindex.h"
  32. #include "3d_cache/sg/sg_coords.h"
  33. #include "3d_cache/sg/sg_colors.h"
  34. #include "3d_cache/sg/sg_normals.h"
  35. SGSHAPE::SGSHAPE( SGNODE* aParent ) : SGNODE( aParent )
  36. {
  37. m_SGtype = S3D::SGTYPE_SHAPE;
  38. m_Appearance = nullptr;
  39. m_RAppearance = nullptr;
  40. m_FaceSet = nullptr;
  41. m_RFaceSet = nullptr;
  42. if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
  43. {
  44. m_Parent = nullptr;
  45. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGSHAPE (type %d)" ),
  46. __FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
  47. }
  48. else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
  49. {
  50. m_Parent->AddChildNode( this );
  51. }
  52. }
  53. SGSHAPE::~SGSHAPE()
  54. {
  55. // drop references
  56. if( m_RAppearance )
  57. {
  58. m_RAppearance->delNodeRef( this );
  59. m_RAppearance = nullptr;
  60. }
  61. if( m_RFaceSet )
  62. {
  63. m_RFaceSet->delNodeRef( this );
  64. m_RFaceSet = nullptr;
  65. }
  66. // delete objects
  67. if( m_Appearance )
  68. {
  69. m_Appearance->SetParent( nullptr, false );
  70. delete m_Appearance;
  71. m_Appearance = nullptr;
  72. }
  73. if( m_FaceSet )
  74. {
  75. m_FaceSet->SetParent( nullptr, false );
  76. delete m_FaceSet;
  77. m_FaceSet = nullptr;
  78. }
  79. }
  80. bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
  81. {
  82. if( nullptr != m_Parent )
  83. {
  84. if( aParent == m_Parent )
  85. return true;
  86. // handle the change in parents
  87. if( notify )
  88. m_Parent->unlinkChildNode( this );
  89. m_Parent = nullptr;
  90. if( nullptr == aParent )
  91. return true;
  92. }
  93. // only a SGTRANSFORM may be parent to a SGSHAPE
  94. if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
  95. return false;
  96. m_Parent = aParent;
  97. if( m_Parent )
  98. m_Parent->AddChildNode( this );
  99. return true;
  100. }
  101. SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
  102. {
  103. if( nullptr == aNodeName || 0 == aNodeName[0] )
  104. return nullptr;
  105. if( !m_Name.compare( aNodeName ) )
  106. return this;
  107. SGNODE* tmp = nullptr;
  108. if( nullptr != m_Appearance )
  109. {
  110. tmp = m_Appearance->FindNode( aNodeName, this );
  111. if( tmp )
  112. {
  113. return tmp;
  114. }
  115. }
  116. if( nullptr != m_FaceSet )
  117. {
  118. tmp = m_FaceSet->FindNode( aNodeName, this );
  119. if( tmp )
  120. {
  121. return tmp;
  122. }
  123. }
  124. // query the parent if appropriate
  125. if( aCaller == m_Parent || nullptr == m_Parent )
  126. return nullptr;
  127. return m_Parent->FindNode( aNodeName, this );
  128. }
  129. void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
  130. {
  131. if( nullptr == aNode )
  132. return;
  133. if( isChild )
  134. {
  135. if( aNode == m_Appearance )
  136. {
  137. m_Appearance = nullptr;
  138. return;
  139. }
  140. if( aNode == m_FaceSet )
  141. {
  142. m_FaceSet = nullptr;
  143. return;
  144. }
  145. }
  146. else
  147. {
  148. if( aNode == m_RAppearance )
  149. {
  150. delNodeRef( this );
  151. m_RAppearance = nullptr;
  152. return;
  153. }
  154. if( aNode == m_RFaceSet )
  155. {
  156. delNodeRef( this );
  157. m_RFaceSet = nullptr;
  158. return;
  159. }
  160. }
  161. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
  162. __FILE__, __FUNCTION__, __LINE__ );
  163. }
  164. void SGSHAPE::unlinkChildNode( const SGNODE* aNode )
  165. {
  166. unlinkNode( aNode, true );
  167. }
  168. void SGSHAPE::unlinkRefNode( const SGNODE* aNode )
  169. {
  170. unlinkNode( aNode, false );
  171. }
  172. bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
  173. {
  174. wxCHECK( aNode, false );
  175. if( S3D::SGTYPE_APPEARANCE == aNode->GetNodeType() )
  176. {
  177. if( m_Appearance || m_RAppearance )
  178. {
  179. if( aNode != m_Appearance && aNode != m_RAppearance )
  180. {
  181. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Appearance "
  182. "nodes" ),
  183. __FILE__, __FUNCTION__, __LINE__ );
  184. return false;
  185. }
  186. return true;
  187. }
  188. if( isChild )
  189. {
  190. m_Appearance = (SGAPPEARANCE*)aNode;
  191. m_Appearance->SetParent( this );
  192. }
  193. else
  194. {
  195. m_RAppearance = (SGAPPEARANCE*)aNode;
  196. m_RAppearance->addNodeRef( this );
  197. }
  198. return true;
  199. }
  200. if( S3D::SGTYPE_FACESET == aNode->GetNodeType() )
  201. {
  202. if( m_FaceSet || m_RFaceSet )
  203. {
  204. if( aNode != m_FaceSet && aNode != m_RFaceSet )
  205. {
  206. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple FaceSet nodes" ),
  207. __FILE__, __FUNCTION__, __LINE__ );
  208. return false;
  209. }
  210. return true;
  211. }
  212. if( isChild )
  213. {
  214. m_FaceSet = (SGFACESET*)aNode;
  215. m_FaceSet->SetParent( this );
  216. }
  217. else
  218. {
  219. m_RFaceSet = (SGFACESET*)aNode;
  220. m_RFaceSet->addNodeRef( this );
  221. }
  222. return true;
  223. }
  224. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object %s is not a valid type for this "
  225. "object (%d)" ),
  226. __FILE__, __FUNCTION__, __LINE__, aNode->GetName(), aNode->GetNodeType() );
  227. return false;
  228. }
  229. bool SGSHAPE::AddRefNode( SGNODE* aNode )
  230. {
  231. return addNode( aNode, false );
  232. }
  233. bool SGSHAPE::AddChildNode( SGNODE* aNode )
  234. {
  235. return addNode( aNode, true );
  236. }
  237. void SGSHAPE::ReNameNodes( void )
  238. {
  239. m_written = false;
  240. // rename this node
  241. m_Name.clear();
  242. GetName();
  243. // rename Appearance
  244. if( m_Appearance )
  245. m_Appearance->ReNameNodes();
  246. // rename FaceSet
  247. if( m_FaceSet )
  248. m_FaceSet->ReNameNodes();
  249. }
  250. bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
  251. {
  252. if( !m_Appearance && !m_RAppearance && !m_FaceSet && !m_RFaceSet )
  253. {
  254. return false;
  255. }
  256. if( aReuseFlag )
  257. {
  258. if( !m_written )
  259. {
  260. aFile << "DEF " << GetName() << " Shape {\n";
  261. m_written = true;
  262. }
  263. else
  264. {
  265. aFile << " USE " << GetName() << "\n";
  266. return true;
  267. }
  268. }
  269. else
  270. {
  271. aFile << " Shape {\n";
  272. }
  273. if( m_Appearance )
  274. m_Appearance->WriteVRML( aFile, aReuseFlag );
  275. if( m_RAppearance )
  276. m_RAppearance->WriteVRML( aFile, aReuseFlag );
  277. if( m_FaceSet )
  278. m_FaceSet->WriteVRML( aFile, aReuseFlag );
  279. if( m_RFaceSet )
  280. m_RFaceSet->WriteVRML( aFile, aReuseFlag );
  281. aFile << "}\n";
  282. return true;
  283. }
  284. bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
  285. {
  286. if( nullptr == parentNode )
  287. {
  288. wxCHECK( m_Parent, false );
  289. SGNODE* np = m_Parent;
  290. while( nullptr != np->GetParent() )
  291. np = np->GetParent();
  292. if( np->WriteCache( aFile, nullptr ) )
  293. {
  294. m_written = true;
  295. return true;
  296. }
  297. return false;
  298. }
  299. wxCHECK( parentNode == m_Parent, false );
  300. if( !aFile.good() )
  301. {
  302. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] bad stream" ),
  303. __FILE__, __FUNCTION__, __LINE__ );
  304. return false;
  305. }
  306. // check if any references are unwritten and swap parents if so
  307. if( nullptr != m_RAppearance && !m_RAppearance->isWritten() )
  308. m_RAppearance->SwapParent(this);
  309. if( nullptr != m_RFaceSet && !m_RFaceSet->isWritten() )
  310. m_RFaceSet->SwapParent( this );
  311. aFile << "[" << GetName() << "]";
  312. #define NITEMS 4
  313. bool items[NITEMS];
  314. int i;
  315. for( i = 0; i < NITEMS; ++i )
  316. items[i] = 0;
  317. i = 0;
  318. if( nullptr != m_Appearance )
  319. items[i] = true;
  320. ++i;
  321. if( nullptr != m_RAppearance )
  322. items[i] = true;
  323. ++i;
  324. if( nullptr != m_FaceSet )
  325. items[i] = true;
  326. ++i;
  327. if( nullptr != m_RFaceSet )
  328. items[i] = true;
  329. for( int jj = 0; jj < NITEMS; ++jj )
  330. aFile.write( (char*)&items[jj], sizeof(bool) );
  331. if( items[0] )
  332. m_Appearance->WriteCache( aFile, this );
  333. if( items[1] )
  334. aFile << "[" << m_RAppearance->GetName() << "]";
  335. if( items[2] )
  336. m_FaceSet->WriteCache( aFile, this );
  337. if( items[3] )
  338. aFile << "[" << m_RFaceSet->GetName() << "]";
  339. if( aFile.fail() )
  340. return false;
  341. m_written = true;
  342. return true;
  343. }
  344. bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
  345. {
  346. wxCHECK( m_Appearance == nullptr && m_RAppearance == nullptr && m_FaceSet == nullptr &&
  347. m_RFaceSet == nullptr, false );
  348. #define NITEMS 4
  349. bool items[NITEMS];
  350. for( int i = 0; i < NITEMS; ++i )
  351. aFile.read( (char*)&items[i], sizeof(bool) );
  352. if( ( items[0] && items[1] ) || ( items[2] && items[3] ) )
  353. {
  354. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
  355. "at position %ul" ),
  356. __FILE__, __FUNCTION__, __LINE__,
  357. static_cast<unsigned long>( aFile.tellg() ) );
  358. return false;
  359. }
  360. std::string name;
  361. if( items[0] )
  362. {
  363. if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
  364. {
  365. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child appearance "
  366. "tag at position %ul" ),
  367. __FILE__, __FUNCTION__, __LINE__,
  368. static_cast<unsigned long>( aFile.tellg() ) );
  369. return false;
  370. }
  371. m_Appearance = new SGAPPEARANCE( this );
  372. m_Appearance->SetName( name.c_str() );
  373. if( !m_Appearance->ReadCache( aFile, this ) )
  374. {
  375. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading appearance "
  376. "'%s'" ),
  377. __FILE__, __FUNCTION__, __LINE__, name );
  378. return false;
  379. }
  380. }
  381. if( items[1] )
  382. {
  383. if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
  384. {
  385. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref appearance tag "
  386. "at position %ul" ),
  387. __FILE__, __FUNCTION__, __LINE__,
  388. static_cast<unsigned long>( aFile.tellg() ) );
  389. return false;
  390. }
  391. SGNODE* np = FindNode( name.c_str(), this );
  392. if( !np )
  393. {
  394. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
  395. "appearance '%s'" ),
  396. __FILE__, __FUNCTION__, __LINE__,
  397. name );
  398. return false;
  399. }
  400. if( S3D::SGTYPE_APPEARANCE != np->GetNodeType() )
  401. {
  402. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not "
  403. "SGAPPEARANCE '%s'" ),
  404. __FILE__, __FUNCTION__, __LINE__,
  405. name );
  406. return false;
  407. }
  408. m_RAppearance = (SGAPPEARANCE*)np;
  409. m_RAppearance->addNodeRef( this );
  410. }
  411. if( items[2] )
  412. {
  413. if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
  414. {
  415. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child face set tag "
  416. "at position %ul" ),
  417. __FILE__, __FUNCTION__, __LINE__,
  418. static_cast<unsigned long>( aFile.tellg() ) );
  419. return false;
  420. }
  421. m_FaceSet = new SGFACESET( this );
  422. m_FaceSet->SetName( name.c_str() );
  423. if( !m_FaceSet->ReadCache( aFile, this ) )
  424. {
  425. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading face set "
  426. "'%s'" ),
  427. __FILE__, __FUNCTION__, __LINE__, name );
  428. return false;
  429. }
  430. }
  431. if( items[3] )
  432. {
  433. if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
  434. {
  435. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref face set tag at "
  436. "position %ul" ),
  437. __FILE__, __FUNCTION__, __LINE__,
  438. static_cast<unsigned long>( aFile.tellg() ) );
  439. return false;
  440. }
  441. SGNODE* np = FindNode( name.c_str(), this );
  442. if( !np )
  443. {
  444. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref face "
  445. "set '%s'" ),
  446. __FILE__, __FUNCTION__, __LINE__,
  447. name );
  448. return false;
  449. }
  450. if( S3D::SGTYPE_FACESET != np->GetNodeType() )
  451. {
  452. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGFACESET "
  453. "'%s'" ),
  454. __FILE__, __FUNCTION__, __LINE__,
  455. name );
  456. return false;
  457. }
  458. m_RFaceSet = (SGFACESET*)np;
  459. m_RFaceSet->addNodeRef( this );
  460. }
  461. if( aFile.fail() )
  462. return false;
  463. return true;
  464. }
  465. bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
  466. std::vector< SMESH >& meshes )
  467. {
  468. SMESH m;
  469. S3D::INIT_SMESH( m );
  470. SGAPPEARANCE* pa = m_Appearance;
  471. SGFACESET* pf = m_FaceSet;
  472. if( nullptr == pa )
  473. pa = m_RAppearance;
  474. if( nullptr == pf )
  475. pf = m_RFaceSet;
  476. // no face sets = nothing to render, which is valid though pointless
  477. if( nullptr == pf )
  478. return true;
  479. if( !pf->validate() )
  480. {
  481. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; inconsistent data" ),
  482. __FILE__, __FUNCTION__, __LINE__ );
  483. return true;
  484. }
  485. if( nullptr == pa )
  486. {
  487. m.m_MaterialIdx = 0;
  488. }
  489. else
  490. {
  491. int idx;
  492. if( !S3D::GetMatIndex( materials, pa, idx ) )
  493. {
  494. m.m_MaterialIdx = 0;
  495. }
  496. else
  497. {
  498. m.m_MaterialIdx = idx;
  499. }
  500. }
  501. SGCOLORS* pc = pf->m_Colors;
  502. SGCOORDS* pv = pf->m_Coords;
  503. SGCOORDINDEX* vidx = pf->m_CoordIndices;
  504. SGNORMALS* pn = pf->m_Normals;
  505. if( nullptr == pc )
  506. pc = pf->m_RColors;
  507. if( nullptr == pv )
  508. pv = pf->m_RCoords;
  509. if( nullptr == pn )
  510. pn = pf->m_RNormals;
  511. // set the vertex points and indices
  512. size_t nCoords = 0;
  513. SGPOINT* pCoords = nullptr;
  514. pv->GetCoordsList( nCoords, pCoords );
  515. size_t nColors = 0;
  516. SGCOLOR* pColors = nullptr;
  517. if( pc )
  518. {
  519. // check the vertex colors
  520. pc->GetColorList( nColors, pColors );
  521. if( nColors < nCoords )
  522. {
  523. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough colors per "
  524. "vertex (%ul vs %ul)" ),
  525. __FILE__, __FUNCTION__, __LINE__, static_cast<unsigned long>( nColors ),
  526. static_cast<unsigned long>( nCoords ) );
  527. return true;
  528. }
  529. }
  530. // set the vertex indices
  531. size_t nvidx = 0;
  532. int* lv = nullptr;
  533. vidx->GetIndices( nvidx, lv );
  534. // note: reduce the vertex set to include only the referenced vertices
  535. std::vector< int > vertices; // store the list of temp vertex indices
  536. std::map< int, unsigned int > indexmap; // map temp vertex to true vertex
  537. std::map< int, unsigned int >::iterator mit;
  538. for( unsigned int i = 0; i < nvidx; ++i )
  539. {
  540. mit = indexmap.find( lv[i] );
  541. if( mit == indexmap.end() )
  542. {
  543. indexmap.emplace( lv[i], vertices.size() );
  544. vertices.push_back( lv[i] );
  545. }
  546. }
  547. if( vertices.size() < 3 )
  548. {
  549. wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough vertices" ),
  550. __FILE__, __FUNCTION__, __LINE__ );
  551. return true;
  552. }
  553. // construct the final vertex/color list
  554. SFVEC3F* lColors = nullptr;
  555. SFVEC3F* lCoords = new SFVEC3F[ vertices.size() ];
  556. int ti;
  557. if( pc )
  558. {
  559. lColors = new SFVEC3F[vertices.size()];
  560. m.m_Color = lColors;
  561. }
  562. if( pc )
  563. {
  564. for( size_t i = 0; i < vertices.size(); ++i )
  565. {
  566. ti = vertices[i];
  567. glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
  568. pt = (*aTransform) * pt;
  569. pColors[ti].GetColor( lColors[i].x, lColors[i].y, lColors[i].z );
  570. lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
  571. }
  572. }
  573. else
  574. {
  575. for( size_t i = 0; i < vertices.size(); ++i )
  576. {
  577. ti = vertices[i];
  578. glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
  579. pt = (*aTransform) * pt;
  580. lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
  581. }
  582. }
  583. m.m_VertexSize = (unsigned int) vertices.size();
  584. m.m_Positions = lCoords;
  585. unsigned int* lvidx = new unsigned int[ nvidx ];
  586. for( unsigned int i = 0; i < nvidx; ++i )
  587. {
  588. mit = indexmap.find( lv[i] );
  589. lvidx[i] = mit->second;
  590. }
  591. m.m_FaceIdxSize = (unsigned int )nvidx;
  592. m.m_FaceIdx = lvidx;
  593. // set the per-vertex normals
  594. size_t nNorms = 0;
  595. SGVECTOR* pNorms = nullptr;
  596. double x, y, z;
  597. pn->GetNormalList( nNorms, pNorms );
  598. SFVEC3F* lNorms = new SFVEC3F[ vertices.size() ];
  599. for( size_t i = 0; i < vertices.size(); ++i )
  600. {
  601. ti = vertices[i];
  602. pNorms[ti].GetVector( x, y, z );
  603. glm::dvec4 pt( x, y, z, 0.0 );
  604. pt = (*aTransform) * pt;
  605. lNorms[i] = SFVEC3F( pt.x, pt.y, pt.z );
  606. }
  607. m.m_Normals = lNorms;
  608. meshes.push_back( m );
  609. return true;
  610. }