GLFM — это API C для разработки мобильных приложений с использованием OpenGL ES. Он во многом вдохновлен GLFW.
GLFM работает на iOS 9, tvOS 9, Android 4.1 (API 16) и WebGL 1.0 (через Emscripten).
Кроме того, GLFM обеспечивает поддержку Metal на iOS и tvOS.
iOS | ТВОС | Андроид | Интернет | |
---|---|---|---|---|
OpenGL ES 2, OpenGL ES 3 | ✔️ | ✔️ | ✔️ | ✔️ |
Металл | ✔️ | ✔️ | Н/Д | Н/Д |
Сетчатка/высокое разрешение | ✔️ | ✔️ | ✔️ | ✔️ |
Ориентация устройства | ✔️ | Н/Д | ✔️ | |
Сенсорные события | ✔️ | ✔️ | ✔️ | ✔️ |
События при наведении мыши | ✔️ 1 | ✔️ | ||
События колеса мыши | ✔️ | |||
Стиль курсора мыши | ✔️ 1 | ✔️ | ||
Ключевые события кода | ✔️ 2 | ✔️ | ✔️ | ✔️ |
Ключевые повторяющиеся события | ✔️ | ✔️ | ||
События ввода символов | ✔️ | ✔️ 3 | ✔️ | ✔️ |
Виртуальная клавиатура | ✔️ | ✔️ | ||
События видимости виртуальной клавиатуры | ✔️ | ✔️ | ||
Акселерометр, магнитометр, гироскоп, вращение устройства | ✔️ | Н/Д | ✔️ | |
Тактильная обратная связь | ✔️ 4 | Н/Д | ✔️ | |
Буфер обмена | ✔️ | Н/Д | ✔️ | ✔️ |
Хромированные вставки («безопасная зона») | ✔️ 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 или новее.
Кроме того, имеется предварительная поддержка macOS с OpenGL 3.2. Версия для macOS полезна для целей разработки, но не является релизной версией. Например, нет функции установки размера окна.
GLFM ограничен по объему и не предназначен для предоставления всего необходимого для приложения. Например, GLFM не предоставляет (и никогда не предоставит) следующее:
Вместо этого GLFM можно использовать с другими кроссплатформенными библиотеками, которые предоставляют то, что нужно приложению.
Для удобства предоставляется файл CMakeLists.txt
, хотя CMake не требуется.
Без CMake:
include
и src
) в свой проект.void glfmMain(GLFMDisplay *display)
в файл C/C++. Для выпускных сборок определите 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
Генератор CMake для проектов Android Studio отсутствует, но вы можете включить 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. Для настольных компьютеров используйте GLFW с выбранной вами IDE.
Если вы предпочитаете не использовать мобильные симуляторы для повседневной разработки, хорошим решением будет использование GLFW, а затем портирование вашего приложения на GLFM. Не все вызовы OpenGL полностью переносятся на OpenGL ES, но для максимальной переносимости OpenGL используйте основной профиль OpenGL 3.2 на настольных компьютерах и OpenGL ES 2.0 на мобильных устройствах.
Почему точкой входа является glfmMain()
, а не main()
?
В противном случае это не будет работать на iOS. Чтобы инициализировать среду Objective-C, функция main()
должна создать пул автоматического выпуска и вызвать функцию UIApplicationMain()
, которая никогда не возвращает . В iOS GLFM не вызывает glfmMain()
до тех пор, пока не будут инициализированы UIApplicationDelegate
и UIViewController
.
Почему GLFM ориентирован на события? Почему GLFM берет на себя основной цикл?
В противном случае он не будет работать ни в iOS (см. выше), ни в HTML5, который управляется событиями.