Einfacher Ausbruch

von Christoph

Man sieht in der Software-Entwicklung immer wieder, dass die Leute eine technische Lösung einführen wollen und dann ihr Problem darauf anpassen (technology driven development). Wer kann es den Ingenieuren verdenken? Technologien machen Spaß, halten kreativ, schaffen Arbeit. Je komplexer desto mehr. So kommen Firmen dann zu Softwaresystemen, die am tatsächlichen Bedarf um ihrer selbst willen geschmeidig vorbei­laufen. Weil ja das Problem erst noch an die Lösung angepasst werden muss, dieser Schritt dann aber nicht mehr gegangen wird, falls er denn überhaupt möglich ist.

Warum erzähle ich das? Nun, ich habe das in meiner Freizeit natürlich auch so gemacht. Ich wollte mal wieder etwas mit Computergrafik, irgendwas mit Shadern entwickeln, also habe ich mir die Probleme SameGame, Ballout und Snake geschaffen.

Jetzt war es aber mal an der Zeit, dem Minimalismus zu huldigen. Nehmen wir an, wir haben die Spielidee und wählen davon ausgehend die Werkzeuge! In diesem Fall ist mein Problem ein Breakout-Klon und meine Lösung ohne prozedurale 3D-Geometrie, Beleuchtungsberechnung und Texturen. Einfach nur Rechtecke, Kreise und etwas Vektormathematik. Entwicklergolf sozusagen - wer die wenigsten Züge braucht, gewinnt.

Bildschirmfoto Breakout

Wenn man das so angeht, kommt schnell heraus, dass man die ganze Grafikkarten-Magie überhaupt nicht benötigt. Das ist auch irgendwie klar, es ging schon 1976 ohne. Man schreibt 2022 natürlich auch nicht mehr Assembler, aber man kann mal versuchen, sich auf die Bordmittel, in diesem Fall von MS Windows, zu beschränken. Es ist zugegebenermaßen etwas Augenwischerei: MS Windows ist, wenn man so will, die fetteste Abhängigkeit, die man sich überhaupt in ein Projekt holen kann. Für Spiele ist das meiner Ansicht nach okay und die Grundannahme ist hierbei, dass die zehntausenden Entwickler bei Microsoft ihre milliardenfach ausgerollte Komplexität einigermaßen im Griff haben. Hier also der Code-Umfang von Breakout in Direct2D für MS Windows.

D:\Projects\Games [master]> cloc.exe .\Breakout\
      35 text files.
      35 unique files.
      30 files ignored.

