News:

The Forum Rules and Guidelines
Our forum has Rules and Guidelines. Please, be kind and read them ;).

CEGUI integration project

Started by Markohs, February 04, 2012, 12:12:48 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Markohs

#35
Yes, agree with you, atm OpenGL is the target, Ogre is not required yet and it's just a unnecessary overhead.

If it's just OpenGL window opening and init, SDL does that for you already if it's compiled with OpenGL support. The one shipped with simutrans already is. That makes your code plattform independent.

The code in my program is (note the SDL_OPENGL parameter):


#ifdef _WIN32
int CALLBACK WinMain(HINSTANCE const hInstance, HINSTANCE, LPSTR, int)
#else
int main(int argc, char **argv)
#endif
{
#ifdef _WIN32
   int    const argc = __argc;
   char** const argv = __argv;
   char         pathname[1024];

#endif

   SDL_Surface * screen;
   atexit (SDL_Quit);
   SDL_Init (SDL_INIT_VIDEO);
   screen = SDL_SetVideoMode (600, 480, 0, SDL_OPENGL);
   if (screen == NULL) {
      fprintf (stderr, "Video: %s\n", SDL_GetError ());
      exit (1);
   }

   renderer = &CEGUI::OpenGLRenderer::bootstrapSystem    (    CEGUI::OpenGLRenderer::TTT_AUTO   );

   SDL_ShowCursor (SDL_DISABLE);
   SDL_EnableUNICODE (1);
   SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

   setup();
   main_loop();

}


Skipping the CEGUI line you should have platform idependent code.

The rest of the relevant code to your interests is:


void inject_input (bool & must_quit)
{
    try{
        SDL_Event e;
        /* go through all available events */
        while (SDL_PollEvent(&e)) {
            /* we use a switch to determine the event type */
            switch (e.type) {
                /* mouse motion handler */
            case SDL_MOUSEMOTION:
                /* we inject the mouse position directly. */
                CEGUI::System::getSingleton().injectMousePosition(static_cast<float>(e.motion.x),static_cast<float>(e.motion.y));
                break;

                /* mouse down handler */
            case SDL_MOUSEBUTTONDOWN:
                /* let a special function handle the mouse button down event */
                handle_mouse_down (e.button.button);
                break;

                /* mouse up handler */
            case SDL_MOUSEBUTTONUP:
                /* let a special function handle the mouse button up event */
                handle_mouse_up (e.button.button);
                break;

                /* key down */
            case SDL_KEYDOWN:
                /* to tell CEGUI that a key was pressed, we inject the scancode. */
                CEGUI::System::getSingleton().injectKeyDown(e.key.keysym.scancode);
                /* as for the character it's a litte more complicated.
                * we'll use for translated unicode value.
                * this is described in more detail below.
                */
                if ((e.key.keysym.unicode & 0xFF80) == 0) {
                    CEGUI::System::getSingleton().injectChar(e.key.keysym.unicode & 0x7F);
                }
                break;

                /* key up */
            case SDL_KEYUP:
                /* like before we inject the scancode directly. */
                CEGUI::System::getSingleton().injectKeyUp(e.key.keysym.scancode);
                break;

                /* WM quit event occured */
            case SDL_QUIT:
                must_quit = true;
                break;

            case SDL_VIDEORESIZE:
                renderer->setDisplaySize(CEGUI::Size(e.resize.w, e.resize.h));
                break;
            }
        }
    }
    catch(CEGUI::Exception &e){
        printf("CEGUI Error: %s", e.getMessage().c_str());
        MessageBoxA( NULL, e.getMessage().c_str(), "Fatal Error", MB_ICONEXCLAMATION|MB_OK );
    }
}


void inject_time_pulse(double& last_time_pulse)
{
    try{
        /* get current "run-time" in seconds */
        double t = 0.001*SDL_GetTicks();
        /* inject the time that passed since the last call */
        CEGUI::System::getSingleton().injectTimePulse( float(t-last_time_pulse) );
        /* store the new time as the last time */
        last_time_pulse = t;
    }catch(CEGUI::Exception &e){
        printf("CEGUI Error: %s", e.getMessage().c_str());
        MessageBoxA( NULL, e.getMessage().c_str(), "Fatal Error", MB_ICONEXCLAMATION|MB_OK );
    }
}

