Show how to modify cursors and offer some useful tool-functions for creating cursors. It can also be used for experiments with the mouse in general.
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
const int DELAY_TIME = 3000;
enum ETimerAction
{
ETA_MOUSE_VISIBLE,
ETA_MOUSE_INVISIBLE,
};
Main header file of the irrlicht, the only file needed to include.
Everything in the Irrlicht Engine can be found in this namespace.
Structure to allow delayed execution of some actions.
struct TimerAction
{
ETimerAction Action;
};
unsigned int u32
32 bit unsigned variable.
struct SAppContext
{
SAppContext()
: Device(0), InfoStatic(0), EventBox(0), CursorBox(0), SpriteBox(0)
, ButtonSetVisible(0), ButtonSetInvisible(0), ButtonSimulateBadFps(0)
, ButtonChangeIcon(0)
, SimulateBadFps(false)
{
}
void update()
{
if (!Device)
return;
u32 timeNow = Device->getTimer()->getTime();
for (
u32 i=0; i < TimerActions.size(); ++i )
{
if ( timeNow >= TimerActions[i].TargetTime )
{
runTimerAction(TimerActions[i]);
TimerActions.erase(i);
}
else
{
++i;
}
}
}
void runTimerAction(const TimerAction& action)
{
if (ETA_MOUSE_VISIBLE == action.Action)
{
Device->getCursorControl()->setVisible(true);
ButtonSetVisible->setEnabled(true);
}
else if ( ETA_MOUSE_INVISIBLE == action.Action)
{
Device->getCursorControl()->setVisible(false);
ButtonSetInvisible->setEnabled(true);
}
}
Add another icon which the user can click and select as cursor later on.
void addIcon(
const stringw& name,
const SCursorSprite &sprite,
bool addCursor=
true)
{
SpriteBox->addItem(name.c_str(), sprite.SpriteId);
Sprites.push_back(sprite);
if ( addCursor )
{
string< wchar_t > stringw
Typedef for wide character strings.
Here we create a hardware cursor from a sprite
Device->getCursorControl()->addIcon(sprite);
CursorBox->addItem(name.c_str());
}
}
IrrlichtDevice * Device;
gui::IGUIStaticText * InfoStatic;
gui::IGUIListBox * EventBox;
gui::IGUIListBox * CursorBox;
gui::IGUIListBox * SpriteBox;
gui::IGUIButton * ButtonSetVisible;
gui::IGUIButton * ButtonSetInvisible;
gui::IGUIButton * ButtonSimulateBadFps;
gui::IGUIButton * ButtonChangeIcon;
array<TimerAction> TimerActions;
bool SimulateBadFps;
array<SCursorSprite> Sprites;
};
Helper function to print mouse event names into a stringw
void PrintMouseEventName(
const SEvent& event,
stringw &result)
{
switch ( event.MouseInput.Event )
{
default:
break;
}
}
@ EMIE_LMOUSE_TRIPLE_CLICK
@ EMIE_MMOUSE_LEFT_UP
Middle mouse button was left up.
@ EMIE_LMOUSE_LEFT_UP
Left mouse button was left up.
@ EMIE_MMOUSE_PRESSED_DOWN
Middle mouse button was pressed down.
@ EMIE_LMOUSE_PRESSED_DOWN
Left mouse button was pressed down.
@ EMIE_LMOUSE_DOUBLE_CLICK
@ EMIE_MMOUSE_TRIPLE_CLICK
@ EMIE_MMOUSE_DOUBLE_CLICK
@ EMIE_RMOUSE_DOUBLE_CLICK
@ EMIE_RMOUSE_TRIPLE_CLICK
@ EMIE_RMOUSE_PRESSED_DOWN
Right mouse button was pressed down.
@ EMIE_RMOUSE_LEFT_UP
Right mouse button was left up.
@ EMIE_MOUSE_MOVED
The mouse cursor changed its position.
Helper function to print all the state information which get from a mouse-event into a stringw
void PrintMouseState(
const SEvent& event,
stringw &result)
{
result +=
stringw(event.MouseInput.X);
result +=
stringw(event.MouseInput.Y);
result +=
stringw(event.MouseInput.Wheel);
if ( event.MouseInput.Shift )
else
if ( event.MouseInput.Control )
else
result +=
stringw(L
"ButtonStates: ");
result +=
stringw(event.MouseInput.ButtonStates);
result +=
stringw(L
"isLeftPressed: ");
if ( event.MouseInput.isLeftPressed() )
else
result +=
stringw(L
"isRightPressed: ");
if ( event.MouseInput.isRightPressed() )
else
result +=
stringw(L
"isMiddlePressed: ");
if ( event.MouseInput.isMiddlePressed() )
else
PrintMouseEventName(event, result);
}
A typical event receiver.
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(SAppContext & context) : Context(context) { }
virtual bool OnEvent(const SEvent& event)
{
{
switch ( event.GUIEvent.EventType )
{
{
u32 timeNow = Context.Device->getTimer()->getTime();
TimerAction action;
action.TargetTime = timeNow + DELAY_TIME;
if ( event.GUIEvent.Caller == Context.ButtonSetVisible )
{
action.Action = ETA_MOUSE_VISIBLE;
Context.TimerActions.push_back(action);
Context.ButtonSetVisible->setEnabled(false);
}
else if ( event.GUIEvent.Caller == Context.ButtonSetInvisible )
{
action.Action = ETA_MOUSE_INVISIBLE;
Context.TimerActions.push_back(action);
Context.ButtonSetInvisible->setEnabled(false);
}
else if ( event.GUIEvent.Caller == Context.ButtonSimulateBadFps )
{
Context.SimulateBadFps = Context.ButtonSimulateBadFps->isPressed();
}
else if ( event.GUIEvent.Caller == Context.ButtonChangeIcon )
{
@ EGET_BUTTON_CLICKED
A button was clicked.
@ EET_GUI_EVENT
An event of the graphical user interface.
Replace an existing cursor icon by another icon. The user has to select both - the icon which should be replaced and the icon which will replace it.
s32 selectedCursor = Context.CursorBox->getSelected();
s32 selectedSprite = Context.SpriteBox->getSelected();
if ( selectedCursor >= 0 && selectedSprite >= 0 )
{
signed int s32
32 bit signed variable.
This does replace the icon.
Context.Device->getCursorControl()->changeIcon((
ECURSOR_ICON)selectedCursor, Context.Sprites[selectedSprite] );
ECURSOR_ICON
Default icons for cursors.
Do also show the new icon.
Context.Device->getCursorControl()->setActiveIcon(
ECURSOR_ICON(selectedCursor) );
}
}
}
break;
{
if ( event.GUIEvent.Caller == Context.CursorBox )
{
@ EGET_LISTBOX_SELECTED_AGAIN
An item in the listbox was selected, which was already selected.
@ EGET_LISTBOX_CHANGED
A new item in a listbox was selected.
Find out which cursor the user selected
s32 selected = Context.CursorBox->getSelected();
if ( selected >= 0 )
{
Here we set the new cursor icon which will now be used within our window.
Context.Device->getCursorControl()->setActiveIcon(
ECURSOR_ICON(selected) );
}
}
}
break;
default:
break;
}
}
{
PrintMouseState(event, infoText);
Context.InfoStatic->setText(infoText.c_str());
{
infoText = L"";
PrintMouseEventName(event, infoText);
Context.EventBox->insertItem(0, infoText.c_str(), -1);
}
}
return false;
}
private:
SAppContext & Context;
};
@ EET_MOUSE_INPUT_EVENT
A mouse input event.
Use several imagefiles as animation frames for a sprite which can be used as cursor icon. The images in those files all need to have the same size. Return sprite index on success or -1 on failure
s32 AddAnimatedIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver,
const array< io::path >& files,
u32 frameTime )
{
if ( !spriteBank || !driver || !files.size() )
return -1;
video::ITexture * tex = driver->getTexture( files[0] );
if ( tex )
{
array< rect<s32> >& spritePositions = spriteBank->getPositions();
u32 idxRect = spritePositions.size();
spritePositions.push_back( rect<s32>(0,0, tex->getSize().Width, tex->getSize().Height) );
SGUISprite sprite;
sprite.frameTime = frameTime;
array< SGUISprite >& sprites = spriteBank->getSprites();
u32 startIdx = spriteBank->getTextureCount();
for (
u32 f=0; f < files.size(); ++f )
{
tex = driver->getTexture( files[f] );
if ( tex )
{
spriteBank->addTexture( driver->getTexture(files[f]) );
gui::SGUISpriteFrame frame;
frame.rectNumber = idxRect;
frame.textureNumber = startIdx+f;
sprite.Frames.push_back( frame );
}
}
sprites.push_back( sprite );
return sprites.size()-1;
}
return -1;
}
Use several images within one imagefile as animation frames for a sprite which can be used as cursor icon The sizes of the icons within that file all need to have the same size Return sprite index on success or -1 on failure
s32 AddAnimatedIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver,
const io::path& file,
const array< rect<s32> >& rects,
u32 frameTime )
{
if ( !spriteBank || !driver || !rects.size() )
return -1;
video::ITexture * tex = driver->getTexture( file );
if ( tex )
{
array< rect<s32> >& spritePositions = spriteBank->getPositions();
u32 idxRect = spritePositions.size();
u32 idxTex = spriteBank->getTextureCount();
spriteBank->addTexture( tex );
SGUISprite sprite;
sprite.frameTime = frameTime;
array< SGUISprite >& sprites = spriteBank->getSprites();
for (
u32 i=0; i < rects.size(); ++i )
{
spritePositions.push_back( rects[i] );
gui::SGUISpriteFrame frame;
frame.rectNumber = idxRect+i;
frame.textureNumber = idxTex;
sprite.Frames.push_back( frame );
}
sprites.push_back( sprite );
return sprites.size()-1;
}
return -1;
}
core::string< fschar_t > path
Type used for all file system related strings.
Create a non-animated icon from the given file and position and put it into the spritebank. We can use this icon later on in a cursor.
s32 AddIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver,
const io::path& file,
const core::rect<s32>& rect )
{
if ( !spriteBank || !driver )
return -1;
video::ITexture * tex = driver->getTexture( file );
if ( tex )
{
core::array< core::rect<irr::s32> >& spritePositions = spriteBank->getPositions();
spritePositions.push_back( rect );
array< SGUISprite >& sprites = spriteBank->getSprites();
spriteBank->addTexture( tex );
gui::SGUISpriteFrame frame;
frame.rectNumber = spritePositions.size()-1;
frame.textureNumber = spriteBank->getTextureCount()-1;
SGUISprite sprite;
sprite.frameTime = 0;
sprite.Frames.push_back( frame );
sprites.push_back( sprite );
return sprites.size()-1;
}
return -1;
}
int main()
{
return 1;
IrrlichtDevice * device =
createDevice(driverType, dimension2d<u32>(640, 480));
if (device == 0)
return 1;
device->setResizable(true);
device->setWindowCaption(L"Cursor control - Irrlicht engine tutorial");
video::IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* env = device->getGUIEnvironment();
gui::IGUISpriteBank * SpriteBankIcons;
SAppContext context;
context.Device = device;
env->addStaticText (L"Cursor state information", rectInfoStatic, true, true);
context.InfoStatic = env->addStaticText (L"", rectInfoStatic, true, true);
env->addStaticText (L"click events (new on top)", rectEventBox, true, true);
context.EventBox = env->addListBox(rectEventBox);
env->addStaticText (L"cursors, click to set the active one", rectCursorBox, true, true);
context.CursorBox = env->addListBox(rectCursorBox);
env->addStaticText (L"sprites", rectSpriteBox, true, true);
context.SpriteBox = env->addListBox(rectSpriteBox);
context.ButtonSetVisible = env->addButton( rect<s32>( 410, 20, 560, 40 ), 0, -1, L"set visible (delayed)" );
context.ButtonSetInvisible = env->addButton( rect<s32>( 410, 50, 560, 70 ), 0, -1, L"set invisible (delayed)" );
context.ButtonSimulateBadFps = env->addButton( rect<s32>( 410, 80, 560, 100 ), 0, -1, L"simulate bad FPS" );
context.ButtonSimulateBadFps->setIsPushButton(true);
context.ButtonChangeIcon = env->addButton( rect<s32>( 410, 140, 560, 160 ), 0, -1, L"replace cursor icon\n(cursor+sprite must be selected)" );
{
}
dimension2d< s32 > dimension2di
Typedef for an integer dimension.
const c8 *const GUICursorIconNames[ECI_COUNT+1]
Names for ECURSOR_ICON.
E_DRIVER_TYPE
An enum for all types of drivers the Irrlicht Engine supports.
@ EDT_COUNT
No driver, just for counting the elements.
IRRLICHT_API IrrlichtDevice *IRRCALLCONV createDevice(video::E_DRIVER_TYPE deviceType=video::EDT_SOFTWARE, const core::dimension2d< u32 > &windowSize=(core::dimension2d< u32 >(640, 480)), u32 bits=16, bool fullscreen=false, bool stencilbuffer=false, bool vsync=false, IEventReceiver *receiver=0)
Creates an Irrlicht device. The Irrlicht device is the root object for using the engine.
Create sprites which then can be used as cursor icons.
SpriteBankIcons = env->addEmptySpriteBank(
io::path(
"cursor_icons"));
context.SpriteBox->setSpriteBank(SpriteBankIcons);
array< io::path > files;
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw1.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw2.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw3.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw3.png") );
files.push_back(
io::path(
"../../media/icon_crosshairs16x16bw2.png") );
SCursorSprite spriteBw;
spriteBw.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver, files, 200 );
spriteBw.SpriteBank = SpriteBankIcons;
spriteBw.HotSpot = position2d<s32>(7,7);
context.addIcon(L"crosshair_bw", spriteBw);
array< rect<s32> > iconRects;
iconRects.push_back( rect<s32>(0,0, 16, 16) );
iconRects.push_back( rect<s32>(16,0, 32, 16) );
iconRects.push_back( rect<s32>(0,16, 16, 32) );
iconRects.push_back( rect<s32>(0,16, 16, 32) );
iconRects.push_back( rect<s32>(16,0, 32, 16) );
SCursorSprite spriteCol;
spriteCol.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), iconRects, 200 );
spriteCol.HotSpot = position2d<s32>(7,7);
spriteCol.SpriteBank = SpriteBankIcons;
context.addIcon(L"crosshair_colored", spriteCol);
rect<s32> rectIcon;
SCursorSprite spriteNonAnimated(SpriteBankIcons, 0, position2d<s32>(7,7));
rectIcon = rect<s32>(0,0, 16, 16);
spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), rectIcon );
context.addIcon(L"crosshair_col1", spriteNonAnimated, false);
rectIcon = rect<s32>(16,0, 32, 16);
spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), rectIcon );
context.addIcon(L"crosshair_col2", spriteNonAnimated, false);
rectIcon = rect<s32>(0,16, 16, 32);
spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver,
io::path(
"../../media/icon_crosshairs16x16col.png"), rectIcon );
context.addIcon(L"crosshair_col3", spriteNonAnimated, false);
MyEventReceiver receiver(context);
device->setEventReceiver(&receiver);
while(device->run() && driver)
{
{
u32 realTimeNow = device->getTimer()->getRealTime();
context.update();
driver->beginScene(true, true, SColor(0,200,200,200));
env->drawAll();
if ( context.SpriteBox )
{
s32 selectedSprite = context.SpriteBox->getSelected();
if ( selectedSprite >= 0 && context.Sprites[selectedSprite].SpriteId >= 0 )
{
SpriteBankIcons->draw2DSprite(
u32(context.Sprites[selectedSprite].SpriteId),
position2di(580, 140), 0, video::SColor(255, 255, 255, 255), 0, realTimeNow);
}
}
driver->endScene();
}
if ( context.SimulateBadFps )
{
device->sleep(500);
}
else
{
device->sleep(10);
}
}
device->drop();
return 0;
}
vector2d< s32 > position2di