mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-27 03:00:32 +01:00
a3adfc196b
We had changed that once before in the other direction in svn r421 Reason back then was "Sleep(0) doesn't allow any lower priority threads to execute" But Microsoft changed the behaviour of Sleep(0) after Windows XP so that's no longer true. And the costs of it is pretty high - due to this using a timer with a 15ms resolutions it meant not just giving up the thread but it also always waited for 15ms on Windows. I also replaced a few sleep calls in examples for that reason with yield() calls. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6459 dfc29bdd-3216-0410-991c-e03cc46cb475
1146 lines
37 KiB
C++
Executable File
1146 lines
37 KiB
C++
Executable File
/** 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;
|
|
}
|
|
|
|
/*
|
|
**/
|