GLFM เป็น C API สำหรับการพัฒนาแอปบนอุปกรณ์เคลื่อนที่ด้วย OpenGL ES ส่วนใหญ่ได้รับแรงบันดาลใจจาก GLFW
GLFM ทำงานบน iOS 9, tvOS 9, Android 4.1 (API 16) และ WebGL 1.0 (ผ่าน Emscripten)
นอกจากนี้ GLFM ยังให้การสนับสนุน Metal บน iOS และ tvOS
ไอโอเอส | tvOS | หุ่นยนต์ | เว็บ | |
---|---|---|---|---|
OpenGL ES 2, OpenGL ES 3 | ||||
โลหะ | ไม่มี | ไม่มี | ||
จอประสาทตา / DPI สูง | ||||
การวางแนวอุปกรณ์ | ไม่มี | |||
เหตุการณ์สัมผัส | ||||
เหตุการณ์การเลื่อนเมาส์ | ✔️1 | |||
เหตุการณ์ล้อเมาส์ | ||||
สไตล์เคอร์เซอร์ของเมาส์ | ✔️1 | |||
เหตุการณ์รหัสคีย์ | ✔️2 | |||
เหตุการณ์สำคัญที่เกิดซ้ำ | ||||
เหตุการณ์การป้อนอักขระ | ✔️3 | |||
แป้นพิมพ์เสมือนจริง | ||||
เหตุการณ์การมองเห็นแป้นพิมพ์เสมือน | ||||
มาตรความเร่ง, แมกนีโตมิเตอร์, ไจโรสโคป, การหมุนอุปกรณ์ | ไม่มี | |||
การตอบสนองแบบสัมผัส | ✔️ 4 | ไม่มี | ||
คลิปบอร์ด | ไม่มี | |||
Chrome แทรก ("พื้นที่ปลอดภัย") | ✔️5 | |||
Chrome ที่แทรกเข้ามามีการเปลี่ยนแปลงกิจกรรม | ✔️5 | |||
เน้นกิจกรรม | ||||
ปรับขนาดเหตุการณ์ | ||||
เหตุการณ์เตือนความจำ | ||||
เหตุการณ์การสูญเสียบริบทของ OpenGL (พื้นผิวถูกทำลาย) |
1. ไอแพดเท่านั้น ต้องใช้ 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++ สำหรับรุ่น release ให้กำหนด NDEBUG
เพื่อลบคำสั่งการบันทึกที่ไม่จำเป็น NDEBUG
ถูกกำหนดโดยอัตโนมัติสำหรับ release build ใน 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
แล้วกด "Finish"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 Core Profile บนเดสก์ท็อปและ OpenGL ES 2.0 บนมือถือ
เหตุใดจุดเริ่มต้น glfmMain()
และไม่ใช่ main()
?
ไม่เช่นนั้นจะไม่สามารถใช้งานบน iOS ได้ ในการเริ่มต้นสภาพแวดล้อม Objective-C ฟังก์ชัน main()
ต้องสร้างพูล autorelease และเรียกใช้ฟังก์ชัน UIApplicationMain()
ซึ่ง จะไม่ส่งคืน บน iOS GLFM จะไม่เรียก glfmMain()
จนกว่า UIApplicationDelegate
และ UIViewController
จะเริ่มต้นได้
เหตุใด GLFM จึงขับเคลื่อนด้วยเหตุการณ์ เหตุใด GLFM จึงเข้าควบคุมลูปหลัก
มิฉะนั้น มันจะไม่ทำงานบน iOS (ดูด้านบน) หรือบน HTML5 ซึ่งขับเคลื่อนด้วยเหตุการณ์