Titelbild in voller Aufloesung (320x480 anamorph statt halbiert)

Stefan-Frage "hatte das Titelbild nicht bessere Aufloesung?" -- ja, bestaetigt.
Die 4 Quadranten KELL256A-D (je 160x240 nativ) wurden bisher auf halbe Hoehe
(160x120) gestaucht -> 320x240, also die halbe vertikale Aufloesung verworfen
(gleiche Fehlklasse wie der Rauser-0.5x-Downscale). Ein RMSE-Vergleich der
beiden Varianten gegen die echte DOSBox-Referenzaufnahme belegt eindeutig die
volle Variante:
  voll (320x480, anamorph angezeigt): RMSE 0.014
  halbiert (320x240):                 RMSE 0.083  (6x schlechter)

Fix: build_title_quadrants nutzt die nativen 160x240-Quadranten -> 320x480-
Bild; angezeigt wird es anamorph auf die volle Fenstergroesse gestreckt
(_blit_title: 320x480 -> 960x720, x3 Breite / x1.5 Hoehe), womit alle 480
Zeilen erhalten bleiben. render_title_wipe_frame arbeitet automatisch bei
320x480 (Hoehe aus get_height()). pcc_surface_half_height entfernt (ungenutzt).

Verifiziert: neues Titelbild sichtbar schaerfer, deckungsgleich zur Referenz;
python -m game --once (headless) exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-07-24 01:59:19 +02:00
co-authored by Claude Opus 4.8
parent 95e5b1edb4
commit ccad606a43
+40 -41
View File
@@ -66,20 +66,17 @@ Serie vermessen, siehe NOTES.md Abschnitt "Boot-Sequenz vermessen". Kurzfassung:
6. kurze schwarze Pause 6. kurze schwarze Pause
7. Titelbild "TONY & FRIENDS in Kellogg's Land" -- die 4 Quadranten KELL256A 7. Titelbild "TONY & FRIENDS in Kellogg's Land" -- die 4 Quadranten KELL256A
(oben links) / B (oben rechts) / C (unten links) / D (unten rechts) sind (oben links) / B (oben rechts) / C (unten links) / D (unten rechts) sind
je 160x240 PCC-Nativaufloesung, werden aber nur bei **halber Groesse** je 160x240 PCC-Nativaufloesung und werden in NATIVER Groesse in ein
(160x120) in ein 2x2-Raster gezeichnet: A|B oben, C|D unten -> 320x240 2x2-Raster gezeichnet: A|B oben, C|D unten -> 320x480 Gesamtbild. Das wird
Gesamtbild. Per Pixel-Rekonstruktion gegen eine echte DOSBox-Aufnahme beim Anzeigen ANAMORPH auf 4:3 (Fenstergroesse) gestreckt -- doppelt hohe
verifiziert. Reveal-Effekt: obere Haelfte (A|B) waechst von oben (Hoehe Pixel, genau wie im Original (siehe _blit_title). KORREKTUR 24.07.2026:
0->120), untere Haelfte (C|D) waechst von unten (Hoehe 0->120) -- treffen frueher wurden die Quadranten auf halbe Hoehe gestaucht (320x240) -- das
sich in der Mitte. Waehrend dieser Reveal-Phase ist die untere Haelfte war falsch (halbe vertikale Aufloesung). RMSE-Vergleich gegen die echte
erst graustichig/entsaettigt MIT Scanlines ueberzogen, die sich danach in DOSBox-Referenz: 0.014 (voll) vs. 0.083 (halbiert). Reveal-Effekt: obere
einer zweiten Phase zu vollen Farben aufloesen (Stefans "Screenshot Haelfte (A|B) waechst von oben, untere (C|D) von unten, treffen sich in
4/5/6"-Effekt). HINWEIS: diese Quadranten nutzen denselben der Mitte (y=240). Waehrend/nach dem Reveal ist die untere Haelfte mit
Downscale-Mechanismus (smoothscale halbe Hoehe) wie die Rauser-Assets Scanlines ueberzogen (KEIN Grau mehr), die sich von der Mitte nach unten
vor dem obigen Fix -- hier bisher KEINE Bildschaerfe-Beschwerde von aufloesen.
Stefan, deshalb unangetastet gelassen. Falls das Titelbild auch mal als
"verwaschen" gemeldet wird: gleicher Fix-Ansatz (native Groesse zeichnen,
nur einmal ganzzahlig hochskalieren) anwendbar.
Alle Nicht-BOB/ICO/MAP-Assets werden per kellogg_formats.load_pcc() (Pillows Alle Nicht-BOB/ICO/MAP-Assets werden per kellogg_formats.load_pcc() (Pillows
PCX-Decoder) aus PCKELL.DAT gelesen -- kein eigener RLE-Code mehr (siehe PCX-Decoder) aus PCKELL.DAT gelesen -- kein eigener RLE-Code mehr (siehe
@@ -220,6 +217,17 @@ def _blit_centered(surface):
keinen veralteten Screen-Bezug hinterlaesst).''' keinen veralteten Screen-Bezug hinterlaesst).'''
blit_scaled_centered(pygame.display.get_surface(), surface, WINDOW_W, WINDOW_H) blit_scaled_centered(pygame.display.get_surface(), surface, WINDOW_W, WINDOW_H)
def _blit_title(surface):
'''Titelbild-Sonderfall: die Quelle ist 320x480 (ein 4:3-Bild mit doppelt
hohen Pixeln -- genau so liegt es im Original vor, siehe Titelbild-
Aufloesungs-Fund 24.07.2026). Es wird ANAMORPH auf die volle Fenstergroesse
gestreckt (320x480 -> 960x720, also x3 Breite / x1.5 Hoehe) -- fuellt das
Fenster wie die 320x240-Screens, behaelt aber die volle vertikale
Aufloesung (480 statt der frueher faelschlich halbierten 240 Zeilen).'''
s = pygame.display.get_surface()
s.blit(pygame.transform.scale(surface, (WINDOW_W, WINDOW_H)), (0, 0))
# "praesentiert"-Text-Faelle in KELLOGGS.PCC (siehe Docstring) # "praesentiert"-Text-Faelle in KELLOGGS.PCC (siehe Docstring)
PRAESENTIERT_FADE_INDICES = [34, 42, 43, 44, 45] PRAESENTIERT_FADE_INDICES = [34, 42, 43, 44, 45]
PRAESENTIERT_FADE_SECONDS = 2.5 PRAESENTIERT_FADE_SECONDS = 2.5
@@ -389,20 +397,6 @@ class Assets:
new_size = (max(1, round(w * scale)), max(1, round(h * scale))) new_size = (max(1, round(w * scale)), max(1, round(h * scale)))
return pygame.transform.scale(surf, new_size) return pygame.transform.scale(surf, new_size)
def pcc_surface_half_height(self, name):
'''Skaliert NUR die Hoehe um 0.5, Breite bleibt nativ -- fuer die
Titelbild-Quadranten KELL256A/B/C/D (160x240 -> 160x120). ACHTUNG:
das ist KEINE gleichmaessige Skalierung wie bei den Rauser-Assets --
per Pixel-Rekonstruktion gegen eine echte DOSBox-Aufnahme verifiziert
(siehe Docstring ganz oben). Nearest-Neighbor (pygame.transform.scale)
statt smoothscale aus dem gleichen Grund wie bei den Rauser-Assets
(siehe pcc_surface_scaled) -- konsistent scharf.'''
surf = self.pcc_surface(name)
w, h = surf.get_size()
new_size = (w, max(1, round(h * 0.5)))
return pygame.transform.scale(surf, new_size)
def fit_scale(src_w, src_h, max_w, max_h): def fit_scale(src_w, src_h, max_w, max_h):
return min(max_w / src_w, max_h / src_h) return min(max_w / src_w, max_h / src_h)
@@ -720,20 +714,25 @@ def scene_rauser(clock, assets, audio_paths):
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def build_title_quadrants(assets): def build_title_quadrants(assets):
'''Liefert die 4 Titelbild-Quadranten bei halber Hoehe (160x120 statt '''Liefert die 4 Titelbild-Quadranten in NATIVER Aufloesung (je 160x240)
160x240 nativ) -- A/B oben, C/D unten. Per Pixel-Rekonstruktion gegen -- A/B oben, C/D unten -> zusammen ein 320x480-Bild. KORREKTUR 24.07.2026:
eine echte DOSBox-Aufnahme verifiziert.''' frueher wurden die Quadranten auf halbe Hoehe (160x120) gestaucht; ein
Vergleich gegen die echte DOSBox-Referenz (RMSE 0.014 voll vs. 0.083
halbiert) zeigt aber, dass das Original das Bild in voller Hoehe fuehrt und
nur ANAMORPH (doppelt hohe Pixel) auf 4:3 anzeigt. Die native Hoehe bleibt
also erhalten und wird erst beim Anzeigen gestreckt (siehe _blit_title).'''
return { return {
'A': assets.pcc_surface_half_height('KELL256A'), 'A': assets.pcc_surface('KELL256A'),
'B': assets.pcc_surface_half_height('KELL256B'), 'B': assets.pcc_surface('KELL256B'),
'C': assets.pcc_surface_half_height('KELL256C'), 'C': assets.pcc_surface('KELL256C'),
'D': assets.pcc_surface_half_height('KELL256D'), 'D': assets.pcc_surface('KELL256D'),
} }
def build_title_image(quads): def build_title_image(quads):
'''Komplettes, ruhendes Titelbild (320x240) aus den 4 halbskalierten '''Komplettes, ruhendes Titelbild (320x480) aus den 4 nativen Quadranten im
Quadranten im 2x2-Raster.''' 2x2-Raster (wird beim Anzeigen anamorph auf 4:3 gestreckt, siehe
_blit_title).'''
a, b, c, d = quads['A'], quads['B'], quads['C'], quads['D'] a, b, c, d = quads['A'], quads['B'], quads['C'], quads['D']
w = a.get_width() + b.get_width() w = a.get_width() + b.get_width()
h = a.get_height() + c.get_height() h = a.get_height() + c.get_height()
@@ -775,10 +774,10 @@ def render_title_wipe_frame(quads, t):
unteren Haelfte loesen sich von der Mitte nach unten auf. Obere Haelfte ist unteren Haelfte loesen sich von der Mitte nach unten auf. Obere Haelfte ist
durchgehend volle Farbe ohne Scanlines (wie in der DOSBox-Referenz).''' durchgehend volle Farbe ohne Scanlines (wie in der DOSBox-Referenz).'''
a, b, c, d = quads['A'], quads['B'], quads['C'], quads['D'] a, b, c, d = quads['A'], quads['B'], quads['C'], quads['D']
half_h = a.get_height() # 120 half_h = a.get_height() # 240 (native Quadrantenhoehe)
full_w = a.get_width() + b.get_width() # 320 full_w = a.get_width() + b.get_width() # 320
canvas = pygame.Surface((full_w, half_h * 2)) canvas = pygame.Surface((full_w, half_h * 2)) # 320x480
canvas.fill((0, 0, 0)) canvas.fill((0, 0, 0))
if t < TITLE_HEIGHT_REVEAL_FRACTION: if t < TITLE_HEIGHT_REVEAL_FRACTION:
@@ -866,12 +865,12 @@ def scene_title(clock, assets, hold_forever=True):
kurz und kehrt zurueck, statt auf eine Taste zu warten.''' kurz und kehrt zurueck, statt auf eine Taste zu warten.'''
quads = build_title_quadrants(assets) quads = build_title_quadrants(assets)
r = wait_or_skip(clock, TITLE_WIPE_SECONDS, r = wait_or_skip(clock, TITLE_WIPE_SECONDS,
lambda t: _blit_centered(render_title_wipe_frame(quads, t))) lambda t: _blit_title(render_title_wipe_frame(quads, t)))
if r == 'quit': if r == 'quit':
return 'quit' return 'quit'
# 'skip' waehrend der Wipe-Animation -> direkt zum fertigen Titelbild # 'skip' waehrend der Wipe-Animation -> direkt zum fertigen Titelbild
title_img = build_title_image(quads) title_img = build_title_image(quads)
draw = lambda _t: _blit_centered(title_img) draw = lambda _t: _blit_title(title_img)
if hold_forever: if hold_forever:
return wait_for_key(clock, draw) return wait_for_key(clock, draw)
return wait_or_skip(clock, 3.0, draw) return wait_or_skip(clock, 3.0, draw)