# Programação com OpenGL/Android GLUT Wrapper

Nosso empacotador(wrapper): Bastidores
Se você planeja escrever seus próprios aplicativos OpenGL ES 2.0, aqui estão algumas dicas de como nosso empacotador(wrapper) funciona:

## Escrevendo código C/C++ para Android

Todos os Aplicativos do Android são escrito em Java, mas você pode chamar códigos em C/C++ usando o JNI (Java Native Interface ), que estão presentes na NDK ( Native Development Kit).
Como você pode fazer isto:
* Escreva um empacotador em Java e C++:
** Disponível a partir do Android 1.5
** O Código C++ pode interagir com um contexto OpenGL ES criado pelo Java
** Para criar um contexto OpenGL ES 2.0 ( com EGL ) diretamente pelo C++ é necessário o Android 2.3/Gingerbread/API android-9
** O OpenGL ES 2.0 está disponível a partir do Android 2.0/API android-5
** Exemplos: na NDK hello-gl2.
* Contando com um "NativeActivity" incorporado ao empacotador Java, e escrevendo apenas em C++:
** Disponivel a partir do Android 2.3/Gingerbread/API android-9
** Use o EGL para criar um contexto OpenGL ES.
** Exemplos na NDK native-activity ( está em OpenGL ES 1.x, mas você pode atualizar ele sem dificuldade)

### Detalhes da Native Activity

O Android 2.3/Gingerbread/API android-9 introduziram o native activities, que permitem escreve um aplicativo sem usar o Java.
Mesmo que o exemplo menciona a API versão 8, colocaremos um 9.
Tambem, certifique-se que esteja assim seu manifest has:
Caso contrário seu aplicativo não iniciará. Seu ponto de entrada será a função android_main(em vez da mais comum que é main ou WinMain) Para uma melhor portabilidade, você pode renomear a versão do pré-processador usando -Dmain=android_main

## Compilador do sistema

O empacotador é baseado no exemplo native-activity, ele usa o código do 'android_native_app_glue' que ofereçe um processamento de eventos non-blocking.
Desde que você não chame diretamente o código glue (seus pontos de entrada são os callbacks usados pelo Android, não o nosso), android_native_app_glue.o ele pode ser retirada pelo compilador, assim vamos chamar seus modelos de pontos de entrada:
Ele usará o OpenGL ES 2.0 (em vez do exemplo em OpenGL Es 1.X):
Para usar o GLM, nós precisaremos ativar o C++ STL:
e mencionar o local aonde foi instalado:
Agora nós vamos declarar nossos arquivo fonte ( tut.cpp ):
para rodar o compilador do sistema:
* Compile o Código em C/C++
* Preparando o compilador Java do sistema (Somente uma vez):
* Criando um pacote .apk:
* E instalando:
* Limpando:
Nós incluiremos todos estes comandos no montador Makefile

## Criando um contexto em OpenGL ES com o EGL

Nós precisamo usar EGL para o OpenGL ES versão 2.0 (não a versão 1.x).
Em primeiro lugar, solicitaremos os contextos disponíveis:
Depois criaremos o contexto:
(Em Java:)
É uma boa prática, mas não é obrigatória, que você de declare os requirementos OpenGL 2.0 no AndroidManifest.xml:
Quando o usuário vai para tela inicial(ou recebe uma chamada), seu aplicativo é pausado, Quando ele volta para o aplicativo, ele continua, mas o contexto OpenGL é perdido, Neste caso, você precisa recarregar todos recursos na GPU (VBOs, texturas e etc...), Existe um evento no Android para detectar se seu aplicativo foi "despausado".
Da mesma forma que quando o usuário precisa o botão voltar, o aplicativo é destruído, mas fica na memória e pode ser reiniciado.
Para nosso empacotador(wrapper), nos consideremos que o aplicativo GLUT não foi desenhado para refazer o contexto OpenGL, muito menos refazer todas as variáveis estaticamente atribuídas. consequentemente o aplicativo sairá completamente enquanto o contexto é perdido, semelhante ao botão fechar dos desktops.

## Eventos no Android

