Portar Quake a Game Boy Advance hubiera parecido imposible, pero Randy Linden logró lograrlo. Así es cómo.
Game Boy Advance es una consola de juegos portátil creada por Nintendo. Fue lanzado en Japón en 2001 y sirvió como sucesor de Game Boy Color. Tenía un ARM7TDMI con frecuencia de 16,78 MHz, 32 kb de RAM de trabajo interna, 256 kb de RAM externa y 96 kb de VRAM. No es la máquina más poderosa, pero hay muchos juegos para la computadora de mano que muchos guardan en la memoria con cariño. Sin embargo, un juego que nunca vio la luz para el dispositivo fue un prototipo de Quake, un juego desarrollado por id Software que ayudó a definir el género de disparos en primera persona que conocemos hoy.
Quake es un juego increíblemente detallado con una banda sonora fantástica y una jugabilidad adictiva y, al igual que DOOM, se ha adaptado a prácticamente todos los dispositivos que puedas imaginar. Su adaptación a Game Boy Advance es particularmente increíble ya que no admite gráficos 3D de forma nativa, y Nintendo comercializó específicamente la computadora de mano como una experiencia de juego bidimensional. Sin embargo, eso no impidió que Randy Linden desarrollara su propio puerto.
Si no estás familiarizado con Linden, ¡es mejor conocido por ser el desarrollador de ambos bleem! (un emulador de PlayStation) y la versión SNES de DOOM, un logro que John Romero, cofundador de id Software, dijo una vez en una entrevista con Shacknews no creía que fuera posible. La habilidad de desarrollo de Linden demostró que si alguien iba a poder hacer realidad Quake en Game Boy Advance, probablemente era él.
Este port ha salido a la luz gracias al lanzamiento del mismo por parte del propio Linden a través del proyecto Forest of Illusion. Forest of Illusion es un proyecto destinado a preservar la historia de los juegos de Nintendo y Linden se acercó para distribuir la copia del puerto Quake que encontró en una tarjeta flash de 256 MB en su posesión.
Nos gustaría agradecer a Randy Linden por dedicar tiempo a responder nuestras preguntas y garantizar la precisión técnica de este artículo. También nos gustaría agradecer Jugador vintage moderno por permitirnos usar las imágenes fijas de su video que fueron necesarias. Este puerto no tiene relación oficial con id Software o ZeniMax y fue desarrollado como un proyecto en solitario por Linden.
Puerto Game Boy Advance de Quake
Técnicamente hablando, es una maravilla que Quake pueda llegar al nivel que lo hace en Game Boy Advance. Funciona a una buena velocidad de fotogramas y mantiene la iluminación y la paleta de colores correctas del juego Quake original. Todo es 3D, incluidas las armas y los monstruos. Los juegos de Game Boy Advance lograban gráficos en 3D normalmente a través de sprites, pero este era el verdadero problema. No utiliza ray casting como lo hacían otros juegos 3D en la computadora de mano, e incluso logra un punto efectos de iluminación en objetos prerenderizados a través de un truco de cambio de paleta para lograr una ilusión de dinámica Encendiendo.
Para ser claros, este port no es el juego completo, y es un prototipo que Linden pretendía llevar a id Software una vez que estuviera terminado para su lanzamiento. Sin embargo, la popularidad de Game Boy Advance comenzó a decaer y, en cambio, el motor personalizado escrito por Linden se convirtió más tarde en el motor de otro juego desarrollado íntegramente por Linden: Cyboid. Linden nos dice que una "gran parte del código" sigue siendo el código ARM original de la versión de Game Boy Advance. Si desea probar Cyboid, hay una versión anterior disponible en Google Play Store, pero el APK oficial ahora se distribuye en Tienda de aplicaciones de Amazon ya que el juego tiene una gran cantidad de código de 32 bits de bajo nivel.
Precio: Gratis.
3.3.
Linden también compartió con nosotros un vídeo de su código ejecutándose en el iPod Video, que sirvió como una de las primeras versiones de Cyboid. Fue construido con el mismo código de motor que se usó para su adaptación de Quake a Game Boy Advance.
La versión de Quake para Game Boy Advance no contiene ninguno de los activos oficiales del juego, como Linden no. contacté a id Software o ZeniMax para distribuir la versión E1M1 que contiene Quake oficial activos.
El juego que se distribuye actualmente también es una versión de depuración. Mantener presionada la tecla R al iniciar llevará al jugador directamente al segundo mapa del juego, y mantener presionada la tecla D hacia la izquierda lo llevará al tercero. También se puede acceder al intercambio de mapas cuando el jugador muere, y los monstruos no atacarán al jugador hasta que éste les dispare primero.
En cuanto a la música, la demostración utiliza archivos públicos .S3M y el mezclador de sonido maneja tanto música estéreo como efectos de sonido.
Límites técnicos
Había una serie de límites en lo que respecta a Game Boy Advance que hacían que este fuera un puerto difícil. Algunos de los mayores obstáculos fueron la baja velocidad del reloj, la falta de capacidades de gráficos 3D de la computadora de mano y la falta de una unidad de punto flotante (FPU). Hubo muchos otros en el camino, pero estos fueron puntos débiles particulares que Linden me describió como problemáticos. Antes de entrar en materia, es importante comprender el diseño de Game Boy Advance.
Game Boy Advance tiene tres conjuntos de RAM: uno es la RAM de trabajo interna (IWRAM), otro es la RAM de trabajo externa (EWRAM) y el tercero es la RAM de video (VRAM). Los 32 kb de IWRAM se utilizan para almacenar instrucciones ARM para una ejecución rápida, mientras que los 256 kb de EWRAM son óptimos para almacenar instrucciones de solo pulgar y fragmentos de datos más pequeños. Como Notas de Rodrigo Copetti, el acceso a EWRAM puede ser hasta seis veces más lento que a IWRAM. Sólo se puede acceder a la mayor parte de la memoria en forma de EWRAM a través de un bus de 16 bits, a pesar de que Game Boy Advance se comercializa como una computadora de mano de 32 bits. Se puede acceder a la IWRAM a través de un bus de 32 bits. La VRAM en Game Boy Advance tiene 96 kb y, si bien es principalmente para almacenar datos gráficos, se encuentra en el mapa de memoria de la CPU y también se puede usar como almacenamiento de memoria normal.
Las instrucciones de pulgar son un subconjunto de instrucciones ARM de 32 bits y son un conjunto de instrucciones codificadas en palabras de 16 bits. Tienen todos los beneficios de las instrucciones de 32 bits sin ocupar tanto espacio, lo que las hace eficientes para un desarrollo optimizado. Esto significa que, si bien el acceso a EWRAM es más lento, las instrucciones Thumb que son eficientes a menudo pueden terminar tan rápidas como las instrucciones ARM almacenadas. en IWRAM, aunque la desventaja de las instrucciones Thumb es que a veces no existe el equivalente Thumb de una instrucción ARM que desea ejecutar. La EWRAM se usó para almacenar la salida de la lógica de transformación matemática 3D, que era básicamente la lista de bordes de polígonos que luego se trazaban línea por línea de exploración mediante el código de rasterización.
Como me dice Linden, la parte más compleja y difícil de todo el port fue el renderizador de línea de escaneo. Consta de más de 10.000 líneas de código ensamblador ARM altamente optimizado que está diseñado para dibujar un conjunto de píxeles en VRAM. El renderizador scanline consumió la mayor parte de la IWRAM de 32 kb. Los bordes más cercanos a la cámara están activos y renderizados, y es esencialmente un gran árbol de partición de espacio binario (BSP). Se usó VRAM para almacenar los resultados de la transformación poligonal en tablas de borde porque no había suficiente IWRAM, pero la VRAM en Game Boy Advance es aún más rápida que la EWRAM. Los gráficos también se almacenaron y mostraron aquí.
Dedicó mucho tiempo a centrarse en las optimizaciones para garantizar que pudiera obtener el tiempo de ejecución más rápido posible. Tres cosas que hizo para acelerar el tiempo de ejecución incluyeron las siguientes:
- Automodificó el código antes de ejecutarlo, por lo que se requirieron menos instrucciones.
- Usó una serie de tablas de búsqueda para cosas como recíproco, seno, coseno, tangente, etc.
- Se cambió el "modo" de la CPU para obtener acceso a registros adicionales (que son como "variables") sin tener que guardar y restaurar los valores de los registros.
Cambiar los modos de la CPU para obtener registros adicionales es una maniobra increíblemente inteligente que permite un acceso rápido a valores cercanos a la CPU para que puedan recuperarse en un solo ciclo de reloj. Como me dice Linden, era posible cambiar registros y recuperar un valor en un ciclo de reloj, en lugar de almacenar un valor en la RAM de Game Boy Advance, lo que lleva más tiempo. La CPU en sí es un procesador de 16,78 MHz, lo que significa que puede completar 16780000 ciclos por segundo. Eso parece mucho, pero cuando necesitas calcular y dibujar cada píxel en la pantalla, se acumulan rápidamente y se vuelve importante reducir tantas operaciones como sea posible.
Lo anterior es la lista de registros generales del chipset ARM7TDMI que se encuentra dentro de Game Boy Advance. Normalmente, los desarrolladores sólo accederían a los registros dentro del modo "Sistema y Usuario" y recurrirían al uso de variables normales fuera de ese. Sin embargo, utilizó registros en los siete modos del chipset, y lo mejor de todo es que Los modos de conmutación aún conservan los valores en los registros de los otros modos, por lo que podría cambiar entre a ellos.
Curiosamente, Linden también mencionó cómo su método de cambio de banco descubrió un error en el emulador Nanoboy Advance. Al final resultó que, ese emulador no admitía el uso de otros modos de la CPU para guardar registros y cambiar, y su demostración de Quake fue el primer juego conocido que realmente lo hizo.
Linden compartió con nosotros una foto de algunas de las notas que creó y explicó cómo optimizó sus cálculos de punto flotante en ausencia de una FPU adecuada.
La imagen de arriba es una que Linden compartió con nosotros a partir de sus notas, y lo que es particularmente interesante son los "recuentos diversos de instrucciones de ciclo ARM". Ideó una forma de optimizar los ciclos de los cálculos para poder reducir el número de ciclos de reloj para un cálculo. Como me lo describió, un número de 8 bits se podía multiplicar en un ciclo de reloj, un número de 16 bits en dos ciclos de reloj, un número de 32 bits en tres ciclos de reloj y un número de 64 bits en cuatro ciclos de reloj. .
"Hubo dos o tres etapas de ejecución [en el procesador ARM]. Digamos, por ejemplo, que multiplico el registro uno por el registro dos y pongo el resultado en el registro tres. Si supiera que el registro dos es un número de 16 bits en lugar de decir multiplicar el registro uno por el registro dos, Lo voltearía y diría que multiplica el registro dos por el registro uno porque eso me ahorraría un reloj. ciclo."
Me dijo que la razón por la que hizo esto fue para exprimir al máximo el rendimiento de Game Boy. Avance, ya que un ciclo de reloj guardado aquí y allá realmente suma cuando se realizan muchos cálculos. realizado. En cuanto al código automodificable, le pedí a Linden que lo explicara.
"El programa proviene del [almacenamiento], transfiere un gran bloque del programa a la RAM interna para su ejecución porque es más rápido. Cada acceso a la RAM es mucho, mucho más lento, así que hago un DMA [Acceso directo a la memoria] de un bloque grande de la ROM a la RAM y luego cambio el código del programa real. Por ejemplo, ARM tiene la capacidad de desplazar operandos hacia la izquierda o hacia la derecha o puede enmascarar ciertos bits como parte del conjunto de instrucciones. La instrucción especifica qué bits vas a enmascarar o cuántos bits vas a desplazar. Entonces, generaría código que modificaría lo que estaba a punto de ejecutarse en función de cuántos bits necesitaba cambiar. Otro ejemplo es el de la multiplicación de matrices 3D. Hay un montón de multiplicaciones involucradas allí. Generaría las instrucciones reales que hacen las multiplicaciones en la RAM interna y luego las ejecutaría para que el código construyera partes de sí mismo mientras se ejecuta".
El código que se modifica automáticamente tiene sus propias desventajas, en particular cuando se trata de depuración. También elimina la necesidad de instrucciones de bifurcación, donde el código saltaría a otra secuencia de ejecución y puede privar al hilo principal de un valioso tiempo de cálculo. Linden también nos dijo que las tablas de búsqueda están perfectamente alineadas en la ROM, de modo que son un múltiplo perfecto de un valor de ocho bits desplazado hacia la izquierda. El tamaño de la tabla de búsqueda es inmenso y no cabe en la RAM, y la alineación también evita la necesidad de una instrucción de carga adicional para obtener la dirección base de la tabla.
En total, el prototipo final se desarrolló durante casi dos años.
El futuro del puerto Quake de Randy Linden
Le pregunté a Linden qué pasaría con el futuro del puerto de Quake y me dijo que estaba poniendo consideración para preguntar a ZeniMax e id Software sobre el lanzamiento de la versión con Quake oficial activos. También me dijo que en algún momento publicará el código fuente, pero actualmente no se compila porque requiere una computadora más antigua.
Le pregunté a Linden por qué eligió Quake y me dijo que le encantaba el juego y le encantaba el desafío de ser un "proyecto imposible", ya que estaba en la parte posterior de su port de DOOM para SNES. También mencionó que si bien no cree que todo el juego pudiera haber sido portado debido a limitaciones de espacio, la gran mayoría del juego podría haber estado en el mismo motor.
Si estás interesado en probar Quake para Game Boy Advance, asegúrate de consultar su lanzamiento en Forest of Illusion, que puedes consultar a continuación.
Descargar del Bosque de la Ilusión