1 /** Example 022 Material Viewer
2
3 This example can be used to play around with material settings and watch the results.
4 Only the default non-shader materials are used in here.
5
6 You have two nodes to make it easier to see which difference your settings will make.
7 Additionally you have one lightscenenode and you can set the global ambient values.
8 */
9
10 #include <irrlicht.h>
11 #include "driverChoice.h"
12
13 using namespace irr;
14
15 #ifdef _MSC_VER
16 #pragma comment(lib, "Irrlicht.lib")
17 #endif
18
19 /*
20 Variables within the empty namespace are globals which are restricted to this file.
21 */
22 namespace
23 {
24 const wchar_t* const DriverTypeNames[] =
25 {
26 L"NULL",
27 L"SOFTWARE",
28 L"BURNINGSVIDEO",
29 L"DIRECT3D8",
30 L"DIRECT3D9",
31 L"OPENGL",
32 0,
33 };
34
35 // For the gui id's
36 enum EGUI_IDS
37 {
38 GUI_ID_OPEN_TEXTURE = 1,
39 GUI_ID_QUIT,
40 GUI_ID_MAX
41 };
42
43 // Name used in texture selection to clear the textures on the node
44 const core::stringw CLEAR_TEXTURE = L"CLEAR texture";
45
46 // some useful color constants
47 const video::SColor SCOL_BLACK = video::SColor(255, 0, 0, 0);
48 const video::SColor SCOL_BLUE = video::SColor(255, 0, 0, 255);
49 const video::SColor SCOL_CYAN = video::SColor(255, 0, 255, 255);
50 const video::SColor SCOL_GRAY = video::SColor(255, 128,128, 128);
51 const video::SColor SCOL_GREEN = video::SColor(255, 0, 255, 0);
52 const video::SColor SCOL_MAGENTA = video::SColor(255, 255, 0, 255);
53 const video::SColor SCOL_RED = video::SColor(255, 255, 0, 0);
54 const video::SColor SCOL_YELLOW = video::SColor(255, 255, 255, 0);
55 const video::SColor SCOL_WHITE = video::SColor(255, 255, 255, 255);
56 }; // namespace
57
58 /*
59 Returns a new unique number on each call.
60 */
makeUniqueId()61 s32 makeUniqueId()
62 {
63 static int unique = GUI_ID_MAX;
64 ++unique;
65 return unique;
66 }
67
68 /*
69 Find out which vertex-type is needed for the given material type.
70 */
getVertexTypeForMaterialType(video::E_MATERIAL_TYPE materialType)71 video::E_VERTEX_TYPE getVertexTypeForMaterialType(video::E_MATERIAL_TYPE materialType)
72 {
73 using namespace video;
74
75 switch ( materialType )
76 {
77 case EMT_SOLID:
78 return EVT_STANDARD;
79
80 case EMT_SOLID_2_LAYER:
81 return EVT_STANDARD;
82
83 case EMT_LIGHTMAP:
84 case EMT_LIGHTMAP_ADD:
85 case EMT_LIGHTMAP_M2:
86 case EMT_LIGHTMAP_M4:
87 case EMT_LIGHTMAP_LIGHTING:
88 case EMT_LIGHTMAP_LIGHTING_M2:
89 case EMT_LIGHTMAP_LIGHTING_M4:
90 return EVT_2TCOORDS;
91
92 case EMT_DETAIL_MAP:
93 return EVT_2TCOORDS;
94
95 case EMT_SPHERE_MAP:
96 return EVT_STANDARD;
97
98 case EMT_REFLECTION_2_LAYER:
99 return EVT_2TCOORDS;
100
101 case EMT_TRANSPARENT_ADD_COLOR:
102 return EVT_STANDARD;
103
104 case EMT_TRANSPARENT_ALPHA_CHANNEL:
105 return EVT_STANDARD;
106
107 case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
108 return EVT_STANDARD;
109
110 case EMT_TRANSPARENT_VERTEX_ALPHA:
111 return EVT_STANDARD;
112
113 case EMT_TRANSPARENT_REFLECTION_2_LAYER:
114 return EVT_2TCOORDS;
115
116 case EMT_NORMAL_MAP_SOLID:
117 case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR:
118 case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA:
119 case EMT_PARALLAX_MAP_SOLID:
120 case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR:
121 case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA:
122 return EVT_TANGENTS;
123
124 case EMT_ONETEXTURE_BLEND:
125 return EVT_STANDARD;
126
127 case EMT_FORCE_32BIT:
128 return EVT_STANDARD;
129 }
130 return EVT_STANDARD;
131 }
132
133 /*
134 Custom GUI-control to edit colorvalues.
135 */
136 class CColorControl : public gui::IGUIElement
137 {
138 public:
139 // Constructor
CColorControl(gui::IGUIEnvironment * guiEnv,const core::position2d<s32> & pos,const wchar_t * text,IGUIElement * parent,s32 id=-1)140 CColorControl(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t *text, IGUIElement* parent, s32 id=-1 )
141 : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect< s32 >(pos, pos+core::dimension2d<s32>(80, 75)))
142 , DirtyFlag(true)
143 , ColorStatic(0)
144 , EditAlpha(0)
145 , EditRed(0)
146 , EditGreen(0)
147 , EditBlue(0)
148 {
149 using namespace gui;
150 ButtonSetId = makeUniqueId();
151
152 const core::rect< s32 > rectControls(0,0,AbsoluteRect.getWidth(),AbsoluteRect.getHeight() );
153 IGUIStaticText * groupElement = guiEnv->addStaticText (L"", rectControls, true, false, this, -1, false);
154 groupElement->setNotClipped(true);
155
156 guiEnv->addStaticText (text, core::rect<s32>(0,0,80,15), false, false, groupElement, -1, false);
157
158 EditAlpha = addEditForNumbers(guiEnv, core::position2d<s32>(0,15), L"a", -1, groupElement );
159 EditRed = addEditForNumbers(guiEnv, core::position2d<s32>(0,30), L"r", -1, groupElement );
160 EditGreen = addEditForNumbers(guiEnv, core::position2d<s32>(0,45), L"g", -1, groupElement );
161 EditBlue = addEditForNumbers(guiEnv, core::position2d<s32>(0,60), L"b", -1, groupElement );
162
163 ColorStatic = guiEnv->addStaticText (L"", core::rect<s32>(60,15,80,75), true, false, groupElement, -1, true);
164
165 guiEnv->addButton (core::rect<s32>(60,35,80,50), groupElement, ButtonSetId, L"set");
166 SetEditsFromColor(Color);
167 }
168
169 // event receiver
OnEvent(const SEvent & event)170 virtual bool OnEvent(const SEvent &event)
171 {
172 if ( event.EventType != EET_GUI_EVENT )
173 return false;
174
175 if ( event.GUIEvent.Caller->getID() == ButtonSetId && event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
176 {
177 Color = GetColorFromEdits();
178 SetEditsFromColor(Color);
179 }
180
181 return false;
182 }
183
184 // set the color values
setColor(const video::SColor & col)185 void setColor(const video::SColor& col)
186 {
187 DirtyFlag = true;
188 Color = col;
189 SetEditsFromColor(Color);
190 }
191
192 // get the color values
getColor() const193 const video::SColor& getColor() const
194 {
195 return Color;
196 }
197
198 // To reset the dirty flag
resetDirty()199 void resetDirty()
200 {
201 DirtyFlag = false;
202 }
203
204 // when the color was changed the dirty flag is set
isDirty() const205 bool isDirty() const
206 {
207 return DirtyFlag;
208 };
209
210 protected:
211
212 // Add a staticbox for a description + an editbox so users can enter numbers
addEditForNumbers(gui::IGUIEnvironment * guiEnv,const core::position2d<s32> & pos,const wchar_t * text,s32 id,gui::IGUIElement * parent)213 gui::IGUIEditBox* addEditForNumbers(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t *text, s32 id, gui::IGUIElement * parent)
214 {
215 using namespace gui;
216
217 core::rect< s32 > rect(pos, pos+core::dimension2d<s32>(10, 15));
218 guiEnv->addStaticText (text, rect, false, false, parent, -1, false);
219 rect += core::position2d<s32>( 20, 0 );
220 rect.LowerRightCorner.X += 20;
221 gui::IGUIEditBox* edit = guiEnv->addEditBox(L"0", rect, true, parent, id);
222 return edit;
223 }
224
225 // Get the color value from the editfields
GetColorFromEdits()226 video::SColor GetColorFromEdits()
227 {
228 video::SColor col;
229
230 if (EditAlpha)
231 {
232 u32 alpha = core::strtoul10(core::stringc(EditAlpha->getText()).c_str());
233 if (alpha > 255)
234 alpha = 255;
235 col.setAlpha(alpha);
236 }
237
238 if (EditRed)
239 {
240 u32 red = core::strtoul10(core::stringc(EditRed->getText()).c_str());
241 if (red > 255)
242 red = 255;
243 col.setRed(red);
244 }
245
246 if (EditGreen)
247 {
248 u32 green = core::strtoul10(core::stringc(EditGreen->getText()).c_str());
249 if (green > 255)
250 green = 255;
251 col.setGreen(green);
252 }
253
254 if (EditBlue)
255 {
256 u32 blue = core::strtoul10(core::stringc(EditBlue->getText()).c_str());
257 if (blue > 255)
258 blue = 255;
259 col.setBlue(blue);
260 }
261
262 return col;
263 }
264
265 // Fill the editfields with the value for the given color
SetEditsFromColor(video::SColor col)266 void SetEditsFromColor(video::SColor col)
267 {
268 DirtyFlag = true;
269 if ( EditAlpha )
270 EditAlpha->setText( core::stringw(col.getAlpha()).c_str() );
271 if ( EditRed )
272 EditRed->setText( core::stringw(col.getRed()).c_str() );
273 if ( EditGreen )
274 EditGreen->setText( core::stringw(col.getGreen()).c_str() );
275 if ( EditBlue )
276 EditBlue->setText( core::stringw(col.getBlue()).c_str() );
277 if ( ColorStatic )
278 ColorStatic->setBackgroundColor(col);
279 }
280
281 private:
282
283 bool DirtyFlag;
284 video::SColor Color;
285 s32 ButtonSetId;
286 gui::IGUIStaticText * ColorStatic;
287 gui::IGUIEditBox * EditAlpha;
288 gui::IGUIEditBox * EditRed;
289 gui::IGUIEditBox * EditGreen;
290 gui::IGUIEditBox * EditBlue;
291 };
292
293 /*
294 Custom GUI-control for to edit all colors typically used in materials and lights
295 */
296 class CAllColorsControl : public gui::IGUIElement
297 {
298 public:
299 // Constructor
CAllColorsControl(gui::IGUIEnvironment * guiEnv,const core::position2d<s32> & pos,const wchar_t * description,bool hasEmissive,IGUIElement * parent,s32 id=-1)300 CAllColorsControl(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t * description, bool hasEmissive, IGUIElement* parent, s32 id=-1)
301 : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect<s32>(pos,pos+core::dimension2d<s32>(60,250)))
302 , ControlAmbientColor(0), ControlDiffuseColor(0), ControlSpecularColor(0), ControlEmissiveColor(0)
303 {
304 core::rect<s32> rect(0, 0, 60, 15);
305 guiEnv->addStaticText (description, rect, false, false, this, -1, false);
306 createColorControls(guiEnv, core::position2d<s32>(0, 15), hasEmissive);
307 }
308
309 // Destructor
~CAllColorsControl()310 virtual ~CAllColorsControl()
311 {
312 ControlAmbientColor->drop();
313 ControlDiffuseColor->drop();
314 if ( ControlEmissiveColor )
315 ControlEmissiveColor->drop();
316 ControlSpecularColor->drop();
317 }
318
319 // Set the color values to those within the material
setColorsToMaterialColors(const video::SMaterial & material)320 void setColorsToMaterialColors(const video::SMaterial & material)
321 {
322 ControlAmbientColor->setColor(material.AmbientColor);
323 ControlDiffuseColor->setColor(material.DiffuseColor);
324 ControlEmissiveColor->setColor(material.EmissiveColor);
325 ControlSpecularColor->setColor(material.SpecularColor);
326 }
327
328 // Update all changed colors in the material
updateMaterialColors(video::SMaterial & material)329 void updateMaterialColors(video::SMaterial & material)
330 {
331 if ( ControlAmbientColor->isDirty() )
332 material.AmbientColor = ControlAmbientColor->getColor();
333 if ( ControlDiffuseColor->isDirty() )
334 material.DiffuseColor = ControlDiffuseColor->getColor();
335 if ( ControlEmissiveColor->isDirty() )
336 material.EmissiveColor = ControlEmissiveColor->getColor();
337 if ( ControlSpecularColor->isDirty() )
338 material.SpecularColor = ControlSpecularColor->getColor();
339 }
340
341 // Set the color values to those from the light data
setColorsToLightDataColors(const video::SLight & lightData)342 void setColorsToLightDataColors(const video::SLight & lightData)
343 {
344 ControlAmbientColor->setColor(lightData.AmbientColor.toSColor());
345 ControlAmbientColor->setColor(lightData.DiffuseColor.toSColor());
346 ControlAmbientColor->setColor(lightData.SpecularColor.toSColor());
347 }
348
349 // Update all changed colors in the light data
updateLightColors(video::SLight & lightData)350 void updateLightColors(video::SLight & lightData)
351 {
352 if ( ControlAmbientColor->isDirty() )
353 lightData.AmbientColor = video::SColorf( ControlAmbientColor->getColor() );
354 if ( ControlDiffuseColor->isDirty() )
355 lightData.DiffuseColor = video::SColorf( ControlDiffuseColor->getColor() );
356 if ( ControlSpecularColor->isDirty() )
357 lightData.SpecularColor = video::SColorf(ControlSpecularColor->getColor() );
358 }
359
360 // To reset the dirty flags
resetDirty()361 void resetDirty()
362 {
363 ControlAmbientColor->resetDirty();
364 ControlDiffuseColor->resetDirty();
365 ControlSpecularColor->resetDirty();
366 if ( ControlEmissiveColor )
367 ControlEmissiveColor->resetDirty();
368 }
369
370 protected:
createColorControls(gui::IGUIEnvironment * guiEnv,const core::position2d<s32> & pos,bool hasEmissive)371 void createColorControls(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, bool hasEmissive)
372 {
373 ControlAmbientColor = new CColorControl( guiEnv, pos, L"ambient", this);
374 ControlDiffuseColor = new CColorControl( guiEnv, pos + core::position2d<s32>(0, 75), L"diffuse", this );
375 ControlSpecularColor = new CColorControl( guiEnv, pos + core::position2d<s32>(0, 150), L"specular", this );
376 if ( hasEmissive )
377 {
378 ControlEmissiveColor = new CColorControl( guiEnv, pos + core::position2d<s32>(0, 225), L"emissive", this );
379 }
380 }
381
382 private:
383 CColorControl* ControlAmbientColor;
384 CColorControl* ControlDiffuseColor;
385 CColorControl* ControlSpecularColor;
386 CColorControl* ControlEmissiveColor;
387 };
388
389 /*
390 GUI-Control to offer a selection of available textures.
391 */
392 class CTextureControl : public gui::IGUIElement
393 {
394 public:
CTextureControl(gui::IGUIEnvironment * guiEnv,video::IVideoDriver * driver,const core::position2d<s32> & pos,IGUIElement * parent,s32 id=-1)395 CTextureControl(gui::IGUIEnvironment* guiEnv, video::IVideoDriver * driver, const core::position2d<s32> & pos, IGUIElement* parent, s32 id=-1)
396 : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect<s32>(pos,pos+core::dimension2d<s32>(100,15)))
397 , DirtyFlag(true), ComboTexture(0)
398 {
399 core::rect<s32> rectCombo(0, 0, AbsoluteRect.getWidth(),AbsoluteRect.getHeight());
400 ComboTexture = guiEnv->addComboBox (rectCombo, this);
401 updateTextures(driver);
402 }
403
OnEvent(const SEvent & event)404 virtual bool OnEvent(const SEvent &event)
405 {
406 if ( event.EventType != EET_GUI_EVENT )
407 return false;
408
409 if ( event.GUIEvent.Caller == ComboTexture && event.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED )
410 {
411 DirtyFlag = true;
412 }
413
414 return false;
415 }
416
417 // Workaround for a problem with comboboxes.
418 // We have to get in front when the combobox wants to get in front or combobox-list might be drawn below other elements.
bringToFront(IGUIElement * element)419 virtual bool bringToFront(IGUIElement* element)
420 {
421 bool result = gui::IGUIElement::bringToFront(element);
422 if ( Parent && element == ComboTexture )
423 result &= Parent->bringToFront(this);
424 return result;
425 }
426
427 // return selected texturename (if any, otherwise 0)
getSelectedTextureName() const428 const wchar_t * getSelectedTextureName() const
429 {
430 s32 selected = ComboTexture->getSelected();
431 if ( selected < 0 )
432 return 0;
433 return ComboTexture->getItem(selected);
434 }
435
436 // reset the dirty flag
resetDirty()437 void resetDirty()
438 {
439 DirtyFlag = false;
440 }
441
442 // when the texture was changed the dirty flag is set
isDirty() const443 bool isDirty() const
444 {
445 return DirtyFlag;
446 };
447
448 // Put the names of all currently loaded textures in a combobox
updateTextures(video::IVideoDriver * driver)449 void updateTextures(video::IVideoDriver * driver)
450 {
451 s32 oldSelected = ComboTexture->getSelected();
452 s32 selectNew = -1;
453 core::stringw oldTextureName;
454 if ( oldSelected >= 0 )
455 {
456 oldTextureName = ComboTexture->getItem(oldSelected);
457 }
458 ComboTexture->clear();
459 for ( u32 i=0; i < driver->getTextureCount(); ++i )
460 {
461 video::ITexture * texture = driver->getTextureByIndex(i);
462 core::stringw name( texture->getName() );
463 ComboTexture->addItem( name.c_str() );
464 if ( !oldTextureName.empty() && selectNew < 0 && name == oldTextureName )
465 selectNew = i;
466 }
467
468 // add another name which can be used to clear the texture
469 ComboTexture->addItem( CLEAR_TEXTURE.c_str() );
470 if ( CLEAR_TEXTURE == oldTextureName )
471 selectNew = ComboTexture->getItemCount()-1;
472
473 if ( selectNew >= 0 )
474 ComboTexture->setSelected(selectNew);
475
476 DirtyFlag = true;
477 }
478
479 private:
480 bool DirtyFlag;
481 gui::IGUIComboBox * ComboTexture;
482 };
483
484 /*
485 Control which allows setting some of the material values for a meshscenenode
486 */
487 struct SMeshNodeControl
488 {
489 // constructor
SMeshNodeControlSMeshNodeControl490 SMeshNodeControl()
491 : Initialized(false), Driver(0), MeshManipulator(0), SceneNode(0), SceneNode2T(0), SceneNodeTangents(0)
492 , AllColorsControl(0), ButtonLighting(0), InfoLighting(0), ComboMaterial(0), TextureControl1(0), TextureControl2(0), ControlVertexColors(0)
493 {
494 }
495
496 // Destructor
~SMeshNodeControlSMeshNodeControl497 virtual ~SMeshNodeControl()
498 {
499 if ( TextureControl1 )
500 TextureControl1->drop();
501 if ( TextureControl2 )
502 TextureControl2->drop();
503 if ( ControlVertexColors )
504 ControlVertexColors->drop();
505 if ( AllColorsControl )
506 AllColorsControl->drop();
507 }
508
initSMeshNodeControl509 void init(scene::IMeshSceneNode* node, IrrlichtDevice * device, const core::position2d<s32> & pos, const wchar_t * description)
510 {
511 if ( Initialized || !node || !device) // initializing twice or with invalid data not allowed
512 return;
513
514 Driver = device->getVideoDriver ();
515 gui::IGUIEnvironment* guiEnv = device->getGUIEnvironment();
516 scene::ISceneManager* smgr = device->getSceneManager();
517 MeshManipulator = smgr->getMeshManipulator();
518
519 SceneNode = node;
520 scene::IMeshManipulator * meshManip = smgr->getMeshManipulator();
521
522 scene::IMesh * mesh2T = meshManip->createMeshWith2TCoords(node->getMesh());
523 SceneNode2T = smgr->addMeshSceneNode(mesh2T, 0, -1, SceneNode->getPosition(), SceneNode->getRotation(), SceneNode->getScale() );
524 mesh2T->drop();
525
526 scene::IMesh * meshTangents = meshManip->createMeshWithTangents(node->getMesh(), false, false, false);
527 SceneNodeTangents = smgr->addMeshSceneNode(meshTangents, 0, -1
528 , SceneNode->getPosition(), SceneNode->getRotation(), SceneNode->getScale() );
529 meshTangents->drop();
530
531 video::SMaterial & material = SceneNode->getMaterial(0);
532 material.Lighting = true;
533 AllColorsControl = new CAllColorsControl(guiEnv, pos, description, true, guiEnv->getRootGUIElement());
534 AllColorsControl->setColorsToMaterialColors(material);
535
536 core::rect<s32> rectBtn(pos + core::position2d<s32>(0, 320), core::dimension2d<s32>(60, 15));
537 ButtonLighting = guiEnv->addButton (rectBtn, 0, -1, L"Lighting");
538 ButtonLighting->setIsPushButton(true);
539 ButtonLighting->setPressed(material.Lighting);
540 core::rect<s32> rectInfo( rectBtn.LowerRightCorner.X, rectBtn.UpperLeftCorner.Y, rectBtn.LowerRightCorner.X+40, rectBtn.UpperLeftCorner.Y+15 );
541 InfoLighting = guiEnv->addStaticText(L"", rectInfo, true, false );
542 InfoLighting->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER );
543
544 core::rect<s32> rectCombo(pos.X, rectBtn.LowerRightCorner.Y, pos.X+100, rectBtn.LowerRightCorner.Y+15);
545 ComboMaterial = guiEnv->addComboBox (rectCombo);
546 for ( int i=0; i <= (int)video::EMT_ONETEXTURE_BLEND; ++i )
547 {
548 ComboMaterial->addItem( core::stringw(video::sBuiltInMaterialTypeNames[i]).c_str() );
549 }
550 ComboMaterial->setSelected( (s32)material.MaterialType );
551
552 core::position2d<s32> posTex(rectCombo.UpperLeftCorner.X,rectCombo.LowerRightCorner.Y);
553 TextureControl1 = new CTextureControl(guiEnv, Driver, posTex, guiEnv->getRootGUIElement());
554 posTex.Y += 15;
555 TextureControl2 = new CTextureControl(guiEnv, Driver, posTex, guiEnv->getRootGUIElement());
556
557 core::position2d<s32> posVertexColors( posTex.X, posTex.Y + 15);
558 ControlVertexColors = new CColorControl( guiEnv, posVertexColors, L"Vertex colors", guiEnv->getRootGUIElement());
559
560 video::S3DVertex * vertices = (video::S3DVertex *)node->getMesh()->getMeshBuffer(0)->getVertices();
561 if ( vertices )
562 {
563 ControlVertexColors->setColor(vertices[0].Color);
564 }
565
566 Initialized = true;
567 }
568
updateSMeshNodeControl569 void update()
570 {
571 if ( !Initialized )
572 return;
573
574 video::SMaterial & material = SceneNode->getMaterial(0);
575 video::SMaterial & material2T = SceneNode2T->getMaterial(0);
576 video::SMaterial & materialTangents = SceneNodeTangents->getMaterial(0);
577
578 s32 selectedMaterial = ComboMaterial->getSelected();
579 if ( selectedMaterial >= (s32)video::EMT_SOLID && selectedMaterial <= (s32)video::EMT_ONETEXTURE_BLEND)
580 {
581 video::E_VERTEX_TYPE vertexType = getVertexTypeForMaterialType((video::E_MATERIAL_TYPE)selectedMaterial);
582 switch ( vertexType )
583 {
584 case video::EVT_STANDARD:
585 material.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial;
586 SceneNode->setVisible(true);
587 SceneNode2T->setVisible(false);
588 SceneNodeTangents->setVisible(false);
589 break;
590 case video::EVT_2TCOORDS:
591 material2T.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial;
592 SceneNode->setVisible(false);
593 SceneNode2T->setVisible(true);
594 SceneNodeTangents->setVisible(false);
595 break;
596 case video::EVT_TANGENTS:
597 materialTangents.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial;
598 SceneNode->setVisible(false);
599 SceneNode2T->setVisible(false);
600 SceneNodeTangents->setVisible(true);
601 break;
602 }
603 }
604
605 updateMaterial(material);
606 updateMaterial(material2T);
607 updateMaterial(materialTangents);
608
609 if ( ButtonLighting->isPressed() )
610 InfoLighting->setText(L"on");
611 else
612 InfoLighting->setText(L"off");
613
614 AllColorsControl->resetDirty();
615 TextureControl1->resetDirty();
616 TextureControl2->resetDirty();
617 ControlVertexColors->resetDirty();
618 }
619
updateTexturesSMeshNodeControl620 void updateTextures()
621 {
622 TextureControl1->updateTextures(Driver);
623 TextureControl2->updateTextures(Driver);
624 }
625
626 protected:
627
updateMaterialSMeshNodeControl628 void updateMaterial(video::SMaterial & material)
629 {
630 AllColorsControl->updateMaterialColors(material);
631 material.Lighting = ButtonLighting->isPressed();
632 if ( TextureControl1->isDirty() )
633 {
634 material.TextureLayer[0].Texture = Driver->getTexture( io::path(TextureControl1->getSelectedTextureName()) );
635 }
636 if ( TextureControl2->isDirty() )
637 {
638 material.TextureLayer[1].Texture = Driver->getTexture( io::path(TextureControl2->getSelectedTextureName()) );
639 }
640 if ( ControlVertexColors->isDirty() )
641 {
642 MeshManipulator->setVertexColors (SceneNode->getMesh(), ControlVertexColors->getColor());
643 MeshManipulator->setVertexColors (SceneNode2T->getMesh(), ControlVertexColors->getColor());
644 MeshManipulator->setVertexColors (SceneNodeTangents->getMesh(), ControlVertexColors->getColor());
645 }
646 }
647
648 bool Initialized;
649 video::IVideoDriver * Driver;
650 scene::IMeshManipulator* MeshManipulator;
651 scene::IMeshSceneNode* SceneNode;
652 scene::IMeshSceneNode* SceneNode2T;
653 scene::IMeshSceneNode* SceneNodeTangents;
654 CAllColorsControl* AllColorsControl;
655 gui::IGUIButton * ButtonLighting;
656 gui::IGUIStaticText* InfoLighting;
657 gui::IGUIComboBox * ComboMaterial;
658 CTextureControl* TextureControl1;
659 CTextureControl* TextureControl2;
660 CColorControl* ControlVertexColors;
661 };
662
663 /*
664 Control to allow setting the color values of a lightscenenode.
665 */
666 struct SLightNodeControl
667 {
668 // constructor
SLightNodeControlSLightNodeControl669 SLightNodeControl() : Initialized(false), SceneNode(0), AllColorsControl(0)
670 {
671 }
672
~SLightNodeControlSLightNodeControl673 virtual ~SLightNodeControl()
674 {
675 if ( AllColorsControl )
676 AllColorsControl->drop();
677 }
678
initSLightNodeControl679 void init(scene::ILightSceneNode* node, gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t * description)
680 {
681 if ( Initialized || !node || !guiEnv) // initializing twice or with invalid data not allowed
682 return;
683 SceneNode = node;
684 AllColorsControl = new CAllColorsControl(guiEnv, pos, description, false, guiEnv->getRootGUIElement());
685 const video::SLight & lightData = SceneNode->getLightData();
686 AllColorsControl->setColorsToLightDataColors(lightData);
687 Initialized = true;
688 }
689
updateSLightNodeControl690 void update()
691 {
692 if ( !Initialized )
693 return;
694
695 video::SLight & lightData = SceneNode->getLightData();
696 AllColorsControl->updateLightColors(lightData);
697 }
698
699 protected:
700 bool Initialized;
701 scene::ILightSceneNode* SceneNode;
702 CAllColorsControl* AllColorsControl;
703 };
704
705 /*
706 Application configuration
707 */
708 struct SConfig
709 {
SConfigSConfig710 SConfig()
711 : RenderInBackground(true)
712 , DriverType(video::EDT_BURNINGSVIDEO)
713 , ScreenSize(640, 480)
714 {
715 }
716
717 bool RenderInBackground;
718 video::E_DRIVER_TYPE DriverType;
719 core::dimension2d<u32> ScreenSize;
720 };
721
722 /*
723 Main application class
724 */
725 class CApp : public IEventReceiver
726 {
727 friend int main(int argc, char *argv[]);
728
729 public:
730 // constructor
CApp()731 CApp()
732 : IsRunning(false)
733 , Device(0)
734 , Camera(0)
735 , GlobalAmbient(0)
736 {
737 }
738
739 // destructor
~CApp()740 ~CApp()
741 {
742 }
743
744 // stop running - will quit at end of mainloop
stopApp()745 void stopApp()
746 {
747 IsRunning = false;
748 }
749
750 // Event handler
OnEvent(const SEvent & event)751 virtual bool OnEvent(const SEvent &event)
752 {
753 if (event.EventType == EET_GUI_EVENT)
754 {
755 gui::IGUIEnvironment* env = Device->getGUIEnvironment();
756
757 switch(event.GUIEvent.EventType)
758 {
759 case gui::EGET_MENU_ITEM_SELECTED:
760 {
761 gui::IGUIContextMenu* menu = (gui::IGUIContextMenu*)event.GUIEvent.Caller;
762 s32 id = menu->getItemCommandId(menu->getSelectedItem());
763
764 switch(id)
765 {
766 case GUI_ID_OPEN_TEXTURE: // File -> Open Texture
767 env->addFileOpenDialog(L"Please select a texture file to open");
768 break;
769 case GUI_ID_QUIT: // File -> Quit
770 stopApp();
771 break;
772 }
773 }
774 break;
775
776 case gui::EGET_FILE_SELECTED:
777 {
778 // load the model file, selected in the file open dialog
779 gui::IGUIFileOpenDialog* dialog =
780 (gui::IGUIFileOpenDialog*)event.GUIEvent.Caller;
781 loadTexture(io::path(dialog->getFileName()).c_str());
782 }
783 break;
784
785 default:
786 break;
787 }
788 }
789
790 return false;
791 }
792
793 protected:
794
795 // Application initialization
796 // returns true when it was successful initialized, otherwise false.
init(int argc,char * argv[])797 bool init(int argc, char *argv[])
798 {
799 // ask user for driver
800 Config.DriverType=driverChoiceConsole();
801 if (Config.DriverType==video::EDT_COUNT)
802 return false;
803
804 // create the device with the settings from our config
805 Device = createDevice(Config.DriverType, Config.ScreenSize);
806 if (!Device)
807 return false;
808 Device->setWindowCaption( DriverTypeNames[Config.DriverType] );
809 Device->setEventReceiver(this);
810
811 scene::ISceneManager* smgr = Device->getSceneManager();
812 video::IVideoDriver * driver = Device->getVideoDriver ();
813 gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment();
814
815 // set a nicer font
816 gui::IGUISkin* skin = guiEnv->getSkin();
817 gui::IGUIFont* font = guiEnv->getFont("../../media/fonthaettenschweiler.bmp");
818 if (font)
819 skin->setFont(font);
820
821 // remove some alpha value because it makes those menus harder to read otherwise
822 video::SColor col3dHighLight( skin->getColor(gui::EGDC_APP_WORKSPACE) );
823 col3dHighLight.setAlpha(255);
824 video::SColor colHighLight( col3dHighLight );
825 skin->setColor(gui::EGDC_HIGH_LIGHT, colHighLight );
826 skin->setColor(gui::EGDC_3D_HIGH_LIGHT, col3dHighLight );
827
828 // Add some textures which are useful to test material settings
829 createDefaultTextures(driver);
830
831 // create a menu
832 gui::IGUIContextMenu * menuBar = guiEnv->addMenu();
833 menuBar->addItem(L"File", -1, true, true);
834
835 gui::IGUIContextMenu* subMenuFile = menuBar->getSubMenu(0);
836 subMenuFile->addItem(L"Open texture ...", GUI_ID_OPEN_TEXTURE);
837 subMenuFile->addSeparator();
838 subMenuFile->addItem(L"Quit", GUI_ID_QUIT);
839
840 // a static camera
841 Camera = smgr->addCameraSceneNode (0, core::vector3df(0, 0, 0),
842 core::vector3df(0, 0, 100),
843 -1);
844
845 // add the nodes which are used to show the materials
846 scene::IMeshSceneNode* nodeL = smgr->addCubeSceneNode (30.0f, 0, -1,
847 core::vector3df(-35, 0, 100),
848 core::vector3df(0, 0, 0),
849 core::vector3df(1.0f, 1.0f, 1.0f));
850 NodeLeft.init( nodeL, Device, core::position2d<s32>(10,20), L"left node" );
851
852 scene::IMeshSceneNode* nodeR = smgr->addCubeSceneNode (30.0f, 0, -1,
853 core::vector3df(35, 0, 100),
854 core::vector3df(0, 0, 0),
855 core::vector3df(1.0f, 1.0f, 1.0f));
856 NodeRight.init( nodeR, Device, core::position2d<s32>(530,20), L"right node" );
857
858 // add one light
859 scene::ILightSceneNode* nodeLight = smgr->addLightSceneNode(0, core::vector3df(0, 0, 0),
860 video::SColorf(1.0f, 1.0f, 1.0f),
861 100.0f);
862 LightControl.init(nodeLight, guiEnv, core::position2d<s32>(270,20), L"light" );
863
864 // one large cube around everything. That's mainly to make the light more obvious.
865 scene::IMeshSceneNode* backgroundCube = smgr->addCubeSceneNode (200.0f, 0, -1, core::vector3df(0, 0, 0),
866 core::vector3df(45, 0, 0),
867 core::vector3df(1.0f, 1.0f, 1.0f));
868 backgroundCube->getMaterial(0).BackfaceCulling = false; // we are within the cube, so we have to disable backface culling to see it
869 backgroundCube->getMaterial(0).EmissiveColor.set(255,50,50,50); // we keep some self lighting to keep texts visible
870
871 // set the ambient light value
872 GlobalAmbient = new CColorControl( guiEnv, core::position2d<s32>(270, 300), L"global ambient", guiEnv->getRootGUIElement());
873 GlobalAmbient->setColor( smgr->getAmbientLight().toSColor() );
874
875 return true;
876 }
877
878 // Update one frame
update()879 bool update()
880 {
881 using namespace irr;
882
883 video::IVideoDriver* videoDriver = Device->getVideoDriver();
884 if ( !Device->run() )
885 return false;
886
887 if ( Device->isWindowActive() || Config.RenderInBackground )
888 {
889 gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment();
890 scene::ISceneManager* smgr = Device->getSceneManager();
891 gui::IGUISkin * skin = guiEnv->getSkin();
892
893 // update our controls
894 NodeLeft.update();
895 NodeRight.update();
896 LightControl.update();
897
898 // update ambient light settings
899 if ( GlobalAmbient->isDirty() )
900 {
901 smgr->setAmbientLight( GlobalAmbient->getColor() );
902 GlobalAmbient->resetDirty();
903 }
904
905 // draw everything
906 video::SColor bkColor( skin->getColor(gui::EGDC_APP_WORKSPACE) );
907 videoDriver->beginScene(true, true, bkColor);
908
909 smgr->drawAll();
910 guiEnv->drawAll();
911
912 videoDriver->endScene();
913 }
914
915 return true;
916 }
917
918 // Run the application. Our main loop.
run()919 void run()
920 {
921 IsRunning = true;
922
923 if ( !Device )
924 return;
925
926 // main application loop
927 while(IsRunning)
928 {
929 if ( !update() )
930 break;
931
932 Device->sleep( 5 );
933 }
934 }
935
936 // Close down the application
quit()937 void quit()
938 {
939 IsRunning = false;
940 GlobalAmbient->drop();
941 GlobalAmbient = NULL;
942 if ( Device )
943 {
944 Device->closeDevice();
945 Device->drop();
946 Device = NULL;
947 }
948 }
949
950 // Create some useful textures.
951 // Note that the function put readability over speed, you shouldn't use setPixel at runtime but for initialization it's nice.
createDefaultTextures(video::IVideoDriver * driver)952 void createDefaultTextures(video::IVideoDriver * driver)
953 {
954 const u32 width = 256;
955 const u32 height = 256;
956 video::IImage * imageA8R8G8B8 = driver->createImage (video::ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
957 if ( !imageA8R8G8B8 )
958 return;
959 const u32 pitch = imageA8R8G8B8->getPitch();
960
961 // some nice square-pattern with 9 typical colors
962 for ( u32 y = 0; y < height; ++ y )
963 {
964 for ( u32 x = 0; x < pitch; ++x )
965 {
966 if ( y < height/3 )
967 {
968 if ( x < width/3 )
969 imageA8R8G8B8->setPixel (x, y, SCOL_BLACK);
970 else if ( x < 2*width/3 )
971 imageA8R8G8B8->setPixel (x, y, SCOL_BLUE);
972 else
973 imageA8R8G8B8->setPixel (x, y, SCOL_CYAN);
974 }
975 else if ( y < 2*height/3 )
976 {
977 if ( x < width/3 )
978 imageA8R8G8B8->setPixel (x, y, SCOL_GRAY);
979 else if ( x < 2*width/3 )
980 imageA8R8G8B8->setPixel (x, y, SCOL_GREEN);
981 else
982 imageA8R8G8B8->setPixel (x, y, SCOL_MAGENTA);
983 }
984 else
985 {
986 if ( x < width/3 )
987 imageA8R8G8B8->setPixel (x, y, SCOL_RED);
988 else if ( x < 2*width/3 )
989 imageA8R8G8B8->setPixel (x, y, SCOL_YELLOW);
990 else
991 imageA8R8G8B8->setPixel (x, y, SCOL_WHITE);
992 }
993 }
994 }
995 driver->addTexture (io::path("CARO_A8R8G8B8"), imageA8R8G8B8);
996
997 // all white
998 imageA8R8G8B8->fill(SCOL_WHITE);
999 driver->addTexture (io::path("WHITE_A8R8G8B8"), imageA8R8G8B8);
1000
1001 // all black
1002 imageA8R8G8B8->fill(SCOL_BLACK);
1003 driver->addTexture (io::path("BLACK_A8R8G8B8"), imageA8R8G8B8);
1004
1005 // gray-scale
1006 for ( u32 y = 0; y < height; ++ y )
1007 {
1008 for ( u32 x = 0; x < pitch; ++x )
1009 {
1010 imageA8R8G8B8->setPixel (x, y, video::SColor(y, x,x,x) );
1011 }
1012 }
1013 driver->addTexture (io::path("GRAYSCALE_A8R8G8B8"), imageA8R8G8B8);
1014
1015 imageA8R8G8B8->drop();
1016 }
1017
1018 // Load a texture and make sure nodes know it when more textures are available.
loadTexture(const io::path & name)1019 void loadTexture(const io::path &name)
1020 {
1021 Device->getVideoDriver()->getTexture(name);
1022 NodeLeft.updateTextures();
1023 NodeRight.updateTextures();
1024 }
1025
1026 private:
1027 SConfig Config;
1028 volatile bool IsRunning;
1029 IrrlichtDevice * Device;
1030 scene::ICameraSceneNode * Camera;
1031 SMeshNodeControl NodeLeft;
1032 SMeshNodeControl NodeRight;
1033 SLightNodeControl LightControl;
1034 CColorControl * GlobalAmbient;
1035 };
1036
1037 /*
1038 A very short main as we do everything else in classes.
1039 */
main(int argc,char * argv[])1040 int main(int argc, char *argv[])
1041 {
1042 CApp APP;
1043
1044 if ( !APP.init(argc, argv) )
1045 {
1046 printf("init failed\n");
1047 return 1;
1048 }
1049
1050 APP.run();
1051 APP.quit();
1052
1053 return 0;
1054 }
1055
1056 /*
1057 **/
1058