Spieleentwicklung gestern und heute

Freitag, 16. Oktober 2020 14:30 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

Montag, 17. August 2020 12:00 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

Freitag, 12. Juni 2020 18:00 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 ;-)

Die Hölle ist gefroren

Mittwoch, 16. Oktober 2019 11:15 von Christoph

Ich bin schon sehr lange im Microsoft-Umfeld unterwegs. Das fing an mit Windows 95 und Turbo Pascal, wechselte dann über Borland Delphi zu Visual C++ 6. In der Uni ging es dann per Visual Studio.NET (2002-2005) zum .NET Framework mit allem Drum und Dran: Windows Forms, Remoting, XML Webservices.

Eines war die ganze Zeit aber klar: Unter Linux kannste das komplett vergessen. Es gab da zwar schon Mono, ich tat das aber als Frickler-Kopie ab. Die haben sich irgendwie die Funktionalität angeguckt und daraus Code engineered. Das kippte in den letzten Jahren. MS hat quasi alles .NET Core als Open Source rausgehauen, hat Github gekauft und unterstützt die Runtime selbst und offiziell auf Linux.

Da ich alle meine Web-Projekte (just for the fun of it) zwischenzeitlich auf ASP.NET Core (aktuell v2.1 LTS) umgestellt habe, reizte es mich natürlich, das mal mit eigenen Augen unter Linux sehen. Was soll ich sagen? Läuft!

Screenshot Linux

Die Dokumentation, um das mit den offiziellen Docker-Images zu erreichen, ist leider nicht die Beste. Auf mich wirkt es sehr umständlich, immer ein eigenes Image zu erzeugen um da sein Zeug reinzupacken, aber es geht natürlich dabei um Produktions-Deployments. Da will man genau ein Image irgendwo hinkopieren. Ich dagegen wollte nur mal schnell die Bits meines Windows-Deployments (vom Server kopiert) unter Linux ASP.NET testen. Dazu findet man nichts, aber das geht auch:

docker run --name devlog -p 8080:80 -v $(pwd):/app -w /app \
  --rm --entrypoint dotnet mcr.microsoft.com/dotnet/core/aspnet:2.1 \
  devlog.dll

Oder etwas eleganter und archivierbarer als docker-compose.yml:

Bayerischer Winter

Sonntag, 10. Februar 2019 10:00 von Christoph

Ich bin kürzlich vom schönen Brandenburg ins winterliche Bayern gefahren. Mit dem eigenen Auto quer durch Deutschland. Nur Brandenburg erkennt man jederzeit: an den dichten Kiefernwäldern links und rechts der Autobahn. Bayern, Baden-Württemberg und Thüringen sind da schon schwerer zu unterscheiden, je weiter man von den Alpen weg ist. Wegen Schneefalls hat der Roadtrip ins Allgäu dann auch schlappe sieben Stunden gedauert.

Für mich war der Schnee nicht überraschend, sondern eher gewollt (für schulmäßig romantische Landschaftsfotos). Die Fernsehsender haben jedoch extra Wetterreporter abgestellt, um über den Wintereinbruch im Winter zu berichten. Und über den Schnee in den Alpen! Wochenlange sibirische Kälte!1!! Nunja.

.NET Framework ist tot

Samstag, 9. Februar 2019 11:30 von Christoph

Da schrieb ich noch vor fast zwei Jahren: Ich bin drauf und dran, von der Blogengine zu einer selbstgebauten Lösung zu wechseln. Ich habe es dann nicht gemacht, weil der Autor löblicherweise anfing, etwas Bloat (Angular!!!) zu entfernen. Hat er dann aber leider nicht weitergeführt, sondern geschrieben, dass er keine Lust mehr auf die Blogengine hat und stattdessen mit etwas Neuem rumspielt. Damit muss man natürlich rechnen - unangenehm ist es aber trotzdem.

Da hat es mich also wieder in den Fingern gejuckt. Doch was tun? Habe mich wieder im Microsoft-Umfeld umgeschaut, wie ich das am besten selber baue. Microsoft hat mich ziemlich früh in der Uni mit dem Studentenprogramm drangekriegt. Seit Visual Studio 2002 bin ich beim .NET Framework dabei, das müsste Version 1.1 gewesen sein. Doch mit dem .NET Framework ist es nun aus. 16 Jahre waren echt eine lange Zeit. MS ist ja verdammt, die Kompatibilität zu erhalten (Developers! Developers! Developers!).

Screenshot Visual Studio 2017

Der neue hippe Kram ist .NET Core und damit ASP.NET Core, ein modularisiertes Framework, das immer noch C# versteht und schwer auf den Paket-Manager Nuget setzt. Habe ich also den Schritt gemacht und die Blogengine einfach mal komplett weggeworfen. Mehrere tausend Dateien. Ich habe nur die 39 Blog-Beiträge und darin referenzierte Resourcen behalten, ansonsten alles from scratch neu geschrieben (insgesamt ein Aufwand von drei Tagen, ich habe viel Bloat einfach weggelassen, wie Trackbacks, Pingbacks, Kommentare, Bewertungen). Das Ergebnis läuft hier gerade.

