GLFM es una API C para el desarrollo de aplicaciones móviles con OpenGL ES. Está inspirado en gran medida en GLFW.
GLFM se ejecuta en iOS 9, tvOS 9, Android 4.1 (API 16) y WebGL 1.0 (a través de Emscripten).
Además, GLFM proporciona soporte para Metal en iOS y tvOS.
iOS | tvOS | Androide | Web | |
---|---|---|---|---|
OpenGL ES 2, OpenGL ES 3 | ✔️ | ✔️ | ✔️ | ✔️ |
Metal | ✔️ | ✔️ | N / A | N / A |
Retina / alto DPI | ✔️ | ✔️ | ✔️ | ✔️ |
Orientación del dispositivo | ✔️ | N / A | ✔️ | |
Eventos táctiles | ✔️ | ✔️ | ✔️ | ✔️ |
Eventos de desplazamiento del mouse | ✔️ 1 | ✔️ | ||
Eventos de la rueda del mouse | ✔️ | |||
Estilo del cursor del mouse | ✔️ 1 | ✔️ | ||
Eventos de código clave | ✔️ 2 | ✔️ | ✔️ | ✔️ |
Eventos clave repetidos | ✔️ | ✔️ | ||
Eventos de entrada de caracteres | ✔️ | ✔️ 3 | ✔️ | ✔️ |
teclado virtual | ✔️ | ✔️ | ||
Eventos de visibilidad del teclado virtual | ✔️ | ✔️ | ||
Acelerómetro, magnetómetro, giroscopio, rotación del dispositivo. | ✔️ | N / A | ✔️ | |
Retroalimentación háptica | ✔️ 4 | N / A | ✔️ | |
Portapapeles | ✔️ | N / A | ✔️ | ✔️ |
Inserciones cromadas ("área segura") | ✔️ 5 | ✔️ | ✔️ | |
Las inserciones de Chrome cambiaron eventos | ✔️ 5 | ✔️ | ✔️ | |
Eventos de enfoque | ✔️ | ✔️ | ✔️ | ✔️ |
Cambiar el tamaño de los eventos | ✔️ | ✔️ | ✔️ | ✔️ |
Eventos de advertencia de memoria | ✔️ | ✔️ | ✔️ | |
Eventos de pérdida de contexto OpenGL (superficie destruida) | ✔️ | ✔️ | ✔️ | ✔️ |
1. Solo iPad. Requiere iOS 13.4 o posterior
2. Requiere iOS/tvOS 13.4 o posterior
3. Requiere tvOS 13.4 o posterior
4. Requiere iOS 13 o posterior
5. Requiere iOS/tvOS 11 o posterior
Además, existe soporte preliminar para macOS con OpenGL 3.2. La versión de macOS es útil para fines de desarrollo, pero no tiene calidad de lanzamiento. No existe ninguna función para establecer el tamaño de la ventana, por ejemplo.
GLFM tiene un alcance limitado y no está diseñado para proporcionar todo lo necesario para una aplicación. Por ejemplo, GLFM no proporciona (y nunca proporcionará) lo siguiente:
En cambio, GLFM se puede utilizar con otras bibliotecas multiplataforma que proporcionan lo que necesita una aplicación.
Se proporciona un archivo CMakeLists.txt
para mayor comodidad, aunque CMake no es necesario.
Sin CMake:
include
y src
) a su proyecto.void glfmMain(GLFMDisplay *display)
en un archivo C/C++. Para versiones de lanzamiento, defina NDEBUG
para eliminar declaraciones de registro superfluas. NDEBUG
se define automáticamente para las versiones de lanzamiento en Android Studio, pero no en Xcode.
Este ejemplo inicializa la visualización en glfmMain()
y dibuja un triángulo en onDraw()
. Un ejemplo más detallado está disponible aquí.
#include "glfm.h"
static GLint program = 0 ;
static GLuint vertexBuffer = 0 ;
static GLuint vertexArray = 0 ;
static void onDraw ( GLFMDisplay * display );
static void onSurfaceDestroyed ( GLFMDisplay * display );
void glfmMain ( GLFMDisplay * display ) {
glfmSetDisplayConfig ( display ,
GLFMRenderingAPIOpenGLES2 ,
GLFMColorFormatRGBA8888 ,
GLFMDepthFormatNone ,
GLFMStencilFormatNone ,
GLFMMultisampleNone );
glfmSetRenderFunc ( display , onDraw );
glfmSetSurfaceDestroyedFunc ( display , onSurfaceDestroyed );
}
static void onSurfaceDestroyed ( GLFMDisplay * display ) {
// When the surface is destroyed, all existing GL resources are no longer valid.
program = 0 ;
vertexBuffer = 0 ;
vertexArray = 0 ;
}
static GLuint compileShader ( const GLenum type , const GLchar * shaderString , GLint shaderLength ) {
GLuint shader = glCreateShader ( type );
glShaderSource ( shader , 1 , & shaderString , & shaderLength );
glCompileShader ( shader );
return shader ;
}
static void onDraw ( GLFMDisplay * display ) {
if ( program == 0 ) {
const GLchar vertexShader [] =
"#version 100n"
"attribute highp vec4 position;n"
"void main() {n"
" gl_Position = position;n"
"}" ;
const GLchar fragmentShader [] =
"#version 100n"
"void main() {n"
" gl_FragColor = vec4(0.85, 0.80, 0.75, 1.0);n"
"}" ;
program = glCreateProgram ();
GLuint vertShader = compileShader ( GL_VERTEX_SHADER , vertexShader , sizeof ( vertexShader ) - 1 );
GLuint fragShader = compileShader ( GL_FRAGMENT_SHADER , fragmentShader , sizeof ( fragmentShader ) - 1 );
glAttachShader ( program , vertShader );
glAttachShader ( program , fragShader );
glLinkProgram ( program );
glDeleteShader ( vertShader );
glDeleteShader ( fragShader );
}
if ( vertexBuffer == 0 ) {
const GLfloat vertices [] = {
0.0 , 0.5 , 0.0 ,
-0.5 , -0.5 , 0.0 ,
0.5 , -0.5 , 0.0 ,
};
glGenBuffers ( 1 , & vertexBuffer );
glBindBuffer ( GL_ARRAY_BUFFER , vertexBuffer );
glBufferData ( GL_ARRAY_BUFFER , sizeof ( vertices ), vertices , GL_STATIC_DRAW );
}
int width , height ;
glfmGetDisplaySize ( display , & width , & height );
glViewport ( 0 , 0 , width , height );
glClearColor ( 0.08f , 0.07f , 0.07f , 1.0f );
glClear ( GL_COLOR_BUFFER_BIT );
#if defined( GL_VERSION_3_0 ) && GL_VERSION_3_0
if ( vertexArray == 0 ) {
glGenVertexArrays ( 1 , & vertexArray );
}
glBindVertexArray ( vertexArray );
#endif
glUseProgram ( program );
glBindBuffer ( GL_ARRAY_BUFFER , vertexBuffer );
glEnableVertexAttribArray ( 0 );
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , GL_FALSE , 0 , 0 );
glDrawArrays ( GL_TRIANGLES , 0 , 3 );
glfmSwapBuffers ( display );
}
Ver glfm.h
Utilice cmake
para generar un proyecto Xcode:
cmake -D GLFM_BUILD_EXAMPLES=ON -B build/apple -G Xcode
open build/apple/GLFM.xcodeproj
En Xcode, cambie al destino glfm_touch
y ejecútelo en un simulador o dispositivo.
Utilice emcmake
para establecer variables ambientales para cmake
y luego cree:
emcmake cmake -D GLFM_BUILD_EXAMPLES=ON -B build/emscripten && cmake --build build/emscripten
Luego ejecute localmente:
emrun build/emscripten/examples
O ejecute un ejemplo específico:
emrun build/emscripten/examples/glfm_touch.html
No existe un generador de CMake para proyectos de Android Studio, pero puede incluir CMakeLists.txt
en un proyecto nuevo o existente.
[path/to/glfm]/build/android
y presione "Finalizar".AndroidManifest.xml
, agregue la
principal así: xml version = " 1.0 " encoding = " utf-8 " ?>
< manifest xmlns : android = " http://schemas.android.com/apk/res/android " >
< uses-feature android : glEsVersion = " 0x00020000 " android : required = " true " />
< application
android : allowBackup = " true "
android : icon = " @mipmap/ic_launcher "
android : label = " @string/app_name "
android : supportsRtl = " true " >
< activity android : name = " android.app.NativeActivity "
android : exported = " true "
android : configChanges = " orientation|screenLayout|screenSize|keyboardHidden|keyboard " >
< meta-data
android : name = " android.app.lib_name "
android : value = " glfm_touch " />
< intent-filter >
< action android : name = " android.intent.action.MAIN " />
< category android : name = " android.intent.category.LAUNCHER " />
intent-filter >
activity >
application >
manifest >
app/build.gradle
, agregue las secciones externalNativeBuild
y sourceSets.main
así: apply plugin : ' com.android.application '
android {
compileSdkVersion 34
ndkVersion ' 23.2.8568313 ' // Last version to support API 16, 17, 18
defaultConfig {
applicationId " com.brackeen.glfmexample "
minSdkVersion 16
targetSdkVersion 34
versionCode 1
versionName " 1.0 "
// Add externalNativeBuild in defaultConfig (1/2)
externalNativeBuild {
cmake {
arguments " -DGLFM_BUILD_EXAMPLES=ON "
}
}
}
// Add sourceSets.main and externalNativeBuild (2/2)
sourceSets . main {
assets . srcDirs = [ " ../../../examples/assets " ]
}
externalNativeBuild {
cmake {
path " ../../../CMakeLists.txt "
}
}
namespace ' com.brackeen.glfmexample '
}
glfmMain
o desde las funciones de devolución de llamada). ¿Qué IDE debo usar? ¿Por qué no hay una implementación de escritorio? Utilice Xcode o Android Studio. Para escritorio, use GLFW con el IDE de su elección.
Si prefiere no utilizar los simuladores móviles para el desarrollo diario, una buena solución es utilizar GLFW y luego migrar su aplicación a GLFM. No todas las llamadas OpenGL se adaptarán perfectamente a OpenGL ES, pero para obtener la máxima portabilidad de OpenGL, utilice OpenGL 3.2 Core Profile en el escritorio y OpenGL ES 2.0 en el móvil.
¿Por qué el punto de entrada es glfmMain()
y no main()
?
De lo contrario, no funcionaría en iOS. Para inicializar el entorno Objective-C, la función main()
debe crear un grupo de liberación automática y llamar a la función UIApplicationMain()
, que nunca devuelve . En iOS, GLFM no llama glfmMain()
hasta que se inicializan UIApplicationDelegate
y UIViewController
.
¿Por qué GLFM se basa en eventos? ¿Por qué GLFM se hace cargo del circuito principal?
De lo contrario, no funcionaría en iOS (ver arriba) o en HTML5, que se basa en eventos.