toggle fullscreen / window mode

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Elmaron
Posts: 27
Joined: Sat Jan 10, 2009 7:22 pm

Post by Elmaron »

christianclavet: I tried your work around. It seems to cause some bugs in Irrlicht though: When creating the second device, the video device, after having created the null device, the video device won't change the resolution when attempting to run in fullscreen mode - it just paints everythingin a window as big as the fullscreen resolution with no border at the top left screen. Either I made something terribly wrong or this is indeed unusable because Irrlicht gets confused about needing to change the screen resolution for the second device or not. (Or maybe it only works flawlessly on Windows - I'm on Linux here)
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You have to drop the first device before creating the second, otherwise resizing might not work.
Elmaron
Posts: 27
Joined: Sat Jan 10, 2009 7:22 pm

Post by Elmaron »

..which makes the whole work-around rather useless :? I really hope Irrlicht will get a way of toggling fullscreen _without_ opening a new device. That would be nearly as awesome as having EMT_TRANSPARENT_VERTEX_ALPHA with lighting fixed!
jeetee
Posts: 15
Joined: Tue Oct 13, 2009 3:09 pm
Contact:

Post by jeetee »

As I'm still new to IrrLicht, I can't seem to get this working correctly, or not entirely..

In my testcase I have created one window with one button in it. Clicking the button should trigger a switch between fullscreen and windowed operation.

What I'm doing in the event reciever is as follows:
  1. Pointer to the device is known upon creation of the EventReciever
  2. Get the pointer to the GUIEnvironment of the device
  3. Get the drivertype and windowsize from the guiEnvironment
  4. call closeDevice upon the devicepointer
  5. call createDevice and store the result in the devicepointer
  6. get the pointer to the GUIEnvironment of the newly created device
  7. assign the pointer from the old environment to the new one.
The result is that indeed my old window dissappears, and my resolution is changed (to 1023*768, which is supported by my card), but the screen remains black for one or twe seconds. After that my application closes.

The closing is caused by breaking out of the mainloop with the following condition:

Code: Select all

while (device->run() && driver)
However when I call device->run() directly after the loop, it returns 1, and driver is also a valid pointer (although still pointing to device->getVideoDriver() from the original device I believe...)

Full code:

Code: Select all

#include "irrlicht/irrlicht.h"
using namespace irr;
using namespace irr::core;
using namespace irr::gui;

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

class EventReciever: public irr::IEventReceiver
{
private:
	irr::IrrlichtDevice* contextDevice;
public:
	EventReciever(irr::IrrlichtDevice const* device);
	~EventReciever();
	virtual bool OnEvent(const irr::SEvent& event);
};


int main(int argc, char* argv[])
{
	//creating the render device - use OpenGL, fall back on software rendering
	IrrlichtDevice* device = createDevice(
			video::EDT_OPENGL,			//E_DRIVER_TYPE videodriver
			dimension2du(1024, 768),	//dimension2d<signed int>& windowSize
			32,							//u32 color bits per pixel
			false,						//bool fullscreen
			false,						//bool stencilbuffer (used for dynamic shadows)
			false,						//bool vsync - only usefull in fullscreen
			NULL						//IEventReceiver* receiver
		);

	if (NULL == device) {
		//we seem to be doomed
		cout << "The application could not be launched, because the graphical" << endl
			 << " interface wasn't started. OpenGL-support is required for this" << endl
			 << " application to work correctly." << endl
			 << endl
			 << "Press Enter/Return-key to close this message...";
		cin.get();
		return 0;
	}

	//driver is needed for drawing and loading textures for example
	video::IVideoDriver* driver = device->getVideoDriver();
	//Environment is needed because that's where everything happens
	IGUIEnvironment* env = device->getGUIEnvironment();

	//disable transparent GUI
	for (long i = 0; i < gui::EGDC_COUNT; ++i) {
		video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
		col.setAlpha(255);
		env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
	}

	//set a readable bitmap font - Arial 10
	IGUIFont* font = env->getFont("irrFont_Arial_10.bmp");
	if (font) {
		env->getSkin()->setFont(font);
		env->getSkin()->setFont(font, EGDF_WINDOW);
	} else {
		cout << "Failed to load the custom (readable) font (irrFont_Arial_10.bmp)" << endl;
	}
	//set a nice caption
	device->setWindowCaption(L"FullScreen Testing");

	//add stuff
	env->addButton(rect<signed int>(20, 100, 600, 300), env->getRootGUIElement(), 1, L"Button", L"ButtonToolTip");
	
	//Create the eventhandler, and link it to the device
	EventReciever* er = new EventReciever(device);
	device->setEventReceiver(er);
	
	//app-loop
	while (device->run() && driver) {
		cout << "device->run() && driver" << endl;
		if (device->isWindowActive()) {
			driver->beginScene(true, false, video::SColor(255, 225, 225, 225));
			env->drawAll();
			driver->endScene();
		}
		device->yield();
	}
	cout << "-----" << endl << "broke out of loop:" << endl << "\tdevice->run() = " << device->run() << endl
		 << "\tdriver = " << driver << endl;
	delete er;
	device->drop();
	return 0;
}

EventReciever::EventReciever(IrrlichtDevice const* device)
{
	this->contextDevice = (IrrlichtDevice*)device;
}

EventReciever::~EventReciever()
{
	;//nothing
}

