Page 1 of 1

setFarValue bug affects getSceneNodeFromScreenCoordinatesBB

Posted: Thu May 24, 2007 3:54 pm
by cvf
After thinking there was a bug at getSceneNodeFromScreenCoordinatesBB, I discovered in my code it was a bug in setFarValue the cause of the problem... this last function, when called with a big value (which is in the f32 range), affects the results of the retreived mouse coordinates...

I have modified the "14.Win32Window" Irrlicht example to show the bug. Here it is the modified version of "main.cpp":

Code: Select all

// this example only runs in windows and demonstrates that Irrlicht
// can run inside a win32 window.

#include <irrlicht.h>
#include <afxwin.h>
#include <windows.h> // this example only runs with windows

using namespace irr;

#pragma comment(lib, "irrlicht.lib")


const int IDFILTER = 8;
irr::scene::ISceneManager* smgr;
video::IVideoDriver* driver;

/////////////////////////////////////////
/////////////////////////////////////////

class C3DWnd : public CWnd
{
public:
	C3DWnd();
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	scene::ISceneNode* m_selectedSceneNode;
protected:
	DECLARE_MESSAGE_MAP()
};

C3DWnd::C3DWnd()
{
	smgr = NULL;
	driver = NULL;
	m_selectedSceneNode = 0;
}

void C3DWnd::OnMouseMove(UINT nFlags, CPoint point)
{
	scene::ISceneNode* selectedSceneNode = 0;
	selectedSceneNode = smgr->getSceneCollisionManager()->getSceneNodeFromScreenCoordinatesBB(core::position2d<s32>(point.x, point.y), IDFILTER);

	if (m_selectedSceneNode)
		if (selectedSceneNode != m_selectedSceneNode)
			m_selectedSceneNode->getMaterial(0).EmissiveColor.set(0,0,0,0);

	if (selectedSceneNode)
	{
		selectedSceneNode->getMaterial(0).EmissiveColor.set(128, 255, 0, 0);
		m_selectedSceneNode = selectedSceneNode;

		driver->beginScene(true, true, 0);
		smgr->drawAll();
		driver->endScene();
	}

	CWnd::OnMouseMove(nFlags, point);
}

BEGIN_MESSAGE_MAP(C3DWnd, CWnd)
	ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

/////////////////////////////////////////
/////////////////////////////////////////


C3DWnd g_3DWnd;
HWND hOKButton;
HWND hWnd;

static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_COMMAND:
		{
			HWND hwndCtl = (HWND)lParam;
			int code = HIWORD(wParam);

			if (hwndCtl == hOKButton)
			{
				DestroyWindow(hWnd);
				PostQuitMessage(0);
				return 0;
			}
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	//case WM_MOUSEMOVE:
	//	break;
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}





int main()
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hpre, LPSTR cmd, int cc)
{
	HINSTANCE hInstance = 0;
	// create dialog

	const char* Win32ClassName = "CIrrlichtWindowsTestDialog";

	WNDCLASSEX wcex;
	wcex.cbSize			= sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)CustomWndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= DLGWINDOWEXTRA;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= NULL;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW);
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= Win32ClassName;
	wcex.hIconSm		= 0;

	RegisterClassEx(&wcex);

	DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION |
		WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX;

	int windowWidth = 800;
	int windowHeight = 600;

	hWnd = CreateWindow( Win32ClassName, "Irrlicht Win32 window example:  ---Shifted Mouse Coordinates Bug---",
		style, 100, 100, windowWidth, windowHeight,
		NULL, NULL, hInstance, NULL);

	RECT clientRect;
	GetClientRect(hWnd, &clientRect);
	windowWidth = clientRect.right;
	windowHeight = clientRect.bottom;

	// create ok button

	hOKButton = CreateWindow("BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT,
		windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, hInstance, NULL);

	// create some text

	CreateWindow("STATIC", "Move the mouse over the objects to see the Shifted Mouse Coordinates Bug\n"\
							"In the left-down corner works fine, but try in the other corners...",
		WS_CHILD | WS_VISIBLE, 20, 20, 600, 40, hWnd, NULL, hInstance, NULL);

	// create window to put irrlicht in

	//HWND hIrrlichtWindow = CreateWindow("BUTTON", "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
	//		50, 80, 700, 430, hWnd, NULL, hInstance, NULL);

	g_3DWnd.CreateEx(NULL, "BUTTON", "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
								50, 80, 700, 430, hWnd, NULL, NULL);
	g_3DWnd.SetFocus();

	// create irrlicht device in the button window

	irr::SIrrlichtCreationParameters param;
