ADD/MOD: added application templates for glfw3 and SDL2

#129 Merged at e01db54
Repository
lucebac
Branch
application-templates-devel
Repository
cegui
Branch
v0-8
Author
  1. Luca Ebach
Reviewers
Description
No description

Comments (22)

  1. Martin Preisler

    This is a great pull request that just needs a bit of polishing before it's merged. lucebac is however busy with university. Volunteers super welcome.

      1. Luca Ebach author

        I will integrate that when I continue to work on this. Should be the case at the latest in march, I think.

  2. Daniel Gibson

    This doesn't even build (at least on my Linux box), for several reasons:

    • FindSDL2.cmake is missing
      Unfortunately, there isn't an "official" FindSDL2.cmake, so every project seems to use one derived from cmake's FindSDL.cmake, copied from one another..
      The one from RBDoom3BFG works for me: https://github.com/RobertBeckebans/RBDOOM-3-BFG/blob/master/neo/cmake/FindSDL2.cmake
    • For include_directories you should use ${SDL2_INCLUDE_DIR}, not ${SDL_H_PATH}
    • Linking fails with tons of "undefined references" to CEGUI::String stuff in SDL2.cpp
    • I guess I don't get that far, but probably linking might also fail because you don't link against ${SDL2_LIBRARY}
    • cegui_add_dependency(CEGUITemplate_SDL2 ${CEGUI_OPENGL_RENDERER_LIBNAME}) - I guess you mean ${CEGUI_OPENGL3_RENDERER_LIBNAME} ?
      At least the code explicitly uses OpenGL3Renderer.

    I gave up at that point.

    What I actually wanted to do was improving the SDL2 template (use the aforementioned table to map the scancodes, support more mouse buttons, support SDL_TEXTINPUT events etc) and learn a bit about using cegui itself to create GUIs.. but fighting the buildsystem got too frustrating.

    BTW: I was building in debug mode and with the internal utf32 string class (not std::string). I created a build/ directory (at the root of the cegui repo) to build, as usual with cmake.

    1. Luca Ebach author

      Well, it is not suprising that you were not able to build, because CEGUI doesn't officially support SDL2 and GLFW3 at the moment. But I will work on this in march, after my uni exams.

      Edit: Anyways, I was able to build those at least on my Windows system. These files are aimed only to show a minimal code setup to run CEGUI.

      1. Daniel Gibson

        Does it have to?
        I thought this was an example how to integrate cegui into a project that uses SDL2/GLFW3, so the dependencies to those libs are handled by application_templates/CMakeLists.txt

        Anyway, good luck with your exams and I might try again in march :-)

          1. Daniel Gibson

            Yeah, you need to supply FindSDL2.cmake, but apart from that I think everything SDL2-specific can be done in the cmake file for the SDL2 template, so it doesn't need to be "global".

            (Unless you plan deeper SDL2 support, e.g. by supporting injecting SDL events directly)

            1. Luca Ebach author

              I will most probably add the file you linked above (i had an eye on it too) to our repo, but up until now i had no time to prepare it.

              I don't think we plan deeper SDL(2) support, because CEGUI has to receive events from SDL to work properly. Why should there be any need to have CEGUI inject events into SDL?

              1. Daniel Gibson

                No, what I meant was something like GuiContext::injectSDL2Event(SDL_Event ev).. but I guess that doesn't make too much sense and a good application template (+that scancode mapping table in the separate .h that you can just drop into your own projects) is good enough for people that wanna use cegui with SDL2.

                1. Lukas Meindl

                  We won't add library-dependent functions that have no equivalent in other similar libraries, such as the one you mentioned. That does not seem useful to me and is very specific.

                2. Luca Ebach author

                  I agree, because GuiContext::injectSDL2Event(SDL_Event ev) would only forward the event to SDL. In that case I would prefer to have the user inject the event directly into SDL.

                  1. Daniel Gibson

                    No, it wouldn't. It would inject the SDL2 event from SDL_PollEvent() into cegui, which would do the injection of actual cegui events internally.

                    But that's a bad idea obviously and I only mentioned this because to me this is the only scenario where "global" SDL2-support in cegui (and not just for the application template) would make sense.

    2. Luca Ebach author
      • FindSDL2.cmake is missing
      • Unfortunately, there isn't an "official" FindSDL2.cmake, so every project seems to use one derived from cmake's FindSDL.cmake, copied from one another.. The one from RBDoom3BFG works for me: https://github.com/RobertBeckebans/RBDOOM-3-BFG/blob/master/neo/cmake/FindSDL2.cmake For include_directories you should use ${SDL2_INCLUDE_DIR}, not ${SDL_H_PATH}
      • I guess I don't get that far, but probably linking might also fail because you don't link against ${SDL2_LIBRARY}
      • cegui_add_dependency(CEGUITemplate_SDL2 ${CEGUI_OPENGL_RENDERER_LIBNAME}) - I guess you mean ${CEGUI_OPENGL3_RENDERER_LIBNAME} ? At least the code explicitly uses OpenGL3Renderer.

      These points are already on my ToDo-List and I will fix them all (hopefully ;) )

  3. Daniel Gibson

    I have some untested (for aforementioned reasons..) code that you could integrate:
    (Dumping this here so I can get it out of my mind for now ;-))

    // (...)
    
    #include "sdl2_scancode_mappings.h" // gives us static int scanCodeToKeyNum[SDL_NUM_SCANCODES]
    CEGUI::Key::Scan toCEGUIKey(SDL_Scancode key)
    {
        int keyscan = scanCodeToKeyNum[static_cast<int>(key)];
        return static_cast<CEGUI::Key::Scan>(keyscan);
    }
    
    // (...)
    
    void InjectUTF8Text( const char* utf8str )
    {
        static SDL_iconv_t cd = SDL_iconv_t( -1 );
    
        if( cd == SDL_iconv_t( -1 ) )
        {
            // note: just "UTF-32" doesn't work as toFormat, because then you get BOMs, which we don't want.
            const char* toFormat = "UTF-32LE"; // TODO: what does CEGUI expect on big endian machines?
            cd = SDL_iconv_open( toFormat, "UTF-8" );
            if( cd == SDL_iconv_t( -1 ) )
            {
                std::cerr << "Couldn't initialize SDL_iconv for UTF-8 to UTF-32!" << std::endl;
                return;
            }
        }
    
        // utf8str has at most SDL_TEXTINPUTEVENT_TEXT_SIZE (32) chars,
        // so we won't have have more utf32 chars than that
        int32 utf32buf[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};
    
        // we'll convert utf8str to a utf32 string, saved in utf32buf.
        // the utf32 chars will be injected into cegui
    
        size_t len = strlen( utf8str );
    
        size_t inbytesleft = len;
        size_t outbytesleft = 4 * SDL_TEXTINPUTEVENT_TEXT_SIZE; // *4 because utf-32 needs 4x as much space as utf-8
        char* outbuf = ( char* )utf32buf;
        size_t n = SDL_iconv( cd, &utf8str, &inbytesleft, &outbuf, &outbytesleft );
    
        if( n == size_t( -1 ) ) // some error occured during iconv
        {
            std::cerr << "Converting UTF-8 string " << itf8str << " from SDL_TEXTINPUT to UTF-32 failed!" << std::endl;
        }
    
        for(int i=0; i<SDL_TEXTINPUTEVENT_TEXT_SIZE; ++i)
        {
            if(utf32buf[i] == 0)
                break; // end of string
    
            CEGUI::System::getSingleton().getDefaultGUIContext().injectChar( utf32buf[i] );
        }
    
        // reset cd so it can be used again
        SDL_iconv( cd, NULL, &inbytesleft, NULL, &outbytesleft );
    }
    // (...)
    
    // in the event loop in SDL_main():
    // (...)
        case SDL_TEXTINPUT:
            InjectUTF8Text( ev.text.text );
            break;
    
        // (...)
        case SDL_WINDOWEVENT:
            // (...)
            else if(event.window.event == SDL_WINDOWEVENT_LEAVE)
            {
                CEGUI::System::getSingleton().getDefaultGUIContext().injectMouseLeaves();
            }
    // (...)
    

    Having the iconv descriptor as a static function variable is slightly ugly, if you mind that feel free to move it somewhere else, the point is that one shouldn't recreate it for every textinput event (i.e. potentially every keypress)

    Oh, one more comment on your code: I'd make all those "helper functions" (in that case, everything besides main()) static or put them into an anonymous namespace to make sure they don't conflict with other globally exported functions from some lib or whatever.

      1. Daniel Gibson

        how else would you use them?

        ok, in this case conflicts are kinda unlikely (SDL2 uses SDL_* for all exported functions), but it's still good practice to either use your own namespace or at least use static functions/the anonymous namespace to avoid conflicts.

        1. Lukas Meindl

          When i think of "globally exported" i think of functions without namespace or ones that are not member functions. Exporting them within namespaces is of course fine but without is "dirty". Even with a prefix.

  4. Lukas Meindl

    This will be merged as soon as lucebac feels it is ready. So if anyone has input, this is the last chance. After that feel free to make PRs