github.com/AlDanial/cloc v 1.90  T=0.10 s (235.4 files/s, 20617.1 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C++                              5            206             47            778
XML                              7              0              0            361
C/C++ Header                     8             65             23            204
Windows Resource File            1             51             63            163
JSON                             2              0              0             53
-------------------------------------------------------------------------------
SUM:                            23            322            133           1559
-------------------------------------------------------------------------------

Und schließlich die Downloads: Zip (32 Bit) | Zip (64 Bit). Wie immer gilt: einfach entpacken und ausprobieren, keine Installation, keine Systemveränderungen.

Die Ballspiel-Trilogie

von Christoph

»Wann hast du eigentlich zuletzt einen Arkustangens benutzt?«
»Na letzte Woche!«

Ja okay, ich gebe es zu: davor auch einige Jahre nicht mehr. Kürzlich habe ich es gebraucht, um den Winkel zwischen einem Fixpunkt und dem Mauszeiger zu bestimmen. Konkreter den Winkel eines am Ende fixierten virtuellen Kanonenrohrs und seiner beweglichen Mündung (gemessen zum Horizont).

Der Leser ahnt es schon. Ein neues Spiel! Und ich nenne es Ballout. Es ist im wesentlichen ein Klon von Puzzle Bobble (manchmal auch Bust a Move), ich habe es nur nicht so getauft, um nicht in irgendwelche markenrechtlichen Schusslinien zu geraten. Es basiert wieder einmal auf der von mir selbst entwickelten SameGame-Engine und enthält damit auch eine annehmbare physikalische Simulation.

Nach SameGame und Snake ist das nun schon das dritte Spiel auf dieser Technologie-Basis. Damit hat sich die Wiederverwendung wohl gelohnt - und natüüürlich war es von Anfang an als Trilogie geplant. Komplexitätsmäßig siedelt sich Ballout knapp über Snake an. Die Logik ist eben nicht übermäßig extravagant wenn man die Physik und Grafik bereits einmal vorbereitet hat.

Und jetzt nicht lange fackeln! Alle Spiele der Trilogie unter MS Windows ausprobieren: Zip (32 Bit) | Zip (64 Bit)

Snakegame Code-Metriken

von Christoph

Kürzlich habe ich irgendwo einen Artikel gesehen: "Game Engine unter 50 MByte Größe". Das war als Werbung gedacht und der herausragende Punkt war also offensichtlich wie schlank der Code ist. Ich habe mich gefragt, ob die das ernst meinen. Dann wurde mir klar, dass die Entwickler vermutlich den Begriff Engine falsch benutzen. Ich kann nur vermuten, dass in dem Paket auch Resourcen (Modelle, Texturen, Audio) und natürlich Dokumentation mit drin sind. Mich hätte aber schon interessiert, was die Größe nur der Algorithmen einer schlanken Game Engine ist.

Die Frage drängte sich umso mehr auf, weil ich ja vor Kurzem selbst wieder mit SameGame ein kleines Spiel geschrieben habe ‐ zugegeben ein sehr einfaches Spiel aber nichts desto trotz in modernem C++ mit GPU-Beschleunigung. Also nächster Schritt: den weitestgehend generischen Code in eine Bibliothek (SameGame Engine) ausgelagert und auf dieser Basis den Klassiker Snake nachgebaut. Am Ende sind alles nur Kugeln. Mittels cloc habe ich schließlich die Codezeilen der Bibliotheken und Anwendungen durchgezählt, ausgenommen Kommentare und Leerzeilen.

Etwa ein Drittel von SameGame war allgemeiner Grafik-Code (Geometrie, Instancing), dazu noch etwas Dateibehandlung (Konfiguration und Highscores). Nicht extrahiert habe ich Physik und sowieso nicht verschiebbar war die SameGame-Spiellogik. Neu hinzu kam ein signifikanter Anteil an Visual Studio Boilerplate, aber um den muss man sich glücklicherweise nicht übermäßig selbst sorgen. So ist im Resultat der ausgelagerte Grafik-Code in etwa genauso groß wie die Snake-Logik. Oder anders ausgedrückt: Snake nur halb so groß wie es ohne wiederverwendete "Engine" wäre.

Und hier noch die Downloads für MS Windows: Zip (32 Bit) | Zip (64 Bit)

Grafikperformance und Physik

von Christoph

Ich habe das neue SameGame noch mehr aufgebohrt. Nach der Fertigstellung von Gameplay und Grafik habe ich es knallhart auf Performance optimiert. Das ist bei so einem einfachen Spiel natürlich überhaupt nicht nötig (wir reden hier schließlich nicht von Doom Eternal), aber es geht ja um Spaß am Gerät. Insofern ist es also doch nötig.

Zunächst einmal habe ich Instancing eingeführt. Es werden letztlich immer nur Kugeln gezeichnet, also konstante Geometrie jeweils mit anderer Farbe und Koordinatentransformation. Der klassische Ansatz setzt Farbe, setzt Transformation und feuert Draw-Calls in einer Schleife, die auf der CPU (Hauptprozessor) läuft und regelmäßig an die GPU (Grafikkarte) übergibt. Instancing verschiebt das komplett auf die GPU: packe n Farben und n Transformationen in den Grafikspeicher und befehle der GPU genau einmal, die Kugelgeometrie n mal zu rendern.

Screenshot SameGame Physics

Das skaliert massiv. Ich habe das Spielfeld via Konfigurationsdatei testweise auf 150x150 vergrößert. Der CPU ist es egal, ob sie eine oder 20000 Transformationen in einem Rutsch auf die Grafikkarte lädt. Letztere wiederum rendert 16 Mio. Dreiecke (700 pro Kugel) schön verteilt auf Kernen und Pipelines inklusive Per-Pixel-Beleuchtung. Ab 20000 Kugeln fängt die Framerate langsam an zu sinken - aber alles noch spielbar. Man könnte das leicht noch weiter verbessern, indem man bei mehr Kugeln niedriger aufgelöste Geometrie verwendet (Level of Detail). Wenn irgendjemand jemals regelmäßig mit mehr als 20k Kugeln spielt, mache ich das vielleicht.

Nun langweilt sich die CPU also, abgesehen von ein paar Mauspositions-Berechungen. Wer den Screenshot oben aufmerksam betrachtet, wird feststellen, dass die Kugeln nun auch nicht mehr in einem Raster liegen. Das kommt von einer Arbeitsbeschaffungsmaßnahme. Es werkelt nun nämlich eine Physik-Engine, die dafür sorgt, dass die Kugeln realistisch fallen, voneinander und von den Begrenzungen abprallen sowie mit Spin und Drall rollen. Die Simulation läuft in einem separaten Thread, so dass Grafik-Updates davon nicht beeinträchtigt werden (abzüglich kurzer Mutex-Synchronisation). Unabhängig von der Grafikperformance aktualisiert die Physik die Spielwelt 60 mal pro Sekunde.

SameGame Physics (Download Zip für Windows, 64 Bit) benutzt also konstant zwei CPU-Kerne (1. Grafik/UI und 2. Physik) sowie alle Grafikkerne, die vorhanden sind. Schön, auf was man als Entwickler so alles zugreifen kann, um das Optimum herauszuholen.

Spieleentwicklung gestern und heute

von Christoph

Als Computergrafik-Gesamtübung habe ich SameGame noch einmal neu implementiert. Erst als ich fertig war, ist mir aufgefallen, dass das ziemlich genau 18 Jahre nach der ersten Version war. Das Programm ist jetzt also offiziell volljährig. Und tatsächlich habe ich den Original-Quelltext auch noch - oh man, wie sich die Zeiten ändern. Es folgt ein kurzer Vergleich zwischen damals (links im Bild) und heute (rechts im Bild).

Montage SameGame

SameGame32 schrieb ich 2002 im Borland C++-Builder. Visual Studio war noch ein teures Produkt für Profis (was habe ich mich gefreut, als Student an eine Vollversion zu kommen). Heute ist das umgekehrt: der C++-Builder wollte in die Oberschicht vordringen und hat dabei jegliches Klientel verloren. Visual Studio hat es als Community-Version in die Breite geschafft, der C++-Builder in die Bedeutungslosigkeit.

Die Fenstergröße war damals fixiert. Das klingt harmlos, war aber Symptom einer bedeutenden Einschränkung: das Spiel tat nur so, als wäre es 3D. Tatsächlich wurden Bitmaps mittels DirectX 7 an feste Koordinaten eines Rasters kopiert. Die Kugeln lagen als bmp-Datei in den Anwendungsresourcen und zwar alle 3 Farben aus jeweils 18 Winkeln (ingesamt 54 Standbilder). Eine volle Drehung bestand aus Abspielen der 18 Bilder. Aus den Mauskoordinaten ließ sich trivial bestimmen, welche Kugel gerade überfahren wird und damit die Animation abgespielt werden muss. Die Einzelbilder wurden mit POV-Ray vorberechnet. Ja, es gab bereits Raytracing, allerdings weit weg von Echtzeit.

Nun ist das komplett anders. Beleuchtungsberechnung in Hardware ist lange Standard. Dementsprechend werden keine Bitmaps mehr kopiert sondern triangulierte Kugeln im 3D-Raum gerendert. Mit der invertierten Projektion lässt sich bestimmen, welche Kugel selektiert ist und damit ist die Fenstergröße nun frei verstellbar. Ich habe mich an das Endresultat mit 3 Shadern herangetastet: Gitternetz-Shader, Textur-Shader und schließlich Phong-Beleuchtung, was sehr nahe am damaligen Effekt ist.

Meine Grafik-Hardware kratzt das überhaupt nicht. Sie liefert Bilder so schnell wie der Monitor sie darstellen kann. Die Animationen sind entsprechend weich. Was für ein Unterschied zu den 18 Einzelbildern. Der Refresh war seinerzeit übrigens an einen Timer gekoppelt, der auf 75 ms eingestellt war. Das ergibt 13 Frames pro Sekunde oder anderthalb Sekunden für eine komplette Kugeldrehung. Keine Ahnung, wie ich auf diese Zahl kam. Wahrscheinlich durch Ausprobieren bis es bei maximaler Resourcenschonung auf einem Röhrenmonitor ausreichend flüssig aussah.

Mehr Vulkan-Grafik

von Christoph

Wie zuletzt beschrieben, ist die Grafik-API Vulkan derzeit mein Hobbyschwerpunkt. Als weiteres Kleinprojekt habe ich den Quake 3 Model Viewer portiert. Das Ding begleitet mich nun schon sehr lange, von DirectX 8 über OpenGL 2 und 4 bis neuerdings Vulkan. Natürlich braucht man dafür keine derart schweren Geschütze - Quake 3 lief schon vor 20 Jahren rund. Allerdings ist das Format vergleichsweise leicht zu implementieren und man streift jedes Thema einmal: Texturierung, Animation, indizierte Koordinaten.

Screenshot Q3View Vulkan

Kühn wie ich so bin habe ich auch gleich einmal probiert, das Grafik-Backend (in diesem Fall natürlich Vulkan) austauschbar zu machen, um ggf. da einmal OpenGL oder sonstwas dranzuhängen. Zunächst für eine super Idee befunden, kann ich davon nun abraten. Die APIs sind derart unterschiedlich, dass wenig bleibt, was man abstrahieren kann. Das Ganze wirkt krass aufgesetzt und macht die Architektur nur komplizierter. Daher mein Ratschlag: wenn man sich für ein Grafik-API entscheidet, kann man ruhig all in gehen. Pluggable Backends können sich gern die großen Entwicklungsfirmen leisten, die Horden von Entwicklern an ihre Engines ansetzen.

Meine kleine Vulkan-Hilfsbibliothek ist weiter gewachsen, zum Beispiel um Klassen für Texturierung und Tiefen-Pufferung. Wie ich zuletzt schrieb: schade, dass jeder seine eigenen Wrapper erfindet, aber glücklicherweise schreibt man sie nur einmal. Es ist auch nicht so, dass ich nicht versucht habe, existierende Libraries zu finden. V-EZ (Vulkan easy) von AMD sah zum Beispiel vielversprechend aus. Der Solo-Entwickler darf daran allerdings nicht mehr entwickeln. Das Projekt ist also hochoffiziell tot, es steht nur nicht dran. Und von dieser Art findet man zahllose mehr. Die Grundsatzfrage bei der Sache ist natürlich: Was will man mit einem generischen Wrapper für Vulkan? Da kommt doch dann OpenGL raus. Die Frage ist berechtigt :)