void render_gui()
{
    /* clear the colour buffer */
    glClear( GL_COLOR_BUFFER_BIT );
    /* render the GUI */
    try{
        CEGUI::System::getSingleton().renderGUI();
    }catch(CEGUI::Exception &e){
        printf("CEGUI Error: %s", e.getMessage().c_str());
        MessageBoxA( NULL, e.getMessage().c_str(), "Fatal Error", MB_ICONEXCLAMATION|MB_OK );
    }
    /* Update the screen */
    SDL_GL_SwapBuffers();
}

void main_loop ()
{
    bool must_quit = false;
    /* get "run-time" in seconds */
    double last_time_pulse = 0.001*static_cast<double>(SDL_GetTicks());
    while (!must_quit) {
        inject_input (must_quit);
        inject_time_pulse (last_time_pulse);
        render_gui ();
    }
}


This code can be easily merged in simsys_opengl.cc

setup() only does things relevant to CEGUI.

I'd be happy if you could please upload your code when you want to the simutrans3d branch for further development. :)

Ters

Since you got OpenGL up and running from SDL, all I've got are dr_textur, dr_flush, dr_textur_init and dr_textur_resize. But I must rewrite these for SDL first.

Spike

I want to voice again my support for the 3D branch and this project, because I think an OpenGL rendering backend and a new UI library address some very important issues in Simutrans.

Markohs

#38
Thx, Hajo.

I could use some help on the CEGUI GUI re-implementation, plus pixelart if you are interested, by the way. ;)

There are lots of bitmaps to be designed, windows to be layout and code to be implemented.

I can post my TODO here to see if you or anyone is interested in some of the work needed.

This cegui project opens the door to lots of creative work, now you can scale, rotate, alphablend items very easy, I'm pretty sure many cool things can be done and added to simutrans.

Ters

Here's a changed simsys_s.cc that sets up OpenGL, draws to an OpenGL texture and renders a quad with this texture. On its own, a very pointless thing to do.
Somehow the dirty rectangle stuff works here, though I use the same OpenGL commands at the same places. I'm not sure why, but I do not reuse the same texture after resize if it's big enough like simsys_w.cc does and my OpenGL version of that did.
This code assumes that the system supports textures of any size.
For the way forward, I would suggest putting the existing user interface into a CEGUI component and gradually move windows out of it into CEGUI. Is whatever has been done with CEGUI on its own available somewhere like Simutrans 3D is?

Markohs

okay, i'll mix this with mi cegui code and upload it to simutrans3d svn as soon as I can. thank you

Markohs

#41
Okay, I just added a new visual studio project named SimutransCEGUI to the simutrans3d branch, with your code replacing simsys.

Had to update to svn HEAD since my copy wasa bit older and had a old version of simsys.h that was incompatible, since they fixed some parameters and code like 2 weeks ago. Now we are in sync with simutrans code.

This update also broke current simutrans3D code but well, not really important since CEGUI is my focus now.

It works good for me too, except a window resize renders a whole white screen here. I'll have it a look to your code to try to see what's wrong.

My CEGUI code so far it's on a separate project without integrating to sumutrans yet. I can post it here if you want but it's notthing too interesting, I'll mix it to simutransCEGUI today so everybody can help with the development if they want.

Thank you!

Ters

A white screen means that the texture was not created properly, or that the texture created is unusable.

Markohs

Works good on a ATI Radeon card, but fails on the resize on nVidia

Markohs

Getting closer to make this work, still something wrong, through ;)


IgorEliezer

ummm... I always suspected there's something wrong with my screen. Thanks for pointing out.

* IgorEliezer goes upside down.

Ters

Not so wrong as my first OpenGL version, which used glDrawPixels rather than a textured quad. It was both upside down and not at the same time. Very confusing to look at, almost like seeing the map from below.

isidoro

Quote from: Markohs on February 14, 2012, 01:12:16 AM
Getting closer to make this work, still something wrong, through ;)

That is easy, Markoh.  It is due to the city being in the southern hemisphere.  Just move it...  :D ;D

Markohs

#48
haha ;)

I hope I can give it a look soon, a bit busy with work and final project again till the weekend comes. :)

The code is in SVN for the case someone wants to code and patch something meanwhile.

Markohs

I could give this a look at the expense of the time I should have spent for friday's presentation. ;)

