Jump to content

CEGUI & Leadwerks


Rick
 Share

Recommended Posts

So after about a day of messing around with CEGUI I was able to get it working in Leadwerks. Which is very exciting! I think CEGUI should be the GUI of choice for Leadwerks, but I realize after working with it some that it's a big pain and a intimidating task to setup.

 

There are so many different choices to choose from that it's kind of insane. The good thing about this is that it's open source. So I'm going to make a little side project to try and make the usage of CEGUI in Leadwerks much easier and straight forward. This will however add bloat and/or reduce the customization of the what code to use. However I think this is a valid trade off because I think no one uses CEGUI because they think it's complicated (and they are right).

 

It also has LUA Support!

 

I think if we/I can get CEGUI working easier with Leadwerks it an be the GUI of choice. No more need for all these custom GUI's.

Link to comment
Share on other sites

Yeah, I got the 3 gl commands needed to get this to work correctly in LE from his old post. From what I can tell he didn't go much further with the project. He was combining like 2 other things I think also.

 

The issue I have with CEGUI is the same issue I have with almost all open source projects. It has to many dependencies which are all open source also and you have to compile them all and it's a big pain to work with and get working. My task will be to try and set some defaults for CEGUI with LE to make things easier. I'm going to try and get everything into 1 DLL and 1 lib. I plan on adding some of my own functions/class to help hide the setup of CEGUI with LE, so ppl can just use it.

Link to comment
Share on other sites

I also was working on this, this weekend, I guess I don't need to work on it anymore.. :)

 

Anyways, what I was looking at, is irrlitch and orge are OOP engines, so integration was much easier, than it will be with LE..

 

The Lua part is very cool

AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD

76561197984667096.png

Link to comment
Share on other sites

Anyways, what I was looking at, is irrlitch and orge are OOP engines, so integration was much easier, than it will be with LE..

 

Jut so it's clear I'm not going to rewrite CEGUI :) It will still be OO. What I plan on doing is put it all into 1 dll and 1 library (there are literally like 7 dlls normally which is insane) and adding to this library/dll my own class that will setup CEGUI for use in LE and hide most of the initialization. There is quite a bit of setup required to use CEGUI because it runs on so many different platforms. That setup would be the same for anyone using LE since we know it uses OpenGL and we have to inject our own input into CEGUI. So I have to convert the LE input commands to what CEGUI is expecting. So what you'll end up with is something like:

 

 

class GEGUILeadwerks
{
public:
  void Initialize(){// default init for LE engine}
  void Input(){// inject LE's input to cegui}
  void Draw(){}
};

 

Actually what I'll probably do is just give this class as a normal h/cpp file and not in the library so people can see what it's doing an modify it if they so wish, or you can just include both and use it.

Link to comment
Share on other sites

Yeah, I just meant that to add to the Class of Orge, you just

 

 

class Ogre
{
    [....]

}

 

And this adds to the ogre class.

 

Same with irrlitch,

 

but since LE is OO, we can just add to the LE class. :)

 

 

I got what you are doing though. Looking forward to seeing you implementation.

AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD

76561197984667096.png

Link to comment
Share on other sites

Still working on this. You wouldn't believe how deep the rabbit hole is with this in terms of open source libraries. Since I'm trying to compile all these as static into my 1 dll that will have everything, I have to recompile all the dependency libraries CEGUI has and there are a lot and they aren't all straight forward compiles. Once I'm finished though there will be 1 dll, 1 library, and 1 header file to include in your project to get CEGUI working. Plus I'll create a class that helps encapsulate things to make it easier.

  • Upvote 1
Link to comment
Share on other sites

  • 3 weeks later...

CEGUI implemented by Vex Studios approximately 6 months ago:

 

All the code is attached in a ZIP, and was compatible and working great as of Leadwerks 2.3. Hopefully it helps.

CEGUI.zip

52t__nvidia.png nVidia 530M cpu.gif Intel Core i7 - 2.3Ghz 114229_30245_16_hardware_memory_ram_icon.png 8GB DDR3 RAM Windows7_Start.gif Windows 7 Ultimate (64x)

-----

IconVisualStudio16.png Visual Studio 2010 Ultimate google-Chrome.png Google Chrome PhotoshopLinkIndicator.png Creative Suite 5 icon28.gif FL Studio 10 MicrosoftOfficeLive.png Office 15

-----

csharp.png Expert cpp.png Professional lua_icon.png Expert BMX Programmer

-----

i-windows-live-messenger-2009.pngskype-icon16.pngaim_online.pnggmail.pngicon_48x48_prism-facebook.pngtunein-web.pngyahoo.giftwitter16.png

Link to comment
Share on other sites

