Beiträge: 2.158
Themen: 31
Registriert seit: Mar 2013
Bewertung:
13
Ich finde die Schrift im ersten Bild am angenehmsten zu lesen.
Ist das Zufall oder gewollt, dass im Nachbau die Zeilen mit dem jeweils gleichen Wort des Originals enden?
"Alrik war durstig und hat getrunken."
Beiträge: 3.178
Themen: 109
Registriert seit: Aug 2006
Bewertung:
23
Ich denke, das ist technisch bedingt - genau das würde sich mit einem "eigenen" Zeilenumbruch ja ändern, womit man die Textbox effizienter und sinnvoller befüllen könnte.
Beiträge: 189
Themen: 2
Registriert seit: May 2020
Bewertung:
12
04.11.2023, 17:24
(Dieser Beitrag wurde zuletzt bearbeitet: 04.11.2023, 17:26 von cmfrydos.)
Danke für eure Ideen, ich bin ganz eurer Meinung. Es wäre zwar möglich, den Text dem Original sehr ähnlich zu gestalten, doch würde das an Lesbarkeit kosten. Also besser wir nehmen Schriftschnitt Medium, normale Leerzeichen, und etwas kleineren Text, bzw. größeren Zeilenabstand - im Original können zwei Buchstaben 'verschmelzen', wenn bspw. ein 'g' über einem 'i' steht. Um gewisse Zeilenabstände zu gewährleisten, müsste man die Textboxen aber selbst malen, auch um einen eigenen Textfluss zu ermöglichen:
(03.11.2023, 11:17)aeyol schrieb: Ich denke, das ist technisch bedingt - genau das würde sich mit einem "eigenen" Zeilenumbruch ja ändern, womit man die Textbox effizienter und sinnvoller befüllen könnte.
Genau, aktuell habe ich nur den Befehl für das Zeichnen von Textketten ersetzt. Der nächste Schritt wäre, den Befehl zum Malen der Textboxen anzupassen. So könnte man längere Texte selbstständig umbrechen und die Größe der Textboxen entsprechend anpassen. Das sollte subtil genug sein, um nicht aufzufallen – ob eine Box nun 5 oder 7 Zeilen hat, dürfte kaum jemanden stören. Hauptsache, die Texte bleiben gut lesbar und die Box sieht nicht fehl am Platz aus. Ein zusätzlicher, bisher nicht genannter Vorteil wäre, dass ich die Textboxgrafiken nicht strecken müsste, wie man es im ersten Beispiel meines letzten Posts passiert ist.
Was PT Mono betrifft, werde ich das später ausprobieren, aber ich bezweifle, dass die Originalschriftart eine Monospace-Font ist. Besonders bei Buchstaben wie 'i' oder 't' sieht man die schmalere Breite – und umgekehrt beim Leerzeichen, wie weit es ist. Also scheint es, dass jeder Buchstabe seine eigene fixe Breite hat – aber noch nicht ganz so ausgefeilt wie bei modernen Schriftarten, die Abstände abhängig von den nebeneinanderstehenden Buchstaben anpassen (Stichwort 'Kerning').
Beiträge: 189
Themen: 2
Registriert seit: May 2020
Bewertung:
12
31.01.2024, 22:48
(Dieser Beitrag wurde zuletzt bearbeitet: 02.02.2024, 21:04 von cmfrydos.
Bearbeitungsgrund: Formatierung / Ergänzung
)
Ich hatte mich kürzlich mal mit dem BOB-Dateiformat auseinander gesetzt, die offenen Fragen des Wikis klären können, und den Dateiaufbau zusammen gefasst. Zu Dokuzwecken poste ich es mal hier:
[BOB-Dateiformat in RIVA]
Grundsätzlich alles Unsigned / Little Endian.
BOBs sind gif-ähnliche Bilddateien, die aus einem Hauptbild und vielen kleinen Ausschnitts-Animationen bestehen. Das sind hauptsächlich die zahlreichen Animationen, wenn Bewohner ihre Tür öffnen und die Helden ansprechen. Hier bewegen sich Mund, Augen, Stirnrunzeln usw. unabhängig voneinander und oft auch mit unterschiedlichen Animationslängen, sodass der Gesamteindruck nicht repetitiv wirkt.
Datenaufbau:
Header: 16 Bytes + ein 0x00-Trennbyte
---------------------------------------------------------------------
Off Typ Name Anmerkung
---------------------------------------------------------------------
0 char[3] Signatur 3 Bytes Signatur "BOB"
3 char Trennbyte Ein 0x00-Trennbyte
4 short Version 2 Bytes Version 0x0101
6 byte AnzAnimation 1 Byte Anzahl der Animationen
7 short Konstante 2 Bytes immer 0x010A
9 char[8] Leer8Bytes 8 Bytes immer leer
17 byte LeerByte 1 Byte immer leer, Trennung zum folgenden Abschnitt
---------------------------------------------------------------------
Gibt es Animationen, folgt nun eine Beschreibung, welche (Achtung, einsbasierte) Bildindizes für wie lange gezeigt werden. Dieser Teil der Daten ist doppelt vorhanden! Die einzelnen Teile kommen auch in der jeweiligen Beschreibung der Animation (im Animationsheader) erneut vor.
Miniheader, fasst Längen der nachfolgenden Datenpakete zusammen.
---------------------------------------------------------------------
Datenlängen - Miniheader
---------------------------------------------------------------------
Off Typ Name Anmerkung
---------------------------------------------------------------------
0 char DatenLaenge_1 1 Byte Datenlänge für Animation 1 (Größe in Bytes / 4)
1 char DatenLaenge_2 1 Byte Datenlänge für Animation 2 (Größe in Bytes / 4)
2 char DatenLaenge_3 1 Byte Datenlänge für Animation 3 (Größe in Bytes / 4)
... ... ... ...
n-1 char DatenLaenge_n 1 Byte Datenlänge für Animation n (Größe in Bytes / 4)
---------------------------------------------------------------------
Nun folgen dem Datenlängen - Miniheader die eigentlichen Datenpakete, von denen es für jede Animation eine gibt:
---------------------------------------------------------------------
Animationen Datenpakete
---------------------------------------------------------------------
Off Typ Name Anmerkung
---------------------------------------------------------------------
0 byte StartByte Immer 0x00
1 byte DatenLaenge Datenlänge für die folgende Animationsbeschreibung (entspricht Miniheader)
2 word Bildindex_1 1 Word Bildindex für Animation 1 (einsbasiert)
4 word Anzeigedauer_1 1 Word Anzeigedauer für Animation 1
6 word Bildindex_2 1 Word Bildindex für Animation 2 (einsbasiert)
8 word Anzeigedauer_2 1 Word Anzeigedauer für Animation 2
... ... ... ...
n-4 word Bildindex_n 1 Word Bildindex für Animation n (einsbasiert)
n-2 word Anzeigedauer_n 1 Word Anzeigedauer für Animation n
---------------------------------------------------------------------
n = 2 + DatenLaenge * 4
Die Anzeigedauer ist in einer Einheit von ~45 ms, das heißt ein Bild, das für 10 Anzeigeeinheiten gezeigt wird, wird für etwa 450 ms angezeigt. Sowohl Bildindex als auch Anzeigedauer sind immer < 256, außer bei Adran. Adrans BOB Animation wird jedoch nie im Spiel gezeigt, sodass sich der Effekt nicht beobachten lässt. Was etwas verwunderlich ist, dass die Alternative "Kein Bild", d.h., den Ausschnitt des Hauptbildes zu verwenden, scheinbar nie benutzt wird.
---------------------------------------------------------------------
Header (0 ist auch 'Headerbeginn')
---------------------------------------------------------------------
Off Typ Name Anmerkung
---------------------------------------------------------------------
0 dword Headerlaenge 1 DWord Headerlänge (einschließlich dieser 4 Bytes)
4 dword OffsetDatenEnde 1 DWord Offset zum Datenende vom Headerbeginn aus
8 word BreiteHauptbild 1 Word Breite Hauptbild
10 byte HoeheHauptbild 1 Byte Höhe Hauptbild
11 byte AnzOffsets 1 Byte Anzahl der Offsets (entspricht Anzahl der Animationen)
12 udword OffsetAnimation1 1 UDWord Offset zur Startposition des Animationsheader 1 vom Headerbeginn aus
16 udword OffsetAnimation2 1 UDWord Offset zur Startposition des Animationsheader 2 vom Headerbeginn aus
... ... ... ...
n-4 udword OffsetAnimation_AnzOffsets 1 UDWord Offset zur Startposition der Animation n
---------------------------------------------------------------------
n = 12 + AnzAnimationen * 4
Nun folgt für jede Animation ein Animationsheader
---------------------------------------------------------------------
Animationsheader
---------------------------------------------------------------------
Off Typ Name Anmerkung
---------------------------------------------------------------------
0 char[4] Name 4 Bytes Name/Abkürzung der Animation
4 word XOffset 1 Word X-Offset
6 byte YOffset 1 Byte Y-Offset
7 byte Hoehe 1 Byte Höhe
8 word Breite 1 Word Breite
10 byte ImmerNull 1 Byte Immer 0
11 byte AnzTeilbilder 1 Byte Anzahl der Teilbilder
12 udword StartOffset_1 1 UDWord Startoffset der Bilddaten vom Start des Hauptheaders aus für Teilbild 1
16 udword StartOffset_2 1 UDWord Startoffset der Bilddaten vom Start des Hauptheaders aus für Teilbild 2
... ... ... ...
n-4 udword StartOffset_n 1 UDWord Startoffset der Bilddaten vom Start des Hauptheaders aus für Teilbild n
n byte AnzFramezeiten 1 Byte Anzahl der Framezeiten (entspricht der Anzahl aus dem Miniheader)
n+1 dword Framezeit_1 1 DWord Framezeit für Teilbild 1 (entspricht den Daten aus dem Miniheader: 2 Byte Bildindex + 2 Byte Anzeigedauer)
n+5 dword Framezeit_2 1 DWord Framezeit für Teilbild 2
... ... ... ...
m-4 dword Framezeit_o 1 DWord Framezeit für Teilbild o
---------------------------------------------------------------------
m = n + 1 + 4 * AnzFramezeiten
n = 12 + 4 * AnzTeilbilder
Nun folgen die eigentlichen Bilddaten. Es lohnt sich an dieser Stelle zu bestimmen, ob die Daten komprimiert wurden. Dies steht am Datenende.
Wenn die Daten komprimiert sind, sind diese PP20 komprimiert, wobei anstatt der Signatur "PP20" die komprimierte Größe, die 4 Bytes eingeschlossen, am Anfang steht.
Die Daten des Hauptbildes und jede der Animationen sind dabei einzeln komprimiert, wobei die Teilbilder einer Animation zusammen komprimiert vorliegen. D.h. nach dem Entpacken haben wir:
- Hauptbild-Breite mal Höhe Daten für das Hauptbild und
- Anzahl der Teilbilder * dessen Höhe mal dessen Breite an Bytes für jede Animation. Diese Daten muss man dann einfach in gleich große Pakete für die Einzelbilder zerteilen.
---------------------------------------------------------------------
Datenende
---------------------------------------------------------------------
Off Typ Name Anmerkung
---------------------------------------------------------------------
0 word Unbekannt_1 2 unbekannte Words < 60
2 word Unbekannt_2
4 byte FFByte 1 Byte immer 0xFF
5 byte Komprimiert 1 Byte 1 bei komprimierten Daten, 0 bei unkomprimierten Daten
6 byte[768] Palette_RGB 256 * 3 Bytes Rot-Grün-Blau-Werte der Palette
---------------------------------------------------------------------
Wie Shihan hier entdeckte, muss man jeden Farbwert leicht verändern: c = (c & 0x3f) * 4. Was in den höchsten 2 Bits kodiert ist, ist noch unbekannt.
Zum Anzeigen muss man nun das Hauptbild zeichnen und jede Animation starten. Diese laufen dabei durch ihre (Index, Dauer) - Liste und rendern das dem Index entsprechende Teilbild. Die Zeichenreihenfolge ist dabei noch unklar. Die Kräuterhändlerin beispielsweise sieht immer falsch aus. Entweder bewegt sich nicht der Mund, weil die Tasse diesen überdeckt, oder beim Pusten sehen die Backen falsch aus. Was bei ihr funktioniert, ist statt Index-1 Bilder (die Ersten) zu zeichnen, die Animation auszulassen, d.h., den Ausschnitt vom Hauptbild zu verwenden. Dieses Vorgehen wiederum funktioniert bei anderen .BOBs gar nicht. Dies bleibt also noch ein letztes Rätsel. Ich habe mal ein Screenshot des ungewöhnlichen .BOB von Adran, das ich im Spiel nicht triggern konnte, beigefügt:
Beiträge: 189
Themen: 2
Registriert seit: May 2020
Bewertung:
12
03.02.2024, 17:32
(Dieser Beitrag wurde zuletzt bearbeitet: 05.02.2024, 13:41 von cmfrydos.
Bearbeitungsgrund: Komprimierungsmodus 0x02 in AIF
)
Mhh, ich weiß nicht wie ich das übersehen konnte, aber ich habe wohl etwas mühselig gezeigt, dass das "Neue Format", einfach das "Alte Format" mit einem vorangestellten Pre-Header ist. Ab dem 'Headerbeginn' sind beide Formate identisch.
Der Sinn dahinter erschließt sich mir noch nicht ganz. Vielleicht hat der Pre-Header das Abstimmen der Animationen etwas erleichtert?
@Shihan, falls du mich zum Wiki / Repo hinzufügen magst, kann ich die Artikel zu BoB, 3DM und einigen anderen Formate gerne ergänzen. Da kam jetzt über das letzte Jahr doch so einiges zusammen.
Ich glaube, wir haben dann schon fast alle Formate in Riva geknackt! Was fehlt, sind noch .MOV/.MOF für die Autobewegungen, was sich mit eigenen 'Aufnahmen' in der 1.62 Demo wohl leicht entziffern lässt, sowie 5 Formate von dem MODULEAUTOMAP (.ANN .APA .LST .MSK .MST), die aber übersichtlich aussehen. Ah und dann noch die Dialogformate .LXT und .XDF . Und zuletzt fehlt noch der Komprimierungsmodus 0x02 in AIF, den man noch ausmachen muss.
Ergänzung:
Ich hatte zuletzt noch Spaß mit dem Komprimierungsmodus 0x02 in AIF, der in Riva zwar nur von einem Bild benutzt wird, aber dann doch nachgegeben hat:
Es ist eine Form von Lauflängenkodierung (RLE).
Im Endeffekt muss man immer nur 1 Byte b lesen und entscheiden, ob dieses < 128 ist:
Fall I) b < 128 leitet eine Folge von b + 1 Bytes ein, b selbst nicht mitgezählt, die 1:1 in das Ergebnis kopiert werden.
Fall II) b >= 128 steht immer vor einem Farbcode c. c wird nun 257 - b mal in das Ergebnis geschrieben.
Anders ausgedrückt: Das komprimierte Bild ist also in Pakete b_0, p_0, b_1, p_1, b_2, p_2, b_3, p_3, ... unterteilt,
wobei jedes b_n die Länge von p_n diktiert, und besagt, ob man p_n entweder ein- oder mehrfach in das Ergebnis schreibt.
Auf Fall I) folgt wohl immer Fall II), außer eine Folge ist zu lang, aber dies kommt in dem einen Rivabild nicht vor.
Dass die Fallgrenze bei < 128 liegt, habe ich auch nur geraten, und könnte man nur verifizieren, falls dieser Komprimierungsmodus z.B. auch in Sternenschweif oder der Schicksalsklinge benutzt wird.
|