It works! I just attached a test window. It's all based on Ters code. Just a alpha enabled window on top of simutrans. Events are first processed by CEGUI and if it's not catched by one of it's windows, passed to simutrans. Both the cegui window and simutrans receive the clicks and mousemoves.

I hope to be able to get some of current dialogs rendered with cegu soon, but PAK icons extraction and cegui's imagemap generation have to be done before, at last for the construction toolbars.

The only dialog that's not PAK-dependant is the PAK selection screen.

Perfromance is good, but the screen it's a bit blurry because of the pixels interpolation done by CEGUI, since I didn't rendered on top of the framebuffer as Ter's code does, I mapped the OpenGL texture to a CEGUI/StaticImage that's on the root of the GUI (as background)


Ters

It's ironic to have to reassemble an imageset from one or more pak files, when the pak files themselves are made from an imageset.

I've begun experimenting with CEGUI myself. It looks like some custom renderers and window types are required. And I have to say I don't like CEGUI's abuse of references. Not when it was introduced, not now, and probably never.

Markohs

#51
 Yes, I understand what you say, but we can't avoid that, this game is based in current PAK format and we can't change that now. Once we have the project running and working good, we might be able to shift current PAK's to just a .zip with png imagemaps and textual image/objects descriptions.

I don't like references either, I prefer plain pointers, but they are suposed to make code less error prone, more secure and legible. I try to get used, I never used them before, and I wish they never existed. :) In fact the error I showed two posts ago, was originated from a reference.

The way I thought this so far is making a .scheme, with all the base items, clone WindowsLoook .lookandfeel and make our own. I choosed WindowsLook because I think it looks more similar to current simutrans UI than TharezLook.

The plan whould be:

- Create a simutrans.scheme from windowslook.scheme
- Add all needed widgets to .lookandfeel
- Customize WindowsLook imageset to look like simutrans.
- Create .layout for all windows, and .clone them when needed.

CEGUI documentation is a bit poor too, and they change some things often from release to release, looks like. I'm using 0.7.6 atm.

Also, on the current code I map your OpenGL texture to a background StaticImage Widget, at the borders of the screen you can see the border of the widget. I did this to see this is possible, since we'll need in the future for example on the vehicle window, where you see a sub-render of the vehicle ingame, that will be a StaticImage with a texture over it, rendered. But I think we'll better start with dr_flush just writing straight to the window, and let CEGUI write on top of it each frame, I think.

This is my media folder, for the case you want to have it a look, nothing too special there, still.

Markohs

Back to your original code, I'm trying to figure why resizing doesn't work on my computer here with a nVidia card and why does it work on other with a ATI one.

I found this page dunno if you had it already, Ters.

There it suggests OpenGL context might be destroyed on each SDL_SetVideoMode, but I see you recreate the viewport and the texture after dr_textur_resize.

Do you have any idea where can the problem be?

Ters

Quote from: Markohs on February 16, 2012, 12:35:34 AM
Back to your original code, I'm trying to figure why resizing doesn't work on my computer here with a nVidia card and why does it work on other with a ATI one.

I found this page dunno if you had it already, Ters.

There it suggests OpenGL context might be destroyed on each SDL_SetVideoMode, but I see you recreate the viewport and the texture after dr_textur_resize.

Do you have any idea where can the problem be?

I don't reset all states on resize. More specifically, the state that enables texturing: glEnable(GL_TEXTURE_2D). I think that's the only state I set once and for all.

Quote from: Markohs on February 15, 2012, 06:56:51 PM
I don't like references either, I prefer plain pointers, but they are suposed to make code less error prone, more secure and legible. I try to get used, I never used them before, and I wish they never existed. :) In fact the error I showed two posts ago, was originated from a reference.
References are good, as long as they are used correctly. CEGUI sometimes uses them as pointers, which makes it unclear that they should be treated pointers and not references. They have different uses.

Markohs

#54
I managed to fix it, it needed a glEnable(GL_TEXTURE_2D) after the SDL_SetVideoMode. Just uploaded to SVN.

It whould be nice if someone tried this in linux to see if it's working too.

I'ts built as the SDL version just replacing simsys_s.cc with symsys_opengl.cc and including and linking against OpenGL too.

I started translating the comments, and I have one question. Is there any plan to document the code javadoc style? I'll use @author, @param etc on the comments if you don't mind, to document it and to give proper credit to Ters and me.

