123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146 |
- /** Example 022 Material Viewer
- This example can be used to experiment with material settings and watch the results.
- Only the default non-shader materials are used in here.
- You have a node with a mesh, one dynamic light and global ambient light to play around with.
- You can move the light with cursor-keys and +/-.
- You can move the camera while left-mouse button is clicked.
- */
- // TODO: Should be possible to set all material values by the GUI.
- // For now just change the defaultMaterial in CApp::setActiveMeshNodeType for the rest.
- #include <irrlicht.h>
- #include "driverChoice.h"
- #include "exampleHelper.h"
- #include "main.h"
- using namespace irr;
- #ifdef _MSC_VER
- #pragma comment(lib, "Irrlicht.lib")
- #endif
- /*
- Variables within the empty namespace are globals which are restricted to this file.
- */
- namespace
- {
- // For the gui id's
- enum EGUI_IDS
- {
- GUI_ID_OPEN_TEXTURE = 1,
- GUI_ID_QUIT,
- GUI_ID_MAX
- };
- // Name used in texture selection to clear the textures on the node
- const core::stringw CLEAR_TEXTURE = L"CLEAR texture";
- // some useful color constants
- const video::SColor SCOL_BLACK = video::SColor(255, 0, 0, 0);
- const video::SColor SCOL_BLUE = video::SColor(255, 0, 0, 255);
- const video::SColor SCOL_CYAN = video::SColor(255, 0, 255, 255);
- const video::SColor SCOL_GRAY = video::SColor(255, 128,128, 128);
- const video::SColor SCOL_GREEN = video::SColor(255, 0, 255, 0);
- const video::SColor SCOL_MAGENTA = video::SColor(255, 255, 0, 255);
- const video::SColor SCOL_RED = video::SColor(255, 255, 0, 0);
- const video::SColor SCOL_YELLOW = video::SColor(255, 255, 255, 0);
- const video::SColor SCOL_WHITE = video::SColor(255, 255, 255, 255);
- }; // namespace
- /*
- Returns a new unique number on each call.
- */
- s32 makeUniqueId()
- {
- static int unique = GUI_ID_MAX;
- ++unique;
- return unique;
- }
- /*
- Find out which vertex-type is needed for the given material type.
- */
- video::E_VERTEX_TYPE getVertexTypeForMaterialType(video::E_MATERIAL_TYPE materialType)
- {
- using namespace video;
- switch ( materialType )
- {
- case EMT_SOLID:
- return EVT_STANDARD;
- case EMT_SOLID_2_LAYER:
- return EVT_STANDARD;
- case EMT_LIGHTMAP:
- case EMT_LIGHTMAP_ADD:
- case EMT_LIGHTMAP_M2:
- case EMT_LIGHTMAP_M4:
- case EMT_LIGHTMAP_LIGHTING:
- case EMT_LIGHTMAP_LIGHTING_M2:
- case EMT_LIGHTMAP_LIGHTING_M4:
- return EVT_2TCOORDS;
- case EMT_DETAIL_MAP:
- return EVT_2TCOORDS;
- case EMT_SPHERE_MAP:
- return EVT_STANDARD;
- case EMT_REFLECTION_2_LAYER:
- return EVT_2TCOORDS;
- case EMT_TRANSPARENT_ADD_COLOR:
- return EVT_STANDARD;
- case EMT_TRANSPARENT_ALPHA_CHANNEL:
- return EVT_STANDARD;
- case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
- return EVT_STANDARD;
- case EMT_TRANSPARENT_VERTEX_ALPHA:
- return EVT_STANDARD;
- case EMT_TRANSPARENT_REFLECTION_2_LAYER:
- return EVT_2TCOORDS;
- case EMT_NORMAL_MAP_SOLID:
- case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR:
- case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA:
- case EMT_PARALLAX_MAP_SOLID:
- case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR:
- case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA:
- return EVT_TANGENTS;
- case EMT_ONETEXTURE_BLEND:
- return EVT_STANDARD;
- case EMT_FORCE_32BIT:
- return EVT_STANDARD;
- }
- return EVT_STANDARD;
- }
- /*
- Custom GUI-control to edit color values.
- */
- CColorControl::CColorControl(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t *text, IGUIElement* parent, s32 id)
- : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect< s32 >(pos, pos+core::dimension2d<s32>(80, 75)))
- , DirtyFlag(true)
- , Color(0)
- , ColorStatic(0)
- , EditAlpha(0)
- , EditRed(0)
- , EditGreen(0)
- , EditBlue(0)
- {
- using namespace gui;
- ButtonSetId = makeUniqueId();
- const core::rect< s32 > rectControls(0,0,AbsoluteRect.getWidth(),AbsoluteRect.getHeight() );
- IGUIStaticText * groupElement = guiEnv->addStaticText (L"", rectControls, true, false, this, -1, false);
- groupElement->setNotClipped(true);
- s32 border=guiEnv->getSkin()->getSize(EGDS_TEXT_DISTANCE_X);
- guiEnv->addStaticText(text, core::rect<s32>(border,border,80,15), false, false, groupElement, -1, true);
- EditAlpha = addEditForNumbers(guiEnv, core::position2d<s32>(border,15), L"a", -1, groupElement );
- EditRed = addEditForNumbers(guiEnv, core::position2d<s32>(border,30), L"r", -1, groupElement );
- EditGreen = addEditForNumbers(guiEnv, core::position2d<s32>(border,45), L"g", -1, groupElement );
- EditBlue = addEditForNumbers(guiEnv, core::position2d<s32>(border,60), L"b", -1, groupElement );
- ColorStatic = guiEnv->addStaticText (L"", core::rect<s32>(60,15,80,75), true, false, groupElement, -1, true);
- guiEnv->addButton (core::rect<s32>(60,35,80,50), groupElement, ButtonSetId, L"set");
- setEditsFromColor(Color);
- }
- // event receiver
- bool CColorControl::OnEvent(const SEvent &event)
- {
- if ( event.EventType == EET_GUI_EVENT
- && event.GUIEvent.Caller->getID() == ButtonSetId
- && event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
- {
- Color = getColorFromEdits();
- setEditsFromColor(Color);
- }
- return false;
- }
- // set the color values
- void CColorControl::setColor(const video::SColor& col)
- {
- DirtyFlag = true;
- Color = col;
- setEditsFromColor(Color);
- }
- // Add a statictext for a description + an editbox so users can enter numbers
- gui::IGUIEditBox* CColorControl::addEditForNumbers(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t *text, s32 id, gui::IGUIElement * parent)
- {
- using namespace gui;
- core::recti rect(pos, pos+core::dimension2d<s32>(10, 15));
- guiEnv->addStaticText(text, rect, false, false, parent, -1, false);
- rect += core::position2d<s32>( 20, 0 );
- rect.LowerRightCorner.X += 20;
- gui::IGUIEditBox* edit = guiEnv->addEditBox(L"0", rect, true, parent, id);
- return edit;
- }
- // Get the color value from the editboxes
- video::SColor CColorControl::getColorFromEdits() const
- {
- video::SColor col;
- if (EditAlpha)
- {
- u32 alpha = core::min_(core::strtoul10(core::stringc(EditAlpha->getText()).c_str()), 255u);
- col.setAlpha(alpha);
- }
- if (EditRed)
- {
- u32 red = core::min_(core::strtoul10(core::stringc(EditRed->getText()).c_str()), 255u);
- col.setRed(red);
- }
- if (EditGreen)
- {
- u32 green = core::min_(core::strtoul10(core::stringc(EditGreen->getText()).c_str()), 255u);
- col.setGreen(green);
- }
- if (EditBlue)
- {
- u32 blue = core::min_(core::strtoul10(core::stringc(EditBlue->getText()).c_str()), 255u);
- col.setBlue(blue);
- }
- return col;
- }
- // Fill the editboxes with a color value
- void CColorControl::setEditsFromColor(video::SColor col)
- {
- DirtyFlag = true;
- if ( EditAlpha )
- EditAlpha->setText( core::stringw(col.getAlpha()).c_str() );
- if ( EditRed )
- EditRed->setText( core::stringw(col.getRed()).c_str() );
- if ( EditGreen )
- EditGreen->setText( core::stringw(col.getGreen()).c_str() );
- if ( EditBlue )
- EditBlue->setText( core::stringw(col.getBlue()).c_str() );
- if ( ColorStatic )
- ColorStatic->setBackgroundColor(col);
- }
- /*
- Custom GUI-control for to edit all colors typically used in materials and lights
- */
- // Constructor
- CTypicalColorsControl::CTypicalColorsControl(gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, bool hasEmissive, IGUIElement* parent, s32 id)
- : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect<s32>(pos,pos+core::dimension2d<s32>(60,250)))
- , ControlAmbientColor(0), ControlDiffuseColor(0), ControlSpecularColor(0), ControlEmissiveColor(0)
- {
- ControlAmbientColor = new CColorControl( guiEnv, core::position2d<s32>(0, 0), L"Ambient", this);
- ControlDiffuseColor = new CColorControl( guiEnv, core::position2d<s32>(0, 75), L"Diffuse", this );
- ControlSpecularColor = new CColorControl( guiEnv, core::position2d<s32>(0, 150), L"Specular", this );
- if ( hasEmissive )
- {
- ControlEmissiveColor = new CColorControl( guiEnv, core::position2d<s32>(0, 225), L"Emissive", this );
- }
- }
- // Destructor
- CTypicalColorsControl::~CTypicalColorsControl()
- {
- ControlAmbientColor->drop();
- ControlDiffuseColor->drop();
- if ( ControlEmissiveColor )
- ControlEmissiveColor->drop();
- ControlSpecularColor->drop();
- }
- // Set the color values to those within the material
- void CTypicalColorsControl::setColorsToMaterialColors(const video::SMaterial & material)
- {
- ControlAmbientColor->setColor(material.AmbientColor);
- ControlDiffuseColor->setColor(material.DiffuseColor);
- ControlEmissiveColor->setColor(material.EmissiveColor);
- ControlSpecularColor->setColor(material.SpecularColor);
- }
- // Update all changed colors in the material
- void CTypicalColorsControl::updateMaterialColors(video::SMaterial & material) const
- {
- if ( ControlAmbientColor->isDirty() )
- material.AmbientColor = ControlAmbientColor->getColor();
- if ( ControlDiffuseColor->isDirty() )
- material.DiffuseColor = ControlDiffuseColor->getColor();
- if ( ControlEmissiveColor->isDirty() )
- material.EmissiveColor = ControlEmissiveColor->getColor();
- if ( ControlSpecularColor->isDirty() )
- material.SpecularColor = ControlSpecularColor->getColor();
- }
- // Set the color values to those from the light data
- void CTypicalColorsControl::setColorsToLightDataColors(const video::SLight & lightData)
- {
- ControlAmbientColor->setColor(lightData.AmbientColor.toSColor());
- ControlDiffuseColor->setColor(lightData.DiffuseColor.toSColor());
- ControlSpecularColor->setColor(lightData.SpecularColor.toSColor());
- }
- // Update all changed colors in the light data
- void CTypicalColorsControl::updateLightColors(video::SLight & lightData) const
- {
- if ( ControlAmbientColor->isDirty() )
- lightData.AmbientColor = video::SColorf( ControlAmbientColor->getColor() );
- if ( ControlDiffuseColor->isDirty() )
- lightData.DiffuseColor = video::SColorf( ControlDiffuseColor->getColor() );
- if ( ControlSpecularColor->isDirty() )
- lightData.SpecularColor = video::SColorf(ControlSpecularColor->getColor() );
- }
- // To reset the dirty flags
- void CTypicalColorsControl::resetDirty()
- {
- ControlAmbientColor->resetDirty();
- ControlDiffuseColor->resetDirty();
- ControlSpecularColor->resetDirty();
- if ( ControlEmissiveColor )
- ControlEmissiveColor->resetDirty();
- }
- /*
- GUI-Control to offer a selection of available textures.
- */
- CTextureControl::CTextureControl(gui::IGUIEnvironment* guiEnv, video::IVideoDriver * driver, const core::position2d<s32> & pos, IGUIElement* parent, s32 id)
- : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect<s32>(pos,pos+core::dimension2d<s32>(150,15)))
- , DirtyFlag(true), ComboTexture(0)
- {
- core::rect<s32> rectCombo(0, 0, AbsoluteRect.getWidth(),AbsoluteRect.getHeight());
- ComboTexture = guiEnv->addComboBox (rectCombo, this);
- updateTextures(driver);
- }
- bool CTextureControl::OnEvent(const SEvent &event)
- {
- if ( event.EventType == EET_GUI_EVENT
- && event.GUIEvent.Caller == ComboTexture
- && event.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED )
- {
- DirtyFlag = true;
- }
- return false;
- }
- // Workaround for a problem with comboboxes.
- // We have to get in front when the combobox wants to get in front or combobox-list might be drawn below other elements.
- bool CTextureControl::bringToFront(IGUIElement* element)
- {
- bool result = gui::IGUIElement::bringToFront(element);
- if ( Parent && element == ComboTexture )
- result &= Parent->bringToFront(this);
- return result;
- }
- // return selected texturename (if any, otherwise 0)
- const wchar_t * CTextureControl::getSelectedTextureName() const
- {
- s32 selected = ComboTexture->getSelected();
- if ( selected < 0 )
- return 0;
- return ComboTexture->getItem(selected);
- }
- void CTextureControl::selectTextureByName(const irr::core::stringw& name)
- {
- for (u32 i=0; i< ComboTexture->getItemCount(); ++i)
- {
- if ( name == ComboTexture->getItem(i))
- {
- ComboTexture->setSelected(i);
- DirtyFlag = true;
- return;
- }
- }
- }
- // Put the names of all currently loaded textures in a combobox
- void CTextureControl::updateTextures(video::IVideoDriver * driver)
- {
- s32 oldSelected = ComboTexture->getSelected();
- core::stringw oldTextureName;
- if ( oldSelected >= 0 )
- {
- oldTextureName = ComboTexture->getItem(oldSelected);
- }
- ComboTexture->clear();
- s32 selectNew = -1;
- for ( u32 i=0; i < driver->getTextureCount(); ++i )
- {
- video::ITexture * texture = driver->getTextureByIndex(i);
- core::stringw name( texture->getName() );
- ComboTexture->addItem( name.c_str() );
- if ( !oldTextureName.empty() && selectNew < 0 && name == oldTextureName )
- selectNew = i;
- }
- // add another name which can be used to clear the texture
- ComboTexture->addItem( CLEAR_TEXTURE.c_str() );
- if ( CLEAR_TEXTURE == oldTextureName )
- selectNew = ComboTexture->getItemCount()-1;
- if ( selectNew >= 0 )
- ComboTexture->setSelected(selectNew);
- DirtyFlag = true;
- }
- /*
- Control which allows setting some of the material values for a meshscenenode
- */
- void CMaterialControl::init(IrrlichtDevice * device, const core::position2d<s32> & pos, const wchar_t * description)
- {
- if ( Initialized || !device) // initializing twice or with invalid data not allowed
- return;
- Driver = device->getVideoDriver ();
- gui::IGUIEnvironment* guiEnv = device->getGUIEnvironment();
- s32 top = pos.Y;
- // Description
- guiEnv->addStaticText(description, core::rect<s32>(pos.X, top, pos.X+150, top+15), true, false, 0, -1, true);
- top += 15;
- // Control for material type
- core::rect<s32> rectCombo(pos.X, top, pos.X+150, top+15);
- top += 15;
- ComboMaterial = guiEnv->addComboBox (rectCombo);
- for ( int i=0; i <= (int)video::EMT_ONETEXTURE_BLEND; ++i )
- {
- ComboMaterial->addItem( core::stringw(video::sBuiltInMaterialTypeNames[i]).c_str() );
- }
- ComboMaterial->setSelected(0);
- // Control to enable/disabling material lighting
- core::rect<s32> rectBtn(core::position2d<s32>(pos.X, top), core::dimension2d<s32>(100, 15));
- top += 15;
- ButtonLighting = guiEnv->addButton (rectBtn, 0, -1, L"Lighting");
- ButtonLighting->setIsPushButton(true);
- core::rect<s32> rectInfo( rectBtn.LowerRightCorner.X, rectBtn.UpperLeftCorner.Y, rectBtn.LowerRightCorner.X+50, rectBtn.UpperLeftCorner.Y+15 );
- InfoLighting = guiEnv->addStaticText(L"", rectInfo, true, false );
- InfoLighting->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER );
- // Controls for colors
- TypicalColorsControl = new CTypicalColorsControl(guiEnv, core::position2d<s32>(pos.X, top), true, guiEnv->getRootGUIElement());
- top += 300;
- guiEnv->addStaticText(L"Shininess", core::rect<s32>(pos.X, top, pos.X + 150, top + 15), true, false, 0, -1, true);
- top += 15;
- ShininessControl = guiEnv->addScrollBar(true, core::rect<s32>(pos.X, top, pos.X + 150, top + 15));
- ShininessControl->setMax(10000);
- top += 20;
- // Controls for selecting the material textures
- guiEnv->addStaticText(L"Textures", core::rect<s32>(pos.X, top, pos.X+150, top+15), true, false, 0, -1, true);
- top += 15;
- // The default material types only use first 2 textures
- irr::u32 maxTextures = core::min_(2u, irr::video::MATERIAL_MAX_TEXTURES);
- for (irr::u32 i=0; i<maxTextures; ++i)
- {
- TextureControls.push_back(new CTextureControl(guiEnv, Driver, core::position2di(pos.X, top), guiEnv->getRootGUIElement()));
- top += 15;
- }
- Initialized = true;
- }
- void CMaterialControl::setMaterial(const irr::video::SMaterial & material)
- {
- if (ComboMaterial)
- ComboMaterial->setSelected( (s32)material.MaterialType );
- if (ButtonLighting)
- ButtonLighting->setPressed(material.Lighting);
- if (TypicalColorsControl)
- TypicalColorsControl->setColorsToMaterialColors(material);
- for (irr::u32 i=0; i<TextureControls.size(); ++i)
- TextureControls[i]->setDirty();
- if (ShininessControl)
- ShininessControl->setPos((int)(material.Shininess*100.f));
- }
- void CMaterialControl::update(scene::IMeshSceneNode* sceneNode, scene::IMeshSceneNode* sceneNode2T, scene::IMeshSceneNode* sceneNodeTangents)
- {
- if ( !Initialized )
- return;
- video::SMaterial & material = sceneNode->getMaterial(0);
- video::SMaterial & material2T = sceneNode2T->getMaterial(0);
- video::SMaterial & materialTangents = sceneNodeTangents->getMaterial(0);
- s32 selectedMaterial = ComboMaterial->getSelected();
- if ( selectedMaterial >= (s32)video::EMT_SOLID && selectedMaterial <= (s32)video::EMT_ONETEXTURE_BLEND)
- {
- // Show the node which has a mesh to work with the currently selected material
- video::E_VERTEX_TYPE vertexType = getVertexTypeForMaterialType((video::E_MATERIAL_TYPE)selectedMaterial);
- switch ( vertexType )
- {
- case video::EVT_STANDARD:
- material.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial;
- sceneNode->setVisible(true);
- sceneNode2T->setVisible(false);
- sceneNodeTangents->setVisible(false);
- break;
- case video::EVT_2TCOORDS:
- material2T.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial;
- sceneNode->setVisible(false);
- sceneNode2T->setVisible(true);
- sceneNodeTangents->setVisible(false);
- break;
- case video::EVT_TANGENTS:
- materialTangents.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial;
- sceneNode->setVisible(false);
- sceneNode2T->setVisible(false);
- sceneNodeTangents->setVisible(true);
- break;
- }
- }
- // Always update materials of all nodes, otherwise the tool is confusing to use.
- updateMaterial(material);
- updateMaterial(material2T);
- updateMaterial(materialTangents);
- if ( ButtonLighting->isPressed() )
- InfoLighting->setText(L"is on");
- else
- InfoLighting->setText(L"is off");
- TypicalColorsControl->resetDirty();
- for (irr::u32 i=0; i<TextureControls.size(); ++i)
- TextureControls[i]->resetDirty();
- }
- void CMaterialControl::updateTextures()
- {
- for (irr::u32 i=0; i<TextureControls.size(); ++i)
- TextureControls[i]->updateTextures(Driver);
- }
- void CMaterialControl::selectTextures(const irr::core::stringw& name)
- {
- for (irr::u32 i=0; i<TextureControls.size(); ++i)
- TextureControls[i]->selectTextureByName(name);
- }
- bool CMaterialControl::isLightingEnabled() const
- {
- return ButtonLighting && ButtonLighting->isPressed();
- }
- void CMaterialControl::updateMaterial(video::SMaterial & material)
- {
- TypicalColorsControl->updateMaterialColors(material);
- material.Lighting = ButtonLighting->isPressed();
- for (irr::u32 i=0; i<TextureControls.size(); ++i)
- {
- if ( TextureControls[i]->isDirty() )
- {
- material.TextureLayer[i].Texture = Driver->findTexture( io::path(TextureControls[i]->getSelectedTextureName()) );
- }
- }
- material.Shininess = ShininessControl->getPos() * 0.01f;
- }
- /*
- Control to allow setting the color values of a lightscenenode.
- */
- void CLightNodeControl::init(scene::ILightSceneNode* node, gui::IGUIEnvironment* guiEnv, const core::position2d<s32> & pos, const wchar_t * description)
- {
- if ( Initialized || !node || !guiEnv) // initializing twice or with invalid data not allowed
- return;
- gui::IGUIStaticText* st = guiEnv->addStaticText(description, core::rect<s32>(pos.X, pos.Y, pos.X+80, pos.Y+15), true, false, 0, -1, true);
- st->setAlignment(irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT);
- TypicalColorsControl = new CTypicalColorsControl(guiEnv, core::position2d<s32>(pos.X, pos.Y+15), false, guiEnv->getRootGUIElement());
- TypicalColorsControl->setAlignment(irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT);
- const video::SLight & lightData = node->getLightData();
- TypicalColorsControl->setColorsToLightDataColors(lightData);
- Initialized = true;
- }
- void CLightNodeControl::update(scene::ILightSceneNode* node)
- {
- if ( !Initialized )
- return;
- video::SLight & lightData = node->getLightData();
- TypicalColorsControl->updateLightColors(lightData);
- }
- /*
- Main application class
- */
- // Event handler
- bool CApp::OnEvent(const SEvent &event)
- {
- if (event.EventType == EET_GUI_EVENT)
- {
- gui::IGUIEnvironment* env = Device->getGUIEnvironment();
- switch(event.GUIEvent.EventType)
- {
- case gui::EGET_MENU_ITEM_SELECTED:
- {
- gui::IGUIContextMenu* menu = (gui::IGUIContextMenu*)event.GUIEvent.Caller;
- s32 id = menu->getItemCommandId(menu->getSelectedItem());
- switch(id)
- {
- case GUI_ID_OPEN_TEXTURE: // File -> Open Texture
- env->addFileOpenDialog(L"Please select a texture file to open");
- break;
- case GUI_ID_QUIT: // File -> Quit
- setRunning(false);
- break;
- }
- }
- break;
- case gui::EGET_FILE_SELECTED:
- {
- // load the texture file, selected in the file open dialog
- gui::IGUIFileOpenDialog* dialog =
- (gui::IGUIFileOpenDialog*)event.GUIEvent.Caller;
- loadTexture(io::path(dialog->getFileName()).c_str());
- }
- break;
- case gui::EGET_COMBO_BOX_CHANGED:
- if (event.GUIEvent.Caller == ComboMeshType )
- {
- irr::scene::IMeshSceneNode* currentNode = getVisibleMeshNode();
- if (currentNode)
- {
- // ensure next mesh will get same color and material settings
- if ( ControlVertexColors )
- {
- video::S3DVertex * vertices = (video::S3DVertex *)currentNode->getMesh()->getMeshBuffer(0)->getVertices();
- ControlVertexColors->setColor(vertices[0].Color);
- }
- if ( MeshMaterialControl )
- MeshMaterialControl->setMaterial(currentNode->getMaterial(0));
- }
- setActiveMeshNodeType((ENodeType)ComboMeshType->getSelected());
- return true;
- }
- break;
- default:
- break;
- }
- }
- else if (event.EventType == EET_KEY_INPUT_EVENT)
- {
- KeysPressed[event.KeyInput.Key] = event.KeyInput.PressedDown;
- }
- else if (event.EventType == EET_MOUSE_INPUT_EVENT)
- {
- if (!MousePressed && event.MouseInput.isLeftPressed())
- {
- gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment();
- if ( guiEnv->getHovered() == guiEnv->getRootGUIElement() ) // Click on background
- {
- MousePressed = true;
- MouseStart.X = event.MouseInput.X;
- MouseStart.Y = event.MouseInput.Y;
- }
- }
- else if (MousePressed && !event.MouseInput.isLeftPressed())
- {
- MousePressed = false;
- }
- }
- return false;
- }
- // Application initialization
- // returns true when it was successful initialized, otherwise false.
- bool CApp::init(int argc, char *argv[])
- {
- // ask user for driver
- Config.DriverType=driverChoiceConsole();
- if (Config.DriverType==video::EDT_COUNT)
- return false;
- // create the device with the settings from our config
- Device = createDevice(Config.DriverType, Config.ScreenSize);
- if (!Device)
- return false;
- Device->setWindowCaption( core::stringw(video::DRIVER_TYPE_NAMES[Config.DriverType]).c_str() );
- Device->setEventReceiver(this);
- scene::ISceneManager* smgr = Device->getSceneManager();
- video::IVideoDriver * driver = Device->getVideoDriver ();
- gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment();
- MeshManipulator = smgr->getMeshManipulator();
- // set a nicer font
- gui::IGUISkin* skin = guiEnv->getSkin();
- gui::IGUIFont* font = guiEnv->getFont(getExampleMediaPath() + "fonthaettenschweiler.bmp");
- if (font)
- skin->setFont(font);
- // remove some alpha value because it makes those menus harder to read otherwise
- video::SColor col3dHighLight( skin->getColor(gui::EGDC_APP_WORKSPACE) );
- col3dHighLight.setAlpha(255);
- video::SColor colHighLight( col3dHighLight );
- skin->setColor(gui::EGDC_HIGH_LIGHT, colHighLight );
- skin->setColor(gui::EGDC_3D_HIGH_LIGHT, col3dHighLight );
- // Add some textures which are useful to test material settings
- createDefaultTextures(driver);
- // create a menu
- gui::IGUIContextMenu * menuBar = guiEnv->addMenu();
- menuBar->addItem(L"File", -1, true, true);
- gui::IGUIContextMenu* subMenuFile = menuBar->getSubMenu(0);
- subMenuFile->addItem(L"Open texture ...", GUI_ID_OPEN_TEXTURE);
- subMenuFile->addSeparator();
- subMenuFile->addItem(L"Quit", GUI_ID_QUIT);
- // a static camera
- Camera = smgr->addCameraSceneNode (0, core::vector3df(0, 30, -50),
- core::vector3df(0, 0, 0),
- -1);
- setActiveMeshNodeType(ENT_CUBE);
- const s32 controlsTop = 20;
- MeshMaterialControl = new CMaterialControl();
- MeshMaterialControl->init( Device, core::position2d<s32>(10,controlsTop), L"Material");
- MeshMaterialControl->setMaterial(SceneNode->getMaterial(0));
- MeshMaterialControl->selectTextures(core::stringw("CARO_A8R8G8B8")); // set a useful default texture
- // add one light
- const f32 lightRadius = 80.f;
- NodeLight = smgr->addLightSceneNode(0, core::vector3df(0, 30, -70),
- video::SColorf(1.0f, 1.0f, 1.0f),
- lightRadius);
- LightControl = new CLightNodeControl();
- LightControl->init(NodeLight, guiEnv, core::position2d<s32>(550,controlsTop), L"Dynamic light" );
- #if 0 // enable to have some visual feedback for the light size
- scene::IMeshSceneNode* lightRadiusNode = smgr->addSphereSceneNode(lightRadius, 64, NodeLight);
- lightRadiusNode->getMaterial(0).Lighting = false;
- lightRadiusNode->getMaterial(0).Wireframe = true;
- #endif
- // one large cube around everything. That's mainly to make the light more obvious.
- scene::IMeshSceneNode* backgroundCube = smgr->addCubeSceneNode (200.0f, 0, -1, core::vector3df(0, 0, 0),
- core::vector3df(45, 0, 0),
- core::vector3df(1.0f, 1.0f, 1.0f));
- backgroundCube->getMaterial(0).BackfaceCulling = false; // we are within the cube, so we have to disable backface culling to see it
- backgroundCube->getMaterial(0).EmissiveColor.set(255,50,50,50); // we keep some self lighting to keep texts visible
- // Add a the mesh UI controls
- gui::IGUIStaticText* stMesh = guiEnv->addStaticText(L"Mesh", core::rect<s32>(440, controlsTop, 520, controlsTop+15), true, false, 0, -1, true);
- stMesh->setAlignment(irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT);
- ComboMeshType = guiEnv->addComboBox(core::rect<s32>(440, controlsTop+16, 520, controlsTop+30), 0, -1);
- ComboMeshType->setAlignment(irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT);
- ComboMeshType->addItem(L"cube");
- ComboMeshType->addItem(L"sphere");
- ComboMeshType->addItem(L"sphere highres");
- ControlVertexColors = new CColorControl( guiEnv, core::position2d<s32>(440, controlsTop+30), L"Vertex colors", guiEnv->getRootGUIElement());
- ControlVertexColors->setAlignment(irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT);
- ControlVertexColors->setColor(irr::video::SColor(255,255,255,255));
- // Add a control for ambient light
- GlobalAmbient = new CColorControl( guiEnv, core::position2d<s32>(550, 300), L"Global ambient", guiEnv->getRootGUIElement());
- GlobalAmbient->setColor( smgr->getAmbientLight().toSColor() );
- GlobalAmbient->setAlignment(irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_LOWERRIGHT, irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT);
- return true;
- }
- /*
- Update one frame
- */
- bool CApp::update()
- {
- video::IVideoDriver* videoDriver = Device->getVideoDriver();
- if ( !Device->run() )
- return false;
- // Figure out delta time since last frame
- u32 newTick = Device->getTimer()->getRealTime();
- f32 deltaTime = RealTimeTick > 0 ? f32(newTick-RealTimeTick)/1000.f : 0.f; // in seconds
- RealTimeTick = newTick;
- if ( Device->isWindowActive() || Config.RenderInBackground )
- {
- gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment();
- scene::ISceneManager* smgr = Device->getSceneManager();
- gui::IGUISkin * skin = guiEnv->getSkin();
- // update our controls
- MeshMaterialControl->update(SceneNode, SceneNode2T, SceneNodeTangents);
- LightControl->update(NodeLight);
- // Update vertices
- if ( ControlVertexColors->isDirty() )
- {
- MeshManipulator->setVertexColors (SceneNode->getMesh(), ControlVertexColors->getColor());
- MeshManipulator->setVertexColors (SceneNode2T->getMesh(), ControlVertexColors->getColor());
- MeshManipulator->setVertexColors (SceneNodeTangents->getMesh(), ControlVertexColors->getColor());
- ControlVertexColors->resetDirty();
- }
- // update ambient light settings
- if ( GlobalAmbient->isDirty() )
- {
- smgr->setAmbientLight( GlobalAmbient->getColor() );
- GlobalAmbient->resetDirty();
- }
- const float zoomSpeed = (KeysPressed[KEY_LSHIFT] ? 40.f : 10.f) * deltaTime;
- const float rotationSpeed = (KeysPressed[KEY_LSHIFT] ? 20.f : 100.f) * deltaTime;
- // Let the user move the light around
- irr::gui::IGUIElement* focus=guiEnv->getFocus(); // some checks to prevent interfering with UI input
- if ( !focus || focus == guiEnv->getRootGUIElement()
- || focus->getType() == irr::gui::EGUIET_STATIC_TEXT
- || focus->getType() == irr::gui::EGUIET_BUTTON
- )
- {
- if ( KeysPressed[KEY_PLUS] || KeysPressed[KEY_ADD])
- ZoomOut(NodeLight, zoomSpeed);
- if ( KeysPressed[KEY_MINUS] || KeysPressed[KEY_SUBTRACT])
- ZoomOut(NodeLight, -zoomSpeed);
- if ( KeysPressed[KEY_RIGHT])
- RotateHorizontal(NodeLight, rotationSpeed);
- if ( KeysPressed[KEY_LEFT])
- RotateHorizontal(NodeLight, -rotationSpeed);
- UpdateRotationAxis(NodeLight, LightRotationAxis);
- if ( KeysPressed[KEY_UP])
- RotateAroundAxis(NodeLight, rotationSpeed, LightRotationAxis);
- if ( KeysPressed[KEY_DOWN])
- RotateAroundAxis(NodeLight, -rotationSpeed, LightRotationAxis);
- }
- // Let the user move the camera around
- if (MousePressed && !focus)
- {
- gui::ICursorControl* cursorControl = Device->getCursorControl();
- const core::position2d<s32>& mousePos = cursorControl->getPosition ();
- RotateHorizontal(Camera, rotationSpeed * (MouseStart.X - mousePos.X));
- RotateAroundAxis(Camera, rotationSpeed * (mousePos.Y - MouseStart.Y), CameraRotationAxis);
- MouseStart = mousePos;
- }
- // draw everything
- video::SColor bkColor( skin->getColor(gui::EGDC_APP_WORKSPACE) );
- videoDriver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, bkColor);
- smgr->drawAll();
- guiEnv->drawAll();
- if ( MeshMaterialControl->isLightingEnabled() )
- {
- // draw a line from the light to the target
- video::SMaterial lineMaterial;
- lineMaterial.Lighting = false;
- videoDriver->setMaterial(lineMaterial);
- videoDriver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
- videoDriver->draw3DLine(NodeLight->getAbsolutePosition(), SceneNode->getAbsolutePosition());
- }
- videoDriver->endScene();
- }
- // be nice
- Device->yield();
- return true;
- }
- // Close down the application
- void CApp::quit()
- {
- IsRunning = false;
- delete LightControl;
- LightControl = NULL;
- delete MeshMaterialControl;
- MeshMaterialControl = NULL;
- if ( ControlVertexColors )
- {
- ControlVertexColors->drop();
- ControlVertexColors = NULL;
- }
- if ( GlobalAmbient )
- {
- GlobalAmbient->drop();
- GlobalAmbient = NULL;
- }
- if ( Device )
- {
- Device->closeDevice();
- Device->drop();
- Device = NULL;
- }
- }
- // Create some useful textures.
- void CApp::createDefaultTextures(video::IVideoDriver * driver)
- {
- const u32 width = 256;
- const u32 height = 256;
- video::IImage * imageA8R8G8B8 = driver->createImage (video::ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
- if ( !imageA8R8G8B8 )
- return;
- const u32 pitch = imageA8R8G8B8->getPitch();
- // Some nice square-pattern with 9 typical colors
- // Note that the function put readability over speed, you shouldn't use setPixel at runtime but for initialization it's nice.
- for ( u32 y = 0; y < height; ++ y )
- {
- for ( u32 x = 0; x < pitch; ++x )
- {
- if ( y < height/3 )
- {
- if ( x < width/3 )
- imageA8R8G8B8->setPixel (x, y, SCOL_BLACK);
- else if ( x < 2*width/3 )
- imageA8R8G8B8->setPixel (x, y, SCOL_BLUE);
- else
- imageA8R8G8B8->setPixel (x, y, SCOL_CYAN);
- }
- else if ( y < 2*height/3 )
- {
- if ( x < width/3 )
- imageA8R8G8B8->setPixel (x, y, SCOL_GRAY);
- else if ( x < 2*width/3 )
- imageA8R8G8B8->setPixel (x, y, SCOL_GREEN);
- else
- imageA8R8G8B8->setPixel (x, y, SCOL_MAGENTA);
- }
- else
- {
- if ( x < width/3 )
- imageA8R8G8B8->setPixel (x, y, SCOL_RED);
- else if ( x < 2*width/3 )
- imageA8R8G8B8->setPixel (x, y, SCOL_YELLOW);
- else
- imageA8R8G8B8->setPixel (x, y, SCOL_WHITE);
- }
- }
- }
- driver->addTexture (io::path("CARO_A8R8G8B8"), imageA8R8G8B8);
- // all white
- imageA8R8G8B8->fill(SCOL_WHITE);
- driver->addTexture (io::path("WHITE_A8R8G8B8"), imageA8R8G8B8);
- // all black
- imageA8R8G8B8->fill(SCOL_BLACK);
- driver->addTexture (io::path("BLACK_A8R8G8B8"), imageA8R8G8B8);
- // gray-scale
- for ( u32 y = 0; y < height; ++ y )
- {
- for ( u32 x = 0; x < pitch; ++x )
- {
- imageA8R8G8B8->setPixel (x, y, video::SColor(y, x,x,x) );
- }
- }
- driver->addTexture (io::path("GRAYSCALE_A8R8G8B8"), imageA8R8G8B8);
- imageA8R8G8B8->drop();
- }
- // Load a texture and make sure UI knows it when more textures are available.
- void CApp::loadTexture(const io::path &name)
- {
- Device->getVideoDriver()->getTexture(name);
- MeshMaterialControl->updateTextures();
- }
- void CApp::RotateHorizontal(irr::scene::ISceneNode* node, irr::f32 angle)
- {
- if ( node )
- {
- core::vector3df pos(node->getPosition());
- core::vector2df dir(pos.X, pos.Z);
- dir.rotateBy(angle);
- pos.X = dir.X;
- pos.Z = dir.Y;
- node->setPosition(pos);
- }
- }
- void CApp::RotateAroundAxis(irr::scene::ISceneNode* node, irr::f32 angle, const irr::core::vector3df& axis)
- {
- if ( node )
- {
- // TOOD: yeah, doesn't rotate around top/bottom yet. Fixes welcome.
- core::vector3df pos(node->getPosition());
- core::matrix4 mat;
- mat.setRotationAxisRadians (core::degToRad(angle), axis);
- mat.rotateVect(pos);
- node->setPosition(pos);
- }
- }
- void CApp::ZoomOut(irr::scene::ISceneNode* node, irr::f32 units)
- {
- if ( node )
- {
- core::vector3df pos(node->getPosition());
- irr::f32 len = pos.getLength() + units;
- pos.setLength(len);
- node->setPosition(pos);
- }
- }
- void CApp::UpdateRotationAxis(irr::scene::ISceneNode* node, irr::core::vector3df& axis)
- {
- // Find a perpendicular axis to the x,z vector. If none found (vector straight up/down) continue to use the existing one.
- core::vector3df pos(node->getPosition());
- if ( !core::equals(pos.X, 0.f) || !core::equals(pos.Z, 0.f) )
- {
- axis.X = -pos.Z;
- axis.Z = pos.X;
- axis.normalize();
- }
- }
- void CApp::setActiveMeshNodeType(ENodeType nodeType)
- {
- scene::ISceneManager* smgr = Device->getSceneManager();
- if ( SceneNode )
- smgr->addToDeletionQueue(SceneNode);
- SceneNode = nullptr;
- if ( SceneNode2T )
- smgr->addToDeletionQueue(SceneNode2T);
- SceneNode2T = nullptr;
- if ( SceneNodeTangents )
- smgr->addToDeletionQueue(SceneNodeTangents);
- SceneNodeTangents = nullptr;
- // default material
- video::SMaterial defaultMaterial;
- defaultMaterial.Shininess = 20.f;
-
- // add the nodes which are used to show the materials
- const irr::f32 size = 35.f;
- if ( nodeType == ENT_CUBE )
- {
- SceneNode = smgr->addCubeSceneNode (size, 0, -1,
- core::vector3df(0, 0, 0),
- core::vector3df(0.f, 45.f, 0.f),
- core::vector3df(1.0f, 1.0f, 1.0f),
- scene::ECMT_1BUF_24VTX_NP);
- // avoid wrong colored lines at cube-borders (uv's go from 0-1 currently, which does not work well with interpolation)
- for ( u32 i=0; i < irr::video::MATERIAL_MAX_TEXTURES_USED; ++i)
- {
- defaultMaterial.TextureLayer[i].TextureWrapU = irr::video::ETC_CLAMP_TO_EDGE;
- defaultMaterial.TextureLayer[i].TextureWrapV = irr::video::ETC_CLAMP_TO_EDGE;
- }
- }
- else
- {
- SceneNode = smgr->addSphereSceneNode(size * 0.5f, nodeType == ENT_SPHERE_HIGHRES ? 128 : 16);
- }
- // off center to test shader
- //SceneNode->setPosition(core::vector3df(20.f, -4.f, 10.f));
- //SceneNode->setScale(core::vector3df(1.f, 0.2f, 1.5f));
- //SceneNode->setRotation(core::vector3df(0.f, 30.f, -10.f));
- //defaultMaterial.NormalizeNormals = true;
- SceneNode->getMaterial(0) = defaultMaterial;
- // SceneNode->setDebugDataVisible(scene::EDS_NORMALS); // showing normals can sometimes be useful to understand what's going on
- // create nodes with other vertex types
- scene::IMesh * mesh2T = MeshManipulator->createMeshWith2TCoords(SceneNode->getMesh());
- SceneNode2T = smgr->addMeshSceneNode(mesh2T, 0, -1, SceneNode->getPosition(), SceneNode->getRotation(), SceneNode->getScale() );
- mesh2T->drop();
- scene::IMesh * meshTangents = MeshManipulator->createMeshWithTangents(SceneNode->getMesh(), false, false, false);
- SceneNodeTangents = smgr->addMeshSceneNode(meshTangents, 0, -1
- , SceneNode->getPosition(), SceneNode->getRotation(), SceneNode->getScale() );
- meshTangents->drop();
- }
- irr::scene::IMeshSceneNode* CApp::getVisibleMeshNode() const
- {
- if ( SceneNode && SceneNode->isVisible() )
- return SceneNode;
- if ( SceneNode2T && SceneNode2T->isVisible() )
- return SceneNode2T;
- if ( SceneNodeTangents && SceneNodeTangents->isVisible() )
- return SceneNodeTangents;
- return nullptr;
- }
- /*
- Short main as most is done in classes.
- */
- int main(int argc, char *argv[])
- {
- CApp APP;
- if ( !APP.init(argc, argv) )
- {
- printf("init failed\n");
- APP.quit();
- return 1;
- }
- APP.setRunning(true);
- /*
- main application loop
- */
- while(APP.isRunning())
- {
- if ( !APP.update() )
- break;
- }
- APP.quit();
- return 0;
- }
- /*
- **/
|