Programação com OpenGL/Android GLUT Wrapper: diferenças entre revisões

[edição verificada][revisão pendente]
Conteúdo apagado Conteúdo adicionado
m <source> -> <syntaxhighlight> (phab:T237267)
 
Linha 23:
 
Mesmo que o exemplo menciona a API versão <code>8</code>, colocaremos um <code>9</code>.
<sourcesyntaxhighlight lang="xml">
<uses-sdk android:minSdkVersion="9" />
</syntaxhighlight>
</source>
Tambem, certifique-se que esteja assim seu manifest has:
<sourcesyntaxhighlight lang="xml">
<application ...
android:hasCode="true"
</syntaxhighlight>
</source>
Caso contrário seu aplicativo não iniciará.
Seu ponto de entrada será a função <code>android_main</code>(em vez da mais comum que é <code>main</code> ou <code>WinMain</code>)
Linha 38:
 
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.
<sourcesyntaxhighlight lang="make">
<!-- Android.mk -->
LOCAL_STATIC_LIBRARIES := android_native_app_glue
...
$(call import-module,android/native_app_glue)
</syntaxhighlight>
</source>
 
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), <code>android_native_app_glue.o</code> ele pode ser retirada pelo compilador, assim vamos chamar seus modelos de pontos de entrada:
<sourcesyntaxhighlight lang="cpp">
// Certifique que o glue foi retirado.
app_dummy();
</syntaxhighlight>
</source>
Ele usará o OpenGL ES 2.0 (em vez do exemplo em OpenGL Es 1.X):
<sourcesyntaxhighlight lang="xml">
<!-- Android.mk -->
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2
</syntaxhighlight>
</source>
 
Para usar o GLM, nós precisaremos ativar o C++ STL:
<sourcesyntaxhighlight lang="xml">
<!-- Application.mk -->
APP_STL := gnustl_static
</syntaxhighlight>
</source>
e mencionar o local aonde foi instalado:
<sourcesyntaxhighlight lang="xml">
<!-- Android.mk -->
LOCAL_CPPFLAGS := -I/usr/src/glm
</syntaxhighlight>
</source>
 
Agora nós vamos declarar nossos arquivo fonte ( tut.cpp ):
<sourcesyntaxhighlight lang="xml">
<!-- Android.mk -->
LOCAL_SRC_FILES := main.c GL/glew.c tut.cpp
</syntaxhighlight>
</source>
 
para rodar o compilador do sistema:
* Compile o Código em C/C++
<sourcesyntaxhighlight lang="bash">
ndk-build NDK_DEBUG=1 V=1
</syntaxhighlight>
</source>
* Preparando o compilador Java do sistema (Somente uma vez):
<sourcesyntaxhighlight lang="bash">
android update project --name wikibooks-opengl --path . --target "android-10"
</syntaxhighlight>
</source>
* Criando um pacote .apk:
<sourcesyntaxhighlight lang="bash">
ant debug
</syntaxhighlight>
</source>
* E instalando:
<sourcesyntaxhighlight lang="bash">
ant installd
# ou manualmente:
adb install -r bin/wikibooks-opengl.apk
</syntaxhighlight>
</source>
* Limpando:
<sourcesyntaxhighlight lang="bash">
ndk-build clean
ant clean
</syntaxhighlight>
</source>
 
Nós incluiremos todos estes comandos no montador <code>Makefile</code>
Linha 105:
 
Em primeiro lugar, solicitaremos os contextos disponíveis:
<sourcesyntaxhighlight lang="cpp">
const EGLint attribs[] = {
...
Linha 113:
...
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
</syntaxhighlight>
</source>
Depois criaremos o contexto:
<sourcesyntaxhighlight lang="cpp">
static const EGLint ctx_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
Linha 121:
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attribs);
</syntaxhighlight>
</source>
 
(Em Java:)
<sourcesyntaxhighlight lang="java">
setEGLContextClientVersion(2);
// ou em um Renderizador personalizado:
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
</syntaxhighlight>
</source>
 
É uma boa prática, mas não é obrigatória, que você de declare os requirementos OpenGL 2.0 no <code>AndroidManifest.xml</code>:
<sourcesyntaxhighlight lang="xml">
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
<uses-sdk android:targetSdkVersion="9" android:minSdkVersion="9"></uses-sdk>
</syntaxhighlight>
</source>
 
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".
Linha 190:
 
Primeiro, nosso native activity trabalha com seu próprio segmento, então precisamos de cuidado ao recuperar o JNI handle em <code>android_main</code>:
<sourcesyntaxhighlight lang="cpp">
JNIEnv* env = state_param->activity->env;
JavaVM* vm = state_param->activity->vm;
vm->AttachCurrentThread(&env, NULL);
</syntaxhighlight>
</source>
 
Então vamos pegar o estado em nossa chamada instanciada NativeActivity:
<sourcesyntaxhighlight lang="cpp">
jclass activityClass = env->GetObjectClass(state_param->activity->clazz);
</syntaxhighlight>
</source>
 
Então nós decidiremos aonde extrair os arquivos. Então usaremos um cache padrão de diretório:
<sourcesyntaxhighlight lang="cpp">
// Get path to cache dir (/data/data/org.wikibooks.OpenGL/cache)
jmethodID getCacheDir = env->GetMethodID(activityClass, "getCacheDir", "()Ljava/io/File;");
Linha 215:
chdir(app_dir);
env->ReleaseStringUTFChars(jpath, app_dir);
</syntaxhighlight>
</source>
 
Nos agora vamos pegar o AssetManager NativeActivity:
<sourcesyntaxhighlight lang="cpp">
#include <android/asset_manager.h>
</syntaxhighlight>
</source>
<sourcesyntaxhighlight lang="cpp">
jobject assetManager = state_param->activity->assetManager;
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
</syntaxhighlight>
</source>
 
Agora a extração é simples: navegaremos pelos arquivos e copiaremos para o disco um por um:
<sourcesyntaxhighlight lang="cpp">
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
Linha 241:
}
AAssetDir_close(assetDir);
</syntaxhighlight>
</source>
 
Agora, todos os arquivos podem ser acessados usando um fopen/cout do aplicativo.
Linha 253:
 
Pela opção:
<sourcesyntaxhighlight lang="xml">
<activity ...
android:screenOrientation="portrait"
</syntaxhighlight>
</source>
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.
 
Linha 262:
O manuseador <code>onSurfaceChanged_native</code> no montador(wrapper) <code>android_app_NativeActivity.cpp</code> não parece criar
o evento<code>onNativeWindowResized</code> adequadamente na mudança de orientação, Então vamos monitora-lo regularmente:
<sourcesyntaxhighlight lang="cpp">
/* glutMainLoop */
 
Linha 282:
continue;
}
</syntaxhighlight>
</source>
Agora nos podemos processar o evento:
<sourcesyntaxhighlight lang="cpp">
static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) {
struct android_app* android_app = (struct android_app*)activity->instance;
Linha 293:
android_app_write_cmd(android_app, APP_CMD_WINDOW_RESIZED);
}
</syntaxhighlight>
</source>
 
Nota: é possivel processar pelo evento <code>APP_CMD_CONFIG_CHANGED</code>, 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:
<sourcesyntaxhighlight lang="cpp">
/* android_main */
state_param->activity->callbacks->onContentRectChanged = onContentRectChanged;
Linha 311:
glutPostRedisplay();
}
</syntaxhighlight>
</source>
 
== Eventos de entrada do dispositivo ==