Dann habe ich auch gleich noch Geogen v4 auf .NET Core portiert. Das soll ja angeblich auch schneller laufen. Eigentlich ging es mir aber um die Zukunftssicherheit - ich will nicht auf dem Trockenen sitzen, wenn Windows Server irgendwann kein .NET Framework mehr mitbringt. Manchmal ist das auch schade, wie Microsoft so durch die Technologien huscht. Als sie den SQL Server Compact mit ASP.NET Unterstützung eingeführt haben, war ich wirklich glücklich, eine In-Process Alternative zum SQL Server zu haben. Leider haben sie die Unterstützung inzwischen komplett eingestellt. Argh! Hätte ich nur gleich auf Sqlite gesetzt.

Über Softwarekomplexität

Dienstag, 25. April 2017 10:44 von Christoph

Ich mag Komplexität nicht. Die kann man nicht dauerhaft beherrschen. Kontrollverlust.

Das ist mir beim Aktualisieren der Blogsoftware wieder ganz enorm aufgefallen. Ich hoste ja ungewöhnlicherweise auf einem Windows-Server und bevorzuge serverseitig ASP.NET. Für das Devlog habe ich auf den Platzhirschen zurückgegriffen, die Blogengine.NET. Die war mal schlank, übersichtlich und recht wartbar. Aber die Security. Darf man auf Updates verzichten? Eher nicht. So habe ich in Abständen die Updates mitgemacht und war immer mehr ernüchtert. Was vorher schlank, übersichtlich und recht wartbar war, wurde nun zu Angular, Bootstrap und Webgrease. Leute, mal echt: muss das sein? Ich war ganz nah dran, das alles wegzuschmeißen und einen statischen Seitengenerator zu verwenden. Oder mir selber einen zu schreiben. Dieses Jahr dann jedoch die erfreuliche Nachricht. Das Pendel schwingt wieder zurück. Man rückt ab vom Bloat.

Ich habe das durch meine recht eigentümliche Updatestrategie bemerken dürfen. Die offizielle Anleitung besagt, die neuen Dateien einfach in die alte Installation integrieren. Nein! Dann bleibt doch nicht mehr verwendeter Code rumliegen, stellt schlimmstenfalls Sicherheitsrisiken dar. Ich mache das anders: Neue Installation anlegen und Dateien aus der alten, von denen ich weiß, dass sie gebraucht werden, dort integrieren (Konfigurationen, Themes, Blog-Beiträge). Dann mit Git vergleichen: 1000 Änderungen, davon jedoch 500 echtes Löschen - also nicht jQuery 2.1 entfernen und jQuery 2.4 hinzufügen, sondern wirklich weg! Das ist gut. Es zeigt, dass die Autoren erkannt haben, wie sie übertrieben. Die Abhängigkeitsübertreibung war nicht gut, der Erkenntnisgewinn schon.

Die meisten Entwickler schaffen nur Schritt 1. Die Javascript- und Ruby-on-Rails-Leute sind so ein Beispiel. Es gibt da auch Gute, aber es gibt insgesamt einfach sehr viele, so dass die Schlechten absolut auch mehr sind. Die haben ein Problem und schauen nach einem Gem/ Node-Package. Wiederverwendung ist ja an sich nichts Schlechtes, es ist ein Mittel gegen Komplexität. Aber was die da gemacht haben, entbehrt wirklich allem was gut und rein ist. Ich habe das mal gesehen. Problem war: wir brauchen einen Datensatz aus der Datenbank via Web-API als JSON. Lösung: irgendein Rails-Exporter Gem ergoogelt. Das brauchte aber auch Authentifizierung (abhängiges Gem). Das wiederum sollte auch nebenläufig gehen (abhängiges Gem). Das wiederum musste synchroniert werden (abhängiges Gem). Die Synchronisation musste regelmäßig auf Konsistenz geprüft werden (abhängiges Gem). Bumm! Um einen Datensatz als banales JSON auszugeben wurden 10 MByte an Abhängigkeiten (geschätzte 30 Gems) installiert. Naja, immerhin hatte das System dadurch am Ende auch eine Schnittstelle für Cron-Steuerung.

Kurz: Schaut doch mal genau was ihr braucht. Fast nie benötigt man ein Framework. Beobachtet, welche Abhängigkeiten ihr euch einfangt. Oft findet man sehr spezifische und schlanke Lösungen. Wenn nicht, dann baut man sich eben eine. Software-Engineering ist eine kreative Tätigkeit und Verstehen ist der Schlüssel. Wenn man empfohlene Frameworks einfach von Stackoverflow kopiert, dann ist etwas extrem faul.

English Documentation

Sonntag, 15. Mai 2016 08:17 von Christoph

Normalerweiseweise verlinke ich nicht auf andere Blog-Posts oder Social-Media Krimskrams, aber hier hat sich jemand aus den USA die Mühe gemacht, Geogen mehr zu dokumentieren als ich selbst. Die Autorin Elise Ann Wormuth hat auch noch ein paar andere Erfahrungen eingestreut: livinginpast.com.

Die Seite ist recht webzweinullig - man muss Newsletter-Angebote, Cookie-Disclaimer, Übersetzungshilfen usw. wegklicken, aber dann ist sie sehr passioniert aufgemacht.