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 <[email protected]>
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_material.h"
33
34
35WRL1MATERIAL::WRL1MATERIAL( NAMEREGISTER* aDictionary ) : WRL1NODE( aDictionary )
36{
37 colors[0] = nullptr;
38 colors[1] = nullptr;
40}
41
42
44 WRL1NODE( aDictionary )
45{
46 colors[0] = nullptr;
47 colors[1] = nullptr;
49 m_Parent = aParent;
50
51 if( nullptr != m_Parent )
52 m_Parent->AddChildNode( this );
53}
54
55
57{
58 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Destroying Material node." ) );
59
60 // destroy any orphaned color nodes
61 for( int i = 0; i < 2; ++i )
62 {
63 if( nullptr != colors[i] )
64 {
65 if( nullptr == S3D::GetSGNodeParent( colors[i] ) )
67
68 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] destroyed SGCOLOR #%d" ), i );
69 }
70 }
71}
72
73
75{
76 // this node may not own or reference any other node
77 wxCHECK_MSG( false, false, wxT( "AddRefNode is not applicable." ) );
78}
79
80
82{
83 // this node may not own or reference any other node
84 wxCHECK_MSG( false, false, wxT( "AddChildNode is not applicable." ) );
85}
86
87
88bool WRL1MATERIAL::Read( WRLPROC& proc, WRL1BASE* aTopNode )
89{
90 wxCHECK_MSG( aTopNode, false, wxT( "aTopNode is nullptr." ) );
91
92 char tok = proc.Peek();
93
94 if( proc.eof() )
95 {
96 wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
97 " * [INFO] bad file format; unexpected eof %s." ),
98 __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition() );
99
100 return false;
101 }
102
103 if( '{' != tok )
104 {
105 wxLogTrace( traceVrmlPlugin,
106 wxT( "%s:%s:%d\n"
107 " * [INFO] bad file format; expecting '{' but got '%s' %s" ),
108 __FILE__, __FUNCTION__, __LINE__, tok, proc.GetFilePosition() );
109
110 return false;
111 }
112
113 proc.Pop();
114 std::string glob;
115
116 while( true )
117 {
118 if( proc.Peek() == '}' )
119 {
120 proc.Pop();
121 break;
122 }
123
124 if( !proc.ReadName( glob ) )
125 {
126 wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
127 "%s" ),
128 __FILE__, __FUNCTION__, __LINE__, proc.GetError() );
129
130 return false;
131 }
132
133 // expecting one of:
134 // ambientColor
135 // diffuseColor
136 // emissiveColor
137 // shininess
138 // specularColor
139 // transparency
140
141 if( !glob.compare( "specularColor" ) )
142 {
143 if( !proc.ReadMFVec3f( specularColor ) )
144 {
145 wxLogTrace( traceVrmlPlugin,
146 wxT( "%s:%s:%d\n"
147 " * [INFO] invalid specularColor %s\n"
148 " * [INFO] file: '%s'\n"
149 "%s" ),
150 __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
151 proc.GetFileName(), proc.GetError() );
152
153 return false;
154 }
155 }
156 else if( !glob.compare( "diffuseColor" ) )
157 {
158 if( !proc.ReadMFVec3f( diffuseColor ) )
159 {
160 wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
161 " * [INFO] invalid diffuseColor %s\n"
162 " * [INFO] file: '%s'\n"
163 " * [INFO] error: '%s'." ),
164 __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
165 proc.GetFileName(), proc.GetError() );
166
167 return false;
168 }
169 }
170 else if( !glob.compare( "emissiveColor" ) )
171 {
172 if( !proc.ReadMFVec3f( emissiveColor ) )
173 {
174 wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
175 " * [INFO] invalid emissiveColor %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 if( !glob.compare( "shininess" ) )
185 {
186 if( !proc.ReadMFFloat( shininess ) )
187 {
188 wxLogTrace( traceVrmlPlugin,
189 wxT( "%s:%s:%d\n"
190 " * [INFO] invalid shininess %s\n"
191 " * [INFO] file: '%s'\n"
192 " * [INFO] error: '%s'." ),
193 __FILE__, __FUNCTION__, __LINE__, proc.GetFileName(),
194 proc.GetFileName(), proc.GetError() );
195
196 return false;
197 }
198 }
199 else if( !glob.compare( "transparency" ) )
200 {
201 if( !proc.ReadMFFloat( transparency ) )
202 {
203 wxLogTrace( traceVrmlPlugin,
204 wxT( "%s:%s:%d\n"
205 " * [INFO] invalid transparency %s\n"
206 " * [INFO] file: '%s'\n"
207 " * [INFO] error: '%s'." ),
208 __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
209 proc.GetFileName(), proc.GetError() );
210
211 return false;
212 }
213 }
214 else if( !glob.compare( "ambientColor" ) )
215 {
216 if( !proc.ReadMFVec3f( ambientColor ) )
217 {
218 wxLogTrace( traceVrmlPlugin,
219 wxT( "%s:%s:%d\n"
220 " * [INFO] invalid ambientColor %s\n"
221 " * [INFO] file: '%s'\n"
222 " * [INFO] error: '%s'." ),
223 __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
224 proc.GetFileName(), proc.GetError() );
225
226 return false;
227 }
228 }
229 else
230 {
231 wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
232 "* [INFO] bad Material %s.\n"
233 "* [INFO] file: '%s'." ),
234 __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
235 proc.GetFileName() );
236
237 return false;
238 }
239 } // while( true ) -- reading contents of Material{}
240
241 return true;
242}
243
244
246{
247 wxCHECK_MSG( sp, nullptr, wxT( "Bad model: no base data given." ) );
248
249 sp->mat = this;
250
251 return nullptr;
252}
253
254
256{
257 ++aIndex;
258
259 // invalid indices result in the default colors
260 if( aIndex != 0 && aIndex != 1 )
261 aIndex = 0;
262
263 if( nullptr != colors[ aIndex ] )
264 return colors[ aIndex ];
265
266 IFSG_APPEARANCE app( true );
267
268 float red, green, blue, val;
269
270 if( aIndex == 0 || transparency.empty() )
271 val = 0.0;
272 else
273 val = transparency[0];
274
275 checkRange( val );
276 app.SetTransparency( val );
277
278 if( aIndex == 0 || shininess.empty() )
279 val = 0.2f;
280 else
281 val = shininess[0];
282
283 checkRange( val );
284 app.SetShininess( val );
285
286 if( aIndex ==0 || ambientColor.empty() )
287 {
288 red = 0.2f;
289 green = 0.2f;
290 blue = 0.2f;
291 }
292 else
293 {
294 red = ambientColor[0].x;
295 green = ambientColor[0].y;
296 blue = ambientColor[0].z;
297 }
298
299 checkRange( red );
300 checkRange( green );
301 checkRange( blue );
302 app.SetAmbient( red, green, blue );
303
304 if( aIndex == 0 || diffuseColor.empty() )
305 {
306 red = 0.8f;
307 green = 0.8f;
308 blue = 0.8f;
309 }
310 else
311 {
312 red = diffuseColor[0].x;
313 green = diffuseColor[0].y;
314 blue = diffuseColor[0].z;
315 }
316
317 checkRange( red );
318 checkRange( green );
319 checkRange( blue );
320 app.SetDiffuse( red, green, blue );
321
322 if( aIndex > (int)emissiveColor.size() )
323 {
324 red = 0.0;
325 green = 0.0;
326 blue = 0.0;
327 }
328 else
329 {
330 red = emissiveColor[0].x;
331 green = emissiveColor[0].y;
332 blue = emissiveColor[0].z;
333 }
334
335 checkRange( red );
336 checkRange( green );
337 checkRange( blue );
338 app.SetEmissive( red, green, blue );
339
340 if( aIndex > (int)specularColor.size() )
341 {
342 red = 0.0;
343 green = 0.0;
344 blue = 0.0;
345 }
346 else
347 {
348 red = specularColor[0].x;
349 green = specularColor[0].y;
350 blue = specularColor[0].z;
351 }
352
353 checkRange( red );
354 checkRange( green );
355 checkRange( blue );
356 app.SetSpecular( red, green, blue );
357
358 colors[aIndex] = app.GetRawPtr();
359
360 return colors[aIndex];
361}
362
363
364void WRL1MATERIAL::GetColor( SGCOLOR* aColor, int aIndex )
365{
366 if( nullptr == aColor )
367 return;
368
369 // Calculate the color based on the given index using the formula:
370 // color = ( emission + ambient + diffuse + shininess * specular ) / N
371 // where N = number of non-zero components or 1 (if all zero)
372 // If the index exceeds the number of items in a list, use the LAST
373 // item rather than the default; this behavior caters to some bad
374 // models.
375
376 WRLVEC3F rgb;
377 float dRed, dBlue, dGreen;
378 float eRed, eBlue, eGreen;
379 float aRed, aBlue, aGreen;
380 float sRed, sBlue, sGreen;
381 float shiny;
382
383 if( aIndex < 0 || ( aIndex >= (int)diffuseColor.size() ) )
384 {
385 if( !diffuseColor.empty() )
386 {
387 rgb = diffuseColor.back();
388 dRed = rgb.x;
389 dGreen = rgb.y;
390 dBlue = rgb.z;
391 }
392 else
393 {
394 dRed = 0.8f;
395 dGreen = 0.8f;
396 dBlue = 0.8f;
397 }
398 }
399 else
400 {
401 rgb = diffuseColor[aIndex];
402 dRed = rgb.x;
403 dGreen = rgb.y;
404 dBlue = rgb.z;
405 }
406
407 if( aIndex < 0 || ( aIndex >= (int)emissiveColor.size() ) )
408 {
409 if( !emissiveColor.empty() )
410 {
411 rgb = emissiveColor.back();
412 eRed = rgb.x;
413 eGreen = rgb.y;
414 eBlue = rgb.z;
415 }
416 else
417 {
418 eRed = 0.0f;
419 eGreen = 0.0f;
420 eBlue = 0.0f;
421 }
422 }
423 else
424 {
425 rgb = emissiveColor[aIndex];
426 eRed = rgb.x;
427 eGreen = rgb.y;
428 eBlue = rgb.z;
429 }
430
431 if( aIndex < 0 || ( aIndex >= (int)ambientColor.size() ) )
432 {
433 if( !ambientColor.empty() )
434 {
435 rgb = ambientColor.back();
436 aRed = rgb.x;
437 aGreen = rgb.y;
438 aBlue = rgb.z;
439 }
440 else
441 {
442 aRed = 0.2f;
443 aGreen = 0.2f;
444 aBlue = 0.2f;
445 }
446 }
447 else
448 {
449 rgb = ambientColor[aIndex];
450 aRed = rgb.x;
451 aGreen = rgb.y;
452 aBlue = rgb.z;
453 }
454
455 if( aIndex < 0 || ( aIndex >= (int)specularColor.size() ) )
456 {
457 if( !specularColor.empty() )
458 {
459 rgb = specularColor.back();
460 sRed = rgb.x;
461 sGreen = rgb.y;
462 sBlue = rgb.z;
463 }
464 else
465 {
466 sRed = 0.2f;
467 sGreen = 0.2f;
468 sBlue = 0.2f;
469 }
470 }
471 else
472 {
473 rgb = specularColor[aIndex];
474 sRed = rgb.x;
475 sGreen = rgb.y;
476 sBlue = rgb.z;
477 }
478
479 if( aIndex < 0 || ( aIndex >= (int)shininess.size() ) )
480 {
481 if( !shininess.empty() )
482 shiny = shininess.back();
483 else
484 shiny = 0.2f;
485 }
486 else
487 {
488 shiny = shininess[aIndex];
489 }
490
491 checkRange( aRed );
492 checkRange( aGreen );
493 checkRange( aBlue );
494 checkRange( eRed );
495 checkRange( eGreen );
496 checkRange( eBlue );
497 checkRange( dRed );
498 checkRange( dGreen );
499 checkRange( dBlue );
500 checkRange( sRed );
501 checkRange( sGreen );
502 checkRange( sBlue );
503
504 int n = 0;
505
506 if( aRed + aGreen + aBlue > 0.01f )
507 ++n;
508
509 if( eRed + eGreen + eBlue > 0.01f )
510 ++n;
511
512 if( dRed + dGreen + dBlue > 0.01f )
513 ++n;
514
515 if( ( sRed + sGreen + sBlue ) * shiny > 0.01f )
516 ++n;
517
518 if( 0 == n )
519 ++n;
520
521 float red, green, blue;
522
523 red = (eRed + aRed + dRed + sRed * shiny) / n;
524 green = (eGreen + aGreen + dGreen + sGreen * shiny) / n;
525 blue = (eBlue + aBlue + dBlue + sBlue * shiny) / n;
526 checkRange( red );
527 checkRange( green );
528 checkRange( blue );
529 aColor->SetColor( red, green, blue );
530}
531
532
533void WRL1MATERIAL::checkRange( float& aValue )
534{
535 if( aValue < 0.0 )
536 aValue = 0.0;
537 else if( aValue > 1.0 )
538 aValue = 1.0;
539}
540
541
543{
544 if( nullptr == aColor )
545 return;
546
547 if( aColor == colors[0] )
548 {
549 if( nullptr == S3D::GetSGNodeParent( aColor ) )
550 {
551 colors[0] = nullptr;
552 S3D::DestroyNode( aColor );
553 }
554
555 return;
556 }
557
558 if( aColor == colors[1] && nullptr == S3D::GetSGNodeParent( aColor ) )
559 {
560 colors[1] = nullptr;
561 S3D::DestroyNode( aColor );
562 }
563}
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
bool SetEmissive(float aRVal, float aGVal, float aBVal)
bool SetSpecular(float aRVal, float aGVal, float aBVal)
bool SetShininess(float aShininess) noexcept
bool SetAmbient(float aRVal, float aGVal, float aBVal)
bool SetTransparency(float aTransparency) noexcept
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:65
bool SetColor(float aRedVal, float aGreenVal, float aBlueVal)
Definition: sg_base.cpp:85
The base class of all Scene Graph nodes.
Definition: sg_node.h:75
Represent the top node of a VRML1 model.
Definition: vrml1_base.h:46
std::vector< WRLVEC3F > emissiveColor
SGNODE * colors[2]
bool AddChildNode(WRL1NODE *aNode) override
std::vector< WRLVEC3F > ambientColor
void Reclaim(SGNODE *aColor)
Destroy the given color node if it does not have a parent.
bool AddRefNode(WRL1NODE *aNode) override
SGNODE * TranslateToSG(SGNODE *aParent, WRL1STATUS *sp) override
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
void checkRange(float &aValue)
std::vector< WRLVEC3F > diffuseColor
WRL1MATERIAL(NAMEREGISTER *aDictionary)
std::vector< float > transparency
void GetColor(SGCOLOR *aColor, int aIndex)
Compute an SGCOLOR representing the appearance of a vertex or face.
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
std::vector< WRLVEC3F > specularColor
virtual ~WRL1MATERIAL()
std::vector< float > shininess
SGNODE * GetAppearance(int aIndex)
Return an SGAPPEARANCE node representing the appearance for an IndexedFaceSet.
The base class of all VRML1 nodes.
Definition: vrml1_node.h:117
WRL1NODES m_Type
Definition: vrml1_node.h:227
virtual bool AddChildNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:376
WRL1NODE * m_Parent
Definition: vrml1_node.h:226
void Pop(void)
Definition: wrlproc.cpp:2035
char Peek(void)
Definition: wrlproc.cpp:2007
std::string GetFileName(void)
Definition: wrlproc.cpp:1995
bool ReadMFFloat(std::vector< float > &aMFFloat)
Definition: wrlproc.cpp:1393
std::string GetError(void)
Definition: wrlproc.cpp:1960
bool eof(void)
Definition: wrlproc.cpp:1954
bool ReadMFVec3f(std::vector< WRLVEC3F > &aMFVec3f)
Definition: wrlproc.cpp:1839
bool ReadName(std::string &aName)
Definition: wrlproc.cpp:289
std::string GetFilePosition() const
Definition: wrlproc.cpp:1982
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
collects header files for all SG* wrappers and the API
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:494
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Function DestroyNode deletes the given SG* class node.
Definition: ifsg_api.cpp:149
WRL1MATERIAL * mat
Definition: vrml1_node.h:88
glm::vec3 WRLVEC3F
Definition: wrltypes.h:188