Page 1 of 1

Event receiving in multiple scenes with multiple cameras

Posted: Fri Jan 04, 2008 3:45 pm
by Thulsa Doom
Hello people,

I experienced a curious problem.

I use multiple scenes with a Maya style camera in each scene to render
each context to fractions of the output device (splitscreens).

I would like to have each camera act on the same user events.

The problem I experienced is, that only the camera created first
reveives input events and is therfore the only one controllable by the user.


I'm using a custom CEventManager class that manages all program events.
It inherits from IEventReceiver and is passed as
adress of pointer to the createDevice function on program init:
______________________________________

CEventManager emgr;

IrrlichtDevice*
device = createDevice(EDT_SOFTWARE, dimension2d<s32>(800, 600), 16, false, false, false, &emgr);
________________________________________

The custom CEventManager class has a
AttachReceiver(IEventReceiver* receiver) function
which takes all Cameras as input argument
and the inherited and overwritten
OnEvent(const SEvent& event) functon
delivers the events from irrlich to the
registred IEventReceiver objects.

The spotted reason for the mentioned problem is,
that in the default CCameraMayaSceneNode class
the OnEvent function is called directly in
irrlicht befor any event is delivered to the custom
CEventManager. Right after the event is absorbed.
The call from irrlich arises is in the CSeneManager.
The regarding code read as follows:

Called code / callee
CCameraMayaSceneNode.cpp

Code: Select all

//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for 
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
bool CCameraMayaSceneNode::OnEvent(const SEvent& event)
{

if (event.EventType != EET_MOUSE_INPUT_EVENT ||
		!InputReceiverEnabled)
		return false;

	switch(event.MouseInput.Event)
	{
	case EMIE_LMOUSE_PRESSED_DOWN:
		MouseKeys[0] = true;
		break;
	case EMIE_RMOUSE_PRESSED_DOWN:
		MouseKeys[2] = true;
		break;
	case EMIE_MMOUSE_PRESSED_DOWN:
		MouseKeys[1] = true;
		break;
	case EMIE_LMOUSE_LEFT_UP:
		MouseKeys[0] = false;
		break;
	case EMIE_RMOUSE_LEFT_UP:
		MouseKeys[2] = false;
		break;
	case EMIE_MMOUSE_LEFT_UP:
		MouseKeys[1] = false;
		break;
	case EMIE_MOUSE_MOVED:
		{
			video::IVideoDriver* driver = SceneManager->getVideoDriver();
			if (driver)
			{
				core::dimension2d<s32> ssize = SceneManager->getVideoDriver()->getScreenSize();
				MousePos.X = event.MouseInput.X / (f32)ssize.Width;
				MousePos.Y = event.MouseInput.Y / (f32)ssize.Height;
			}
		}
		break;
	case EMIE_MOUSE_WHEEL:
	case EMIE_COUNT:
		break;
	}
	return true;
}
Calling code / caller
CSeneManager.cpp

Code: Select all

//! Posts an input event to the environment. Usually you do not have to
//! use this method, it is used by the internal engine.
bool CSceneManager::postEventFromUser(const SEvent& event)
{
	bool ret = false;
	ICameraSceneNode* cam = getActiveCamera();
	if (cam)
		ret = cam->OnEvent(event);
		
	_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
	return ret;
}

Appling the following changes to the native code
fixes the mentioned problem:


CSeneManager.cpp

Code: Select all

bool CSceneManager::postEventFromUser(const SEvent& event)
{
	bool ret = false;
	ICameraSceneNode* cam = getActiveCamera();
	if (cam)
	{
		if (cam->isInputReceiverEnabled())
			ret = cam->OnEvent(event);
	}

	_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
	return ret;
}
CCameraMayaSceneNode.cpp

Code: Select all

bool CCameraMayaSceneNode::OnEvent(const SEvent& event)
{
	if (event.EventType != EET_MOUSE_INPUT_EVENT)
		return false;

	switch(event.MouseInput.Event)
	{
	case EMIE_LMOUSE_PRESSED_DOWN:
		MouseKeys[0] = true;
		break;
	case EMIE_RMOUSE_PRESSED_DOWN:
		MouseKeys[2] = true;
		break;
	case EMIE_MMOUSE_PRESSED_DOWN:
		MouseKeys[1] = true;
		break;
	case EMIE_LMOUSE_LEFT_UP:
		MouseKeys[0] = false;
		break;
	case EMIE_RMOUSE_LEFT_UP:
		MouseKeys[2] = false;
		break;
	case EMIE_MMOUSE_LEFT_UP:
		MouseKeys[1] = false;
		break;
	case EMIE_MOUSE_MOVED:
		{
			video::IVideoDriver* driver = SceneManager->getVideoDriver();
			if (driver)
			{
				core::dimension2d<s32> ssize = SceneManager->getVideoDriver()->getScreenSize();
				MousePos.X = event.MouseInput.X / (f32)ssize.Width;
				MousePos.Y = event.MouseInput.Y / (f32)ssize.Height;
			}
		}
		break;
	case EMIE_MOUSE_WHEEL:
	case EMIE_COUNT:
		break;
	}
	
	return false;
}
Explantion:

The query of 'bool InputReceiverEnabled'
is transfered from the CCameraMayaSceneNode::OnEvent() to the CSceneManager::postEventFromUser().
No events are delivered to the camera if it doesn't wishes to receive them.

The CCameraMayaSceneNode::OnEvent() does return false now in any case.
So the events are no more absorbed and passed to other objects.
That will give other IEventReceivers (Cameras) the possiblity to act on the same events as well.

I would like to know if similar problems are
also experienced by other users and/or
if anybody sees any collateral compatibility problems with
the changes.

Regards
T.D.