Este proyecto es educativo y Open Source. No se copia código de otros emuladores. Implementación basada únicamente en documentación técnica y tests permitidas.
Paleta Debug: El Test del Rojo
Resumen
El análisis de los datos del Step 0215 es concluyente. Hemos aislado el problema con precisión quirúrgica:
- C++ (PPU): Genera píxeles con valor
3(Correcto, es negro). - Cython (Puente): Transfiere el valor
3intacto a Python (Correcto). - Python (BGP): El registro tiene el valor
0xE4(Correcto, paleta estándar). - Pantalla: Muestra BLANCO.
La Deducción Lógica:
Si la entrada del renderer es 3 y el registro BGP 0xE4 dice que el índice 3 debe mapearse al Color 3... entonces tu definición del "Color 3" en renderer.py es BLANCO.
Solución: Corregimos la definición de colores en renderer.py y, para estar 100% seguros, hacemos que el Color 3 sea ROJO temporalmente. Si vemos rayas rojas, habremos ganado la guerra contra la pantalla blanca.
Concepto de Hardware: La Paleta de Colores de Game Boy
La Game Boy original usa una paleta de 4 tonos de gris/verde que se mapean a índices de color (0-3). El registro BGP (Background Palette, 0xFF47) define cómo se mapean estos índices a los colores reales.
Paleta estándar de Game Boy:
- Color 0: Blanco/Verde claro (224, 248, 208) - El más claro
- Color 1: Gris claro (136, 192, 112) - Gris claro
- Color 2: Gris oscuro (52, 104, 86) - Gris oscuro
- Color 3: Negro/Verde oscuro (8, 24, 32) - El más oscuro
El problema de inversión:
Si la definición de colores en el código Python está invertida o mal definida, el índice 3 (que debería ser negro) se renderizará como blanco. Esto es exactamente lo que está ocurriendo: el pipeline funciona correctamente (C++ envía 3, Python recibe 3, BGP es 0xE4), pero la pantalla es blanca.
El Test del Rojo:
Para confirmar visualmente que tenemos control sobre el mapeo final, forzamos temporalmente que el índice 3 se renderice como ROJO (255, 0, 0). Si vemos rayas rojas en la pantalla, significa que:
- El pipeline de datos funciona correctamente.
- El renderer está aplicando la paleta correctamente.
- El problema era simplemente la definición de colores base.
Fuente: Pan Docs - Background Palette Register (BGP), LCD Control Register.
Implementación
Se implementaron las siguientes modificaciones en src/gpu/renderer.py:
1. Definición Explícita de Colores en __init__
Se añadió una definición explícita de los colores base de Game Boy y una paleta mapeada:
# --- FIX STEP 0216: Definición Explícita de Colores ---
# Game Boy original: 0=Más claro, 3=Más oscuro
# Paleta estándar de Game Boy (verde/amarillo original)
self.COLORS = [
(224, 248, 208), # 0: Blanco/Verde claro (White)
(136, 192, 112), # 1: Gris claro (Light Gray)
(52, 104, 86), # 2: Gris oscuro (Dark Gray)
(8, 24, 32) # 3: Negro/Verde oscuro (Black)
]
# Paleta actual mapeada (índice -> RGB)
self.palette = list(self.COLORS)
# Flag para log de depuración (una sola vez)
self.debug_palette_printed = False
# ----------------------------------------
2. Corrección de Decodificación de Paleta BGP
Se modificó la decodificación de paleta BGP para usar los colores explícitos y añadir el debug visual con rojo:
# Decodificar paleta BGP (cada par de bits representa un color 0-3)
# --- FIX STEP 0216: Usar COLORS explícitos y debug visual ---
palette = [None] * 4
for i in range(4):
color_idx = (bgp >> (i * 2)) & 0x03
palette[i] = self.COLORS[color_idx]
# --- DEBUG VISUAL STEP 0216 ---
# Si el índice final es 3 (Negro), lo forzamos a ROJO
# para confirmar visualmente que estamos pintando lo que queremos.
if color_idx == 3:
palette[i] = (255, 0, 0) # ROJO FUERTE
# -----------------------------
# Log de diagnóstico (una sola vez si cambia BGP o es el primer frame)
if not self.debug_palette_printed:
print(f"\n--- [RENDERER PALETTE DEBUG] ---")
print(f"BGP Raw: 0x{bgp:02X}")
print(f"Mapping:")
for i in range(4):
base_color_idx = (bgp >> (i * 2)) & 0x03
print(f" Index {i} -> BaseColor {base_color_idx} -> RGB {palette[i]}")
print(f"--------------------------------\n")
self.debug_palette_printed = True
# ----------------------------------------
Esta modificación se aplicó en dos lugares:
- En el método que usa el framebuffer C++ (líneas ~467-472).
- En el método Python original (líneas ~593-598).
Tests y Verificación
Comando ejecutado:
python main.py roms/tetris.gb
Resultado esperado:
- Se debe ver rayas verticales ROJAS y blancas en la pantalla.
- El log de depuración debe mostrar el mapeo de paleta con el índice 3 mapeado a ROJO.
Validación:
Si vemos rojo, significa que:
- El pipeline de datos funciona correctamente (C++ → Cython → Python).
- El renderer está aplicando la paleta correctamente.
- El problema era simplemente la definición de colores base.
Próximos pasos después de confirmar el rojo:
- Eliminar el hack del rojo (
if color_idx == 3: ...). - Eliminar el hack de las rayas en C++ (Step 0212).
- Eliminar el hack de
byte=0xFFen C++ (Step 0209). - ¡Y veremos el Tetris!
Archivos Afectados
src/gpu/renderer.py- Corrección de definición de colores y debug visual con rojo
Referencias
- Pan Docs - Background Palette Register (BGP)
- Pan Docs - LCD Control Register
- Step 0215 - Corrección de Paleta: ¿Por qué el Negro es Blanco?
- Step 0212 - Test Rotulador Negro
- Step 0209 - Diagnóstico Radical: Forzar Color Negro