Schließlich habe ich mir noch vcpkg für Bibliotheksmanagement angeschaut. Ich wollte ja das Dekomprimieren von Quake 3-Modellen nicht selber implementieren. Bisher habe ich zlib und weitere Bibliotheken immer für statischen CRT-Link gepatched und dann mit msbuild selbst gebaut. Stellt sich raus: das geht nun auch mit vcpkg. Die patchen Konfigurationen und bauen dann mit cmake. Klingt ganz einfach und praktisch, geht aber natürlich nicht ohne den üblichen Bloat. Die laden sich allen Ernstes beim ersten Ausführen eine portable Powershell, ein kleines MSys und Nuget runter. Gesamtwert entpackt: 1.2 GByte. Das ist bei heutiger Software leider voll der Trend und noch lange nicht das Ende der Fahnenstange. Ich habe mir kürzlich Skia angeschaut. Damit kann man 2D-Grafiken erstellen, also sowas wie eine Linie von oben links nach unten rechts zeichnen. Dazu braucht man ein Google Build-System, Python, Ninja und wenn man das Bauen dann auslöst, fängt das Script an, x abhängige Git-Repos zu kopieren (Unicode, Textrendering, whatever). Man braucht mehr als 2 GByte an Build-Werkzeugen (so groß wie meine erste Festplatte). Raus kommt eine DLL mit 7 Mbyte. Das ist doppelt so groß wie Turbo Pascal 7.