//	param.WindowId = reinterpret_cast<s32>(hIrrlichtWindow); // hColorButton
	param.WindowId = reinterpret_cast<s32>(g_3DWnd.m_hWnd); // hColorButton
	param.DriverType = video::EDT_OPENGL;

	irr::IrrlichtDevice* device = irr::createDeviceEx(param);

	// setup a simple 3d scene

	smgr = device->getSceneManager();
	driver = device->getVideoDriver();

	scene::ICameraSceneNode* cam = smgr->addCameraSceneNode(NULL, core::vector3df(5,5,10),
																core::vector3df(0,0,0));
	cam->setTarget(core::vector3df(10,10,0));

	//scene::ISceneNodeAnimator* anim = smgr->createFlyCircleAnimator(core::vector3df(0,15,0), 30.0f);
	//cam->addAnimator(anim);
	//anim->drop();

	for (int y = 0; y < 10; y++)
	{
		for (int x = 0; x < 10; x++)
		{
			//scene::ISceneNode* DotSceneNode = smgr->addCubeSceneNode(1, NULL, IDFILTER, 
			//												core::vector3df(4*x,4*y,0));

			scene::ISceneNode* DotSceneNode = smgr->addSphereSceneNode(.5, 8, NULL, IDFILTER, 
															core::vector3df(6*x,6*y,0));

			DotSceneNode->getMaterial(0).AmbientColor.set(128, 0, 0, 255);
			DotSceneNode->setMaterialFlag( video::EMF_LIGHTING, true );
			DotSceneNode->setMaterialFlag( video::EMF_NORMALIZE_NORMALS, true);
		}
	}

	smgr->addSkyBoxSceneNode(
	driver->getTexture("../../media/irrlicht2_up.jpg"),
	driver->getTexture("../../media/irrlicht2_dn.jpg"),
	driver->getTexture("../../media/irrlicht2_lf.jpg"),
	driver->getTexture("../../media/irrlicht2_rt.jpg"),
	driver->getTexture("../../media/irrlicht2_ft.jpg"),
	driver->getTexture("../../media/irrlicht2_bk.jpg"));


	// Lights:
	scene::ILightSceneNode* pIrrLight1 = smgr->addLightSceneNode(0, core::vector3df(0.7,0.4,0.6),
													video::SColorf(0.6f, 0.6f, 0.6f));
	pIrrLight1->getLightData().Type = video::ELT_DIRECTIONAL;
	pIrrLight1->getLightData().AmbientColor = video::SColorf(0.6f, 0.6f, 0.6f);

	scene::ILightSceneNode* pIrrLight2 = smgr->addLightSceneNode(0, core::vector3df(-0.4,-0.7,-0.3),
													video::SColorf(0.2f, 0.2f, 0.2f));
	pIrrLight2->getLightData().Type = video::ELT_DIRECTIONAL;


	// show and execute dialog

	ShowWindow(hWnd , SW_SHOW);
	UpdateWindow(hWnd);

	// do message queue

	// Instead of this, you can also simply use your own message loop
	// using GetMessage, DispatchMessage and whatever. Calling
	// Device->run() will cause Irrlicht to dispatch messages internally too.
	// You need not call Device->run() if you want to do your own message
	// dispatching loop, but Irrlicht will not be able to fetch
	// user input then and you have to do it on your own using the window
	// messages, DirectInput, or whatever.

	for (int i = 0; i < 100; i++)
	{
		driver->beginScene(true, true, 0);
		smgr->drawAll();
		driver->endScene();

		cam->setTarget(core::vector3df(i/10.0,i/10.0,2));
		cam->setPosition(core::vector3df(15.0-i/10.0,15.0-i/10.0,8));
		[b]cam->setFarValue(10000000.0f);[/b]
		cam->setScale(core::vector3df(1.0,1.0,1.0));

		Sleep(1);
	}


	MSG msg;
	while (device->run())
	{
		driver->beginScene(true, true, 0);
		smgr->drawAll();
		driver->endScene();

		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		Sleep(1);
	}

	// the alternative, own message dispatching loop without Device->run() would
	// look like this:

	/*MSG msg;
	while (true)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);

			if (msg.message == WM_QUIT)
				break;
		}

		// advance virtual time
		device->getTimer()->tick();

		// draw engine picture
		driver->beginScene(true, true, 0);
		smgr->drawAll();
		driver->endScene();
	}*/

	device->closeDevice();
	device->drop();

	return 0;
}
If you try this you will see the Irrlicht mouse coordinates offset bug at getSceneNodeFromScreenCoordinatesBB.

Just remove the line: cam->setFarValue(10000000.0f);
and everything will work fine.
It also works with a smaller value like: cam->setFarValue(10000.0f);

Maybe this bug is the same at:
http://irrlicht.sourceforge.net/phpBB2/ ... 891#117891

or the one at:
http://irrlicht.sourceforge.net/phpBB2/ ... 892#117892