KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sg_faceset.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015-2017 Cirilo Bernardo <[email protected]>
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, see <https://www.gnu.org/licenses/>.
19 */
20
21
22#include <iostream>
23#include <sstream>
24#include <wx/log.h>
25
32
33
34SGFACESET::SGFACESET( SGNODE* aParent ) : SGNODE( aParent )
35{
37 m_Colors = nullptr;
38 m_Coords = nullptr;
39 m_CoordIndices = nullptr;
40 m_Normals = nullptr;
41 m_RColors = nullptr;
42 m_RCoords = nullptr;
43 m_RNormals = nullptr;
44 valid = false;
45 validated = false;
46
47 if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
48 {
49 m_Parent = nullptr;
50
51 wxLogTrace( MASK_3D_SG,
52 wxT( "%s:%s:%d * [BUG] inappropriate parent to SGFACESET (type %s)" ),
53 __FILE__, __FUNCTION__, __LINE__,
54 aParent->GetNodeType() );
55 }
56 else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
57 {
58 m_Parent->AddChildNode( this );
59 }
60}
61
62
64{
65 // drop references
66 if( m_RColors )
67 {
68 m_RColors->delNodeRef( this );
69 m_RColors = nullptr;
70 }
71
72 if( m_RCoords )
73 {
74 m_RCoords->delNodeRef( this );
75 m_RCoords = nullptr;
76 }
77
78 if( m_RNormals )
79 {
80 m_RNormals->delNodeRef( this );
81 m_RNormals = nullptr;
82 }
83
84 // delete owned objects
85 if( m_Colors )
86 {
87 m_Colors->SetParent( nullptr, false );
88 delete m_Colors;
89 m_Colors = nullptr;
90 }
91
92 if( m_Coords )
93 {
94 m_Coords->SetParent( nullptr, false );
95 delete m_Coords;
96 m_Coords = nullptr;
97 }
98
99 if( m_Normals )
100 {
101 m_Normals->SetParent( nullptr, false );
102 delete m_Normals;
103 m_Normals = nullptr;
104 }
105
106 if( m_CoordIndices )
107 {
108 m_CoordIndices->SetParent( nullptr, false );
109 delete m_CoordIndices;
110 m_CoordIndices = nullptr;
111 }
112}
113
114
115bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
116{
117 if( nullptr != m_Parent )
118 {
119 if( aParent == m_Parent )
120 return true;
121
122 // handle the change in parents
123 if( notify )
124 m_Parent->unlinkChildNode( this );
125
126 m_Parent = nullptr;
127
128 if( nullptr == aParent )
129 return true;
130 }
131
132 // only a SGSHAPE may be parent to a SGFACESET
133 if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
134 return false;
135
136 m_Parent = aParent;
137
138 if( m_Parent )
139 m_Parent->AddChildNode( this );
140
141 return true;
142}
143
144
145SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
146{
147 if( nullptr == aNodeName || 0 == aNodeName[0] )
148 return nullptr;
149
150 if( !m_Name.compare( aNodeName ) )
151 return this;
152
153 SGNODE* np = nullptr;
154
155 if( m_Colors )
156 {
157 np = m_Colors->FindNode( aNodeName, this );
158
159 if( np )
160 return np;
161 }
162
163 if( m_Coords )
164 {
165 np = m_Coords->FindNode( aNodeName, this );
166
167 if( np )
168 return np;
169 }
170
171 if( m_CoordIndices )
172 {
173 np = m_CoordIndices->FindNode( aNodeName, this );
174
175 if( np )
176 return np;
177 }
178
179 if( m_Normals )
180 {
181 np = m_Normals->FindNode( aNodeName, this );
182
183 if( np )
184 return np;
185 }
186
187 // query the parent if appropriate
188 if( aCaller == m_Parent || nullptr == m_Parent )
189 return nullptr;
190
191 return m_Parent->FindNode( aNodeName, this );
192}
193
194
195void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
196{
197 if( nullptr == aNode )
198 return;
199
200 valid = false;
201 validated = false;
202
203 if( isChild )
204 {
205 if( aNode == m_Colors )
206 {
207 m_Colors = nullptr;
208 return;
209 }
210
211 if( aNode == m_Coords )
212 {
213 m_Coords = nullptr;
214 return;
215 }
216
217 if( aNode == m_Normals )
218 {
219 m_Normals = nullptr;
220 return;
221 }
222
223 if( aNode == m_CoordIndices )
224 {
225 m_CoordIndices = nullptr;
226 return;
227 }
228 }
229 else
230 {
231 if( aNode == m_RColors )
232 {
233 delNodeRef( this );
234 m_RColors = nullptr;
235 return;
236 }
237
238 if( aNode == m_RCoords )
239 {
240 delNodeRef( this );
241 m_RCoords = nullptr;
242 return;
243 }
244
245 if( aNode == m_RNormals )
246 {
247 delNodeRef( this );
248 m_RNormals = nullptr;
249 return;
250 }
251 }
252
253 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
254 __FILE__, __FUNCTION__, __LINE__ );
255}
256
257
259{
260 unlinkNode( aNode, true );
261}
262
263
265{
266 unlinkNode( aNode, false );
267}
268
269
270
271bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
272{
273 wxCHECK( aNode, false );
274
275 valid = false;
276 validated = false;
277
278 if( S3D::SGTYPE_COLORS == aNode->GetNodeType() )
279 {
280 if( m_Colors || m_RColors )
281 {
282 if( aNode != m_Colors && aNode != m_RColors )
283 {
284 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
285 __FILE__, __FUNCTION__, __LINE__ );
286
287 return false;
288 }
289
290 return true;
291 }
292
293 if( isChild )
294 {
295 m_Colors = (SGCOLORS*)aNode;
296 m_Colors->SetParent( this );
297 }
298 else
299 {
300 m_RColors = (SGCOLORS*)aNode;
301 m_RColors->addNodeRef( this );
302 }
303
304 return true;
305 }
306
307 if( S3D::SGTYPE_COORDS == aNode->GetNodeType() )
308 {
309 if( m_Coords || m_RCoords )
310 {
311 if( aNode != m_Coords && aNode != m_RCoords )
312 {
313 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
314 __FILE__, __FUNCTION__, __LINE__ );
315
316 return false;
317 }
318
319 return true;
320 }
321
322 if( isChild )
323 {
324 m_Coords = (SGCOORDS*)aNode;
325 m_Coords->SetParent( this );
326 }
327 else
328 {
329 m_RCoords = (SGCOORDS*)aNode;
330 m_RCoords->addNodeRef( this );
331 }
332
333 return true;
334 }
335
336 if( S3D::SGTYPE_NORMALS == aNode->GetNodeType() )
337 {
338 if( m_Normals || m_RNormals )
339 {
340 if( aNode != m_Normals && aNode != m_RNormals )
341 {
342 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Normals nodes" ),
343 __FILE__, __FUNCTION__, __LINE__ );
344
345 return false;
346 }
347
348 return true;
349 }
350
351 if( isChild )
352 {
353 m_Normals = (SGNORMALS*)aNode;
354 m_Normals->SetParent( this );
355 }
356 else
357 {
358 m_RNormals = (SGNORMALS*)aNode;
359 m_RNormals->addNodeRef( this );
360 }
361
362 return true;
363 }
364
365 if( S3D::SGTYPE_COORDINDEX == aNode->GetNodeType() )
366 {
367 if( m_CoordIndices )
368 {
369 if( aNode != m_CoordIndices )
370 {
371 wxLogTrace( MASK_3D_SG,
372 wxT( "%s:%s:%d * [BUG] assigning multiple CoordIndex nodes" ),
373 __FILE__, __FUNCTION__, __LINE__ );
374
375 return false;
376 }
377
378 return true;
379 }
380
382 m_CoordIndices->SetParent( this );
383
384 return true;
385 }
386
387 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object type '%s' is not a valid type for "
388 "this object '%d'" ),
389 __FILE__, __FUNCTION__, __LINE__,
390 aNode->GetName(),
391 aNode->GetNodeType() );
392
393 return false;
394}
395
396
398{
399 return addNode( aNode, false );
400}
401
402
404{
405 return addNode( aNode, true );
406}
407
408
410{
411 m_written = false;
412
413 // rename this node
414 m_Name.clear();
415 GetName();
416
417 // rename all Colors and Indices
418 if( m_Colors )
419 m_Colors->ReNameNodes();
420
421 // rename all Coordinates and Indices
422 if( m_Coords )
423 m_Coords->ReNameNodes();
424
425 if( m_CoordIndices )
426 m_CoordIndices->ReNameNodes();
427
428 // rename all Normals and Indices
429 if( m_Normals )
430 m_Normals->ReNameNodes();
431}
432
433
434bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
435{
436 if( ( nullptr == m_Coords && nullptr == m_RCoords ) || ( nullptr == m_CoordIndices ) )
437 {
438 return false;
439 }
440
441 if( aReuseFlag )
442 {
443 if( !m_written )
444 {
445 aFile << " geometry DEF " << GetName() << " IndexedFaceSet {\n";
446 m_written = true;
447 }
448 else
449 {
450 aFile << "USE " << GetName() << "\n";
451 return true;
452 }
453 }
454 else
455 {
456 aFile << " geometry IndexedFaceSet {\n";
457 }
458
459 if( m_Coords )
460 m_Coords->WriteVRML( aFile, aReuseFlag );
461
462 if( m_RCoords )
463 m_RCoords->WriteVRML( aFile, aReuseFlag );
464
465 if( m_CoordIndices )
466 m_CoordIndices->WriteVRML( aFile, aReuseFlag );
467
468 if( m_Normals || m_RNormals )
469 aFile << " normalPerVertex TRUE\n";
470
471 if( m_Normals )
472 m_Normals->WriteVRML( aFile, aReuseFlag );
473
474 if( m_RNormals )
475 m_RNormals->WriteVRML( aFile, aReuseFlag );
476
477 if( m_Colors )
478 m_Colors->WriteVRML( aFile, aReuseFlag );
479
480 if( m_RColors )
481 m_RColors->WriteVRML( aFile, aReuseFlag );
482
483 aFile << "}\n";
484
485 return true;
486}
487
488
489bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
490{
491 if( nullptr == parentNode )
492 {
493 wxCHECK( m_Parent, false );
494
495 SGNODE* np = m_Parent;
496
497 while( nullptr != np->GetParent() )
498 np = np->GetParent();
499
500 if( np->WriteCache( aFile, nullptr ) )
501 {
502 m_written = true;
503 return true;
504 }
505
506 return false;
507 }
508
509 wxCHECK( parentNode == m_Parent, false );
510
511 if( !aFile.good() )
512 {
513 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
514 __FILE__, __FUNCTION__, __LINE__ );
515
516 return false;
517 }
518
519 // check if any references are unwritten and swap parents if so
520 if( nullptr != m_RCoords && !m_RCoords->isWritten() )
521 m_RCoords->SwapParent( this );
522
523 if( nullptr != m_RNormals && !m_RNormals->isWritten() )
524 m_RNormals->SwapParent( this );
525
526 if( nullptr != m_RColors && !m_RColors->isWritten() )
527 m_RColors->SwapParent( this );
528
529 aFile << "[" << GetName() << "]";
530 #define NITEMS 7
531 bool items[NITEMS];
532 int i;
533
534 for( i = 0; i < NITEMS; ++i )
535 items[i] = 0;
536
537 i = 0;
538 if( nullptr != m_Coords )
539 items[i] = true;
540
541 ++i;
542 if( nullptr != m_RCoords )
543 items[i] = true;
544
545 ++i;
546 if( nullptr != m_CoordIndices )
547 items[i] = true;
548
549 ++i;
550 if( nullptr != m_Normals )
551 items[i] = true;
552
553 ++i;
554 if( nullptr != m_RNormals )
555 items[i] = true;
556
557 ++i;
558 if( nullptr != m_Colors )
559 items[i] = true;
560
561 ++i;
562 if( nullptr != m_RColors )
563 items[i] = true;
564
565 for( int jj = 0; jj < NITEMS; ++jj )
566 aFile.write( (char*) &items[jj], sizeof( bool ) );
567
568 if( items[0] )
569 m_Coords->WriteCache( aFile, this );
570
571 if( items[1] )
572 aFile << "[" << m_RCoords->GetName() << "]";
573
574 if( items[2] )
575 m_CoordIndices->WriteCache( aFile, this );
576
577 if( items[3] )
578 m_Normals->WriteCache( aFile, this );
579
580 if( items[4] )
581 aFile << "[" << m_RNormals->GetName() << "]";
582
583 if( items[5] )
584 m_Colors->WriteCache( aFile, this );
585
586 if( items[6] )
587 aFile << "[" << m_RColors->GetName() << "]";
588
589 if( aFile.fail() )
590 return false;
591
592 m_written = true;
593 return true;
594}
595
596
597bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
598{
600 || m_RNormals )
601 {
602 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] non-empty node" ),
603 __FILE__, __FUNCTION__, __LINE__ );
604
605 return false;
606 }
607
608 #define NITEMS 7
609 bool items[NITEMS];
610
611 for( int i = 0; i < NITEMS; ++i )
612 aFile.read( (char*) &items[i], sizeof( bool ) );
613
614 if( ( items[0] && items[1] ) || ( items[3] && items[4] ) || ( items[5] && items[6] ) )
615 {
616 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
617 "at position %d" ),
618 __FILE__, __FUNCTION__, __LINE__,
619 static_cast<int>( aFile.tellg() ) );
620
621 return false;
622 }
623
624 std::string name;
625
626 if( items[0] )
627 {
628 if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
629 {
630 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child coords tag at "
631 "position %d" ),
632 __FILE__, __FUNCTION__, __LINE__,
633 static_cast<int>( aFile.tellg() ) );
634
635 return false;
636 }
637
638 m_Coords = new SGCOORDS( this );
639 m_Coords->SetName( name.c_str() );
640
641 if( !m_Coords->ReadCache( aFile, this ) )
642 {
643 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
644 "reading coords '%s'" ),
645 __FILE__, __FUNCTION__, __LINE__,
646 name );
647
648 return false;
649 }
650 }
651
652 if( items[1] )
653 {
654 if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
655 {
656 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref coords tag at "
657 "position %d" ),
658 __FILE__, __FUNCTION__, __LINE__,
659 static_cast<int>( aFile.tellg() ) );
660
661 return false;
662 }
663
664 SGNODE* np = FindNode( name.c_str(), this );
665
666 if( !np )
667 {
668 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; cannot find ref "
669 "coords '%s'" ),
670 __FILE__, __FUNCTION__, __LINE__,
671 name );
672
673 return false;
674 }
675
676 if( S3D::SGTYPE_COORDS != np->GetNodeType() )
677 {
678 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; type is not SGCOORDS "
679 "'%s'" ),
680 __FILE__, __FUNCTION__, __LINE__,
681 name );
682
683 return false;
684 }
685
686 m_RCoords = (SGCOORDS*)np;
687 m_RCoords->addNodeRef( this );
688 }
689
690 if( items[2] )
691 {
692 if( S3D::SGTYPE_COORDINDEX != S3D::ReadTag( aFile, name ) )
693 {
694 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad coord index tag at "
695 "position %d" ),
696 __FILE__, __FUNCTION__, __LINE__,
697 static_cast<int>( aFile.tellg() ) );
698
699 return false;
700 }
701
702 m_CoordIndices = new SGCOORDINDEX( this );
703 m_CoordIndices->SetName( name.c_str() );
704
705 if( !m_CoordIndices->ReadCache( aFile, this ) )
706 {
707 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading coord "
708 "index '%s'" ),
709 __FILE__, __FUNCTION__, __LINE__,
710 name );
711
712 return false;
713 }
714 }
715
716 if( items[3] )
717 {
718 if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
719 {
720 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child normals tag "
721 "at position %d" ),
722 __FILE__, __FUNCTION__, __LINE__,
723 static_cast<int>( aFile.tellg() ) );
724
725 return false;
726 }
727
728 m_Normals = new SGNORMALS( this );
729 m_Normals->SetName( name.c_str() );
730
731 if( !m_Normals->ReadCache( aFile, this ) )
732 {
733 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading normals "
734 "'%s'" ),
735 __FILE__, __FUNCTION__, __LINE__,
736 name );
737
738 return false;
739 }
740 }
741
742 if( items[4] )
743 {
744 if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
745 {
746 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref normals tag at "
747 "position %d" ),
748 __FILE__, __FUNCTION__, __LINE__,
749 static_cast<int>( aFile.tellg() ) );
750
751 return false;
752 }
753
754 SGNODE* np = FindNode( name.c_str(), this );
755
756 if( !np )
757 {
758 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: cannot find ref normals "
759 "'%s'" ),
760 __FILE__, __FUNCTION__, __LINE__,
761 name );
762
763 return false;
764 }
765
766 if( S3D::SGTYPE_NORMALS != np->GetNodeType() )
767 {
768 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: type is not SGNORMALS '%s'" ),
769 __FILE__, __FUNCTION__, __LINE__,
770 name );
771
772 return false;
773 }
774
775 m_RNormals = (SGNORMALS*)np;
776 m_RNormals->addNodeRef( this );
777 }
778
779 if( items[5] )
780 {
781 if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
782 {
783 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child colors tag "
784 "at position %d" ),
785 __FILE__, __FUNCTION__, __LINE__,
786 static_cast<int>( aFile.tellg() ) );
787
788 return false;
789 }
790
791 m_Colors = new SGCOLORS( this );
792 m_Colors->SetName( name.c_str() );
793
794 if( !m_Colors->ReadCache( aFile, this ) )
795 {
796 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading colors "
797 "'%s'" ),
798 __FILE__, __FUNCTION__, __LINE__,
799 name );
800
801 return false;
802 }
803 }
804
805 if( items[6] )
806 {
807 if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
808 {
809 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref colors tag at "
810 "position %d" ),
811 __FILE__, __FUNCTION__, __LINE__,
812 static_cast<int>( aFile.tellg() ) );
813
814 return false;
815 }
816
817 SGNODE* np = FindNode( name.c_str(), this );
818
819 if( !np )
820 {
821 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref colors "
822 "'%s'" ),
823 __FILE__, __FUNCTION__, __LINE__,
824 name );
825
826 return false;
827 }
828
829 if( S3D::SGTYPE_COLORS != np->GetNodeType() )
830 {
831 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGCOLORS "
832 "'%s'" ),
833 __FILE__, __FUNCTION__, __LINE__,
834 name );
835
836 return false;
837 }
838
839 m_RColors = (SGCOLORS*)np;
840 m_RColors->addNodeRef( this );
841 }
842
843 if( aFile.fail() )
844 return false;
845
846 return true;
847}
848
849
851{
852 // verify the integrity of this object's data
853 if( validated )
854 return valid;
855
856 // ensure we have at least coordinates and their normals
857 if( ( nullptr == m_Coords && nullptr == m_RCoords )
858 || ( nullptr == m_Normals && nullptr == m_RNormals )
859 || ( nullptr == m_CoordIndices ) )
860 {
861 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertices, vertex indices, "
862 "or normals" ),
863 __FILE__, __FUNCTION__, __LINE__ );
864
865 validated = true;
866 valid = false;
867 return false;
868 }
869
870 // check that there are >3 vertices
871 SGCOORDS* coords = m_Coords;
872
873 if( nullptr == coords )
874 coords = m_RCoords;
875
876 size_t nCoords = 0;
877 SGPOINT* lCoords = nullptr;
878 coords->GetCoordsList( nCoords, lCoords );
879
880 if( nCoords < 3 )
881 {
882 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; fewer than 3 vertices" ),
883 __FILE__, __FUNCTION__, __LINE__ );
884
885 validated = true;
886 valid = false;
887 return false;
888 }
889
890 // check that nVertices is divisible by 3 (facets are triangles)
891 size_t nCIdx = 0;
892 int* lCIdx = nullptr;
893 m_CoordIndices->GetIndices( nCIdx, lCIdx );
894
895 if( nCIdx < 3 || ( nCIdx % 3 > 0 ) )
896 {
897 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertex indices or not "
898 "multiple of 3" ),
899 __FILE__, __FUNCTION__, __LINE__ );
900
901 validated = true;
902 valid = false;
903 return false;
904 }
905
906 // check that vertex[n] >= 0 and < nVertices
907 for( size_t i = 0; i < nCIdx; ++i )
908 {
909 if( lCIdx[i] < 0 || lCIdx[i] >= (int)nCoords )
910 {
911 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; vertex index out of "
912 "bounds" ),
913 __FILE__, __FUNCTION__, __LINE__ );
914
915 validated = true;
916 valid = false;
917 return false;
918 }
919 }
920
921 // check that there are as many normals as vertices
922 size_t nNorms = 0;
923 SGVECTOR* lNorms = nullptr;
924 SGNORMALS* pNorms = m_Normals;
925
926 if( nullptr == pNorms )
927 pNorms = m_RNormals;
928
929 pNorms->GetNormalList( nNorms, lNorms );
930
931 if( nNorms != nCoords )
932 {
933 wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; number of normals (%ul) does "
934 "not match number of vertices (%ul)" ),
935 __FILE__, __FUNCTION__, __LINE__,
936 static_cast<unsigned long>( nNorms ),
937 static_cast<unsigned long>( nCoords ) );
938
939 validated = true;
940 valid = false;
941 return false;
942 }
943
944 // if there are colors then ensure there are as many colors as vertices
945 SGCOLORS* pColors = m_Colors;
946
947 if( nullptr == pColors )
948 pColors = m_RColors;
949
950 if( nullptr != pColors )
951 {
952 // we must have at least as many colors as vertices
953 size_t nColor = 0;
954 SGCOLOR* pColor = nullptr;
955 pColors->GetColorList( nColor, pColor );
956 }
957
958 validated = true;
959 valid = true;
960 return true;
961}
962
963
964void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
965{
966 if( m_CoordIndices )
967 m_CoordIndices->GatherCoordIndices( aIndexList );
968}
969
970
972{
973 SGCOORDS* coords = m_Coords;
974
975 if( m_RCoords )
976 coords = m_RCoords;
977
978 if( nullptr == coords || coords->coords.empty() )
979 return false;
980
981 if( m_Normals && !m_Normals->norms.empty( ) )
982 return true;
983
984 if( m_RNormals && !m_RNormals->norms.empty( ) )
985 return true;
986
987 return coords->CalcNormals( this, aPtr );
988}
const char * name
Define an RGB color set for a scenegraph object.
Definition sg_colors.h:35
bool GetColorList(size_t &aListSize, SGCOLOR *&aColorList)
An object to maintain a coordinate index list.
Define a vertex coordinate set for a scenegraph object.
Definition sg_coords.h:37
std::vector< SGPOINT > coords
Definition sg_coords.h:68
bool GetCoordsList(size_t &aListSize, SGPOINT *&aCoordsList)
bool CalcNormals(SGFACESET *callingNode, SGNODE **aPtr=nullptr)
Calculate normals for this coordinate list and sets the normals list in the parent SGFACESET.
bool validated
Definition sg_faceset.h:87
void GatherCoordIndices(std::vector< int > &aIndexList)
Add all internal coordinate indices to the given list in preparation for a normals calculation.
void unlinkRefNode(const SGNODE *aNode) override
Remove pointers to a referenced node.
SGCOORDS * m_RCoords
Definition sg_faceset.h:82
SGCOORDINDEX * m_CoordIndices
Definition sg_faceset.h:77
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Search the tree of linked nodes and return a reference to the first node found with the given name.
bool addNode(SGNODE *aNode, bool isChild)
SGCOORDS * m_Coords
Definition sg_faceset.h:76
bool CalcNormals(SGNODE **aPtr)
SGFACESET(SGNODE *aParent)
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
SGNORMALS * m_Normals
Definition sg_faceset.h:78
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
void unlinkChildNode(const SGNODE *aNode) override
Remove references to an owned child.
void unlinkNode(const SGNODE *aNode, bool isChild)
SGCOLORS * m_RColors
Definition sg_faceset.h:81
SGNORMALS * m_RNormals
Definition sg_faceset.h:83
bool AddRefNode(SGNODE *aNode) override
virtual ~SGFACESET()
bool valid
Definition sg_faceset.h:86
bool validate(void)
SGCOLORS * m_Colors
Definition sg_faceset.h:75
bool AddChildNode(SGNODE *aNode) override
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
virtual bool WriteCache(std::ostream &aFile, SGNODE *parentNode)=0
Write this node's data to a binary cache file.
const char * GetName(void)
Definition sg_node.cpp:142
SGNODE * GetParent(void) const noexcept
Returns a pointer to the parent SGNODE of this object or NULL if the object has no parent (ie.
Definition sg_node.cpp:106
S3D::SGTYPES GetNodeType(void) const noexcept
Return the type of this node instance.
Definition sg_node.cpp:100
SGNODE * m_Parent
Pointer to parent node; may be NULL for top level transform.
Definition sg_node.h:223
SGNODE(SGNODE *aParent)
Definition sg_node.cpp:72
std::string m_Name
name to use for referencing the entity by name.
Definition sg_node.h:225
void delNodeRef(const SGNODE *aNode)
Remove a pointer to a node which references this node, but does not own.
Definition sg_node.cpp:181
bool m_written
Set to true when the object has been written after a ReNameNodes().
Definition sg_node.h:226
S3D::SGTYPES m_SGtype
Type of Scene Graph node.
Definition sg_node.h:224
Define a set of vertex normals for a scene graph object.
Definition sg_normals.h:35
bool GetNormalList(size_t &aListSize, SGVECTOR *&aNormalList)
S3D::SGTYPES ReadTag(std::istream &aFile, std::string &aName)
Read the text tag of a binary cache file which is the NodeTag and unique ID number combined.
@ SGTYPE_COLORS
Definition sg_types.h:35
@ SGTYPE_SHAPE
Definition sg_types.h:41
@ SGTYPE_FACESET
Definition sg_types.h:37
@ SGTYPE_NORMALS
Definition sg_types.h:40
@ SGTYPE_COORDS
Definition sg_types.h:38
@ SGTYPE_COORDINDEX
Definition sg_types.h:39
#define NITEMS
Define a number of macros to aid in repetitious code which is probably best expressed as a preprocess...