Ich werd zu alt für so'n Scheiß. Aber High Performance Computergrafik mit C++ ist schon ganz schön geil.

Meine kurze Geschichte der Computergrafik

von Christoph

Die Anfänge

Vor etwa 25 Jahren fing es an. Computergrafik war eigentlich der Grund, mich mit Programmierung zu beschäftigen. Wer entwickelt schon freiwillig Datenbanken oder Textverarbeitungen? Es muss knallen und blinken! Meine ersten Schritte waren in Turbo Pascal. Während in der Schule Konsolenprogramme entwickelt wurden, habe ich zu Hause den Grafik-Modus für mich entdeckt. Dabei kam ein 2D Space-Shooter heraus. Eine Enterprise (Bitmap via Suchmaschine Altavista gefunden), die Asteroiden ausweicht und abknallt. Leider sind die Quellen verloren gegangen - oder sie sind auf den Disketten im Keller, für die ich kein Laufwerk mehr habe. Irgendwann kam der Wechsel auf Delphi und da stellte sich heraus, dass mein Ansatz von Computergrafik nicht performant war. Ich denke, im Hintergrund werkelte dort GDI. Der Engpass führte mich jedenfalls zu:

DirectX

Wenn man von Windows und Delphi kommt, ist DirectX als Grafikschnittstelle naheliegend. Ich hatte inzwischen C++ gelernt und Microsoft DirectX war quasi alternativlos. Ernstzunehmenden Kontakt hatte ich mit Version 7 (SameGame) und Version 8.1 (Superball). Hier lernte ich, wie das mit dem Rendering in Spielen funktioniert: man zeichnet x mal pro Sekunde die komplette Szene, weil schnell genug. In Turbo Pascal habe ich noch maximal effizient nur die Rechtecke aktualisiert, in denen sich etwas geändert hat. Außerdem kam ich hier in Kontakt mit Transformationen, Projektionen und Matrizen. Erstaunlich viel wurde jedoch von DirectX und Hilfsbibliotheken abgenommen. Rückblickend war DirectX 8 ein guter Einstieg. In die folgenden Versionen habe ich nur noch sporadisch geschaut. Richtig entwickelt habe ich dort nichts mehr, denn an der Universität kam ich zu:

OpenGL