EDIT: I compiled a release Windows version also, I'd appreciate enybody that can spare some minutes to try it and report any problems and sucesses, with some basic system information (Windows version and video card). Download from here.

Dwachs

#55
QuoteI started translating the comments, and I have one question. Is there any plan to document the code javadoc style? I'll use @author, @param etc on the comments if you don't mind, to document it and to give proper credit to Ters and me.
please do! Then doxygen can generate some sensible documentation.

Edit: it compiles. The colors are tuned to make every pakset look excentrique.

I did not follow this thread nor the svn logs, which files did you modify to make opengl version running? Would it make sense to commit the opengl stuff to standard (including proper Makefile support).

Parsley, sage, rosemary, and maggikraut.

Markohs

 Hi, thank you for trying it out.

Ok, I'll comment it then. :)

The opengl version just needs the new simsys_opengl.cc, it's standalone. I think it's a good idea to include the opengl version straight  in standard branch since it's just another backend that might be useful for something, even performance should be the same as simsys_s.cc, but can work better in some plattforms (I read somewere that the SDL version doesn't work on Mac good enough).

But first I'd like to document it better, fix that excentrique bug and of course make the Makefile to work. I did add a 'opengl' backend in the Makefile, did that work?

From the screenshot I think the components are picked wrong in the texture, looks like it doesn't have a green channel, that might be the problem, I'll have it a look. :)

Dwachs

Quote from: Markohs on February 17, 2012, 08:39:08 AM
I did add a 'opengl' backend in the Makefile, did that work?
Did not saw that first, I hand-edited the sdl-backend branch. There were two extra )'s, which I removed now, it compiles for me using backend=opengl.
Parsley, sage, rosemary, and maggikraut.

prissi

Sorry, you mean the 3D branch? Or did I miss something in my week away? I see no standalone OpenGL-support ???

Markohs

Yea prissi, the branches/simutrans3d/simsys_opengl.cc is a standalone OpenGL backend, no other files modified. Might have some bugs yet, but it works good in windows, looks like.

Markohs

#60
Okay, I'll try to explain the situation.

CEGUI works sightly different than the curren UI:

- It's rendered to a separate texture, once each frame, using the 3D engine, so the dirty areas management code is useless, the result is blended with the backgraound after that.
- It already has a container hierarchy implemented, so widgets inside a framed window,, move with them automatically.
- Uses unified screen dimensions, X=> 0..1, Y=>0..1
- It's based on widget callbacks, like the current simutrans does with action_listener and gui_action_creator_t classes. Centralizing the event handling in a single callback simutrans stype is nto something the CEUI creator likes but looks like it's possible.
- dialogs layout can be done in-code, C++ sentences like current simutrans code does, or thay can be read from a separate .layout XML file, making it possible to change the dialogs without the need to recompile the project.

So, how can I implement this? there are verious approaches I'd like you to give your oppinion in, in all approaches I assume we'll need non-CEGUI, simutrans interface, so we can change CEGUI for another GUI library in the future if we want to.

1) First, simplest solution is just implement the current widgets using CEGUI widgets, and try to disable zeichnen (draw) calls. This implementation is feasible, with some changes like the widgets have to be attached to the parent window and some minor adjustements I think.
2) The second option is having all dialogs load a external XML layout, and define default actions to be linked with some buttons. For example the File selection layout will be searched for a "Load" button, and if it has one, linked with the Load file action.
3) The third option is like the second one, but exposing a list of actions in the layout, and implement all the functionality in the LUA language, exposing if to the dialog creator, so he can decide how to manage the dialog events, and extend its functionality (like for example, showing minimap screenshots of the savegames, a game summary, or spawning new dialogs.

From option 2 and beyound, I was thinking on the possibility of decoupling the gui dialogs from the actions, implementing "actions" on their own, like "load savegame", "spawn a confirmation dialog", "delete a file", "spawn finances dialog", "read this directory".

What do you think of all of this, I'm overdoing this and I should just try to go option 1?

Spike

Quote from: Markohs on February 23, 2012, 09:54:47 AM
- Uses unified screen dimensions, X=> 0..1, Y=>0..1

My head is not made for math, so maybe it's all good already. But I want to ask if a transform from 0..1 to 0..1024 will put a line with one pixel with exactly on a pixel boundary? Will it be blurred over two pixels?

If there is pixel precise rounding, then, imagine this:

Assuming that you have a button width of 0.05 and like a button position of 0.1

Further assuming that the 0.1 position will result in pixel 100.2 and the width will be 50.3 pixels. This button will then strech from pxiel 100.2 rounded to 100 to pixel 150.5 rounded to 150.

And even further assuming that a second button exist with width 0.05 and a position of 0.102

That second button might then start at pixel 100.4 and run for 50.3 pixels, this time starting at 100 (rounded) but ending at 150.7 rounded to 151

Will the second button be 1 pixel wider then, even that both have a width of 0.05 defined?

My numbers are most likely not correct - I just try to sketch a scenario where a rounding action will lead to a one pixel difference, and I'm asking if such can happen with CEGUI or if this is mathmatically impossible.

edit: ... or unimportant. Just curious what actually will happen there :)

