No cursor movement and event problems

Jenilee

02-06-2010 22:15:13

Hi everybody!

I picked up QuickGUI today because it looked neat. I am basing my code on one of the OGRE tutorials, however I am running into some problems.

First off, here's the code I'm using:


#include <Ogre.h>
#include <OIS/OIS.h>
#include <QuickGUI.h>

using namespace Ogre;

class ClickCatcher
{
public:
ClickCatcher();
virtual ~ClickCatcher();

void test(const QuickGUI::EventArgs& args);
};

void ClickCatcher::test(const QuickGUI::EventArgs& args)
{
const QuickGUI::MouseEventArgs& mea = dynamic_cast<const QuickGUI::MouseEventArgs&>(args);

if(mea.button == QuickGUI::MB_Left)
{
}
}



class ExitListener : public FrameListener
{
public:
ExitListener(OIS::Keyboard *keyboard, OIS::Mouse *mouse, QuickGUI::GUIManager* guimanager)
{
mKeyboard = keyboard;
mMouse = mouse;
mGUIManager = guimanager;
}

bool frameStarted(const FrameEvent& evt)
{
mKeyboard->capture();
mMouse->capture();

return !mKeyboard->isKeyDown(OIS::KC_ESCAPE);
}

bool keyPressed(const OIS::KeyEvent &arg)
{
mGUIManager->injectChar(static_cast<Ogre::UTFString::unicode_char>(arg.text));
mGUIManager->injectKeyDown(static_cast<QuickGUI::KeyCode>(arg.key));

return true;
}

bool keyReleased(const OIS::KeyEvent &arg)
{
mGUIManager->injectKeyUp(static_cast<QuickGUI::KeyCode>(arg.key));

return true;
}

bool mouseMoved(const OIS::MouseEvent &arg)
{
mGUIManager->injectMousePosition(arg.state.X.abs, arg.state.Y.abs);

float z = arg.state.Z.rel;
if(z != 0)
mGUIManager->injectMouseWheelChange(z);

return true;
}

bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
{
mGUIManager->injectMouseButtonDown(static_cast<QuickGUI::MouseButtonID>(id));

return true;
}

bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
{
mGUIManager->injectMouseButtonUp(static_cast<QuickGUI::MouseButtonID>(id));

return true;
}

private:
OIS::Keyboard* mKeyboard;
OIS::Mouse* mMouse;
QuickGUI::GUIManager* mGUIManager;
};

class Application
{
public:
void go()
{
createRoot();
SetupQuickGUI();
defineResources();
setupRenderSystem();
createRenderWindow();
initializeResourceGroups();
setupScene();
CreateQuickGUI();
setupInputSystem();
createFrameListener();
startRenderLoop();
}

~Application()
{
mInputManager->destroyInputObject(mKeyboard);
mInputManager->destroyInputObject(mMouse);
OIS::InputManager::destroyInputSystem(mInputManager);

DestroyQuickGUI();

delete mListener;
delete mRoot;
}

private:
Root* mRoot;
SceneManager* mSceneManager;
ExitListener* mListener;

OIS::Keyboard* mKeyboard;
OIS::Mouse* mMouse;
OIS::InputManager* mInputManager;

QuickGUI::GUIManager* mGUIManager;

void createRoot()
{
mRoot = new Root();
mSceneManager = NULL;
mKeyboard = NULL;
mMouse = NULL;
mInputManager = NULL;
mListener = NULL;
mGUIManager = NULL;
}

void SetupQuickGUI()
{
QuickGUI::registerScriptReader();
}

void CreateQuickGUI()
{
new QuickGUI::Root();
QuickGUI::SkinTypeManager::getSingleton().loadTypes();

QuickGUI::GUIManagerDesc desc;
desc.sceneManager = mSceneManager;
desc.viewport = mSceneManager->getCamera("Camera")->getViewport();
desc.queueID = Ogre::RENDER_QUEUE_OVERLAY;

mGUIManager = QuickGUI::Root::getSingletonPtr()->createGUIManager(desc);

QuickGUI::SheetDesc* sd = QuickGUI::DescManager::getSingleton().getDefaultSheetDesc();
sd->resetToDefault();
sd->widget_dimensions.size = QuickGUI::Size(800,600);
QuickGUI::Sheet* mySheet = QuickGUI::SheetManager::getSingleton().createSheet(sd);

QuickGUI::ButtonDesc* bd = QuickGUI::DescManager::getSingleton().getDefaultButtonDesc();
bd->widget_name = "MyButton";
bd->widget_dimensions.size = QuickGUI::Size(100,25);
bd->widget_dimensions.position = QuickGUI::Point(50,50);
QuickGUI::Button* myButton = mySheet->createButton(bd);
myButton->setText("Test Button");

// myButton->addWidgetEventHandler(QuickGUI::WIDGET_EVENT_MOUSE_BUTTON_UP, &ClickCatcher::test, this);

// I have commented the above line out because I get the follow error if I do not:
// error C2660: 'QuickGUI::Widget::addWidgetEventHandler' : function does not take 3 arguments
//
// QuickGUIWidget.h however lists this:
// You may see Visual Studio give an error warning such as "error C2660: 'QuickGUI::Widget::addWidgetEventHandler' : function does not take 3 arguments".
// This is an incorrect error message. Make sure your function pointer points to a function which returns void, and takes parameter "const EventArgs&".
//
// I guess my code is wrong somehow, I just can't figure out why.

mGUIManager->setActiveSheet(mySheet);
}

void DestroyQuickGUI()
{
delete QuickGUI::Root::getSingletonPtr();
}

void defineResources()
{
String secName, typeName, archName;
ConfigFile cf;
cf.load("resources.cfg");

ConfigFile::SectionIterator seci = cf.getSectionIterator();
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
}
}

}