Das war das erste API, das ich nicht autodidaktisch erlernt habe (naja, einen kurzen Ausflug zu NeHe's Tutorials mal ausgenommen - wer hat die nicht gelesen?). Stattdessen habe ich einige Semester sehr hilfreiche Einführung genossen und die dann mit der hervorragenden OpenGL Superbible vertieft. Die wurde mit Neuauflagen leider immer schlechter. Richtig angefangen habe ich mit Version 2.0 (Bildschirmschoner) und das dann weiter verfolgt bis zur Version 4.x (Quake 3 Model Viewer). Die Evolution von OpenGL schrittweise mitzumachen war übrigens goldrichtig. Das Ding ist nämlich immer komplizierter geworden. Ich habe mir nach v3 in meinem jugendlichen Leichtsinn mal kurz Vulkan angeschaut, bin aber kläglich gescheitert. Dann zurück zu OpenGL v4 und schwupps war viel klarer, was in Vulkan vor sich geht. Der nächsten Evolutionsstufe der Computergrafik.

Vulkan

Screenshot Vulkan Application

Vulkan (direkter Konkurrent von DirectX 12) ist verdammt kompliziert und ich hatte auch noch eines der schlechtesten Bücher aller Zeiten dazu. Es gibt auch einfach zu wenig gedruckte Literatur. So brauchte ich gute drei Jahre bis ich es noch einmal wagte. Ohne Bücher. Nur mit der Spec und Beispielen von AMD und LunarG auf Github. Ich konnte das nicht auf mir sitzen lassen und diesmal habe ich es geschafft (Shapefile Viewer). Der Pfad zu Vulkan ist aber wirklich steinig. Ich kann mir schwer vorstellen, wie ambitionierte Hobby-Entwickler von Null auf Vulkan kommen sollen. Nun muss man sich nicht wie ich über DirectX und mehrere Generationen OpenGL anpirschen, aber die mathematische und technische Schwelle ist enorm. Ich kann jedoch bestätigen, was ID-Software auf einer Konferenz gesagt hat: man muss die Hürde nur einmal nehmen und den Boilerplate schreiben. Dann stehen einem alle hochperformanten Türen offen.

Ausblick

OpenGL ist einfach der Platzhirsch. Mächtig, etabliert und gut erlernbar. Wenn man sich um die komplizierten Features nicht kümmern möchte, nimmt man einfach die aus den frühen 2000ern. Oder man mischt ein paar moderne rein, die man für beherrschbar hält (beispielsweise multi sample anti aliasing). In Vulkan wird man schonungslos aktueller Grafikkartenarchitektur ausgesetzt, um am Ende ein Quentchen schneller zu sein. Lernaufwand und Schwierigkeitsgrad sind hoch. Das Erfolgsgefühl dementsprechend auch.

Ergo: Für einfache und schnelle Ergebnisse setze man auf OpenGL. Will man statt mit 200 lieber mit 210 FPS rendern und sich dafür wahnsinnig verrenken dann auf Vulkan. Das ist verrückt, denn eigentlich geht der Trend in der gesamten Softwarebranche in die entgegengesetzte Richtung: man stapelt so lange Wrapper und Abstraktionen, bis man keine Details mehr sehen kann und verstehen muss. Erfrischend altmodisch, in Vulkan die volle Kontrolle und Verantwortung zu haben. Ab jetzt nur noch das bei mir ;-)

MusicDb v1.0 veröffentlicht

von Christoph

Man hat ja über die Jahre so eine Musiksammlung auf dem PC angelegt und zwischenzeitlich auch mal vergessen, was man in grauer Vorzeit alles mochte. Vor bereits etwa 12 Jahren habe ich dazu das Konsolenprogramm "listmp3" geschrieben, das die Dateien in einem Verzeichnis in eine schicke HTML-Übersicht formatiert. Über das Auslesen der ID3-Tags (eingebettete Meta-Daten wie Interpret und Album) hatte ich einen Artikel im PC Magazin verfasst.

Nun, nach so langer Zeit, habe ich MusicDb v1.0 als Quasi-Nachfolger veröffentlicht. Natürlich ist alles viel besser!1!! Aber im Ernst - da ich mich weiterentwickelt habe, ist in MusicDb nur noch wenig vom alten Programm übergeblieben. Eigentlich nur noch die Idee von der HTML-Übersicht. MusicDb ist eine Windows-Anwendung und indiziert Verzeichnisse in eine Sqlite Datenbank. Die Meta-Daten dafür extrahiert die Taglib und für das Vorhören per Doppelklick ist die BASS-Bibliothek zuständig.

Für mehr Interaktion ist nun ein Webserver integriert, nämlich Civetweb. Im Browser wird es dann richtig interessant. Ein HTML5-Frontend erlaubt die rasend schnelle Suche nach Datennamen oder Bestandteilen der Meta-Daten (das Backend ist C++ via Civetweb). Dank HTML5-Audio lassen sich Suchergebnisse in Playlisten einordnen und da es sich um einen Webserver handelt auch auf anderen PCs im Netzwerk anhören. Fast schon ein richtiger Mediaserver!