Mesmo que escrevamos um código nativo, nosso aplicativo será iniciado em um processo Java, usando o android.app.NativeActivity oferecido como ativador. que é o processo responsável por receber os eventos do dispositivo e passar para seu aplicativo.
Funcionamento:
* O Android envia um evento para o processo NativeActivity do Java.
* O Activity do Java, chamara todas as funções de callback(chamadas de fundo) (ex: tal como protected void onLowMemory em caso de memória baixa)
* O NativeActivity chamará todas as funções JNI correspondente em seu android_app_NativeActivity(ex: void onLowMemory_native(...)
* O android_app_NativeActivity.cpp chamará as chamadas NativeCode correspondente no android_native_app_glue.c (ex: void onLowMemory(...)
* O android_native_app_glue.c escreve uma messagem através do C como pipe(2) (ex: APP_CMD_LOW_MEMORY, e retornára imediatamente para o processo Java não ficar preso (Senão será oferecido ao usuário que ele seja encerrado)
* Em sua native app, regularmente, checaremos os eventos que estão na fila e as chamadas android_native_app_glue.c process_cmd (ou process_input)
* vamos voltar para o nivel acima em android_native_app_glue.c, Aonde o process_cmd executará um pré evento e um pós evento genérico que intermediaria as chamadas ao nosso aplicativo onAppCmd.
* Voltando ao nosso app, aonde pelo onAppCmd (ex: engine_nandle_cmd) processa os eventos que estão por ultimo!

## Recursos ou Assets

Os aplicativos do Android normalmente extraem os recursos ( como shaders or meshes ) de uma arquivo .apk ( um tipo de arquivo Zip).
* Os recursos estão localizados na sub-pasta res/ (ex. res/layout); Existem funções do Android que carregam eles dependendo do seu tipo.
* Os Assets estão localizados na pasta assets/ e são acessadas por meio de uma estrutura de diretório mais tradicional.
Isto não é comum em aplicativos GLUT, assim vamos fazer os recursos ficarem disponíveis com mais facilidade:
* Usando um wrapper(montador) com fopen/open.
** Carregando com LD_PRELOAD, como em zlibc
* Usando o kernel ptrace hooks
* Redefinindo o fopen do seu arquivo .cpp
* Extraindo os arquivos antecipadamente
A implementação de um montador(wrapper) é tedioso, porque seu aplicativo o chamara por meio da JNI. Isto significa que não podemos apenas fazer um execv de outro aplicativo depois de ajustar o LD_PRELOAD, em vez disto precisamos iniciar um processo filho, antes de todos os eventos do Android, e ajustar um IPC para compartilhar a estrutura de dados do android_app e do ALooper, o ptrace também requer um processo filho.
Redefinindo o fopen localmente podemos trabalhar com a função do C fopen, mas não com a do C++ cout
Pré-extraindo todos os ativadores adicionais exigem um espaço em disco para gravar os arquivos, mas é apenas uma solução razoável.

## Acessando os recursos

Desenvolvedores podem estruturar os acesso ao recursos mais facilmente pela NDK:
* A API do Android: você pode chamar uma função do Java por meio da JNI, mas pegar um descritor do arquivo requer o uso de uma função não-oficial e apenas trabalhar com arquivos descompactados; usaremos um operador de Buffer Java ao invés de um tediosa do C/C++
* libzip: você pode acessar mais facilmente um arquivo .apk com libzip, por isto você precisa integrar a biblioteca ao compilador do sistema.
* API do NDK: no ultimo Android 2.3/Gingerbread/API android-9,tem uma api NDK para acessar os recursos.
Vamos usar a API do NDK, isto não é transparente para o desenvolvedor(sem a substituição do fopen/cout) mas é razoavelmente mais fácil de usar.
O que é um pouco mais complicado é pegar o AssetManager pelo Java/JNI na sua native activity.
Nota: Usaremos um sintaxe levemente simplificada do C++(não é uma sintaxe C) para o JNI.
Primeiro, nosso native activity trabalha com seu próprio segmento, então precisamos de cuidado ao recuperar o JNI handle em android_main:
Então vamos pegar o estado em nossa chamada instanciada NativeActivity:
Então nós decidiremos aonde extrair os arquivos. Então usaremos um cache padrão de diretório:
Nos agora vamos pegar o AssetManager NativeActivity:
Agora a extração é simples: navegaremos pelos arquivos e copiaremos para o disco um por um:
Agora, todos os arquivos podem ser acessados usando um fopen/cout do aplicativo.
Esta tecnica é adaptada por nosso tutorial, mas provavelmente não para um grande aplicativo. Neste caso, você pode usar:
* Requisitar um privilégio de escrita no cartão de memória(SD) para extrair os arquivos nele (é isto que o "port" do SDL no Android faz)
* Usar o wrapper para acessar os seu arquivos que serão usados pelo AssetManager no Android ( cuidado é um acesso somente-leitura)

## Orientações

Pela opção:
Seu aplicativo pode trabalhar apenas no modo portrait, independente do seu dispositivo ou das formas. Isto não é recomendado mas é muito usado em alguns jogos.
Para manusear as orientção mais eficientemente, você teoricamente precisa checar pelo evento onSurfaceChanged. O manuseador onSurfaceChanged_native no montador(wrapper) android_app_NativeActivity.cpp não parece criar o eventoonNativeWindowResized adequadamente na mudança de orientação, Então vamos monitora-lo regularmente:
Agora nos podemos processar o evento:
Nota: é possivel processar pelo evento APP_CMD_CONFIG_CHANGED, mas isto só acontece depois que tela é redimensionada, isto é muito cedo para pegar o novo tamanho da tela.
O Android pode apenas detectar o nova resolução e depois da troca de buffer, então vamos abusar de outra hook(uma chamada própria no lugar da chamada do original sistema) para obter o evento de redimensionamento:

## Eventos de entrada do dispositivo

Nós reusaremos a função engine_handle_input para este exemplo do native-activity.
É importante ter o return 0 enquanto o evento não é diretamente manuseável, para que o sistema Android faça isto, para instanciá-lo nos comummente deixaremos o Android cuidar do botão de retorno(back).
O framework NativeActivity parece não enviar apropriadamente os eventos de repetição: A tecla é pressionada e despressionada exatamente ao mesmo tempo, e a conta de repetição é sempre 0, Consequentemente não é parece possivel processar as setas do Hacker´s Keyboard sem rescrever parte da framework.
Movimentação (touchscreen) e eventos do teclado são manuseados apenas pelo mesmo canal.
Para acompanhar o usuario quando ele sai do teclas para usar as setas do teclado, nos implementaremos um virtual keypad(VPAD), localizado no canto inferior esquerdo, ativando a touchscreen. O esforço foi feito para evitar a mistura de um evento VPAD e um evento de movimentação e vice-versa.

## Referencia

* ↑ Esta é a técnica usada pelo SDL para o Windows WinMain.