GLFM ist eine C-API für die Entwicklung mobiler Apps mit OpenGL ES. Es ist größtenteils von GLFW inspiriert.
GLFM läuft auf iOS 9, tvOS 9, Android 4.1 (API 16) und WebGL 1.0 (über Emscripten).
Darüber hinaus bietet GLFM Metal-Unterstützung für iOS und tvOS.
iOS | tvOS | Android | Web | |
---|---|---|---|---|
OpenGL ES 2, OpenGL ES 3 | ✔️ | ✔️ | ✔️ | ✔️ |
Metall | ✔️ | ✔️ | N / A | N / A |
Netzhaut / hohe DPI | ✔️ | ✔️ | ✔️ | ✔️ |
Geräteausrichtung | ✔️ | N / A | ✔️ | |
Berühren Sie Ereignisse | ✔️ | ✔️ | ✔️ | ✔️ |
Mouse-Hover-Ereignisse | ✔️ 1 | ✔️ | ||
Mausrad-Events | ✔️ | |||
Mauszeigerstil | ✔️ 1 | ✔️ | ||
Schlüsselcode-Ereignisse | ✔️ 2 | ✔️ | ✔️ | ✔️ |
Wichtige Wiederholungsereignisse | ✔️ | ✔️ | ||
Zeicheneingabeereignisse | ✔️ | ✔️ 3 | ✔️ | ✔️ |
Virtuelle Tastatur | ✔️ | ✔️ | ||
Ereignisse zur Sichtbarkeit der virtuellen Tastatur | ✔️ | ✔️ | ||
Beschleunigungsmesser, Magnetometer, Gyroskop, Geräterotation | ✔️ | N / A | ✔️ | |
Haptisches Feedback | ✔️ 4 | N / A | ✔️ | |
Zwischenablage | ✔️ | N / A | ✔️ | ✔️ |
Chromeinsätze („sicherer Bereich“) | ✔️ 5 | ✔️ | ✔️ | |
Chrome fügt geänderte Ereignisse ein | ✔️ 5 | ✔️ | ✔️ | |
Fokusveranstaltungen | ✔️ | ✔️ | ✔️ | ✔️ |
Größe von Ereignissen ändern | ✔️ | ✔️ | ✔️ | ✔️ |
Speicherwarnereignisse | ✔️ | ✔️ | ✔️ | |
OpenGL-Kontextverlustereignisse (Oberfläche zerstört) | ✔️ | ✔️ | ✔️ | ✔️ |
1. Nur iPad. Erfordert iOS 13.4 oder neuer
2. Erfordert iOS/tvOS 13.4 oder neuer
3. Erfordert tvOS 13.4 oder neuer
4. Erfordert iOS 13 oder neuer
5. Erfordert iOS/tvOS 11 oder neuer
Darüber hinaus gibt es vorläufige Unterstützung für macOS mit OpenGL 3.2. Die macOS-Version ist für Entwicklungszwecke nützlich, hat jedoch keine Release-Qualität. Es gibt beispielsweise keine Funktion zum Einstellen der Fenstergröße.
GLFM hat einen begrenzten Umfang und ist nicht darauf ausgelegt, alles bereitzustellen, was für eine App benötigt wird. GLFM bietet beispielsweise Folgendes nicht an (und wird es auch nie tun):
Stattdessen kann GLFM mit anderen plattformübergreifenden Bibliotheken verwendet werden, die das bereitstellen, was eine App benötigt.
Zur Vereinfachung wird eine CMakeLists.txt
Datei bereitgestellt, CMake ist jedoch nicht erforderlich.
Ohne CMake:
include
und src
) zu Ihrem Projekt hinzu.void glfmMain(GLFMDisplay *display)
-Funktion in eine C/C++-Datei ein. Definieren Sie für Release-Builds NDEBUG
, um überflüssige Protokollierungsanweisungen zu entfernen. NDEBUG
wird automatisch für Release-Builds in Android Studio definiert, jedoch nicht in Xcode.
Dieses Beispiel initialisiert die Anzeige in glfmMain()
und zeichnet ein Dreieck in onDraw()
. Ein ausführlicheres Beispiel finden Sie hier.
#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 );
}
Siehe glfm.h
Verwenden Sie cmake
, um ein Xcode-Projekt zu generieren:
cmake -D GLFM_BUILD_EXAMPLES=ON -B build/apple -G Xcode
open build/apple/GLFM.xcodeproj
Wechseln Sie in Xcode zum glfm_touch
Ziel und führen Sie es auf einem Simulator oder einem Gerät aus.
Verwenden Sie emcmake
, um Umgebungsvariablen für cmake
festzulegen, und erstellen Sie dann:
emcmake cmake -D GLFM_BUILD_EXAMPLES=ON -B build/emscripten && cmake --build build/emscripten
Dann lokal ausführen:
emrun build/emscripten/examples
Oder führen Sie ein konkretes Beispiel aus:
emrun build/emscripten/examples/glfm_touch.html
Es gibt keinen CMake-Generator für Android Studio-Projekte, aber Sie können CMakeLists.txt
in ein neues oder vorhandenes Projekt einbinden.
[path/to/glfm]/build/android
ein und klicken Sie auf „Fertig stellen“.AndroidManifest.xml
die Hauptaktivität
wie folgt hinzu: 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
die Abschnitte externalNativeBuild
und sourceSets.main
wie folgt hinzu: 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
oder von den Rückruffunktionen). Welche IDE soll ich verwenden? Warum gibt es keine Desktop-Implementierung? Verwenden Sie Xcode oder Android Studio. Verwenden Sie für den Desktop GLFW mit der IDE Ihrer Wahl.
Wenn Sie die mobilen Simulatoren nicht für die alltägliche Entwicklung verwenden möchten, ist es eine gute Lösung, stattdessen GLFW zu verwenden und Ihre App später auf GLFM zu portieren. Nicht alle OpenGL-Aufrufe werden perfekt auf OpenGL ES portiert, aber für maximale OpenGL-Portabilität verwenden Sie OpenGL 3.2 Core Profile auf dem Desktop und OpenGL ES 2.0 auf Mobilgeräten.
Warum ist der Einstiegspunkt glfmMain()
und nicht main()
?
Sonst würde es unter iOS nicht funktionieren. Um die Objective-C-Umgebung zu initialisieren, muss die Funktion main()
einen Autorelease-Pool erstellen und die Funktion UIApplicationMain()
aufrufen, die niemals zurückgibt . Unter iOS ruft GLFM glfmMain()
erst auf, nachdem UIApplicationDelegate
und UIViewController
initialisiert wurden.
Warum ist GLFM ereignisgesteuert? Warum übernimmt GLFM die Hauptschleife?
Andernfalls würde es unter iOS (siehe oben) oder unter HTML5, das ereignisgesteuert ist, nicht funktionieren.