Portar Quake para o Game Boy Advance teria parecido impossível, mas Randy Linden conseguiu. Veja como.
O Game Boy Advance é um console de jogos portátil criado pela Nintendo. Foi lançado no Japão em 2001 e serviu como sucessor do Game Boy Color. Ele tinha um ARM7TDMI com clock de 16,78 MHz, 32kb de RAM de trabalho interna, 256kb de RAM externa e 96kb de VRAM. Não é a máquina mais poderosa, mas há muitos jogos para dispositivos portáteis que muitos guardam na memória. Um jogo que nunca viu a luz do dia para o dispositivo foi um protótipo de Quake, um jogo desenvolvido pela id Software que ajudou a definir o gênero de tiro em primeira pessoa que conhecemos hoje.
Quake é um jogo incrivelmente detalhado com uma trilha sonora fantástica e jogabilidade viciante e, assim como DOOM, foi portado para praticamente todos os dispositivos que você possa imaginar. Sua portabilidade para o Game Boy Advance é particularmente incrível, pois não suporta nativamente gráficos 3D, e a Nintendo comercializou especificamente o portátil como sendo uma experiência de jogo bidimensional. Isso não impediu Randy Linden de desenvolver seu próprio porte.
Se você não conhece Linden, ele é mais conhecido por ser o desenvolvedor de ambos os bleem! (um emulador de PlayStation) e a versão SNES de DOOM, uma conquista que John Romero, cofundador da id Software, disse certa vez em entrevista ao Notícias de share-rss ele não achava que fosse possível. A proficiência de desenvolvimento de Linden provou que se alguém fosse capaz de tornar Quake no Game Boy Advance uma realidade, provavelmente seria ele.
Esta porta veio à tona graças ao lançamento da própria Linden por meio do projeto Forest of Illusion. Forest of Illusion é um projeto que visa preservar a história dos jogos da Nintendo, e Linden entrou em contato para distribuir a cópia da versão Quake que ele encontrou em um cartão flash de 256 MB em seu posse.
Gostaríamos de agradecer a Randy Linden por dedicar seu tempo respondendo às nossas perguntas e garantindo a precisão técnica deste artigo. Gostaríamos também de agradecer Jogador vintage moderno por nos permitir usar quaisquer fotos de seu vídeo que fossem necessárias. Esta porta não tem relação oficial com a id Software ou ZeniMax e foi desenvolvida como um projeto solo por Linden.
Versão Game Boy Advance de Quake
Tecnicamente falando, é uma maravilha que Quake possa atingir o nível que atinge no Game Boy Advance. Ele funciona com uma boa taxa de quadros e mantém a iluminação e a paleta de cores corretas do jogo Quake original. Tudo é 3D, incluindo armas e monstros. Os jogos no Game Boy Advance alcançavam gráficos 3D normalmente por meio de sprites, mas esse era o verdadeiro negócio. Ele não faz uso de projeção de raios como outros jogos 3D faziam no portátil e até atinge pontos efeitos de iluminação em objetos pré-renderizados por meio de um truque de mudança de paleta para obter uma ilusão de dinâmica iluminação.
Para ser claro, esta versão não é o jogo completo, e é um protótipo que Linden pretendia levar para a id Software assim que fosse concluído para ser lançado. No entanto, a popularidade do Game Boy Advance começou a diminuir e, em vez disso, o motor personalizado escrito por Linden mais tarde se tornou o motor de outro jogo inteiramente desenvolvido por Linden - Cyboid. Linden nos diz que “uma grande parte do código” ainda é o código ARM original da versão Game Boy Advance. Se você quiser experimentar o Cyboid, uma versão mais antiga está disponível na Google Play Store, mas o APK oficial agora está distribuído no Loja de aplicativos da Amazon já que o jogo tem muito código de 32 bits de baixo nível.
Preço: Grátis.
3.3.
Linden também compartilhou conosco um vídeo de seu código rodando no iPod Video, que serviu para ser uma das primeiras versões do Cyboid. Ele foi construído no mesmo código de mecanismo usado em sua versão Quake para o Game Boy Advance.
A versão de Quake para Game Boy Advance não contém nenhum dos recursos oficiais do jogo, já que Linden não entrou em contato com a id Software ou ZeniMax sobre a distribuição da versão E1M1 que contém Quake oficial ativos.
O jogo atualmente sendo distribuído também é uma versão de depuração. Manter pressionada a tecla R na inicialização levará o jogador direto para o segundo mapa do jogo, e segurar a tecla esquerda no D-pad o levará para o terceiro. A troca de mapas também pode ser acessada quando o jogador morre, e os monstros não atacarão o jogador até que o jogador atire neles primeiro.
Quanto à música, a demo utiliza arquivos públicos .S3M e o mixer de som lida com música estéreo e efeitos sonoros.
Limites técnicos
Havia uma série de limites no que diz respeito ao Game Boy Advance que tornavam este porte difícil. Alguns dos maiores obstáculos foram a baixa velocidade do clock, a falta de recursos gráficos 3D do portátil e a falta de uma unidade de ponto flutuante (FPU). Houve muitos outros ao longo do caminho, mas esses foram pontos específicos que Linden descreveu para mim como problemáticos. Antes de entrarmos nisso, é importante entender o layout do Game Boy Advance.
O Game Boy Advance possui três conjuntos de RAM – um é a RAM de trabalho interna (IWRAM), outro é a RAM de trabalho externa (EWRAM) e o terceiro é a RAM de vídeo (VRAM). Os 32kb de IWRAM são usados para armazenar instruções ARM para execução rápida, enquanto os 256kb de EWRAM são ideais para armazenar instruções somente Thumb e pedaços menores de dados. Como Rodrigo Copetti observa, o acesso à EWRAM pode ser até seis vezes mais lento que o IWRAM. A maior parte da memória na forma de EWRAM só é acessível através de um barramento de 16 bits, apesar do Game Boy Advance ser comercializado como um portátil de 32 bits. O IWRAM pode ser acessado através de um barramento de 32 bits. A VRAM no Game Boy Advance chega a 96kb e, embora seja principalmente para armazenar dados gráficos, é encontrada no mapa de memória da CPU e também pode ser usada como armazenamento de memória normal.
As instruções Thumb são um subconjunto de instruções ARM de 32 bits e são um conjunto de instruções codificadas em palavras de 16 bits. Eles têm todos os benefícios das instruções de 32 bits sem ocupar muito espaço, tornando-os eficientes para um desenvolvimento otimizado. Isso significa que, embora o acesso ao EWRAM seja mais lento, as instruções Thumb sendo eficientes muitas vezes ainda podem acabar tão rápidas quanto as instruções ARM armazenadas. no IWRAM, embora a desvantagem das instruções Thumb seja que às vezes não existe exatamente o equivalente Thumb de uma instrução ARM que você deseja executar. A EWRAM foi usada para armazenar a saída da lógica de transformação matemática 3D, que era basicamente a lista de arestas poligonais que foram então traçadas linha de varredura por linha de varredura pelo código de rasterização.
Como Linden me disse, a parte mais complexa e difícil de todo o port foi o renderizador scanline. Ele consiste em mais de 10.000 linhas de código assembly ARM altamente otimizado, projetado para desenhar um conjunto de pixels para VRAM. O renderizador scanline consumiu a maior parte da IWRAM de 32kb. As bordas mais próximas da câmera são ativas e renderizadas, e é essencialmente uma grande árvore Binary Space Partitioning (BSP). A VRAM foi usada para armazenar os resultados da saída da transformação poligonal em tabelas de borda porque não havia IWRAM suficiente, mas a VRAM no Game Boy Advance ainda é mais rápida que a EWRAM. Os gráficos também foram armazenados e exibidos aqui.
Ele passou muito tempo focando em otimizações para garantir que conseguisse obter o tempo de execução mais rápido possível. Três coisas que ele fez para acelerar o tempo de execução incluíram o seguinte:
- Modificou automaticamente o código antes de ser executado, portanto, menos instruções foram necessárias
- Usei uma série de tabelas de consulta para coisas como recíproco, seno, cosseno, tangente, etc.
- Mudou o "modo" da CPU para obter acesso a registros adicionais (que são como "variáveis") sem ter que salvar e restaurar os valores dos registros.
Alternar os modos da CPU para obter registros adicionais é uma manobra incrivelmente inteligente que permite acesso rápido a valores próximos à CPU para que possam ser recuperados em um único ciclo de clock. Como Linden me disse, era possível trocar de registro e recuperar um valor em um ciclo de clock, em vez de armazenar um valor na RAM do Game Boy Advance, que leva mais tempo. A CPU em si é um processador de 16,78 MHz, o que significa que pode completar 1.678.0000 ciclos por segundo. Parece muito, mas quando você precisa calcular e desenhar cada pixel na tela, eles se somam rapidamente e se torna importante eliminar o máximo de operações possível.
Acima está a lista de registros gerais do chipset ARM7TDMI que está dentro do Game Boy Advance. Normalmente, os desenvolvedores só acessariam os registros dentro do modo "Sistema e Usuário" e recorreriam ao uso de variáveis normais fora dele. Porém, ele fez uso de registros em todos os sete modos do chipset, e o melhor é que os modos de comutação ainda retêm os valores nos registros dos outros modos, então ele poderia alternar entre eles.
Curiosamente, Linden também mencionou como seu método de troca de banco descobriu um bug no emulador Nanoboy Advance. Acontece que aquele emulador não suportava o uso de outros modos da CPU para salvar registros e comutação, e sua demo Quake foi o primeiro jogo conhecido a realmente fazer isso.
Linden compartilhou conosco uma foto de algumas das notas que ele criou e explicou como otimizou seus cálculos de ponto flutuante na ausência de uma FPU adequada.
A imagem acima é aquela que Linden compartilhou conosco a partir de suas anotações, e o que é particularmente interessante são as "contagens diversas de instruções do ciclo ARM". Ele desenvolveu uma maneira de otimizar os ciclos de cálculo para poder reduzir o número de ciclos de clock para um cálculo. Conforme ele me descreveu, um número de 8 bits poderia ser multiplicado em um ciclo de clock, um número de 16 bits em dois ciclos de clock, um número de 32 bits em três ciclos de clock e um número de 64 bits em quatro ciclos de clock. .
“Havia dois ou três estágios de execução [no processador ARM]. Digamos, por exemplo, que eu multiplique o registro um pelo registro dois e coloque o resultado no registro três. Se eu soubesse que o registrador dois era um número de 16 bits, em vez de dizer multiplicar o registrador um pelo registrador dois, eu eu viraria e eu diria multiplicar o registro dois pelo registro um porque isso me pouparia um tempo ciclo."
Ele me disse que a razão pela qual fez isso foi para extrair todo o desempenho do Game Boy Avance, pois um ciclo de clock salvo aqui e ali realmente faz sentido quando muitos cálculos estão sendo realizado. Quanto ao código automodificável, pedi a Linden que o explicasse.
“O programa vem [do armazenamento], ele transfere um grande bloco do programa para a RAM interna para execução porque é mais rápido. Cada acesso à RAM é muito, muito mais lento, então eu faço um DMA [Acesso Direto à Memória] de um grande bloco da ROM para a RAM e depois altero o código real do programa. Por exemplo, o ARM tem a capacidade de deslocar os operandos para a esquerda ou para a direita ou pode mascarar certos bits como parte do conjunto de instruções. A instrução especifica quais bits você irá mascarar ou por quantos bits você irá mudar. Então, eu geraria um código que modificaria o que estava prestes a ser executado com base em quantos bits eu precisava mudar. Outro exemplo é com relação à multiplicação de matrizes 3D. Há um monte de multiplicações envolvidas aí. Eu geraria as instruções reais que estão fazendo as multiplicações na RAM interna e depois as executaria para que o código construísse partes de si mesmo enquanto estava em execução."
O código automodificável tem suas próprias desvantagens, principalmente quando se trata de depuração. Ele também elimina a necessidade de instruções de desvio, onde o código pularia para outra sequência de execução e poderia privar o thread principal de um precioso tempo de computação. Linden também nos disse que as tabelas de consulta estão perfeitamente alinhadas na ROM, de modo que são um múltiplo perfeito de um valor de oito bits deslocado para a esquerda. O tamanho da tabela de consulta é imenso e não cabe na RAM, e o alinhamento também evita a necessidade de uma instrução de carregamento extra para obter o endereço base da tabela.
Ao todo, o protótipo final foi desenvolvido ao longo de quase dois anos.
O futuro do porto Quake de Randy Linden
Perguntei a Linden o que aconteceria com o futuro do porto Quake, e ele me disse que estava colocando considere perguntar à ZeniMax e à id Software sobre o lançamento da versão oficial do Quake ativos. Ele também me disse que em algum momento lançará o código-fonte, mas atualmente ele não é compilado porque requer um computador mais antigo.
Perguntei a Linden por que ele escolheu Quake, e ele me disse que adorou o jogo e adorou o desafio de ser o “projeto impossível”, já que estava na parte de trás de sua versão DOOM para SNES. Ele também mencionou que embora não acredite que todo o jogo possa ter sido portado devido a restrições de espaço, a grande maioria do jogo poderia ter sido no mesmo motor.
Se você estiver interessado em conferir Quake para Game Boy Advance, não deixe de conferir o lançamento dele no Forest of Illusion, que você pode conferir abaixo.
Baixe da Floresta da Ilusão