KiCad PCB EDA Suite
vrml1_material.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  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <iostream>
26 #include <sstream>
27 #include <wx/log.h>
28 
29 #include "vrml1_base.h"
30 #include "vrml1_material.h"
31 #include "plugins/3dapi/ifsg_all.h"
32 
33 
34 WRL1MATERIAL::WRL1MATERIAL( NAMEREGISTER* aDictionary ) : WRL1NODE( aDictionary )
35 {
36  colors[0] = NULL;
37  colors[1] = NULL;
39  return;
40 }
41 
42 
44  WRL1NODE( aDictionary )
45 {
46  colors[0] = NULL;
47  colors[1] = NULL;
49  m_Parent = aParent;
50 
51  if( NULL != m_Parent )
52  m_Parent->AddChildNode( this );
53 
54  return;
55 }
56 
57 
59 {
60  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 2 )
61  wxLogTrace( MASK_VRML, " * [INFO] Destroying Material node\n" );
62  #endif
63 
64  // destroy any orphaned color nodes
65  for( int i = 0; i < 2; ++i )
66  {
67  if( NULL != colors[i] )
68  {
69  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 2 )
70  do {
71  std::ostringstream ostr;
72  ostr << " * [INFO] Destroying SGCOLOR #" << i;
73  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
74  } while( 0 );
75  #endif
76 
77  if( NULL == S3D::GetSGNodeParent( colors[i] ) )
79 
80  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 2 )
81  do {
82  std::ostringstream ostr;
83  ostr << " * [INFO] destroyed SGCOLOR #" << i;
84  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
85  } while( 0 );
86  #endif
87  }
88  }
89 
90  return;
91 }
92 
93 
95 {
96  // this node may not own or reference any other node
97 
98  #ifdef DEBUG_VRML1
99  do {
100  std::ostringstream ostr;
101  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
102  ostr << " * [BUG] AddRefNode is not applicable";
103  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
104  } while( 0 );
105  #endif
106 
107  return false;
108 }
109 
110 
112 {
113  // this node may not own or reference any other node
114 
115  #ifdef DEBUG_VRML1
116  do {
117  std::ostringstream ostr;
118  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
119  ostr << " * [BUG] AddChildNode is not applicable";
120  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
121  } while( 0 );
122  #endif
123 
124  return false;
125 }
126 
127 
128 bool WRL1MATERIAL::Read( WRLPROC& proc, WRL1BASE* aTopNode )
129 {
130  if( NULL == aTopNode )
131  {
132  #ifdef DEBUG_VRML1
133  do {
134  std::ostringstream ostr;
135  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
136  ostr << " * [BUG] aTopNode is NULL";
137  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
138  } while( 0 );
139  #endif
140 
141  return false;
142  }
143 
144  size_t line, column;
145  proc.GetFilePosData( line, column );
146 
147  char tok = proc.Peek();
148 
149  if( proc.eof() )
150  {
151  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
152  do {
153  std::ostringstream ostr;
154  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
155  ostr << " * [INFO] bad file format; unexpected eof at line ";
156  ostr << line << ", column " << column;
157  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
158  } while( 0 );
159  #endif
160 
161  return false;
162  }
163 
164  if( '{' != tok )
165  {
166  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
167  do {
168  std::ostringstream ostr;
169  ostr << proc.GetError() << "\n";
170  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
171  ostr << " * [INFO] bad file format; expecting '{' but got '" << tok;
172  ostr << "' at line " << line << ", column " << column;
173  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
174  } while( 0 );
175  #endif
176 
177  return false;
178  }
179 
180  proc.Pop();
181  std::string glob;
182 
183  while( true )
184  {
185  if( proc.Peek() == '}' )
186  {
187  proc.Pop();
188  break;
189  }
190 
191  if( !proc.ReadName( glob ) )
192  {
193  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
194  do {
195  std::ostringstream ostr;
196  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
197  ostr << proc.GetError();
198  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
199  } while( 0 );
200  #endif
201 
202  return false;
203  }
204 
205  // expecting one of:
206  // ambientColor
207  // diffuseColor
208  // emissiveColor
209  // shininess
210  // specularColor
211  // transparency
212 
213  proc.GetFilePosData( line, column );
214 
215  if( !glob.compare( "specularColor" ) )
216  {
217  if( !proc.ReadMFVec3f( specularColor ) )
218  {
219  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
220  do {
221  std::ostringstream ostr;
222  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
223  ostr << " * [INFO] invalid specularColor at line " << line << ", column ";
224  ostr << column << "\n";
225  ostr << " * [INFO] file: '" << proc.GetFileName() << "'\n";
226  ostr << " * [INFO] message: '" << proc.GetError() << "'";
227  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
228  } while( 0 );
229  #endif
230 
231  return false;
232  }
233  }
234  else if( !glob.compare( "diffuseColor" ) )
235  {
236  if( !proc.ReadMFVec3f( diffuseColor ) )
237  {
238  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
239  do {
240  std::ostringstream ostr;
241  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
242  ostr << " * [INFO] invalid diffuseColor at line " << line << ", column ";
243  ostr << column << "\n";
244  ostr << " * [INFO] file: '" << proc.GetFileName() << "'\n";
245  ostr << " * [INFO] message: '" << proc.GetError() << "'";
246  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
247  } while( 0 );
248  #endif
249 
250  return false;
251  }
252  }
253  else if( !glob.compare( "emissiveColor" ) )
254  {
255  if( !proc.ReadMFVec3f( emissiveColor ) )
256  {
257  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
258  do {
259  std::ostringstream ostr;
260  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
261  ostr << " * [INFO] invalid emissiveColor at line " << line << ", column ";
262  ostr << column << "\n";
263  ostr << " * [INFO] file: '" << proc.GetFileName() << "'\n";
264  ostr << " * [INFO] message: '" << proc.GetError() << "'";
265  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
266  } while( 0 );
267  #endif
268 
269  return false;
270  }
271  }
272  else if( !glob.compare( "shininess" ) )
273  {
274  if( !proc.ReadMFFloat( shininess ) )
275  {
276  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
277  do {
278  std::ostringstream ostr;
279  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
280  ostr << " * [INFO] invalid shininess at line " << line << ", column ";
281  ostr << column << "\n";
282  ostr << " * [INFO] file: '" << proc.GetFileName() << "'\n";
283  ostr << " * [INFO] message: '" << proc.GetError() << "'";
284  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
285  } while( 0 );
286  #endif
287 
288  return false;
289  }
290  }
291  else if( !glob.compare( "transparency" ) )
292  {
293  if( !proc.ReadMFFloat( transparency ) )
294  {
295  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
296  do {
297  std::ostringstream ostr;
298  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
299  ostr << " * [INFO] invalid transparency at line " << line << ", column ";
300  ostr << column << "\n";
301  ostr << " * [INFO] file: '" << proc.GetFileName() << "'\n";
302  ostr << " * [INFO] message: '" << proc.GetError() << "'";
303  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
304  } while( 0 );
305  #endif
306 
307  return false;
308  }
309  }
310  else if( !glob.compare( "ambientColor" ) )
311  {
312  if( !proc.ReadMFVec3f( ambientColor ) )
313  {
314  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
315  do {
316  std::ostringstream ostr;
317  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
318  ostr << " * [INFO] invalid ambientColor at line " << line << ", column ";
319  ostr << column << "\n";
320  ostr << " * [INFO] file: '" << proc.GetFileName() << "'\n";
321  ostr << " * [INFO] message: '" << proc.GetError() << "'";
322  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
323  } while( 0 );
324  #endif
325 
326  return false;
327  }
328  }
329  else
330  {
331  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
332  do {
333  std::ostringstream ostr;
334  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
335  ostr << " * [INFO] bad Material at line " << line << ", column ";
336  ostr << column << "\n";
337  ostr << " * [INFO] file: '" << proc.GetFileName() << "'";
338  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
339  } while( 0 );
340  #endif
341 
342  return false;
343  }
344  } // while( true ) -- reading contents of Material{}
345 
346  return true;
347 }
348 
349 
351 {
352  if( NULL == sp )
353  {
354  #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 )
355  wxLogTrace( MASK_VRML, " * [INFO] bad model: no base data given\n" );
356  #endif
357 
358  return NULL;
359  }
360 
361  sp->mat = this;
362 
363  return NULL;
364 }
365 
366 
368 {
369  ++aIndex;
370 
371  // invalid indices result in the default colors
372  if( aIndex != 0 && aIndex != 1 )
373  aIndex = 0;
374 
375  if( NULL != colors[ aIndex ] )
376  return colors[ aIndex ];
377 
378  IFSG_APPEARANCE app( true );
379 
380  float red, green, blue, val;
381 
382  if( aIndex == 0 || transparency.empty() )
383  val = 0.0;
384  else
385  val = transparency[0];
386 
387  checkRange( val );
388  app.SetTransparency( val );
389 
390  if( aIndex == 0 || shininess.empty() )
391  val = 0.2f;
392  else
393  val = shininess[0];
394 
395  checkRange( val );
396  app.SetShininess( val );
397 
398  if( aIndex ==0 || ambientColor.empty() )
399  {
400  red = 0.2f;
401  green = 0.2f;
402  blue = 0.2f;
403  }
404  else
405  {
406  red = ambientColor[0].x;
407  green = ambientColor[0].y;
408  blue = ambientColor[0].z;
409  }
410 
411  checkRange( red );
412  checkRange( green );
413  checkRange( blue );
414  app.SetAmbient( red, green, blue );
415 
416  if( aIndex == 0 || diffuseColor.empty() )
417  {
418  red = 0.8f;
419  green = 0.8f;
420  blue = 0.8f;
421  }
422  else
423  {
424  red = diffuseColor[0].x;
425  green = diffuseColor[0].y;
426  blue = diffuseColor[0].z;
427  }
428 
429  checkRange( red );
430  checkRange( green );
431  checkRange( blue );
432  app.SetDiffuse( red, green, blue );
433 
434  if( aIndex > (int)emissiveColor.size() )
435  {
436  red = 0.0;
437  green = 0.0;
438  blue = 0.0;
439  }
440  else
441  {
442  red = emissiveColor[0].x;
443  green = emissiveColor[0].y;
444  blue = emissiveColor[0].z;
445  }
446 
447  checkRange( red );
448  checkRange( green );
449  checkRange( blue );
450  app.SetEmissive( red, green, blue );
451 
452  if( aIndex > (int)specularColor.size() )
453  {
454  red = 0.0;
455  green = 0.0;
456  blue = 0.0;
457  }
458  else
459  {
460  red = specularColor[0].x;
461  green = specularColor[0].y;
462  blue = specularColor[0].z;
463  }
464 
465  checkRange( red );
466  checkRange( green );
467  checkRange( blue );
468  app.SetSpecular( red, green, blue );
469 
470  colors[aIndex] = app.GetRawPtr();
471 
472  return colors[aIndex];
473 }
474 
475 
476 void WRL1MATERIAL::GetColor( SGCOLOR* aColor, int aIndex )
477 {
478  if( NULL == aColor )
479  return;
480 
481  // Calculate the color based on the given index using the formula:
482  // color = ( emission + ambient + diffuse + shininess * specular ) / N
483  // where N = number of non-zero components or 1 (if all zero)
484  // If the index exceeds the number of items in a list, use the LAST
485  // item rather than the default; this behavior caters to some bad
486  // models.
487 
488  WRLVEC3F rgb;
489  float dRed, dBlue, dGreen;
490  float eRed, eBlue, eGreen;
491  float aRed, aBlue, aGreen;
492  float sRed, sBlue, sGreen;
493  float shiny;
494 
495  if( aIndex < 0 || ( aIndex >= (int)diffuseColor.size() ) )
496  {
497  if( !diffuseColor.empty() )
498  {
499  rgb = diffuseColor.back();
500  dRed = rgb.x;
501  dGreen = rgb.y;
502  dBlue = rgb.z;
503  }
504  else
505  {
506  dRed = 0.8f;
507  dGreen = 0.8f;
508  dBlue = 0.8f;
509  }
510  }
511  else
512  {
513  rgb = diffuseColor[aIndex];
514  dRed = rgb.x;
515  dGreen = rgb.y;
516  dBlue = rgb.z;
517  }
518 
519  if( aIndex < 0 || ( aIndex >= (int)emissiveColor.size() ) )
520  {
521  if( !emissiveColor.empty() )
522  {
523  rgb = emissiveColor.back();
524  eRed = rgb.x;
525  eGreen = rgb.y;
526  eBlue = rgb.z;
527  }
528  else
529  {
530  eRed = 0.0f;
531  eGreen = 0.0f;
532  eBlue = 0.0f;
533  }
534  }
535  else
536  {
537  rgb = emissiveColor[aIndex];
538  eRed = rgb.x;
539  eGreen = rgb.y;
540  eBlue = rgb.z;
541  }
542 
543  if( aIndex < 0 || ( aIndex >= (int)ambientColor.size() ) )
544  {
545  if( !ambientColor.empty() )
546  {
547  rgb = ambientColor.back();
548  aRed = rgb.x;
549  aGreen = rgb.y;
550  aBlue = rgb.z;
551  }
552  else
553  {
554  aRed = 0.2f;
555  aGreen = 0.2f;
556  aBlue = 0.2f;
557  }
558  }
559  else
560  {
561  rgb = ambientColor[aIndex];
562  aRed = rgb.x;
563  aGreen = rgb.y;
564  aBlue = rgb.z;
565  }
566 
567  if( aIndex < 0 || ( aIndex >= (int)specularColor.size() ) )
568  {
569  if( !specularColor.empty() )
570  {
571  rgb = specularColor.back();
572  sRed = rgb.x;
573  sGreen = rgb.y;
574  sBlue = rgb.z;
575  }
576  else
577  {
578  sRed = 0.2f;
579  sGreen = 0.2f;
580  sBlue = 0.2f;
581  }
582  }
583  else
584  {
585  rgb = specularColor[aIndex];
586  sRed = rgb.x;
587  sGreen = rgb.y;
588  sBlue = rgb.z;
589  }
590 
591  if( aIndex < 0 || ( aIndex >= (int)shininess.size() ) )
592  {
593  if( !shininess.empty() )
594  shiny = shininess.back();
595  else
596  shiny = 0.2f;
597  }
598  else
599  {
600  shiny = shininess[aIndex];
601  }
602 
603  checkRange( aRed );
604  checkRange( aGreen );
605  checkRange( aBlue );
606  checkRange( eRed );
607  checkRange( eGreen );
608  checkRange( eBlue );
609  checkRange( dRed );
610  checkRange( dGreen );
611  checkRange( dBlue );
612  checkRange( sRed );
613  checkRange( sGreen );
614  checkRange( sBlue );
615 
616  int n = 0;
617 
618  if( aRed + aGreen + aBlue > 0.01f )
619  ++n;
620 
621  if( eRed + eGreen + eBlue > 0.01f )
622  ++n;
623 
624  if( dRed + dGreen + dBlue > 0.01f )
625  ++n;
626 
627  if( ( sRed + sGreen + sBlue ) * shiny > 0.01f )
628  ++n;
629 
630  if( 0 == n )
631  ++n;
632 
633  float red, green, blue;
634 
635  red = (eRed + aRed + dRed + sRed * shiny) / n;
636  green = (eGreen + aGreen + dGreen + sGreen * shiny) / n;
637  blue = (eBlue + aBlue + dBlue + sBlue * shiny) / n;
638  checkRange( red );
639  checkRange( green );
640  checkRange( blue );
641  aColor->SetColor( red, green, blue );
642 
643  return;
644 }
645 
646 
647 void WRL1MATERIAL::checkRange( float& aValue )
648 {
649  if( aValue < 0.0 )
650  aValue = 0.0;
651  else if( aValue > 1.0 )
652  aValue = 1.0;
653 
654  return;
655 }
656 
657 
659 {
660  if( NULL == aColor )
661  return;
662 
663  if( aColor == colors[0] )
664  {
665  if( NULL == S3D::GetSGNodeParent( aColor ) )
666  {
667  colors[0] = NULL;
668  S3D::DestroyNode( aColor );
669  }
670 
671  return;
672  }
673 
674  if( aColor == colors[1] && NULL == S3D::GetSGNodeParent( aColor ) )
675  {
676  colors[1] = NULL;
677  S3D::DestroyNode( aColor );
678  }
679 
680  return;
681 }
bool ReadMFFloat(std::vector< float > &aMFFloat)
Definition: wrlproc.cpp:1376
virtual ~WRL1MATERIAL()
bool ReadMFVec3f(std::vector< WRLVEC3F > &aMFVec3f)
Definition: wrlproc.cpp:1824
WRL1BASE represents the top node of a VRML1 model.
Definition: vrml1_base.h:45
std::vector< WRLVEC3F > emissiveColor
SGNODE * colors[2]
void Pop(void)
Definition: wrlproc.cpp:2007
glm::vec3 WRLVEC3F
Definition: wrltypes.h:185
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
bool GetFilePosData(size_t &line, size_t &column)
Definition: wrlproc.cpp:1951
bool SetTransparency(float aTransparency) noexcept
#define MASK_VRML
Definition: wrltypes.h:37
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:636
bool SetColor(float aRedVal, float aGreenVal, float aBlueVal)
Definition: sg_base.cpp:104
SGNODE represents the base class of all Scene Graph nodes.
Definition: sg_node.h:76
collects header files for all SG* wrappers and the API
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:66
void checkRange(float &aValue)
WRL1MATERIAL(NAMEREGISTER *aDictionary)
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Function DestroyNode deletes the given SG* class node.
Definition: ifsg_api.cpp:210
#define NULL
bool SetAmbient(float aRVal, float aGVal, float aBVal)
WRL1NODE represents the base class of all VRML1 nodes.
Definition: vrml1_node.h:111
std::vector< WRLVEC3F > ambientColor
SGNODE * TranslateToSG(SGNODE *aParent, WRL1STATUS *sp) override
Function TranslateToSG produces a representation of the data using the intermediate scenegraph struct...
std::vector< float > shininess
bool SetShininess(float aShininess) noexcept
char Peek(void)
Definition: wrlproc.cpp:1979
std::string GetFileName(void)
Definition: wrlproc.cpp:1967
virtual bool AddChildNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:442
SGNODE * GetAppearance(int aIndex)
Function GetAppearance returns an SGAPPEARANCE node representing the appearance for an IndexedFaceSet...
bool SetEmissive(float aRVal, float aGVal, float aBVal)
std::vector< float > transparency
bool SetSpecular(float aRVal, float aGVal, float aBVal)
WRL1NODES m_Type
Definition: vrml1_node.h:119
bool ReadName(std::string &aName)
Definition: wrlproc.cpp:280
void GetColor(SGCOLOR *aColor, int aIndex)
Function GetColor computes an SGCOLOR representing the appearance of a vertex or face.
std::vector< WRLVEC3F > specularColor
WRL1NODE * m_Parent
Definition: vrml1_node.h:118
std::string GetError(void)
Definition: wrlproc.cpp:1945
bool AddChildNode(WRL1NODE *aNode) override
bool eof(void)
Definition: wrlproc.cpp:1939
bool AddRefNode(WRL1NODE *aNode) override
void Reclaim(SGNODE *aColor)
Function Reclaim will destroy the given color node if it does not have a parent.
std::vector< WRLVEC3F > diffuseColor
WRL1MATERIAL * mat
Definition: vrml1_node.h:69