  • 2 weeks later...

Yeah, I got the 3 gl commands needed to get this to work correctly in LE from his old post. From what I can tell he didn't go much further with the project. He was combining like 2 other things I think also.

 

Yea, I actually have two versions of CEGUI and Leadwerks (2.8) currently. I didn't ever update that old thread back in the day due to project interest reasons, but here's some information and opinions on the matter if you are still looking into this topic.

 

Version 1: Leadwerks + CEGUI

 

Integrating CEGUI into Leadwerks alone is very simple. All you literally have to do is create the CEGUI OpenGLRenderer after Leadwerks has been started and you are set. While this is quick and easy, you start to run into performance issues when injecting input into CEGUI from Leadwerks. Since all input calls have to be polled through the API, you will be continuously having to inject input state which can be very inefficient when no events are actually happening. On my PC at least, it kind of feels 'sluggish' from always injecting the mouse position each frame. This could be optimized of course, but I'd rather do something that is shown in the second version below.

 

Here is a simple example that utilizes the CEGUI Lua scripting module and works alongside Leadwerks. I just load the GUI itself from one of the CEGUI scripts that comes with the SDK. (Note: code is not 'complete' yet, still looking at some issues with OGL state changes, so that's why those 3 commands from before are missing)

 

#include "engine.h"
#include <CEGUI.h>
#include <RendererModules/OpenGL/CEGUIOpenGLRenderer.h>
#include <scriptingModules/LuaScriptModule/CEGUILua.h>
#include <lua.hpp>

int main(int argc, char** argv)
{
lua_State * lua = lua_open();

luaL_openlibs(lua);

Initialize();
Graphics(800, 600);

CEGUI::OpenGLRenderer & renderer = CEGUI::OpenGLRenderer::create();
CEGUI::System & sys = CEGUI::System::create(renderer);

CEGUI::LuaScriptModule & script_module = CEGUI::LuaScriptModule::create(lua);
sys.setScriptingModule(&script_module);

CEGUI::DefaultResourceProvider* rp = static_cast<CEGUI::DefaultResourceProvider*>(CEGUI::System::getSingleton().getResourceProvider());
const char* dataPathPrefix = "data";
char resourcePath[MAX_PATH];
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "schemes/");
rp->setResourceGroupDirectory("schemes", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "imagesets/");
rp->setResourceGroupDirectory("imagesets", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "fonts/");
rp->setResourceGroupDirectory("fonts", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "layouts/");
rp->setResourceGroupDirectory("layouts", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "looknfeel/");
rp->setResourceGroupDirectory("looknfeels", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "lua_scripts/");
rp->setResourceGroupDirectory("lua_scripts", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "xml_schemas/");
rp->setResourceGroupDirectory("schemas", resourcePath);  

CEGUI::Imageset::setDefaultResourceGroup("imagesets");
CEGUI::Font::setDefaultResourceGroup("fonts");
CEGUI::Scheme::setDefaultResourceGroup("schemes");
CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
CEGUI::WindowManager::setDefaultResourceGroup("layouts");
CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
if(parser->isPropertyPresent("SchemaDefaultResourceGroup"))
	parser->setProperty("SchemaDefaultResourceGroup", "schemas");  

script_module.executeScriptFile("demo8.lua", "");

if(!CreateWorld()) 
{
	MessageBoxA(0, "Failed to create world.", "Error", MB_ICONERROR);
	return Terminate();
}
TEntity c = CreateCube();
TCamera cam=CreateCamera();
CameraClearColor(cam,Vec4(0,0,1,1));
MoveEntity(cam,Vec3(0,0,-10));
TLight light=CreateDirectionalLight();
RotateEntity(light,Vec3(65,45,0));
TBuffer buffer=CreateBuffer(GraphicsWidth(), GraphicsHeight(), BUFFER_COLOR | BUFFER_DEPTH | BUFFER_NORMAL);
HideMouse();
while(!KeyHit(KEY_ESCAPE))
{
	TurnEntity(c, Vec3(0, 1, 0));
	UpdateWorld();
	SetBuffer(buffer);
	RenderWorld();
	SetBuffer(BackBuffer());
	RenderLights(buffer);
	CEGUI::System::getSingleton().renderGUI();
	Flip();
	CEGUI::System::getSingleton().injectMousePosition(MouseX(), MouseY());
}

sys.setScriptingModule(0);
CEGUI::LuaScriptModule::destroy(script_module);

CEGUI::System::destroy();
CEGUI::OpenGLRenderer::destroy(renderer);

lua_close(lua);
lua = 0;

return Terminate();
}

 

ss1k.th.png

 

So this is the quick and easy way. It 'works', but you will start to run into some event issues due to what is exposed to us in the C API of Leadwerks. This leads to the second version.

 

Version 2: Leadwerks + CEGUI + SFML

 

The direction I am going to go in is using another framework to manage the window that Leadwerks creates. By doing this, I know have access to all the events that are otherwise taken care of internally by the engine. As a result, CEGUI works more smoothly with Leadwerks since you are not having to directly inject polled input every so many frames but instead can just inject input events as they happen.

 

Here is the code for this version, which has slightly more implemented than the Version 1

#include <engine.h>

#include <windows.h>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/String.hpp>

#include <CEGUI.h>
#include <CEGUIDefaultResourceProvider.h>
#include <RendererModules/OpenGL/CEGUIOpenGLRenderer.h>
#include <scriptingModules/LuaScriptModule/CEGUILua.h>

#include <lua.hpp>

std::map<sf::Key::Code, CEGUI::Key::Scan> mKeyMap;
std::map<sf::Mouse::Button, CEGUI::MouseButton> mMouseButtonMap;

void SetupEvents()
{
mKeyMap[sf::Key::Escape] = CEGUI::Key::Escape;mKeyMap[sf::Key::Num1] = CEGUI::Key::One;
mKeyMap[sf::Key::Num2] = CEGUI::Key::Two;mKeyMap[sf::Key::Num3] = CEGUI::Key::Three;
mKeyMap[sf::Key::Num4] = CEGUI::Key::Four;mKeyMap[sf::Key::Num5] = CEGUI::Key::Five;
mKeyMap[sf::Key::Num6] = CEGUI::Key::Six;mKeyMap[sf::Key::Num7] = CEGUI::Key::Seven;
mKeyMap[sf::Key::Num8] = CEGUI::Key::Eight;mKeyMap[sf::Key::Num9] = CEGUI::Key::Nine;
mKeyMap[sf::Key::Num0] = CEGUI::Key::Zero;mKeyMap[sf::Key::Dash] = CEGUI::Key::Minus;
mKeyMap[sf::Key::Equal] = CEGUI::Key::Equals;mKeyMap[sf::Key::Back] = CEGUI::Key::Backspace;
mKeyMap[sf::Key::Tab] = CEGUI::Key::Tab;mKeyMap[sf::Key::Q] = CEGUI::Key::Q;
mKeyMap[sf::Key::W] = CEGUI::Key::W;mKeyMap[sf::Key::E] = CEGUI::Key::E;
mKeyMap[sf::Key::R] = CEGUI::Key::R;mKeyMap[sf::Key::T] = CEGUI::Key::T;
mKeyMap[sf::Key::Y] = CEGUI::Key::Y;mKeyMap[sf::Key::U] = CEGUI::Key::U;
mKeyMap[sf::Key::I] = CEGUI::Key::I;mKeyMap[sf::Key:] = CEGUI::Key:;
mKeyMap[sf::Key:] = CEGUI::Key:;mKeyMap[sf::Key::LBracket] = CEGUI::Key::LeftBracket;
mKeyMap[sf::Key::RBracket] = CEGUI::Key::RightBracket;mKeyMap[sf::Key::Return] = CEGUI::Key::Return;
mKeyMap[sf::Key::LControl] = CEGUI::Key::LeftControl;mKeyMap[sf::Key::A] = CEGUI::Key::A;
mKeyMap[sf::Key::S] = CEGUI::Key::S;mKeyMap[sf::Key:] = CEGUI::Key:;
mKeyMap[sf::Key::F] = CEGUI::Key::F;mKeyMap[sf::Key::G] = CEGUI::Key::G;
mKeyMap[sf::Key::H] = CEGUI::Key::H;mKeyMap[sf::Key::J] = CEGUI::Key::J;
mKeyMap[sf::Key::K] = CEGUI::Key::K;mKeyMap[sf::Key::L] = CEGUI::Key::L;
mKeyMap[sf::Key::SemiColon] = CEGUI::Key::Semicolon;mKeyMap[sf::Key::LShift] = CEGUI::Key::LeftShift;
mKeyMap[sf::Key::BackSlash] = CEGUI::Key::Backslash;mKeyMap[sf::Key::Z] = CEGUI::Key::Z;
mKeyMap[sf::Key::X] = CEGUI::Key::X;mKeyMap[sf::Key::C] = CEGUI::Key::C;
mKeyMap[sf::Key::V] = CEGUI::Key::V;mKeyMap[sf::Key::B] = CEGUI::Key::B;
mKeyMap[sf::Key::N] = CEGUI::Key::N;mKeyMap[sf::Key::M] = CEGUI::Key::M;
mKeyMap[sf::Key::Comma] = CEGUI::Key::Comma;mKeyMap[sf::Key::Period] = CEGUI::Key::Period;
mKeyMap[sf::Key::Slash] = CEGUI::Key::Slash;mKeyMap[sf::Key::RShift] = CEGUI::Key::RightShift;
mKeyMap[sf::Key::Multiply] = CEGUI::Key::Multiply;mKeyMap[sf::Key::LAlt] = CEGUI::Key::LeftAlt;
mKeyMap[sf::Key::Space] = CEGUI::Key::Space;mKeyMap[sf::Key::F1] = CEGUI::Key::F1;
mKeyMap[sf::Key::F2] = CEGUI::Key::F2;mKeyMap[sf::Key::F3] = CEGUI::Key::F3;
mKeyMap[sf::Key::F4] = CEGUI::Key::F4;mKeyMap[sf::Key::F5] = CEGUI::Key::F5;
mKeyMap[sf::Key::F6] = CEGUI::Key::F6;mKeyMap[sf::Key::F7] = CEGUI::Key::F7;
mKeyMap[sf::Key::F8] = CEGUI::Key::F8;mKeyMap[sf::Key::F9] = CEGUI::Key::F9;
mKeyMap[sf::Key::F10] = CEGUI::Key::F10;mKeyMap[sf::Key::Numpad7] = CEGUI::Key::Numpad7;
mKeyMap[sf::Key::Numpad8] = CEGUI::Key::Numpad8;mKeyMap[sf::Key::Numpad9] = CEGUI::Key::Numpad9;
mKeyMap[sf::Key::Subtract] = CEGUI::Key::Subtract;mKeyMap[sf::Key::Numpad4] = CEGUI::Key::Numpad4;
mKeyMap[sf::Key::Numpad5] = CEGUI::Key::Numpad5;mKeyMap[sf::Key::Numpad6] = CEGUI::Key::Numpad6;
mKeyMap[sf::Key::Add] = CEGUI::Key::Add;mKeyMap[sf::Key::Numpad1] = CEGUI::Key::Numpad1;
mKeyMap[sf::Key::Numpad2] = CEGUI::Key::Numpad2;mKeyMap[sf::Key::Numpad3] = CEGUI::Key::Numpad3;
mKeyMap[sf::Key::Numpad0] = CEGUI::Key::Numpad0;mKeyMap[sf::Key::F11] = CEGUI::Key::F11;
mKeyMap[sf::Key::F12] = CEGUI::Key::F12;mKeyMap[sf::Key::F13] = CEGUI::Key::F13;
mKeyMap[sf::Key::F14] = CEGUI::Key::F14;mKeyMap[sf::Key::F15] = CEGUI::Key::F15;
mKeyMap[sf::Key::RControl] = CEGUI::Key::RightControl;mKeyMap[sf::Key::Divide] = CEGUI::Key::Divide;
mKeyMap[sf::Key::RAlt] = CEGUI::Key::RightAlt;mKeyMap[sf::Key::Pause] = CEGUI::Key::Pause;
mKeyMap[sf::Key::Home] = CEGUI::Key::Home;mKeyMap[sf::Key::Up] = CEGUI::Key::ArrowUp;
mKeyMap[sf::Key::PageUp] = CEGUI::Key::PageUp;mKeyMap[sf::Key::Left] = CEGUI::Key::ArrowLeft;
mKeyMap[sf::Key::Right] = CEGUI::Key::ArrowRight;mKeyMap[sf::Key::End] = CEGUI::Key::End;
mKeyMap[sf::Key::Down] = CEGUI::Key::ArrowDown;mKeyMap[sf::Key::PageDown] = CEGUI::Key::PageDown;
mKeyMap[sf::Key::Insert] = CEGUI::Key::Insert;mKeyMap[sf::Key::Delete] = CEGUI::Key::Delete;
mMouseButtonMap[sf::Mouse::Left] = CEGUI::LeftButton;
mMouseButtonMap[sf::Mouse::Middle] = CEGUI::MiddleButton;
mMouseButtonMap[sf::Mouse::Right] = CEGUI::RightButton;
mMouseButtonMap[sf::Mouse::XButton1] = CEGUI::X1Button;
mMouseButtonMap[sf::Mouse::XButton2] = CEGUI::X2Button;
}
CEGUI::Key::Scan toCEGUIKey(sf::Key::Code Code)
{
if (mKeyMap.find(Code) == mKeyMap.end())
{
	return (CEGUI::Key::Scan)0;
}
return mKeyMap[Code];
}

CEGUI::MouseButton toCEGUIMouseButton(sf::Mouse::Button Button)
{
if (mMouseButtonMap.find(Button) == mMouseButtonMap.end())
{
	return (CEGUI::MouseButton)0;
}
return mMouseButtonMap[button];
}

int main(int argc, char *argv[])
{
lua_State * lua = lua_open();

luaL_openlibs(lua);

SetupEvents();

bool gDone = false;

// Setup Leadwerks
Initialize();

// Use the CRC of the string "Leadwerks" to set a unique title
SetAppTitle("258BD7E6");

// Setup the graphics based on the size of the control
Graphics(1024, 768);

// Get the rendering context from Leadwerks
HGLRC leContext = wglGetCurrentContext();

// We will use CEGUI to handle the mouse
HideMouse();

// Now we can find our application's window handle based on the class and title
HWND leWnd = FindWindowA("BlitzMax GLGraphics", "258BD7E6");

// And we can rename it, so we can still run other instances of this application
SetWindowTextA(leWnd, "Leadwerks + SFML + CEGUI");

// Create the main window
sf::WindowSettings params;
params.UserContext = PtrToUint(leContext);
params.OverrideMsgs = true;
sf::RenderWindow gWindow(leWnd, params);

// Limit to 60 frames per second
gWindow.UseVerticalSync(true);
gWindow.SetFramerateLimit(60);

CEGUI::OpenGLRenderer & renderer = CEGUI::OpenGLRenderer::create();
CEGUI::System & sys = CEGUI::System::create(renderer);

CEGUI::LuaScriptModule & script_module = CEGUI::LuaScriptModule::create(lua);
sys.setScriptingModule(&script_module);

CEGUI::DefaultResourceProvider* rp = static_cast<CEGUI::DefaultResourceProvider*>(CEGUI::System::getSingleton().getResourceProvider());
const char* dataPathPrefix = "datafiles";
char resourcePath[MAX_PATH];
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "schemes/");
rp->setResourceGroupDirectory("schemes", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "imagesets/");
rp->setResourceGroupDirectory("imagesets", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "fonts/");
rp->setResourceGroupDirectory("fonts", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "layouts/");
rp->setResourceGroupDirectory("layouts", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "looknfeel/");
rp->setResourceGroupDirectory("looknfeels", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "lua_scripts/");
rp->setResourceGroupDirectory("lua_scripts", resourcePath);
_snprintf(resourcePath, MAX_PATH - 1, "%s/%s", dataPathPrefix, "xml_schemas/");
rp->setResourceGroupDirectory("schemas", resourcePath);  

CEGUI::Imageset::setDefaultResourceGroup("imagesets");
CEGUI::Font::setDefaultResourceGroup("fonts");
CEGUI::Scheme::setDefaultResourceGroup("schemes");
CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
CEGUI::WindowManager::setDefaultResourceGroup("layouts");
CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
if(parser->isPropertyPresent("SchemaDefaultResourceGroup"))
	parser->setProperty("SchemaDefaultResourceGroup", "schemas");  

script_module.executeScriptFile("demo8.lua", "");

// Setup Leadwerks with some basic stuff
TWorld world = CreateWorld();
TEntity camera = CreateCamera();
PositionEntity(camera, Vec3(0, 2, -5));
TEntity light = CreateDirectionalLight();
RotateEntity(light, Vec3(45, 45, 0));
TBuffer buffer = CreateBuffer(GraphicsWidth(), GraphicsHeight(), BUFFER_COLOR | BUFFER_DEPTH | BUFFER_NORMAL);
TEntity mesh = CreateCube();
PositionEntity(mesh, Vec3(0, 2, 0));

TVec3 camrotation = Vec3(0);
float mx = 0;
float my = 0;
float move = 0;
float strafe = 0;

CEGUI::MouseCursor * cursor = CEGUI::MouseCursor::getSingletonPtr();
cursor->show();

bool bMouseDown = false;

sf::Event Event;
while(!gDone)
{
	while(gWindow.GetEvent(Event))
	{
		switch(Event.Type)
		{
			case sf::Event::TextEntered: CEGUI::System::getSingleton().injectChar(Event.Text.Unicode); break;
			case sf::Event::KeyPressed: CEGUI::System::getSingleton().injectKeyDown(toCEGUIKey(Event.Key.Code)); break;
			case sf::Event::KeyReleased: CEGUI::System::getSingleton().injectKeyUp(toCEGUIKey(Event.Key.Code)); break;
			case sf::Event::MouseMoved: CEGUI::System::getSingleton().injectMousePosition(static_cast<float>(Event.MouseMove.X), static_cast<float>(Event.MouseMove.Y)); break;
			case sf::Event::MouseButtonPressed: CEGUI::System::getSingleton().injectMouseButtonDown(toCEGUIMouseButton(Event.MouseButton.Button)); break;
			case sf::Event::MouseButtonReleased: CEGUI::System::getSingleton().injectMouseButtonUp(toCEGUIMouseButton(Event.MouseButton.Button)); break;
			case sf::Event::MouseWheelMoved: CEGUI::System::getSingleton().injectMouseWheelChange(static_cast<float>(Event.MouseWheel.Delta)); break;
			case sf::Event::Closed: gDone = true; break;
		}
	}

	gWindow.SetActive();

	TurnEntity(mesh);
	UpdateAppTime();
	UpdateWorld();
	SetBuffer(buffer);
	RenderWorld();
	SetBuffer(BackBuffer());
	RenderLights(buffer);

	glPushAttrib(GL_ALL_ATTRIB_BITS);
	DrawText(0, 0, "Press F1 to bring back the GUI window.");
	glPopAttrib();

	CEGUI::System::getSingleton().renderGUI();

	gWindow.Display();
}

sys.setScriptingModule(0);
CEGUI::LuaScriptModule::destroy(script_module);

CEGUI::System::destroy();
CEGUI::OpenGLRenderer::destroy(renderer);

lua_close(lua);
lua = 0;

Terminate();

return EXIT_SUCCESS;
}

 