MusicDb ist ein Experiment, wie sich die Programmierung bei mir in 12 Jahren verändert hat. Die Sprache ist immernoch die Gleiche: C++, sonst ist aber alles anders. Open-Source wird viel stärker eingesetzt, in MusicDb allein 7 Bibliotheken. Eine sinnvolle Architektur zur Integration ist viel wichtiger geworden als die Ersterfindung des Rades. Diese Form von Komplexitätsbewältigung erlaubt die Konzentration auf das, was wirklich wichtig ist: coole Features.

Doch genug philosophiert. MusicDb gibt es hier zu Download: https://christoph.stoepel.net/ViewSoftware?id=126

Bibliotheken, die man kennen muss (C++)

von Christoph

Das mag einige jetzt überraschen aber: das Rad wurde bereits erfunden. Softwareentwicklung macht Spaß, aber kreative Leistung ist dadurch gekennzeichnet, dass sie eben neu ist. Dass man die vorhandenen Resourcen nutzt, um etwas nicht Dagewesenes zu erstellen. In diesem Post möchte ich einige dieser Resourcen vorstellen, die in meiner Werkzeugkiste einen festen Platz gefunden haben und die die stabile Basis für Neuentwicklungen bilden.

  • Die Windows Template Library (aktuell v8.1) ist eine sehr schlanke Alternative zur MFC, der Bibliothek für grafische Oberflächen unter MS Windows. Die Lernkurve ist etwas steil. Wie der Name bereits andeutet, setzt die WTL massiv auf Templates. Sie stellt aber trotzdem eine deutliche Vereinfachung der GUI-Entwicklung im Vergleich zur nackten WinAPI dar ohne den Bloat der MFC.
  • Die Cairo Grafikbibliothek (aktuell v1.10.2) ist für mich unverzichtbarer Bestandteil geworden, wenn es um 2D-Visualisierungen geht. Wie GDI oder GDI+ kapselt Cairo alles: von der Textausgabe über Punkte, Linien bis hin zu Polygonen. Und das schöne: plattformunabhängig und mit verschiedenen Ausgabezielen wie zum Beispiel PNG, PDF, SVG oder eben ein Windows Fenster. (Democode im Github)
  • Kryptographie gefällig? Verschlüsselung? Symmetrisch, asymmetrisch? Prüfsummen, Base32-Codierung? Die Crypto++ Library (aktuell v5.6.1) hat sie alle! Wann immer Kryptographie benötigt wird, ist das die Bibliothek meiner Wahl. Zum Beispiel bei Software-Lizensierung über Produktschlüssel. Weiterhin sehr gut, dass Kompression über die ZLib (aktuell v1.2.5) bereits eingebaut ist. Diese nutze ich meist auch in ihrer ungekapselten Rohform, wenn es mal ohne Verschlüsselung geht.
  • SQLite (aktuell v3.7) hat sich für mich als Allzweckwaffe für Datenspeicherung etabliert. In diese dateibasierte embedded Datenbank passt einfach alles. Und der Zugriff funktioniert allerbequemst mit standardisierten SQL-Queries. Das beste: die Datenbanken lassen sich auch aus .NET ansprechen und dass sie auch auf anderen Betriebssystemen als MS Windows lesbar sind, muss garnicht mehr erwähnt werden.

Mir fallen noch viel mehr ein, aber man sollte Aufzählungen aus didaktischen Gründen nicht wuchern lassen. Deswegen erwähne ich nur kurz und zum selbst weiterrecherchieren noch cURL (aktuell v2.20) zum Herunterladen von Daten aus dem Web (und zum Beispiel cachen mit SQLite s.o.) sowie Googles v8 (aktuell v3.5), der rasenden Javascript-Engine aus dem Chrome Browser (Democode im Github).

Der Cairo-Compilier-Krampf

von Christoph

Achtung sehr technisch. Ich schreibe diesen Eintrag hauptsächlich aus Eigennutz, denn ich muss irgendwie festhalten, wie man die Cairo-Bibliothek compiliert. Ich habe dafür unübertriebene drei Stunden gebraucht und das will ich beim nächsten mal unbedingt verhindern. Cairo ist eine quelloffene 2D-Vektorgrafik-Bibliothek für Entwickler. Im wesentlichen kann man damit Linien, Dreiecke, Vierecke und Mehrecke (also Kreise, Texte und beliebeige Polygone) zeichnen. Und das ganze wahnsinnig performant und gleichzeitig plattformunabhängig. D.h. für Windows: keine GDI Odyssee und auch keine GDI+ DLL-Hölle.

