• Erste Schritte mit unserer libRocket

      0 comments

    Wie letztes Mal schon angekündigt, wollen wir uns nun mit einem kleinen Projekt beschäftigen, das uns erlaubt ein bisschen mit libRocket herum zu spielen. Das Visual Studio Projekt könnt ihr hier downloaden.

    Die Solution besteht aus 2 Projekten: „rocketTemplate“ und „Shell“. „Shell“ stammt aus den Samples von libRocket und stellt uns alles nötige zur Verfügung, um direkt mit libRocket loslegen zu können. Wir bekommen ein Fenster zur Darstellung, in das libRocket rendert und alle Eingabe werden an libRocket weitergeleitet.
    „rocketTemplate“ ist unser eigentliches Projekt. Es besteht nur aus der „main.cpp“ und einer Klasse namens „SystemInterface“, dazu später mehr. Dazu kommen noch einige wichtige Dateien. Der Ordner „lib“ enthält die Bibliotheken von libRocket und in den Ordnern „Release“ bzw. „Debug“ findet man die zugehörigen Dlls.
    Als Letztes benötigen wir noch den Ordner „assets“. Darin befinden sich ein paar HTML/CSS Dateien und Fonts.

    Schauen wir uns die „main.cpp“ im Detail an.

    #include <Rocket/Core.h>
    #include <Rocket/Debugger.h>
    #include <Input.h>
    #include <Shell.h>
    #include "SystemInterface.h"

    Die „Core.h“ benötigen wir immer, damit haben wir Zugriff auf libRocket. Der Debugger ist optional. Er kann nützlich sein, wenn man komplexere Dokumente erstellt. Mehr dazu findet man in der libRocket Doku.
    „Input.h“ und „Shell.h“ stammen von unserem „Shell“ Projekt. Wir benötigen die Funktionen daraus für die Ein/Ausgabe.

    Rocket::Core::Context* context = NULL;
     
    void GameLoop()
    {
    	glClear(GL_COLOR_BUFFER_BIT);
     
    	context->Update();
    	context->Render();
     
    	Shell::FlipBuffers();
    }

    Dies ist die Hauptschleife unseres Programmes. Sie wird von der „Shell“ jedes Frame aufgerufen. Erst wird der Inhalt unseres Fensters gelöscht, dann wird „Update“ von libRocket aufgerufen, was die Eingaben verarbeitet und die GUI-Elemente entsprechend anpasst und dann lassen wir libRocket die GUI rendern. Zum Schluss wird das aktuelle Bild noch angezeigt. In einem Spiel würde man die Aufrufe einfach in die Hauptschleife integrieren.

    Als nächstes folgt die Main-Methode, welche beim Start unseres Programmes aufgerufen wird.

    if (!Shell::Initialise("../assets/") ||
    	!Shell::OpenWindow("Rocket Template", true))
    {
    	Shell::Shutdown();
    	return -1;
    }

    Mit Hilfe der „Shell“ legen wir den Ordner „assets“ als aktuelles Verzeichnis fest und öffnen ein Fenster für unser Programm. Geht etwas schief, dann beenden wir alles korrekt.

    ShellRenderInterfaceOpenGL opengl_renderer;
    Rocket::Core::SetRenderInterface(&opengl_renderer);

    Wir sagen libRocket, dass wir das OpenGL RenderInterface der Shell zur Darstellung verwenden wollen.

    SystemInterface system_interface;
    Rocket::Core::SetSystemInterface(&system_interface);

    Und übergeben unser eigenes SystemInterface. Diese Klasse muss vor allem eine Methode implementieren.

    float SystemInterface::GetElapsedTime()
    {
    	return Shell::GetElapsedTime();
    }

    Diese Methode soll die Zeit zurückgeben, die seit Start unseres Programmes vergangen ist. Benutzt wird dies für Animationen und andere zeitabhängige Dinge in libRocket. Wir leiten hier einfach auf die Funktion der Shell weiter.

    Rocket::Core::Initialise();

    Damit initialisieren wir libRocket. Dies muss unbedingt geschehen, allerdings erst nachdem ein RenderInterface und ein SystemInterface übergeben wurden.

    context = Rocket::Core::CreateContext("main",
        Rocket::Core::Vector2i(1024, 768));

    Damit erstellen wir einen libRocket context. Dieser wird benötigt, um unsere GUI darzustellen, außerdem bestimmen wir so die virtuellen Ausmaße unseres Fensters.

    Rocket::Debugger::Initialise(context);
    Input::SetContext(context);
     
    Shell::LoadFonts("../assets/");

    Der Debugger ist, wie schon gesagt, völlig optional, kann aber nützlich sein. Danach binden wir die Inputs, welche uns die Shell zur Verfügung stellt, an unseren Context. Alle Tastatur- und Mauseingaben werden also an die Objekte in unserem Context weitergeleitet. Und dann laden wir noch unsere Fonts, die in unserer Beispiel-GUI verwendet werden.

    Rocket::Core::ElementDocument* document = 
        context->LoadDocument("../assets/main.rml");
    if (document != NULL)
    {
    	document->Show();
    	document->RemoveReference();
    }

    Nun laden wir unser Dokument, unsere HTML-Datei, die unsere GUI beschreibt und stellen sie dar.

    Shell::EventLoop(GameLoop);

    Nun starten wie unsere Hauptschleife. Diese läuft nun bis wir das Programm schließen.

    context->RemoveReference();
    Rocket::Core::Shutdown();
     
    Shell::CloseWindow();
    Shell::Shutdown();
     
    return 0;

    Danach beenden wir noch alles wieder und sind auch schon fertig.

    Bleiben noch die HTML/CSS Dateien. Diese stellen ein ganz einfaches (hässliches) Fenster dar. Es hat einen Titel und einen Text als Inhalt. Man kann an dem Beispiel aber auch schon einige Besonderheiten von libRocket sehen.

    <handle move_target="#document">

    Dies finden wir in der „window.rml“ Datei. Und mehr ist nicht nötig, um unser Fenster verschiebbar zu machen. Man kann also das Fenster im Bereich mit dem Text „Titel“ einfach anklicken und so unser Fenster (Dokument) herum bewegen. Wir müssen dazu nicht eine Zeile Code schreiben.
    Und so lässt sich einiges in den HTML Dateien ausdrucken. Dadurch kann jeder an der GUI basteln, ohne dass er programmieren können muss. Vom Programmierer wird nur das Gerüst zur Verfügung gestellt und ein Grafiker kann dann nach belieben am Design der GUI schrauben. Dies war z.B. mit MFC früher nicht wirklich machbar.

    Dies soll es für heute gewesen sein, danke für’s lesen!
    NicoB