Global Elements (Easy)

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Global Elements (Easy)

Post by Moo »

Hello :)
First off, I have to mention this is probably one of the most beginner-esque questions, not to say pathetically n00b. It probably is because of my lack of C++ experience more than my lack of Irrlicht knowledge, though I hope a great soul could help me solve my problem.

Alright, enough babble, let's get started: I want to make the Irrlicht "Device" and all its "sub-elements" (i.e. driver, smgr, etc.) global. My (not-so-) brilliant idea was to stuff all that into a global header file (originally named "Global.h"). It would consequently also include the basic outline of an Irrlicht structure. Here is my header:

Code: Select all

#pragma once
#include <irrlicht.h>

#ifdef _IRR_WINDOWS_
	#pragma comment(lib, "Irrlicht.lib")
	#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

IrrlichtDevice* Device = createDevice(EDT_DIRECT3D9, dimension2d<s32>(800, 600), 32, false, false, false, 0);
IVideoDriver* Driver = Device->getVideoDriver();
ISceneManager* Scene = Device->getSceneManager();
IGUIEnvironment* Interface = Device->getGUIEnvironment();
ICursorControl* Cursor = Device->getCursorControl();
IFileSystem* Filesys = Device->getFileSystem();
In my mind, logically, it would have allowed me to use calls directly to "Device" or "Scene" wherever I used "#include Global.h" at the beginning of the file. Well, fool I am, I keep getting a LNK2005 error because of the redifinition of these elements.

Code: Select all

1>------ Build started: Project: Client, Configuration: Debug Win32 ------
1>Linking...
1>Terrain.obj : error LNK2005: "class irr::gui::ICursorControl * Cursor" (?Cursor@@3PAVICursorControl@gui@irr@@A) already defined in Client.obj
1>Terrain.obj : error LNK2005: "class irr::gui::IGUIEnvironment * Interface" (?Interface@@3PAVIGUIEnvironment@gui@irr@@A) already defined in Client.obj
1>Terrain.obj : error LNK2005: "class irr::video::IVideoDriver * Driver" (?Driver@@3PAVIVideoDriver@video@irr@@A) already defined in Client.obj
1>Terrain.obj : error LNK2005: "class irr::IrrlichtDevice * Device" (?Device@@3PAVIrrlichtDevice@irr@@A) already defined in Client.obj
1>Terrain.obj : error LNK2005: "class irr::scene::ISceneManager * Scene" (?Scene@@3PAVISceneManager@scene@irr@@A) already defined in Client.obj
1>Terrain.obj : error LNK2005: "class irr::io::IFileSystem * Filesys" (?Filesys@@3PAVIFileSystem@io@irr@@A) already defined in Client.obj
1>C:\Night\Code\Debug\Client.exe : fatal error LNK1169: one or more multiply defined symbols found
I have tried many things, but I cannot figure out how to make these elements global. If anyone wonders, this whole thing is to make a terrain class with collision in it, which therefore needs a smgr reference to create the node in the constructor. My other alternative, in my opinion, would be to pass a pointer to the currently used scene in the constructor parameters, but I hope there is another alternative.

Oh, and by the way, at the moment, Global.h is called from Terrain.h and Main.cpp.

Thanks, and please forgive my English :')
-Lazlo
wITTus
Posts: 167
Joined: Tue Jun 24, 2008 7:41 pm
Location: Germany

Post by wITTus »

Easy 8)

Isn't good C++, though. Well, depends. In your case, it's not.

Edit: Don't forget that each .cpp file is compiled as single 'code unit'. All code units are linked together then. Of course the linker will complain if a symbol has been defined twice in a code unit or between different code units (that is, c++ files), except if it has been declared with the 'extern' keyword. And: Put declarations in headers and definitions in c++ files. Also don't forget that the #include directive simply replaces the "#include 'Bla'" with the content 'Bla' in the .cpp file. In case that multiple code units want to use the same header file, read on "include guards".

Edit2: And don't use "#pragma once", it's not portable.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

I think there are much prettier ways to make globals, though globals are always discouraged. One nice way is to do static members in larger classes such as :

IrrlichtDevice* getDevice()
{ return mDevice; }

and then just add a

#define irrDevice getDevice()


This means that anywhere in code, the irrDevice is a pointer so you can use

irrDevice->setWindowCaption anywhere, without includes, and without redefintions .

This works better with statics in classes, to keep things in check.

and again, globals are discouraged, use proper structures instead
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Post by Moo »

I pretty much understood I shouldn't use globals then. But when you're talking about a proper structure, what do you mean? In my case, should one of the class constructor parameters be a pointer to the smgr? Or is there another way?

Thanks for all your help :)
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Post by Moo »

I am sorry to 'bump' this thread, however this problem stops me from progressing and I am afraid I can't get help from anywhere else than these forums. ^^ Any insight is greatly appreciated
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

If you must then use singletons. I REALLY don't like it when people do that though.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
wITTus
Posts: 167
Joined: Tue Jun 24, 2008 7:41 pm
Location: Germany

Post by wITTus »

Moo wrote:I am sorry to 'bump' this thread, however this problem stops me from progressing and I am afraid I can't get help from anywhere else than these forums. ^^ Any insight is greatly appreciated
Why? I've already posted the solution. If you insist to do it this way, put the variables in a single code unit, like for example "myIrrlichtPointers.cpp" and every time you use these files in another cpp file, you simply declare your vars global on top like so:

extern IrrlichtDevice* Blah;

All cpp files with this declaration would then use the same pointer `Blah'.

Edit: You should, however, consider FuzzYspo0N's proposal. It will become very difficult to control non-const access to these pointers within larger applications.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

What i meant by proper structure is what blindside was saying, using singletons or one of those other frowned upon models :D

there is also the fact that including header files inside other header files is bound to create loops somewhere.

The redundancy problem can probably also be solved with forward declaration. For example :

DataSystem needs the class called GameEngineClass : so instead of including the GameEngine.h i simply put stuff like

class CDataObject;
class CGameEngine;


At the top of my datasystem.h

Hope that makes sense, the classes dont need to be declared yet (as mentioned by wITTus already (the code being built into objects, if it already exists then dont reinclude it, just inform the code that it will exist at some stage)
Spkka
Posts: 32
Joined: Fri Jan 02, 2009 8:30 am

Post by Spkka »

Post Reply