GLFM は、OpenGL ES を使用したモバイル アプリ開発用の C API です。これは主に GLFW からインスピレーションを受けています。
GLFM は、iOS 9、tvOS 9、Android 4.1 (API 16)、および WebGL 1.0 (Emscripten 経由) で実行されます。
さらに、GLFM は iOS および tvOS での Metal サポートを提供します。
iOS | テレビOS | アンドロイド | ウェブ | |
---|---|---|---|---|
OpenGL ES2、OpenGL ES3 | ✔️ | ✔️ | ✔️ | ✔️ |
金属 | ✔️ | ✔️ | 該当なし | 該当なし |
Retina / 高 DPI | ✔️ | ✔️ | ✔️ | ✔️ |
デバイスの向き | ✔️ | 該当なし | ✔️ | |
タッチイベント | ✔️ | ✔️ | ✔️ | ✔️ |
マウスホバーイベント | ✔️1 | ✔️ | ||
マウスホイールイベント | ✔️ | |||
マウスカーソルのスタイル | ✔️1 | ✔️ | ||
キーコードイベント | ✔️ 2 | ✔️ | ✔️ | ✔️ |
キーリピートイベント | ✔️ | ✔️ | ||
文字入力イベント | ✔️ | ✔️ 3 | ✔️ | ✔️ |
仮想キーボード | ✔️ | ✔️ | ||
仮想キーボード可視化イベント | ✔️ | ✔️ | ||
加速度計、磁力計、ジャイロスコープ、デバイスの回転 | ✔️ | 該当なし | ✔️ | |
触覚フィードバック | ✔️ 4 | 該当なし | ✔️ | |
クリップボード | ✔️ | 該当なし | ✔️ | ✔️ |
Chrome インセット (「安全領域」) | ✔️ 5 | ✔️ | ✔️ | |
Chrome は変更されたイベントを挿入します | ✔️ 5 | ✔️ | ✔️ | |
注目のイベント | ✔️ | ✔️ | ✔️ | ✔️ |
イベントのサイズ変更 | ✔️ | ✔️ | ✔️ | ✔️ |
メモリ警告イベント | ✔️ | ✔️ | ✔️ | |
OpenGL コンテキスト損失イベント (サーフェスの破壊) | ✔️ | ✔️ | ✔️ | ✔️ |
1.iPadのみ。 iOS 13.4以降が必要です
2. iOS/tvOS 13.4以降が必要です
3.tvOS 13.4以降が必要です
4. iOS 13以降が必要です
5. iOS/tvOS 11以降が必要です
さらに、OpenGL 3.2 による macOS の予備サポートもあります。 macOS バージョンは開発目的には役立ちますが、リリース品質ではありません。ウィンドウサイズなどを設定する機能はありません。
GLFM は範囲が限られており、アプリに必要なものをすべて提供するように設計されていません。たとえば、GLFM は次のものを提供しません (今後も提供しません)。
代わりに、GLFM は、アプリに必要なものを提供する他のクロスプラットフォーム ライブラリと一緒に使用できます。
CMakeLists.txt
ファイルは便宜上提供されていますが、CMake は必須ではありません。
CMake を使用しない場合:
include
およびsrc
内) をプロジェクトに追加します。void glfmMain(GLFMDisplay *display)
関数を含めます。リリース ビルドの場合は、 NDEBUG
を定義して余分なログ ステートメントを削除します。 NDEBUG
は、Android Studio のリリース ビルドに対して自動的に定義されますが、Xcode では定義されません。
この例では、 glfmMain()
で表示を初期化し、 onDraw()
で三角形を描画します。より詳細な例はここで入手できます。
#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 );
}
glfm.h を参照してください。
cmake
使用して Xcode プロジェクトを生成します。
cmake -D GLFM_BUILD_EXAMPLES=ON -B build/apple -G Xcode
open build/apple/GLFM.xcodeproj
Xcode で、 glfm_touch
ターゲットに切り替えて、シミュレーターまたはデバイス上で実行します。
emcmake
使用してcmake
の環境変数を設定し、以下をビルドします。
emcmake cmake -D GLFM_BUILD_EXAMPLES=ON -B build/emscripten && cmake --build build/emscripten
次に、ローカルで実行します。
emrun build/emscripten/examples
または、特定の例を実行します。
emrun build/emscripten/examples/glfm_touch.html
Android Studio プロジェクト用の CMake ジェネレーターはありませんが、新規または既存のプロジェクトにCMakeLists.txt
を含めることができます。
[path/to/glfm]/build/android
と入力して「完了」を押します。AndroidManifest.xml
に、次のようにメインの
を追加します。 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
に、次のようにexternalNativeBuild
セクションとsourceSets.main
セクションを追加します。 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
またはコールバック関数から) 呼び出す必要があります。 どの IDE を使用すればよいですか?なぜデスクトップ実装がないのでしょうか? Xcode または Android Studio を使用します。デスクトップの場合は、選択した IDE で GLFW を使用します。
日常の開発にモバイル シミュレーターを使用したくない場合は、代わりに GLFW を使用し、後でアプリを GLFM に移植するのが良い解決策です。すべての OpenGL 呼び出しが OpenGL ES に完全に移植されるわけではありませんが、OpenGL の移植性を最大限に高めるには、デスクトップでは OpenGL 3.2 Core Profile を、モバイルでは OpenGL ES 2.0 を使用してください。
エントリ ポイントがmain()
ではなくglfmMain()
) なのはなぜですか?
そうしないと、iOS では動作しません。 Objective-C 環境を初期化するには、 main()
関数で自動解放プールを作成し、 UIApplicationMain()
関数を呼び出す必要がありますが、この関数はを返しません。 iOS では、GLFM はUIApplicationDelegate
とUIViewController
が初期化されるまでglfmMain()
を呼び出しません。
GLFM はなぜイベント駆動型なのでしょうか?なぜ GLFM がメインループを引き継ぐのですか?
そうしないと、iOS (上記を参照) やイベント駆動型の HTML5 では機能しません。