1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 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 <algorithm>
26 #include <cmath>
27 #include <cstring>
28 #include <iostream>
29 #include <sstream>
30 #include <wx/log.h>
31 
32 #include "3d_cache/sg/sg_node.h"
33 #include "plugins/3dapi/c3dmodel.h"
34 
35 
36 static const std::string node_names[S3D::SGTYPE_END + 1] = {
37     "TXFM",
38     "APP",
39     "COL",
40     "COLIDX",
41     "FACE",
42     "COORD",
43     "COORDIDX",
44     "NORM",
45     "SHAPE",
46     "INVALID"
47 };
48 
49 
50 static unsigned int node_counts[S3D::SGTYPE_END] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
51 
52 
GetNodeTypeName(S3D::SGTYPES aType)53 char const* S3D::GetNodeTypeName( S3D::SGTYPES aType ) noexcept
54 {
55     return node_names[aType].c_str();
56 }
57 
58 
getNodeName(S3D::SGTYPES nodeType,std::string & aName)59 static void getNodeName( S3D::SGTYPES nodeType, std::string& aName )
60 {
61     if( nodeType < 0 || nodeType >= S3D::SGTYPE_END )
62     {
63         aName = node_names[S3D::SGTYPE_END];
64         return;
65     }
66 
67     unsigned int seqNum = node_counts[nodeType];
68     ++node_counts[nodeType];
69 
70     std::ostringstream ostr;
71     ostr << node_names[nodeType] << "_" << seqNum;
72     aName = ostr.str();
73 }
74 
75 
SGNODE(SGNODE * aParent)76 SGNODE::SGNODE( SGNODE* aParent )
77 {
78     m_Parent = aParent;
79     m_Association = nullptr;
80     m_written = false;
81     m_SGtype = S3D::SGTYPE_END;
82 }
83 
84 
~SGNODE()85 SGNODE::~SGNODE()
86 {
87     if( m_Parent )
88         m_Parent->unlinkChildNode( this );
89 
90     if( m_Association )
91         *m_Association = nullptr;
92 
93     std::list< SGNODE* >::iterator sBP = m_BackPointers.begin();
94     std::list< SGNODE* >::iterator eBP = m_BackPointers.end();
95 
96     while( sBP != eBP )
97     {
98         (*sBP)->unlinkRefNode( this );
99         ++sBP;
100     }
101 }
102 
103 
GetNodeType(void) const104 S3D::SGTYPES SGNODE::GetNodeType( void ) const noexcept
105 {
106     return m_SGtype;
107 }
108 
109 
GetParent(void) const110 SGNODE* SGNODE::GetParent( void ) const noexcept
111 {
112     return m_Parent;
113 }
114 
115 
SwapParent(SGNODE * aNewParent)116 bool SGNODE::SwapParent( SGNODE* aNewParent )
117 {
118     if( aNewParent == m_Parent )
119         return true;
120 
121     if( nullptr == aNewParent )
122         return false;
123 
124     if( nullptr == m_Parent )
125     {
126         if( aNewParent->AddChildNode( this ) )
127             return true;
128 
129         return false;
130     }
131 
132     if( aNewParent->GetNodeType() != m_Parent->GetNodeType() )
133         return false;
134 
135     SGNODE* oldParent = m_Parent;
136     m_Parent->unlinkChildNode( this );
137     m_Parent = nullptr;
138     aNewParent->unlinkRefNode( this );
139     aNewParent->AddChildNode( this );
140     oldParent->AddRefNode( this );
141 
142     return true;
143 }
144 
145 
GetName(void)146 const char* SGNODE::GetName( void )
147 {
148     if( m_Name.empty() )
149         getNodeName( m_SGtype, m_Name );
150 
151     return m_Name.c_str();
152 }
153 
154 
SetName(const char * aName)155 void SGNODE::SetName( const char* aName )
156 {
157     if( nullptr == aName || 0 == aName[0] )
158         getNodeName( m_SGtype, m_Name );
159     else
160         m_Name = aName;
161 }
162 
163 
GetNodeTypeName(S3D::SGTYPES aNodeType) const164 const char* SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept
165 {
166     return node_names[aNodeType].c_str();
167 }
168 
169 
addNodeRef(SGNODE * aNode)170 void SGNODE::addNodeRef( SGNODE* aNode )
171 {
172     if( nullptr == aNode )
173         return;
174 
175     std::list< SGNODE* >::iterator np =
176         std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
177 
178     if( np != m_BackPointers.end() )
179         return;
180 
181     m_BackPointers.push_back( aNode );
182 }
183 
184 
delNodeRef(const SGNODE * aNode)185 void SGNODE::delNodeRef( const SGNODE* aNode )
186 {
187     if( nullptr == aNode )
188         return;
189 
190     std::list< SGNODE* >::iterator np =
191         std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
192 
193     if( np != m_BackPointers.end() )
194     {
195         m_BackPointers.erase( np );
196         return;
197     }
198 
199     wxLogTrace( MASK_3D_SG, "%s:%s:%d * [BUG] delNodeRef() did not find its target, "
200                 "this node type %d, referenced node type %d", __FILE__, __FUNCTION__, __LINE__,
201                 m_SGtype, aNode->GetNodeType() );
202 }
203 
204 
AssociateWrapper(SGNODE ** aWrapperRef)205 void SGNODE::AssociateWrapper( SGNODE** aWrapperRef ) noexcept
206 {
207     wxCHECK( aWrapperRef && *aWrapperRef == this, /* void */ );
208 
209     // if there is an existing association then break it and emit a warning
210     // just in case the behavior is undesired
211     if( m_Association )
212     {
213         *m_Association = nullptr;
214 
215         wxLogTrace( MASK_3D_SG,
216                     "%s:%s:%d * [WARNING] association being broken with previous wrapper",
217                     __FILE__, __FUNCTION__, __LINE__ );
218     }
219 
220     m_Association = aWrapperRef;
221 }
222 
DisassociateWrapper(SGNODE ** aWrapperRef)223 void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef ) noexcept
224 {
225     if( !m_Association )
226         return;
227 
228     wxCHECK( aWrapperRef, /* void */ );
229 
230     wxCHECK( *aWrapperRef == *m_Association && aWrapperRef == m_Association, /* void */ );
231 
232     m_Association = nullptr;
233 }
234 
235 
ResetNodeIndex(void)236 void SGNODE::ResetNodeIndex( void ) noexcept
237 {
238     for( int i = 0; i < (int)S3D::SGTYPE_END; ++i )
239         node_counts[i] = 1;
240 }
241 
242 
GetMatIndex(MATLIST & aList,SGNODE * aNode,int & aIndex)243 bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
244 {
245     aIndex = 0;
246 
247     wxCHECK( aNode && S3D::SGTYPE_APPEARANCE == aNode->GetNodeType(), false );
248 
249     SGAPPEARANCE* node = (SGAPPEARANCE*)aNode;
250 
251     std::map< SGAPPEARANCE const*, int >::iterator it = aList.matmap.find( node );
252 
253     if( it != aList.matmap.end() )
254     {
255         aIndex = it->second;
256         return true;
257     }
258 
259     int idx = (int)aList.matorder.size();
260     aList.matorder.push_back( node );
261     aList.matmap.insert( std::pair< SGAPPEARANCE const*, int >( node, idx ) );
262     aIndex = idx;
263 
264     return true;
265 }
266 
267 
INIT_SMATERIAL(SMATERIAL & aMaterial)268 void S3D::INIT_SMATERIAL( SMATERIAL& aMaterial )
269 {
270     aMaterial = {};
271 }
272 
273 
INIT_SMESH(SMESH & aMesh)274 void S3D::INIT_SMESH( SMESH& aMesh ) noexcept
275 {
276     aMesh = {};
277 }
278 
279 
INIT_S3DMODEL(S3DMODEL & aModel)280 void S3D::INIT_S3DMODEL( S3DMODEL& aModel ) noexcept
281 {
282     aModel = {};
283 }
284 
285 
FREE_SMESH(SMESH & aMesh)286 void S3D::FREE_SMESH( SMESH& aMesh ) noexcept
287 {
288     if( nullptr != aMesh.m_Positions )
289     {
290         delete [] aMesh.m_Positions;
291         aMesh.m_Positions = nullptr;
292     }
293 
294     if( nullptr != aMesh.m_Normals )
295     {
296         delete [] aMesh.m_Normals;
297         aMesh.m_Normals = nullptr;
298     }
299 
300     if( nullptr != aMesh.m_Texcoords )
301     {
302         delete [] aMesh.m_Texcoords;
303         aMesh.m_Texcoords = nullptr;
304     }
305 
306     if( nullptr != aMesh.m_Color )
307     {
308         delete [] aMesh.m_Color;
309         aMesh.m_Color = nullptr;
310     }
311 
312     if( nullptr != aMesh.m_FaceIdx )
313     {
314         delete [] aMesh.m_FaceIdx;
315         aMesh.m_FaceIdx = nullptr;
316     }
317 
318     aMesh.m_VertexSize = 0;
319     aMesh.m_FaceIdxSize = 0;
320     aMesh.m_MaterialIdx = 0;
321 }
322 
323 
FREE_S3DMODEL(S3DMODEL & aModel)324 void S3D::FREE_S3DMODEL( S3DMODEL& aModel )
325 {
326     if( nullptr != aModel.m_Materials )
327     {
328         delete [] aModel.m_Materials;
329         aModel.m_Materials = nullptr;
330     }
331 
332     aModel.m_MaterialsSize = 0;
333 
334     if( nullptr != aModel.m_Meshes )
335     {
336         for( unsigned int i = 0; i < aModel.m_MeshesSize; ++i )
337             FREE_SMESH( aModel.m_Meshes[i] );
338 
339         delete [] aModel.m_Meshes;
340         aModel.m_Meshes = nullptr;
341     }
342 
343     aModel.m_MeshesSize = 0;
344 }
345