Die derzeit aktuelle Version ist Cairo 1.10 vom 25. September 2010. Das Ziel ist ein Kompilat in eine einzige DLL (die man einfach zusammen mit der Anwendungs-Exe weitergibt) unter Visual Studio 2010. Nun wäre die Geschichte kein Krampf, wenn es sich bei Cairo nicht vorrangig um ein Linux-Projekt handeln würde. Die Windows- Unterstützung ist also allenfalls rudimentär.

1. Doch fangen wir von vorne an: Benötigt wird natürlich erstmal der Cairo-Quelltext. Ebenfalls herunterzuladen ist das aktuelle Pixman-Paket. Darin sind die absoluten Low-Level Routinen für Cairo zu finden. Weiterhin bestehen Abhängigkeiten zur zlib (aktuell v1.2.5) und zur libpng (aktuell v1.4.4). Während sich letztere beiden mit einer Visual Studio-Solution bauen lassen, sind bei Pixman und Cairo nur Makefiles mitgeliefert. Die sind allerdings zu kompliziert für Microsofts NMake, so dass man sich am besten MSYS mit einem richtigen Make installiert. Tja. Nur dass die MSYS-Leute ihr System in einzelne Archive verpackt deployen. Anstelle sich 500 Einzel-Archive herunterzuladen und zu entpacken, empfehle ich das MozillaBuild-Paket. Da kriegt man zwar noch einiges mehr, aber wenigstens läuft das ganze dann und scheitert nicht an einer fehlenden DLL.

2. ZLib bauen ist recht einfach über die Solution im Contrib-Ordner. Wir wählen die statische Variante (zlibstat) in der Releasekonfiguration. In den Projekteigenschaften sicherstellen, dass die Codegenerierung auf Multithreaded (MT, wir wollen keine Abhängigkeiten in die Microsoft CRT!) eingestellt ist und los gehts. Die libpng liefert eine VS2010-Solution mit, die ist aber doof konfigiert. Also die 7.1er wählen und upgraden. Release-Konfiguration wählen, das Verzeichnis der aktuellen zlib als zusaätzliches Includeverzeichnis angeben, Codegenerierung auf MT umstellen und in den Präprozessor-Direktiven des Compilers "ZLIB_WINAPI" hinzufügen, denn wir wollen die zlib später nicht als externe DLL sondern direkt in Cairo.

3. Pixman bauen. Hier kommt das erste Mal unser neu erworbenes Make aus dem MSYS-Package zum Einsatz. Zumindest wenn das Makefile.win32 schon perfekt wäre. Ein Änderung ist noch nötig, da wir die MS-CRT ja nicht als Abhängigkeit haben wollen: in Zeile 21 zu den CFLAGS ist wiederum der Schalter -MT einzufügen. Dann gehts auch los: start-msvc10.bat von MozillaBuild starten, in der erscheinenden bash zum pixman navigieren und "make -f Makefile.win32 CFG=release" führt zum Glück.

4. Cairo fit machen. In der bash zu Cairo/src navigieren und "make -f Makefile.win32 CFG=release" eingeben. Was nun kommt sind Fehlermeldungen. Tjo. Das Makefile für Windows ist ein nicht gepflegter ungetesteter Trümmerhaufen. Zunächst einmal fehlt die Datei cairo-features.h. Diese sollte in einem Make-Lauf erstellt werden. Die passende Regel wird aber offenbar nie angestoßen. Etwas Suche in den Sourcen offenbart wie sie aussehen sollte (am besten einfach kopieren und einfügen):

#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H 1

#define CAIRO_HAS_WIN32_SURFACE 1
#define CAIRO_HAS_WIN32_FONT 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
#define CAIRO_HAS_PS_SURFACE 1
#define CAIRO_HAS_PDF_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_RECORDING_SURFACE 1
#define CAIRO_HAS_USER_FONT 1
#define CAIRO_HAS_INTERPRETER 1

#endif

5. Reparatur und Anpassung der Makefiles. Src/Makefile.sources ist nicht nur für NMake zu kompliziert sondern auch für MSYS zu proprietär: Im Notepad öffnen und suchen und ersetzen nach if mit ifdef. build/Makefile.win32.common öffnen und in Zeile 20 die MS_MDFLAGS von -MD nach -MT umstellen (beim Debug analog auf -MTd aber ich erstelle hier nur das Release). Im folgenden sind zwischen Zeile 25 und 37 einige Pfade hart codiert. Diese sind an die tatsächlichen Gegebenheiten anzupassen. Insbesondere haben sämtliche Abhängigkeiten bei mir eine Versionsnummer im Pfadnamen. In Zeile 40 zu den DEFAULT_CFLAGS noch die Option -DZLIB_WINAPI anhängen, weil die zlib ja statisch in die DLL soll.