ss2a.th.png

 

There are other ways to do this, but I just liked SFML by preference. You could probably write some quick Win32 code to take care of the input issues with Version 1 and have less dependencies and all, but I had already worked out how to modify SFML to work with Leadwerks, so I just stuck with that into looking into other alternatives. You;d probably just subclass the main window's WndProc and add the code to inject the input events as they happened rather than injecting the polled input.

 

The issue I have with CEGUI is the same issue I have with almost all open source projects. It has to many dependencies which are all open source also and you have to compile them all and it's a big pain to work with and get working. My task will be to try and set some defaults for CEGUI with LE to make things easier. I'm going to try and get everything into 1 DLL and 1 lib. I plan on adding some of my own functions/class to help hide the setup of CEGUI with LE, so ppl can just use it.

 

This used to bother me a lot as well. I always wanted just one 'thing' to deal with rather than over 9000 little things.

 

However, over time I've come to realize that project organization far trumps all of the little issues of having too many dependencies or packages to work with in a project. By not trying to combine everything or consolidate into one package, you make updating a lot easier on yourself. In addition, your work is more usable by people who want complete control over how things work or have specific needs of their dependences.

 

The most common example involves Lua. Ogre3D uses Lua, CEGUI uses Lua, and your own project might use Lua. That's three (!) different Lua packages in one project. That's a nightmare in itself due to Lua interop issues across different versions due to whatever reasons. As a result, your project needs to use one base Lua and share it across all three projects. Good libraries are setup so this is possible. You can just take the sources of those libraries and rip out the Lua and point them to your common one.

 