//return true is the event was processed
bool EventReciever::OnEvent(const irr::SEvent& event)
{
	IGUIEnvironment* env = contextDevice->getGUIEnvironment();
	//IGUIElement* statusbar = env->getRootGUIElement()->getElementFromId(STATUS_BAR, true);
	switch (event.EventType) {
		case EET_GUI_EVENT: { //button presses etc
			s32 id = event.GUIEvent.Caller->getID();
			switch (event.GUIEvent.EventType) {
				//! A button was clicked.
				case EGET_BUTTON_CLICKED: {
					switch (id) {
						case 1: {
							if (!contextDevice->isFullscreen()) {
								//change from windowed to fullscreen
								video::E_DRIVER_TYPE deviceType = contextDevice->getVideoDriver()->getDriverType();
								dimension2du windowSize = env->getVideoDriver()->getScreenSize();
cout << "Closing device" << endl;
								contextDevice->closeDevice();
cout << "contextDevice->closeDevice() called" << endl;
								//contextDevice->drop();
cout << "Creating new device" << endl;
								contextDevice = createDevice(deviceType, windowSize, 32, true, false, false, this);
cout << "...created" << endl;
cout << "Requesting new environment..." << endl;
								IGUIEnvironment* tempEnv = contextDevice->getGUIEnvironment();
cout << "Setting pointer to the new environment (env was " << env << " tempEnv is " << tempEnv << ")" << endl;
								tempEnv = env;
cout << "done (tempEnv is now " << tempEnv << ")" << endl;
							} else {
								//change from fullscreen to windowed
								video::E_DRIVER_TYPE deviceType = contextDevice->getVideoDriver()->getDriverType();
								dimension2du windowSize = env->getVideoDriver()->getScreenSize();
								contextDevice->closeDevice();
								//contextDevice->drop();
								contextDevice = createDevice(deviceType, windowSize, 32, false, false, false, this);
								IGUIEnvironment* tempEnv = contextDevice->getGUIEnvironment();
								tempEnv = env;
							}
							return true;
						} break;
						default: {
							cout << "Pressed a Button";
						} break;
					}
				} break;

				//! A file has been selected in the file dialog
				case EGET_FILE_SELECTED: 
				//! The mouse cursor hovered over a gui element.
				case EGET_ELEMENT_HOVERED: 
				//! A menu item was selected in a (context) menu
				case EGET_MENU_ITEM_SELECTED: 
				//! The mouse cursor left the hovered element.
				case EGET_ELEMENT_LEFT: 
				//! A gui element has lost its focus.
				/** GUIEvent.Caller is losing the focus to GUIEvent.Element.
				If the event is absorbed then the focus will not be changed. */
				case EGET_ELEMENT_FOCUS_LOST:
				//! A gui element has got the focus.
				/** If the event is absorbed then the focus will not be changed. */
				case EGET_ELEMENT_FOCUSED:
				//! An element would like to close.
				/** Windows and context menus use this event when they would like to close,
				this can be cancelled by absorbing the event. */
				case EGET_ELEMENT_CLOSED:
				//! A scrollbar has changed its position.
				case EGET_SCROLL_BAR_CHANGED:
				//! A checkbox has changed its check state.
				case EGET_CHECKBOX_CHANGED:
				//! A new item in a listbox was seleted.
				case EGET_LISTBOX_CHANGED:
				//! An item in the listbox was selected, which was already selected.
				case EGET_LISTBOX_SELECTED_AGAIN:
				//! A file open dialog has been closed without choosing a file
				case EGET_FILE_CHOOSE_DIALOG_CANCELLED:
				//! 'Yes' was clicked on a messagebox
				case EGET_MESSAGEBOX_YES:
				//! 'No' was clicked on a messagebox
				case EGET_MESSAGEBOX_NO:
				//! 'OK' was clicked on a messagebox
				case EGET_MESSAGEBOX_OK:
				//! 'Cancel' was clicked on a messagebox
				case EGET_MESSAGEBOX_CANCEL:
				//! In an editbox was pressed 'ENTER'
				case EGET_EDITBOX_ENTER:
				//! The tab was changed in an tab control
				case EGET_TAB_CHANGED:
				//! The selection in a combo box has been changed
				case EGET_COMBO_BOX_CHANGED:
				//! The value of a spin box has changed
				case EGET_SPINBOX_CHANGED:
				//! A table has changed
				case EGET_TABLE_CHANGED:
				case EGET_TABLE_HEADER_CHANGED:
				case EGET_TABLE_SELECTED_AGAIN:
				default: {
					//nothing
				} break;
			}
		} break;
		case EET_LOG_TEXT_EVENT: { //consuming them doesn't send the output to the console
			return true;
		} break;
		case EET_MOUSE_INPUT_EVENT:
		case EET_KEY_INPUT_EVENT:
		case EET_JOYSTICK_INPUT_EVENT:
		case EET_USER_EVENT:
		default: {
			//nothing to do with these, just pass them on
		} break;
	}
	return false;
}
jeetee
Posts: 15
Joined: Tue Oct 13, 2009 3:09 pm
Contact:

Post by jeetee »

Should I post an even more stripped version of the code as testcase? (which would be just removing empty cases, fontloading and custom coloring
actually)

Or am I correct in stating that switching devices/environments in an EventReciever is impossible? It seems even to be impossible to destroy the device withouth destroying it's environment, let alone reassigning the environment to a new device..

I have also thought of another way to achieve this, but it would involve creating a function that recreates my complete device/guiEnv. And that is a rather messy way of dealing with this issue.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You seem to drop the device and later on try to reuse the old content of the destroyed device. This is not possible. Upon device destruction, all ressources that you created with device functions (including scene manager and gui environment functions) are destroyed as well. You must recreate them.
jeetee
Posts: 15
Joined: Tue Oct 13, 2009 3:09 pm
Contact:

Post by jeetee »

Thx for the response.
I'll redesign the EventReciever so it calls a createfunction for my GUI, which updates the driver and device pointer for the gameloop as well.
Post Reply