void setupRenderSystem()
{
if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())
throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");
}

void createRenderWindow()
{
mRoot->initialise(true, "Tutorial Render Window");
}

void initializeResourceGroups()
{
TextureManager::getSingleton().setDefaultNumMipmaps(5);
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

void setupScene()
{
mSceneManager = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager");
Camera *cam = mSceneManager->createCamera("Camera");
Viewport *vp = mRoot->getAutoCreatedWindow()->addViewport(cam);

// set its position, direction
cam->setPosition(Vector3(0,10,500));
cam->lookAt(Vector3(0,0,0));
cam->setNearClipDistance(5);

vp->setBackgroundColour(ColourValue(100,100,100));
cam->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));

mSceneManager->setAmbientLight(ColourValue(0, 0, 0));
mSceneManager->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);

Entity* ent = mSceneManager->createEntity("Ninja", "ninja.mesh");
ent->setCastShadows(true);

mSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(ent);

Light* light = mSceneManager->createLight("Light1");
light->setType(Light::LT_POINT);
light->setPosition(Vector3(0, 150, 250));

mSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(light);
}

void setupInputSystem()
{
size_t windowHnd = 0;
std::ostringstream windowHndStr;
OIS::ParamList pl;
RenderWindow *win = mRoot->getAutoCreatedWindow();

win->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
mInputManager = OIS::InputManager::createInputSystem(pl);

try
{
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, false));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, false));

unsigned int width, height, depth;
int top, left;
win->getMetrics(width, height, depth, left, top);
const OIS::MouseState &ms = mMouse->getMouseState();
ms.width = width;
ms.height = height;
}
catch (const OIS::Exception &e)
{
throw Exception(42, e.eText, "Application::setupInputSystem");
}

}

void createFrameListener()
{
mListener = new ExitListener(mKeyboard, mMouse, mGUIManager);
mRoot->addFrameListener(mListener);
}

void startRenderLoop()
{
mRoot->startRendering();
}
};

#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
int main(int argc, char **argv)
#endif
{
try
{
Application app;
app.go();
}
catch(Exception& e)
{
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
fprintf(stderr, "An exception has occurred: %s\n",
e.getFullDescription().c_str());
#endif
}

return 0;
}


The problem I'm experiencing is twofold. Firstly, when I compile and run this, it does indeed show a basic GUI: a button and a cursor are shown.
Unfortunately, it doesn't seem to respond to any mouse movements at all, despite the frame listener I'm using to inject the events.

The second problem I'm having is with the addWidgetEventHandler function. As the commented code states, I am correctly calling the function
as far as I can tell, but I guess my compiler disagrees with me.

I'd appreciate any light anyone could shed on these issues.

Thanks in advance!

kungfoomasta

03-06-2010 17:17:01

Hi Jenilee, sorry for not responding sooner, I forgot. :oops:

myButton->addWidgetEventHandler(QuickGUI::WIDGET_EVENT_MOUSE_BUTTON_UP, &ClickCatcher::test, this);

In the above code, "this" is referring to an instance of a class of type "Application". However the function signature you provided was a function "test" that belongs to the class definition "ClickCatcher". The instance passed in must match the type specified in the function signature. Basically when the event occurs, QuickGUI will execute:

(pointer to instance)->test(args);

The pointer to instance must be a class that has a function specified (ie test).

I recommend adding the following function to your Application class, and removing your ClickCatcher class:

void test(const QuickGUI::EventArgs& args);

The alternative would be to have the Application class create an instance of the ClickCatcher class, and then use it:

ClickCatcher* myClickCatcher = new ClickCatcher();
myButton->addWidgetEventHandler(QuickGUI::WIDGET_EVENT_MOUSE_BUTTON_UP, &ClickCatcher::test, myClickCatcher);


As for the UI not updating, the problem is that your input callbacks are never being called. Your framelistener class should also inherit from the OIS::KeyListener and OIS::MouseListener classes, and be registerred with OIS.

class MyFrameListener :
public Ogre::FrameListener,
public OIS::KeyListener,
public OIS::MouseListener
{
...


Registerring with OIS:

//Create all devices
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( ... ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( ... ));

mKeyboard->setEventCallback(MyFrameListenerInstance);
mMouse->setEventCallback(MyFrameListenerInstance);


Now the OIS Mouse and Keyboard instances will use your FrameListener's callback methods when events occur.

Jenilee

03-06-2010 18:38:06

Thanks a bunch, your suggestions both worked! It also seems I forgot to set the Mouse and Keyboard listeners to "buffered mode".