If instead Ogre, CEGUI, and your own project all came as one consolidated lib, then you'd have a real problem on hand. If the Lua versions are so different that they can't all work together in compiled form, then you'd need to get the source and recompile it all, causing more work to be done. Now to get to the point: project organization.

 

Let's say if everyone started to create their projects in a consistent meaningful way. For Visual Studio, this would be to create a new Solution Workspace and then adding your game project as a new project to it. Then, you have a Common folder that contains all your 3rd party stuff. A Bin folder is for executing and contains the DLLs and assets as needed. This would look like this:

ss3f.th.png

 

Inside your Common folder, you have 3rd party libraries setup usually in a form of a folder having an "include" and a "lib" if they are precompiled.

ss4v.th.png

 

Now it's just a matter of setting up each project in your solution to point to the directories. You could do it once via the Global settings in VS, but I prefer not doing that due to possible compatibility issues across different projects that use similar libraries but different versions. For each 3rd party component you are going to be:

1. Adding the Include directory to the project

2. Adding the Lib directory to the project

3. Adding any source files to the project folders

4. Linking the libs via project settings (no pragmas!)

5. Adding the header files to the project folders (makes life easier on Intellisense)

 

Honestly, we're looking at no more than about 5 minutes of work max per 3rd party component we add. We only have to do this once per a project and then we can copy paste as needed. It can be a little tedious, I mean this is what my library settings line looks like:

