⚠️ Clean-Room / Educativo

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

Fecha: 2025-12-22 Step ID: 0216 Estado: DRAFT

Resumen

El análisis de los datos del Step 0215 es concluyente. Hemos aislado el problema con precisión quirúrgica:

  1. C++ (PPU): Genera píxeles con valor 3 (Correcto, es negro).
  2. Cython (Puente): Transfiere el valor 3 intacto a Python (Correcto).
  3. Python (BGP): El registro tiene el valor 0xE4 (Correcto, paleta estándar).
  4. 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:

  1. El pipeline de datos funciona correctamente.
  2. El renderer está aplicando la paleta correctamente.
  3. 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:

  1. En el método que usa el framebuffer C++ (líneas ~467-472).
  2. 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:

  1. El pipeline de datos funciona correctamente (C++ → Cython → Python).
  2. El renderer está aplicando la paleta correctamente.
  3. El problema era simplemente la definición de colores base.

Próximos pasos después de confirmar el rojo:

  1. Eliminar el hack del rojo (if color_idx == 3: ...).
  2. Eliminar el hack de las rayas en C++ (Step 0212).
  3. Eliminar el hack de byte=0xFF en C++ (Step 0209).
  4. ¡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