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 (C) 2020 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 
25 #include <iostream>
26 #include <sstream>
27 #include <wx/log.h>
28 
29 #include "3d_cache/sg/sg_index.h"
30 
31 
SGINDEX(SGNODE * aParent)32 SGINDEX::SGINDEX( SGNODE* aParent ) : SGNODE( aParent )
33 {
34     if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
35     {
36         m_Parent = nullptr;
37 
38         wxLogTrace( MASK_3D_SG, "%s:%s:%d * [BUG] inappropriate parent to SGINDEX (type '%d')",
39                     __FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
40     }
41 }
42 
43 
~SGINDEX()44 SGINDEX::~SGINDEX()
45 {
46     index.clear();
47 }
48 
49 
SetParent(SGNODE * aParent,bool notify)50 bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
51 {
52     if( nullptr != m_Parent )
53     {
54         if( aParent == m_Parent )
55             return true;
56 
57         // handle the change in parents
58         if( notify )
59             m_Parent->unlinkChildNode( this );
60 
61         m_Parent = nullptr;
62 
63         if( nullptr == aParent )
64             return true;
65     }
66 
67     // only a SGFACESET may be parent to a SGINDEX and derived types
68     if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
69         return false;
70 
71     m_Parent = aParent;
72 
73     if( m_Parent )
74         m_Parent->AddChildNode( this );
75 
76     return true;
77 }
78 
79 
FindNode(const char * aNodeName,const SGNODE * aCaller)80 SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
81 {
82     if( nullptr == aNodeName || 0 == aNodeName[0] )
83         return nullptr;
84 
85     if( !m_Name.compare( aNodeName ) )
86         return this;
87 
88     return nullptr;
89 }
90 
91 
unlinkChildNode(const SGNODE * aCaller)92 void SGINDEX::unlinkChildNode( const SGNODE* aCaller ) noexcept
93 {
94     // Node should have no children or refs.
95     wxCHECK( false, /* void */ );
96 }
97 
98 
unlinkRefNode(const SGNODE * aCaller)99 void SGINDEX::unlinkRefNode( const SGNODE* aCaller ) noexcept
100 {
101     // Node should have no children or refs.
102     wxCHECK( false, /* void */ );
103 }
104 
105 
AddRefNode(SGNODE * aNode)106 bool SGINDEX::AddRefNode( SGNODE* aNode ) noexcept
107 {
108     // Node should have no children or refs.
109     wxCHECK( false, false );
110 
111     return false;
112 }
113 
114 
AddChildNode(SGNODE * aNode)115 bool SGINDEX::AddChildNode( SGNODE* aNode ) noexcept
116 {
117     // Node should have no children or refs.
118     wxCHECK( false, false );
119 
120     return false;
121 }
122 
123 
GetIndices(size_t & nIndices,int * & aIndexList)124 bool SGINDEX::GetIndices( size_t& nIndices, int*& aIndexList )
125 {
126     if( index.empty() )
127     {
128         nIndices = 0;
129         aIndexList = nullptr;
130         return false;
131     }
132 
133     nIndices = index.size();
134     aIndexList = & index[0];
135     return true;
136 }
137 
138 
SetIndices(size_t nIndices,int * aIndexList)139 void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
140 {
141     index.clear();
142 
143     if( 0 == nIndices || nullptr == aIndexList )
144         return;
145 
146     for( size_t i = 0; i < nIndices; ++i )
147         index.push_back( aIndexList[i] );
148 
149     return;
150 }
151 
152 
AddIndex(int aIndex)153 void SGINDEX::AddIndex( int aIndex )
154 {
155     index.push_back( aIndex );
156 }
157 
158 
ReNameNodes(void)159 void SGINDEX::ReNameNodes( void )
160 {
161     m_written = false;
162 
163     // rename this node
164     m_Name.clear();
165     GetName();
166 }
167 
168 
WriteVRML(std::ostream & aFile,bool aReuseFlag)169 bool SGINDEX::WriteVRML( std::ostream& aFile, bool aReuseFlag )
170 {
171     if( index.empty() )
172         return false;
173 
174     if( S3D::SGTYPE_COORDINDEX == m_SGtype )
175         return writeCoordIndex( aFile );
176 
177     return writeColorIndex( aFile );
178 }
179 
180 
writeCoordIndex(std::ostream & aFile)181 bool SGINDEX::writeCoordIndex( std::ostream& aFile )
182 {
183     size_t n = index.size();
184 
185     wxCHECK_MSG( n % 3 == 0, false,
186                  "Coordinate index is not divisible by three (violates triangle constraint)" );
187 
188     aFile << " coordIndex [\n  ";
189 
190     // indices to control formatting
191     int nv0 = 0;
192     int nv1 = 0;
193 
194     for( size_t i = 0; i < n; )
195     {
196         aFile << index[i];
197         ++i;
198 
199         if( ++nv0 == 3 )
200         {
201             aFile << ",-1";
202             ++nv1;
203             nv0 = 0;
204         }
205 
206         if( i < n )
207         {
208             aFile << ",";
209 
210             if( nv1 == 8 )
211             {
212                 nv1 = 0;
213                 aFile << "\n  ";
214             }
215         }
216     }
217 
218     aFile << "]\n";
219 
220     return true;
221 }
222 
223 
writeColorIndex(std::ostream & aFile)224 bool SGINDEX::writeColorIndex( std::ostream& aFile )
225 {
226     aFile << " colorIndex [\n  ";
227     return writeIndexList( aFile );
228 }
229 
230 
writeIndexList(std::ostream & aFile)231 bool SGINDEX::writeIndexList( std::ostream& aFile )
232 {
233     // index to control formatting
234     int nv = 0;
235     size_t n = index.size();
236 
237     for( size_t i = 0; i < n; )
238     {
239         aFile << index[i];
240         ++i;
241 
242         if( i < n )
243         {
244             aFile << ",";
245 
246             if( ++nv == 20 )
247             {
248                 aFile << "\n  ";
249                 nv = 0;
250             }
251         }
252     }
253 
254     aFile << "]\n";
255 
256     return true;
257 }
258 
259 
WriteCache(std::ostream & aFile,SGNODE * parentNode)260 bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
261 {
262     if( nullptr == parentNode )
263     {
264         wxCHECK( m_Parent, false );
265 
266         SGNODE* np = m_Parent;
267 
268         while( nullptr != np->GetParent() )
269             np = np->GetParent();
270 
271         if( np->WriteCache( aFile, nullptr ) )
272         {
273             m_written = true;
274             return true;
275         }
276 
277         return false;
278     }
279 
280     wxCHECK( parentNode == m_Parent, false );
281 
282     if( !aFile.good() )
283     {
284         wxLogTrace( MASK_3D_SG, "%s:%s:%d * [INFO] bad stream",
285                     __FILE__, __FUNCTION__, __LINE__ );
286 
287         return false;
288     }
289 
290     aFile << "[" << GetName() << "]";
291     size_t npts = index.size();
292     aFile.write( (char*)&npts, sizeof(size_t) );
293 
294     for( size_t i = 0; i < npts; ++i )
295         aFile.write( (char*)&index[i], sizeof(int) );
296 
297     if( aFile.fail() )
298         return false;
299 
300     m_written = true;
301     return true;
302 }
303 
304 
ReadCache(std::istream & aFile,SGNODE * parentNode)305 bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
306 {
307     wxCHECK( index.empty(), false );
308 
309     size_t npts;
310     aFile.read( (char*)&npts, sizeof(size_t) );
311     int tmp;
312 
313     if( aFile.fail() )
314         return false;
315 
316     for( size_t i = 0; i < npts; ++i )
317     {
318         aFile.read( (char*) &tmp, sizeof( int ) );
319 
320         if( aFile.fail() )
321             return false;
322 
323         index.push_back( tmp );
324     }
325 
326     return true;
327 }
328