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