Landscape Creator

Es ist zu lange her dass ich etwas über ein interessantes Programmierprojekt gepostet habe, daher tue ich dies jetzt. [Wie ich schon mal erwähnte][lastpost], arbeite ich an einem Leveleditor für mein neues Eisenbahnspiel, also ein Programm mit dem ich dafür eine Landschaft erstellen kann. Dies ist in den letzten beiden Wochen deutlich besser geworden, was man am besten in einem Screenshot sehen kann.

![Natürlich funktioniert das mit dem Screenshot nicht immer.][screenshot]

Was sieht man hier? Drei Werkzeuge (Berg machen, Tal machen und mit einer Farbe malen) funktionieren schon. Die beiden Werkzeuge, die die Geometrie verändern, tun dies noch nicht so glatt wie sie sollten, aber sie laufen. Das malen arbeitet direkt auf der Grafikkarte[^1], was nicht viel Vorteil bringt aber cool klingt. Rückgängig und Wiederherstellen geht beliebig oft, man kann darüber hinaus Dateien öffnen und speichern. Das malen von Texturen (z.B. echtes Gras) auf die Landschaft kommt einigermaßen voran, man hat zumindest schon das Feld, wo man sich eine Textur auswählen kann.

Bei dieser Arbeit habe ich ein paar interessante Sachen entdeckt, die ich hier mal erwähnen wollte. Das ganze ist allerdings sehr technisch.

Kein Garbage Collection

Garbage Collection, also dass der Speicher des Programms automatisch verwaltet wird, sollte man nie zusammen mit OpenGL einsetzen. Man kann schon, aber Apples OpenGL Profiler funktioniert nicht damit. Dieses Programm ist aber die beste Möglichkeit, herauszufinden, wieso Code nichts oder was falsches zeichnet, und ist meines Erachtens deutlich wichtiger als das bisschen Bequemlichkeit durch automatische Speicherverwaltung.

Core Data kann schwierig sein

Dies ist das erste Mal, dass ich Core Data einsetze, eine Technologie von Apple die Speichern, Öffnen und so weiter sowohl vereinfachen als auch erweitern soll. Es stellt sich heraus, dass es Sachen gibt, die Core Data mag und gut tut, Sachen, die etwas Arbeit brauchen und Sachen, die einfach nicht gehen, und mein Programm hat natürlich etwas aus allen dreien. Eine OpenGL-Textur in Core Data speichern, aber auf der GPU zu bearbeiten, ist zum Beispiel nicht sinnvoll möglich (aber auch zugegebenermaßen eine seltene Anwendung). Nun verwende ich ein Paketformat (d.h. eine Datei ist tatsächlich ein Ordner, sieht aber nicht so aus), in dem eine Core Data-Datei und Extradateien für Texturen und Höhenwerte enthalten sind. Das war nicht ganz einfach, aber Apple bietet da [sehr hilfreichen Beispielcode][NSPersistentDocumentFileWrappers].

OpenGL ist irgendwie Mist

OpenGL ist prima für viele Sachen, aber man kommt auch leicht in Ecken, die es nicht mehr mag. Ein schönes Beispiel ist der OpenGL Kontext, was man sich ungefähr als das Fenster in das man zeichnet plus die zugehörigen Resourcen vorstellen kann. Dieser Kontext schwebt irgendwo im Hintergrund, nur selten gesehen und verwendet, was prima funktioniert bis man zwei davon hat. Ich habe zwei pro offenem Dokument (der Bildbrowser für die Texturauswahl verwendet aus irgend einem Grund auch OpenGL) und theoretisch beliebig viele offene Dokumente, was dies ein durchaus interessantes Problem macht. In der Zeichenroutine ist der Kontext immer der richtige, aber wenn ich zwischendurch Parameter anpasse (z.B. Farbe, in der ich male), ist er das nicht zwingend, so dass ich häufig Umständen etwas völlig falsches ändere.

Man kann manuell den aktuellen Kontext ändern. Es muss nur jeder Code, der OpenGL aufruft, Zugriff auf den Kontext haben, diesen setzen und am Ende am besten den vorherigen wieder herstellen. Es geht aber auch mehr oder weniger einfacher.

Apple bietet [OpenGL Makro-Header][oglmacros], was gewissermaßen die normalen OpenGL-Funktionen sind, nur ist jetzt der Kontext eine Variable die ich explizit bereitstelle. Der Gedanke ist vor allem bessere Performance, damit OpenGL nicht zuerst nachsehen muss welcher Kontext aktuell ist, aber es hilft hier auch Kontextwechsel komplett einzusparen. Dafür muss die benötigte cgl_ctx-Variable einfach nur eine Instanzvariable werden:

@interface SomeGLUsingCode : NSObject
{
    CGLContextObj cgl_ctx;
    /* ... */
}
- (id)initWithContext:(CGLContextObj)context;
@end

In der Implementation dann entsprechend setzen:

- (id)initWithContext:(CGLContextObj)context;
{
    if (![super init]) return nil;
    cgl_ctx = context;
    ...
    return self;
}

Nun werden alle OpenGL-Aufrufe, die das Objekt macht, im richtigen Kontext gemacht. Es gibt aber ein Problem hier: Es funktioniert nur in selbstgeschriebenem Code, nicht mit Bibliotheken die selbst OpenGL aufrufen - insbesondere GLU versagt hier schon. Es ist aber prinzipiell legal, dies als Ersatz für Kontextwechsel zu verwenden, zumindest [verwendet offizieller Apple-Beispielcode es explizit zu diesem Zweck][oglmacrosample].

Die Zukunft

Als nächstes müsste dann das Texturzeichnen rein. Danach kommt direkt der Exporter für das iPhone, dann versuche ich die Landschaft auf dem Gerät zu zeichen. Danach werden Schienen und statische Objekte sehr interessant sein, vielleicht noch mit Zusatzcode um speziell viele Bäume effizient zu verwalten. Wasser kommt viel später, wenn mir langweilig ist.

Nebenbei, ich plane nicht diesen Leveleditor an andere zu geben - ich schließe es aber auch nicht aus, besonders falls ich ihn mal für [Hubschrauber][hubi] verwende. Ich garantiere aber, dass es nie eine Windows-Version geben wird, außer wenn eines der Cocoa-Zu-Windows-Projekte im Internet plötzlich über Nacht völlig genial wird.

[^1]: Tatsächlich sind ein paar Sachen beim Rückgängig machen nicht auf der Grafikkarte, aber das reine Zeichnen ist komplett dort.

Geschrieben am 10. Juni 2009 um 10:23

3 Kommentare

  1. Geschrieben 15 Juni 2009

    Björn

    Wird es auch eine Windows-Version geben?
    xD Schertz bei Seite...

    Aber wie sieht es mit Linux aus ?!?

    Das Programm sieht durchaus interessant aus und erinnert ein wenig an den "RollerCoaster Tycoon"-Level-Editor.
    Wofür ist das A in der Menüleiste zuständig? Kann man damit Text auf die Map schreiben?
    Was genau für ein Sinn hat es einen Leveleditor auf einem Mobiltelefon aufzurufen?

    Durch schütteln kann das iPhone doch Zufallszahlen erzeugen, oder? Die kann man dann nutzen um das Gelände zufällig erstellen zu lassen. Das würde ich lustig finden ^^

    Kann Hubschrauber denn die erstellten Maps auch auslesen und wenn ja, funktioniert das auch unter Windows (oder stirbt die komplette Hubschrauberreihe für Windows)?

    Alle Map-relevanten Dateien befinden sich dann in dem "Ordner"? Das wäre besser als bei Half-Life wo man Texturen und Objekte extra beisteuern muss...

    Und wo wir gerade bei Valve sind, das Steinpflaster und die Wiesen sehen verdächtig nach Half-Life Source aus?!?

  2. Geschrieben 16 Juni 2009

    Torsten (admin)

    Linux sieht schlecht aus. GNUStep läuft unter Linux vielleicht besser, aber ich verwende gerne und viel modernere Features von Cocoa, die GNUStep eventuell noch nicht hat. Abgesehen davon ist das Userinterface von GNUStep grauenhaft.

    Das A öffnet die Schriftarten-Palette, die ich hier nicht verwende (ist nur ein Standardfeature, ich war zu faul es zu entfernen). Analog tut der Drucker auch nichts.

    Der Leveleditor wird nicht auf dem iPhone aufgerufen, ich erstelle damit auf dem Mac meine Level, die ich dann in ein optimiertes Format konvertiere und dann auf dem Gerät nur anzeige.

    Hubschrauber kann die Maps derzeit nicht auslesen. Ich müsste dafür idealerweise sowohl das Programm als auch Hubschrauber umschreiben (was ich aber gut machen könnte). Das würde ich aber dann auch auf Windows portieren.

    Ja, alles in einem Ordner, so lange es im Editor bleibt. Die Steine und Wiesen sind von http://mayang.com/textures/ (hm, Links in den Kommentaren wären eine interessante Idee...), so weit ich weiß hat das nichts mit Valve zu tun.

New comments can no longer be posted because it got to annoying to fight all the spam.