6. Patchen der Sourcen für den VC++-Compiler, da dieser keine Implementierung von lround in math.h kennt. In cairoint.h die Zeile 955 so erweitern, dass dort #if DISABLE_SOME_FLOATING_POINT || defined(_MSC_VER) steht. In cairo-misc.c in Zeile 486 dieselbe Erweiterung vornehmen.

make -f Makefile.win32 dynamic CFG=release

7. Et voila. Eine cairo.dll von knapp 1 MByte ohne extravangante Abhängigkeiten aber mit der Fähigkeit PNGs und PDFs zu erzeugen. Hoffentlich wird das mit der nächsten Version etwas einfacher.

GeoStat 2010 Beta

von Christoph

Die Beta-Version von GeoStat 2010 zur Verkartung beliebiger Daten gibt es nun hier zum Download (Zip-Datei, 7.5 MByte). Beta-Version bedeutet, dass das Projekt nicht ganz fertig ist und möglicherweise noch Fehler enthalten kann. Es handelt sich dementsprechend um eine Vorschau, die für interessierte Nutzer veröffentlicht wird. Die erstellten Karten sind nicht zur Veröffentlichung freigegeben, ein entsprechender Hinweis wird in der Karte vermerkt. Die Installation des Programms ist nicht notwendig, es genügt alle Dateien des Archivs in ein Verzeichnis zu entpacken.

Die vorliegende Beta beherrscht den Import statistischer Basisdaten im

  • CSV-Format (Textdateien die manuell oder via Export von Excel, OpenOffice Calc, etc. erstellt werden können)
  • Geogen Familiennamendaten (benötigt die Geogen-CDR oder den Geogen-Download)
  • vorberechneten XML-Statistiken (bislang nicht dokumentiert, zur internen Verwendung des Programms)

Die Methode der CSV-Dateien ist sicherlich die einfachste. Erstellen Sie eine Datei namens Beispiel.txt. Hierin schreiben Sie zeilenweise Ihre Datensätze. Jede Zeile ein Datensatz. GeoStat 2010 benötigt zur Kartierung mindestens eine Postleitzahl und einen Ortsnamen. Die einzelnen Einträge müssen Sie durchgehend mit demselben Zeichen trennen. Empfohlen ist das Komma, das Semikolon, Tab oder Doppelpunkt. Wollen Sie beispielsweise Ihre Familie kartieren, schreiben Sie in jede Zeile ein Familienmitglied mit Adresse getrennt durch Komma.

Christoph Stöpel,14974,Ludwigsfelde
Christoph Stöpels Bruder,14974,Ludwigsfelde
Grakein Stöpel,14480,Potsdam

Innerhalb von GeoStat 2010 wählen Sie im Hauptmenü Datei den Punkt Daten importieren und hierin Von CSV/Text. Im erscheinenden Assistenten wählen Sie Ihre Beispieldatei aus. Das Programm versucht automatisch den Spaltentrenner zu erkennen. Sollte das Komma nicht identifiziert worden sein, können Sie dies manuell einstellen. Der nächste Schritt ist entscheidend für die Kartierung. Hier beschreiben Sie, in welcher Spalte GeoStat 2010 welche Daten findet. Im oberen Beispiel enthält Spalte 1 den Titel, Spalte 2 die Postleitzahl und Spalte 3 den Ortsnamen. Stellen Sie dies auch so ein, wie im Bilschirmfoto gezeigt.

GeoStat Importassistent

Anschließend startet die Berechnung der Statistik und die Kartierung. Dies kann je nach Leistung Ihres PCs einige Zeit in Anspruch nehmen. Erzeugt werden Karten, die die Statistiken zugeordnet zu Landkreisen, in Clustern oder anamorph verzerrt darstellen. Über die Toolbar oder das Hauptmenü können Sie zwischen den verschiedenen Ansichten wechseln. Über das Menü Datei/Speichern unter können Sie die aktuelle Karte in verschiedenen Formaten sichern.

Systemvoraussetzungen:

  • Betriebssystem MS Windows XP SP3, Vista, 7 oder neuer
  • Prozessor mit 2 GHz oder mehr
  • 512 MByte Arbeitsspeicher
  • 25 MByte freier Festplattenspeicher

Bekannte Probleme in dieser Beta-Version:

  • Die Zusammenlegung von Aachen Stadt und Land zu einem Landkreis ist noch nicht integriert. Die Landkreise werden gemäß Stand vom 31.12.2009 getrennt behandelt.
  • Das Speichern von Karten im HTML-Format berücksichtigt nicht die aktuelle Ansicht und exportiert immer die Cluster-Ansicht.
  • Die Karte der HTML-Ansicht ist etwas großformatig, so dass Nutzer innerhalb des Browserfenster häufig scrollen müssen.