ndd.lib lua_d.lib sfml-audio-s-d.lib sfml-graphics-s-d.lib sfml-main-d.lib sfml-network-s-d.lib sfml-system-s-d.lib sfml-window-s-d.lib opengl32.lib glu32.lib CEGUIBase_d.lib CEGUICoronaImageCodec_d.lib CEGUIDevILImageCodec_d.lib CEGUIDirect3D9Renderer_d.lib CEGUIDirect3D10Renderer_d.lib CEGUIExpatParser_d.lib CEGUIFalagardWRBase_d.lib CEGUIFreeImageImageCodec_d.lib CEGUIIrrlichtRenderer_d.lib CEGUILuaScriptModule_d.lib CEGUIOgreRenderer_d.lib CEGUIOpenGLRenderer_d.lib CEGUISILLYImageCodec_d.lib CEGUITGAImageCodec_d.lib CEGUITinyXMLParser_d.lib CEGUIXercesParser_d.lib tolua++_d.lib

And slightly easier, this is my includes:

../common/cegui/include;../common/leadwerks;../common/lua/include;../common/nd/include;../Common/sfml/include

 

But let's consider what we gain:

 

1. Easy redeployment: We can compress a library in Common and send it to someone else. All they do is put it in their Common and then update project settings with the paths. They don't even have to do this themselves since they can just copy/paste the lines needed. If you look at my includes, you'll see they are relative paths rather than absolute, so anyone can use them as long as they are using a similar project setup.

 

