KiCad PCB EDA Suite
vrml1_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) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  * Copyright (C) 2021 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 
26 #include <iostream>
27 #include <sstream>
28 #include <wx/log.h>
29 
30 #include "vrml1_base.h"
31 #include "vrml1_faceset.h"
32 #include "vrml1_coords.h"
33 #include "vrml1_material.h"
34 #include "wrlfacet.h"
35 #include "plugins/3dapi/ifsg_all.h"
36 
37 
38 WRL1FACESET::WRL1FACESET( NAMEREGISTER* aDictionary ) : WRL1NODE( aDictionary )
39 {
41 }
42 
43 
44 WRL1FACESET::WRL1FACESET( NAMEREGISTER* aDictionary, WRL1NODE* aParent ) :
45  WRL1NODE( aDictionary )
46 {
48  m_Parent = aParent;
49 
50  if( nullptr != m_Parent )
51  m_Parent->AddChildNode( this );
52 }
53 
54 
56 {
57  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Destroying IndexedFaceSet with %zu children, "
58  "%zu references, and %zu back pointers." ),
59  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
60 }
61 
62 
64 {
65  // this node may not own or reference any other node
66  wxCHECK_MSG( false, false, wxT( "AddRefNode is not applicable." ) );
67 }
68 
69 
71 {
72  // this node may not own or reference any other node
73  wxCHECK_MSG( false, false, wxT( "AddChildNode is not applicable." ) );
74 }
75 
76 
77 bool WRL1FACESET::Read( WRLPROC& proc, WRL1BASE* aTopNode )
78 {
79  char tok = proc.Peek();
80 
81  if( proc.eof() )
82  {
83  wxLogTrace( traceVrmlPlugin,
84  wxT( "%s:%s:%d\n"
85  " * [INFO] bad file format; unexpected eof %s." ),
86  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition() );
87 
88  return false;
89  }
90 
91  if( '{' != tok )
92  {
93  wxLogTrace( traceVrmlPlugin,
94  wxT( "%s:%s:%d\n"
95  " * [INFO] bad file format; expecting '{' but got '%s' %s." ),
96  __FILE__, __FUNCTION__, __LINE__, tok, proc.GetFilePosition() );
97 
98  return false;
99  }
100 
101  proc.Pop();
102  std::string glob;
103 
104  while( true )
105  {
106  if( proc.Peek() == '}' )
107  {
108  proc.Pop();
109  break;
110  }
111 
112  if( !proc.ReadName( glob ) )
113  {
114  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n%s" ),
115  __FILE__, __FUNCTION__, __LINE__, proc.GetError() );
116 
117  return false;
118  }
119 
120  // expecting one of:
121  // coordIndex[]
122  // materialIndex[]
123 
124  if( !glob.compare( "coordIndex" ) )
125  {
126  if( !proc.ReadMFInt( coordIndex ) )
127  {
128  wxLogTrace( traceVrmlPlugin,
129  wxT( "%s:%s:%d\n"
130  " * [INFO] invalid coordIndex %s.\n"
131  " * [INFO] file: '%s'\n"
132  "%s" ),
133  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
134  proc.GetFileName(), proc.GetError() );
135 
136  return false;
137  }
138  }
139  else if( !glob.compare( "materialIndex" ) )
140  {
141  if( !proc.ReadMFInt( matIndex ) )
142  {
143  wxLogTrace( traceVrmlPlugin,
144  wxT( "%s:%s:%d\n"
145  " * [INFO] invalid materialIndex %s.\n"
146  " * [INFO] file: '%s'\n"
147  "%s" ),
148  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
149  proc.GetFileName(), proc.GetError() );
150 
151  return false;
152  }
153  }
154  else if( !glob.compare( "normalIndex" ) )
155  {
156  if( !proc.ReadMFInt( normIndex ) )
157  {
158  wxLogTrace( traceVrmlPlugin,
159  wxT( "%s:%s:%d\n"
160  " * [INFO] invalid normalIndex %s\n"
161  " * [INFO] file: '%s'\n"
162  "%s" ),
163  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
164  proc.GetFileName(), proc.GetError() );
165 
166  return false;
167  }
168  }
169  else if( !glob.compare( "textureCoordIndex" ) )
170  {
171  if( !proc.ReadMFInt( texIndex ) )
172  {
173  wxLogTrace( traceVrmlPlugin,
174  wxT( "%s:%s:%d\n"
175  " * [INFO] invalid textureCoordIndex %s.\n"
176  " * [INFO] file: '%s'\n"
177  "%s" ),
178  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
179  proc.GetFileName(), proc.GetError() );
180 
181  return false;
182  }
183  }
184  else
185  {
186  wxLogTrace( traceVrmlPlugin,
187  wxT( "%s:%s:%d\n"
188  " * [INFO] invalid IndexedFaceSet %s.\n"
189  " * [INFO] file: '%s'" ),
190  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
191  proc.GetFileName() );
192 
193  return false;
194  }
195  } // while( true ) -- reading contents of IndexedFaceSet{}
196 
197  return true;
198 }
199 
200 
202 {
203  // note: m_sgNode is unused because we cannot manage everything
204  // with a single reused transform due to the fact that VRML1
205  // may use a MatrixTransformation entity which is impossible to
206  // decompose into Rotate,Scale,Transform via an analytic expression.
207  if( !m_Parent )
208  {
209  wxLogTrace( traceVrmlPlugin, " * [INFO] bad model: no parent node." );
210 
211  return nullptr;
212  }
213  else
214  {
215  if( nullptr == sp )
216  {
217  wxLogTrace( traceVrmlPlugin, " * [INFO] bad model: no base data given." );
218 
219  return nullptr;
220  }
221  }
222 
223  m_current = *sp;
224 
225  if( nullptr == m_current.coord )
226  {
227  wxLogTrace( traceVrmlPlugin, " * [INFO] bad model: no vertex set." );
228  return nullptr;
229  }
230 
231  if( nullptr == m_current.mat )
232  {
233  wxLogTrace( traceVrmlPlugin, " * [INFO] bad model: no material set." );
234  return nullptr;
235  }
236 
237  WRLVEC3F* pcoords;
238  size_t coordsize;
239 
240  m_current.coord->GetCoords( pcoords, coordsize );
241  size_t vsize = coordIndex.size();
242 
243  if( coordsize < 3 || vsize < 3 )
244  {
245  wxLogTrace( traceVrmlPlugin,
246  wxT( " * [INFO] bad model: coordsize = %zu, indexsize = %zu" ),
247  coordsize, vsize );
248 
249  return nullptr;
250  }
251 
252  // 1. create the vertex/normals/colors lists
253  SGNODE* sgcolor = nullptr;
255  size_t matSize = matIndex.size();
256 
257  switch( mbind )
258  {
262  break;
263 
265 
266  if( matIndex.empty() )
267  {
268  wxLogTrace( traceVrmlPlugin,
269  wxT( " * [INFO] bad model: per face indexed but no indices" ) );
270 
271  // support bad models by temporarily switching bindings
273  sgcolor = m_current.mat->GetAppearance( 0 );
274  }
275 
276  break;
277 
278  default:
279 
280  // use the first appearance definition
281  sgcolor = m_current.mat->GetAppearance( 0 );
282  break;
283  }
284 
285  // copy the data into FACET structures
286 
287  SHAPE lShape;
288  FACET* fp = nullptr;
289  size_t iCoord;
290  int idx; // coordinate index
291  size_t cidx = 0; // color index
292  SGCOLOR pc1;
293 
294  if( mbind == WRL1_BINDING::BIND_OVERALL || mbind == WRL1_BINDING::BIND_DEFAULT )
295  {
296  // no per-vertex colors; we can save a few CPU cycles
297  for( iCoord = 0; iCoord < vsize; ++iCoord )
298  {
299  idx = coordIndex[iCoord];
300 
301  if( idx < 0 )
302  {
303  if( nullptr != fp )
304  {
305  if( fp->HasMinPoints() )
306  fp = nullptr;
307  else
308  fp->Init();
309  }
310 
311  continue;
312  }
313 
314  // if the coordinate is bad then skip it
315  if( idx >= (int)coordsize )
316  continue;
317 
318  if( nullptr == fp )
319  fp = lShape.NewFacet();
320 
321  // push the vertex value and index
322  WRLVEC3F vf;
323  glm::vec4 pt = glm::vec4( pcoords[idx].x, pcoords[idx].y, pcoords[idx].z, 1.0 );
324  pt = m_current.txmatrix * pt;
325  vf.x = pt.x;
326  vf.y = pt.y;
327  vf.z = pt.z;
328 
329  fp->AddVertex( vf, idx );
330  }
331  }
332  else
333  {
334  for( iCoord = 0; iCoord < vsize; ++iCoord )
335  {
336  idx = coordIndex[iCoord];
337 
338  if( idx < 0 )
339  {
340  if( nullptr != fp )
341  {
342  if( fp->HasMinPoints() )
343  fp = nullptr;
344  else
345  fp->Init();
346  }
347 
348  if( mbind == WRL1_BINDING::BIND_PER_FACE
350  ++cidx;
351 
352  continue;
353  }
354 
355  // if the coordinate is bad then skip it
356  if( idx >= (int)coordsize )
357  continue;
358 
359  if( nullptr == fp )
360  fp = lShape.NewFacet();
361 
362  // push the vertex value and index
363  WRLVEC3F vf;
364  glm::vec4 pt = glm::vec4( pcoords[idx].x, pcoords[idx].y, pcoords[idx].z, 1.0 );
365  pt = m_current.txmatrix * pt;
366  vf.x = pt.x;
367  vf.y = pt.y;
368  vf.z = pt.z;
369 
370  fp->AddVertex( vf, idx );
371 
372  // push the color if appropriate
373  switch( mbind )
374  {
376 
377  if( !fp->HasColors() )
378  {
379  m_current.mat->GetColor( &pc1, cidx );
380  fp->AddColor( pc1 );
381  }
382 
383  break;
384 
386  m_current.mat->GetColor( &pc1, idx );
387  fp->AddColor( pc1 );
388  break;
389 
391 
392  if( !fp->HasColors() )
393  {
394  if( cidx >= matSize )
395  m_current.mat->GetColor( &pc1, matIndex.back() );
396  else
397  m_current.mat->GetColor( &pc1, matIndex[cidx] );
398 
399  fp->AddColor( pc1 );
400  }
401 
402  break;
403 
405 
406  if( matIndex.empty() )
407  {
408  m_current.mat->GetColor( &pc1, idx );
409  }
410  else
411  {
412  if( iCoord >= matSize )
413  m_current.mat->GetColor( &pc1, matIndex.back() );
414  else
415  m_current.mat->GetColor( &pc1, matIndex[iCoord] );
416  }
417 
418  fp->AddColor( pc1 );
419 
420  break;
421 
422  default:
423  break;
424  }
425  }
426  }
427 
428  // extract the final data set
429  SGNODE* np = lShape.CalcShape( aParent, sgcolor, m_current.order, m_current.creaseLimit );
430 
431  return np;
432 }
Represent the top node of a VRML1 model.
Definition: vrml1_base.h:45
SGNODE * TranslateToSG(SGNODE *aParent, WRL1STATUS *sp) override
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
SGNODE * CalcShape(SGNODE *aParent, SGNODE *aColor, WRL1_ORDER aVertexOrder, float aCreaseLimit=0.74317, bool isVRML2=false)
Definition: wrlfacet.cpp:703
bool AddRefNode(WRL1NODE *aNode) override
void Pop(void)
Definition: wrlproc.cpp:2035
glm::vec3 WRLVEC3F
Definition: wrltypes.h:188
WRL1_BINDING matbind
Definition: vrml1_node.h:97
WRL1STATUS m_current
Definition: vrml1_node.h:236
WRL1COORDS * coord
Definition: vrml1_node.h:94
float creaseLimit
Definition: vrml1_node.h:109
void AddVertex(WRLVEC3F &aVertex, int aIndex)
Add the vertex and its associated index to the internal list of polygon vertices.
Definition: wrlfacet.cpp:191
void Init()
Definition: wrlfacet.cpp:158
std::vector< int > texIndex
Definition: vrml1_faceset.h:56
bool ReadMFInt(std::vector< int > &aMFInt32)
Definition: wrlproc.cpp:1504
The base class of all Scene Graph nodes.
Definition: sg_node.h:74
collects header files for all SG* wrappers and the API
std::list< WRL1NODE * > m_BackPointers
Definition: vrml1_node.h:230
glm::mat4 txmatrix
Definition: vrml1_node.h:103
declares classes to help manage normals calculations from VRML files
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
void AddColor(const SGCOLOR &aColor)
Add the given RGB color to the internal list.
Definition: wrlfacet.cpp:204
std::vector< int > normIndex
Definition: vrml1_faceset.h:55
WRL1_BINDING
Definition: wrltypes.h:100
std::list< WRL1NODE * > m_Refs
Definition: vrml1_node.h:232
bool HasColors()
Definition: wrlfacet.cpp:182
bool AddChildNode(WRL1NODE *aNode) override
The base class of all VRML1 nodes.
Definition: vrml1_node.h:116
std::vector< int > matIndex
Definition: vrml1_faceset.h:54
std::string GetFilePosition() const
Definition: wrlproc.cpp:1982
An abstract shape on 2D plane.
Definition: shape.h:116
std::vector< int > coordIndex
Definition: vrml1_faceset.h:53
char Peek(void)
Definition: wrlproc.cpp:2007
std::string GetFileName(void)
Definition: wrlproc.cpp:1995
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
virtual bool AddChildNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:376
SGNODE * GetAppearance(int aIndex)
Return an SGAPPEARANCE node representing the appearance for an IndexedFaceSet.
virtual ~WRL1FACESET()
WRL1NODES m_Type
Definition: vrml1_node.h:227
FACET * NewFacet()
Definition: wrlfacet.cpp:695
Definition: wrlfacet.h:42
bool ReadName(std::string &aName)
Definition: wrlproc.cpp:289
void GetColor(SGCOLOR *aColor, int aIndex)
Compute an SGCOLOR representing the appearance of a vertex or face.
WRL1FACESET(NAMEREGISTER *aDictionary)
WRL1NODE * m_Parent
Definition: vrml1_node.h:226
std::string GetError(void)
Definition: wrlproc.cpp:1960
void GetCoords(WRLVEC3F *&aCoordList, size_t &aListSize)
bool eof(void)
Definition: wrlproc.cpp:1954
WRL1_ORDER order
Definition: vrml1_node.h:106
WRL1MATERIAL * mat
Definition: vrml1_node.h:88
bool HasMinPoints()
Definition: wrlfacet.cpp:173
std::list< WRL1NODE * > m_Children
Definition: vrml1_node.h:231