Markohs

I'll have it a look after I come back from the hairdresser and explain it further, but basically the 3D engine will interpolate and blur around the pixel positions. :)




Markohs

Well, okay, I think I understand your question.

There is no extra rounding appart of what a C++ float variable has, and that's about 7-8 decimal digits if I'm not wrong (I just googled it). that gives us a maximum window size of 10.000.000x10.000.000 pixels. So until displays get bigger than that, there should be no problem in positioning lines of a exact pixel with.

Another issue is how do you place a pixel in a exact position of a screen making it to no start "polluting" pixels next to it. from the top of my head, I guess you just:

float f_pos_x = ((float)i_pos_x+0.5) / w_width_x;

Another issue that arises sometimes is what happens when a image is scaled when you draw it on a screen, like this:



Here you can see, in the "shadow" of the trees and the borders of the trees, that in my code I initialized the transparent areas to "transparent WHITE". when the image is rendered on screen, near the edges of the pixels, the interpolation gives a gradient between the non-transparent pixel and the transparent one. Since those pixels are stored in 1 bit alpha and 5 for each color (16 packed), there is no gradient between transparent and not transparent, creating that white effect on the border.

I don't know the exact details of how CEGUI manages this, but I guess the code just makes sure the coordinates you give are near the center of a pixel, but even if it didn't, you as a programmer will for sure create the coordinates manually with a statement like the one I typed before, so it will end in coordinates very near to the center of the real pixels of the renders. The only exception to this whould be when you use animated effects to deform the GUI elements, where pixels will for sure end in position more near to be in-between the pixels. Or if you rendered the GUI to a texture, that has a different resolution than the final window.

But that just is not very important, I guess, since usually you will apply a antialias as a postprocess anyway, so all the image will look even smoother.

Isaac Eiland-Hall

Wow, that latest image reminds me very much of an old DOS golfing game I played in the late 80s or very early 90s... hehe

Can I just occasionally post a cheerleading post in here? Let me know if I'm a bother, because I can't say much on-topic, but I still wanted to say: Wow. I love how this is progressing!

Markohs

Sure, I like to hear comments from people, it makes me feel like someone cares. ;) Thank you!

IgorEliezer

#66
Quote from: Markohs on February 24, 2012, 02:21:30 AM
it makes me feel like someone cares. ;) Thank you!
Hehe... Someone and beyond.

I believe most of people would not feel like posting when they don't have a lengthy post in mind. I don't know but a lot of online communities out there have a "no flood" rule: don't post if you don't have anything significant to say or whatever, then people kind of refrain themselves from posting.

On the other hand, things have taught me that, while for an admin or moderator a post which contains only "I like it" or "Nice!" may sound like a "pointless post", posts like that may be important for people who are working on project. Feedbacks, even if it's just "I like it", are always encouraging.

Isaac Eiland-Hall

Quote from: IgorEliezer on February 24, 2012, 04:31:52 AM
Feedbacks, even if it's just "I like it", are always encouraging.

I like it! ;-)

Markohs

I uploaded a new update to the svn, with a draft of the design of the new GUI, documentation can be found here.

Any comment is welcome.

Markohs

#69
Small update:

Just a small demo video showing what's working so far, just pak selection and loading screen, but all that look-and-feel is customizable/skinnable without the need to recompile simutrans.

I know the design is not really nice at the eyes, but I hope some graphical artist gets bored some day and starts skinning that properly. :)

The idea is using that loading screen layout for all processes that use a progressbar (enlarge map, load savegame), maybe with some alpha blending in the logo, or some animation, we'll see.