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