2. Easy Updating: Let's say we want to migrate to a new version of a library. Rename the folder in Common and use the new one. If things go bad, it's just a matter of renaming again. If we need to share one common library across other libraries, this is easy as well since it's already part of the project path.

 

And lets consider the costs:

 

1. File Bloat: Meh, just part of the territory when using C++. ;)

 

So if anything, I'm going to recommend to you that you don't spend your time on trying to work against the bloated design of some of these OSS libraries and instead just work with it. By setting up a common project organization such as I described above, there's no real need to muck around with the sources and cripple yourself when patches come around. Instead, you can just concentrate on your wrapper for everything that makes use of any format of the library, whether a user wants to use it as a DLL or as a static library.

 

I think that'd ensure that your work goes a lot further and lasts a lot longer than otherwise. Just my thoughts on the matter though, good luck with your project! :)

Edited by Drew_Benton
Link to comment
Share on other sites

I tried several GUI libraries, but they are all bloated like hell and don't look nowhere how I want a GUI to look (simple, clean and good looking). I decided then to make my own which took a few days, but I got what I wanted, not more, not less.

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

Great article Drew, thanks for sharing this and explaining it all so well. Like Lumooja I am quite able to write my own if need be but I'm certainly willing to look at available libraries first as I, like most, have so many things on my 'to do list'. CEGUI has always looked like one of the better and easier integrated libs.

Intel Core i5 2.66 GHz, Asus P7P55D, 8Gb DDR3 RAM, GTX460 1Gb DDR5, Windows 7 (x64), LE Editor, GMax, 3DWS, UU3D Pro, Texture Maker Pro, Shader Map Pro. Development language: C/C++

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...