Skip to content

Commit d2150d5

Browse files
committed
OpenGL command from the Flutter App work
1 parent 81d2d7b commit d2150d5

18 files changed

+8726
-117
lines changed

example/lib/main.dart

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'dart:async';
2+
import 'dart:ffi';
23

4+
import 'package:ffi/ffi.dart';
35
import 'package:flutter/material.dart';
46
import 'package:flutter/services.dart';
57
import 'package:flutter_web_gl/flutter_web_gl.dart';
@@ -28,19 +30,18 @@ class _MyAppState extends State<MyApp> {
2830
String platformVersion;
2931
// Platform messages may fail, so we use a try/catch PlatformException.
3032
try {
31-
platformVersion = await FlutterWebGl.platformVersion;
33+
platformVersion = await FlutterWebGL.platformVersion;
3234
} on PlatformException {
3335
platformVersion = 'Failed to get platform version.';
3436
}
37+
FlutterWebGL.initOpenGL();
3538

3639
try {
37-
textureId = await FlutterWebGl.createTexture(200, 100);
40+
textureId = await FlutterWebGL.createTexture(200, 100);
3841
} on PlatformException {
3942
print("failed to get texture id");
4043
}
4144

42-
FlutterWebGl.initOpenGL();
43-
4445
// If the widget was removed from the tree while the asynchronous platform
4546
// message was in flight, we want to discard the reply rather than calling
4647
// setState to update our non-existent appearance.
@@ -55,19 +56,95 @@ class _MyAppState extends State<MyApp> {
5556
Widget build(BuildContext context) {
5657
return MaterialApp(
5758
home: Scaffold(
59+
backgroundColor: Colors.red,
5860
appBar: AppBar(
5961
title: const Text('Plugin example app'),
6062
),
6163
body: Center(
6264
child: Column(
6365
children: [
6466
Text('Running on: $_platformVersion\n'),
65-
SizedBox(
66-
width: 200, height: 100, child: Texture(textureId: textureId))
67+
SizedBox(width: 600, height: 400, child: Texture(textureId: textureId)),
68+
MaterialButton(
69+
onPressed: draw,
70+
color: Colors.grey,
71+
child: Text('Draw'),
72+
),
6773
],
6874
),
6975
),
7076
),
7177
);
7278
}
79+
80+
void draw() async {
81+
final gl = FlutterWebGL.rawOpenGl;
82+
gl.glClearColor(0, 0, 60, 255);
83+
gl.glClear(GL_COLOR_BUFFER_BIT);
84+
85+
final points = [-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0];
86+
87+
Pointer<Uint32> vbo = allocate();
88+
gl.glGenBuffers(1, vbo);
89+
gl.glBindBuffer(GL_ARRAY_BUFFER, vbo.address);
90+
gl.glBufferData(GL_ARRAY_BUFFER, points.length, floatListToArrayPointer(points).cast(), GL_STATIC_DRAW);
91+
92+
int vertexShader = gl.glCreateShader(GL_VERTEX_SHADER);
93+
gl.glShaderSource(
94+
vertexShader, 1, Pointer<Void>.fromAddress(Utf8.toUtf8(vertexShaderSource).cast().address).cast(), nullptr);
95+
gl.glCompileShader(vertexShader);
96+
Pointer<Uint32> success = allocate();
97+
gl.glGetShaderiv(vertexShader, GL_COMPILE_STATUS, success.cast());
98+
print(success.value);
99+
100+
int fragmentShader = gl.glCreateShader(GL_FRAGMENT_SHADER);
101+
gl.glShaderSource(
102+
fragmentShader, 1, Pointer<Pointer<Int8>>.fromAddress(Utf8.toUtf8(fragmentShaderSource).address), nullptr);
103+
gl.glCompileShader(fragmentShader);
104+
gl.glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, success.cast());
105+
print(success.value);
106+
107+
final shaderProgram = gl.glCreateProgram();
108+
gl.glAttachShader(shaderProgram, vertexShader);
109+
gl.glAttachShader(shaderProgram, fragmentShader);
110+
gl.glLinkProgram(shaderProgram);
111+
gl.glGetProgramiv(shaderProgram, GL_LINK_STATUS, success.cast());
112+
print(success.value);
113+
114+
gl.glUseProgram(shaderProgram);
115+
116+
gl.glDeleteShader(vertexShader);
117+
gl.glDeleteShader(fragmentShader);
118+
gl.glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * 4, nullptr); //this was in original (void*)0
119+
gl.glEnableVertexAttribArray(0);
120+
gl.glDrawArrays(GL_TRIANGLES, 0, 3);
121+
122+
await FlutterWebGL.updateTexture(textureId);
123+
}
124+
}
125+
126+
const vertexShaderSource = //
127+
'#version 330 core\n' //
128+
'layout (location = 0) in vec3 aPos;\n' //
129+
'\n' //
130+
'void main()\n' //
131+
'{\n' //
132+
' gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n' //
133+
'}\n'; //
134+
135+
const fragmentShaderSource = //
136+
'#version 330 core\n' //
137+
'out vec4 FragColor;\n' //
138+
'\n' //
139+
'void main()\n' //
140+
'{\n' //
141+
' FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n' //
142+
'} \n'; //
143+
144+
Pointer<Float> floatListToArrayPointer(List<double> list) {
145+
final ptr = allocate<Float>(count: list.length);
146+
for (var i = 0; i < list.length; i++) {
147+
ptr.elementAt(i).value = list[i];
148+
}
149+
return ptr;
73150
}

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ packages:
6565
source: hosted
6666
version: "1.2.0-nullsafety.3"
6767
ffi:
68-
dependency: transitive
68+
dependency: "direct main"
6969
description:
7070
name: ffi
7171
url: "https://pub.dartlang.org"

example/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ environment:
99
sdk: ">=2.12.0-0 <3.0.0"
1010

1111
dependencies:
12+
ffi: 0.2.0-nullsafety.1
1213
flutter:
1314
sdk: flutter
1415

lib/flutter_web_gl.dart

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,51 @@
11
import 'dart:async';
2-
import 'dart:ffi' as ffi;
2+
import 'dart:ffi';
33

44
import 'package:dylib/dylib.dart';
5+
import 'package:ffi/ffi.dart';
56
import 'package:flutter/foundation.dart';
67
import 'package:flutter/services.dart';
78
import 'package:flutter_web_gl/lib_egl.dart';
89
import 'package:opengl_es_bindings/opengl_es_bindings.dart';
910

1011
export 'package:opengl_es_bindings/opengl_es_bindings.dart';
1112

12-
class FlutterWebGl {
13+
class FlutterWebGL {
1314
static const MethodChannel _channel = const MethodChannel('flutter_web_gl');
1415

1516
static LibOpenGLES? _libOpenGLES;
17+
static Pointer<Void> _display = nullptr;
18+
static late Pointer<Void> _config;
19+
static late Pointer<Void> _baseAppContext;
20+
static late Pointer<Void> _pluginContext;
21+
static late Pointer<Void> _dummySurface;
22+
1623
static LibOpenGLES get rawOpenGl {
1724
final libPath = resolveDylibPath(
1825
'libGLESv2',
1926
);
20-
return _libOpenGLES ??= LibOpenGLES(ffi.DynamicLibrary.open(libPath));
27+
return _libOpenGLES ??= LibOpenGLES(DynamicLibrary.open(libPath));
2128
}
2229

2330
static Future<String> get platformVersion async {
2431
final String version = await _channel.invokeMethod('getPlatformVersion');
2532
return version;
2633
}
2734

28-
static void initOpenGL() {
29-
final display = eglGetDisplay();
30-
final initializeResult = eglInitialize(display);
35+
static void initOpenGL() async {
36+
/// make sure we don't call this twice
37+
if (_display != nullptr) {
38+
return;
39+
}
40+
_display = eglGetDisplay();
41+
final initializeResult = eglInitialize(_display);
3142

3243
debugPrint('EGL version: $initializeResult');
3344

3445
final chooseConfigResult = eglChooseConfig(
35-
display,
46+
_display,
3647
attributes: {
37-
EglConfigAttribute.renderableType: EglValue.openglEs2Bit.toIntValue(),
48+
EglConfigAttribute.renderableType: EglValue.openglEs3Bit.toIntValue(),
3849
EglConfigAttribute.redSize: 8,
3950
EglConfigAttribute.greenSize: 8,
4051
EglConfigAttribute.blueSize: 8,
@@ -44,24 +55,55 @@ class FlutterWebGl {
4455
maxConfigs: 1,
4556
);
4657

47-
final config = chooseConfigResult[0];
58+
_config = chooseConfigResult[0];
4859

49-
final context = eglCreateContext(
50-
display,
51-
config,
52-
contextClientVersion: 2,
60+
_baseAppContext = eglCreateContext(
61+
_display,
62+
_config,
63+
contextClientVersion: 3,
64+
);
65+
_pluginContext = eglCreateContext(
66+
_display,
67+
_config,
68+
shareContext: _baseAppContext,
69+
contextClientVersion: 3,
5370
);
5471

55-
final surface = eglCreatePbufferSurface(display, config, attributes: {
72+
/// to make a context current you have to provide some texture even if you don't use it afterwards
73+
_dummySurface = eglCreatePbufferSurface(_display, _config, attributes: {
5674
EglSurfaceAttributes.width: 16,
5775
EglSurfaceAttributes.height: 16,
5876
});
59-
eglMakeCurrent(display, surface, surface, context);
77+
eglMakeCurrent(_display, _dummySurface, _dummySurface, _baseAppContext);
78+
79+
// The plugin makes sure that it doesn't matter if this is called multiple times
80+
await _channel
81+
.invokeMethod('initOpenGL', {'openGLContext': _pluginContext.address});
82+
// final p = FlutterWebGl.rawOpenGl.glGetString(GL_VENDOR);
83+
// String str = Utf8.fromUtf8(p.cast());
6084
}
6185

6286
static Future<int> createTexture(int width, int height) async {
6387
final result =
6488
await _channel.invokeMethod('createTexture', [width, height]);
89+
90+
Pointer<Uint32> fbo = allocate();
91+
rawOpenGl.glGenFramebuffers(1, fbo);
92+
rawOpenGl.glBindFramebuffer(GL_FRAMEBUFFER, fbo.value);
93+
94+
final rbo = result['rbo'] as int;
95+
rawOpenGl.glBindRenderbuffer(GL_RENDERBUFFER, rbo);
96+
97+
rawOpenGl.glFramebufferRenderbuffer(
98+
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
99+
final frameBufferCheck = rawOpenGl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
100+
print(frameBufferCheck);
101+
// final p = rawOpenGl.glGetString(GL_VENDOR);
102+
// String str = Utf8.fromUtf8(p.cast());
65103
return result["textureId"];
66104
}
105+
106+
static Future<void> updateTexture(int textureId) async {
107+
await _channel.invokeMethod('updateTexture', {"textureId": textureId});
108+
}
67109
}

lib/lib_egl.dart

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,20 @@ List<Pointer<Void>> eglChooseConfig(
9999
Pointer<Void> eglCreateContext(
100100
Pointer<Void> display,
101101
Pointer<Void> config, {
102-
int contextClientVersion = 1,
102+
int contextClientVersion = 3,
103103
Pointer<Void>? shareContext,
104+
bool isDebugContext = false,
104105
}) {
105-
final attributeList = allocate<Int32>(count: 3);
106+
final attributeList = allocate<Int32>(count: 5);
106107
attributeList[0] = EGL_CONTEXT_CLIENT_VERSION;
107108
attributeList[1] = contextClientVersion;
108-
attributeList[2] = EglValue.none.toIntValue();
109+
if (isDebugContext) {
110+
attributeList[2] = EglValue.none.toIntValue();
111+
} else {
112+
attributeList[2] = EGL_CONTEXT_OPENGL_DEBUG;
113+
attributeList[3] = EGL_TRUE;
114+
attributeList[4] = EglValue.none.toIntValue();
115+
}
109116

110117
final nativeCallResult = _libEGL.eglCreateContext(
111118
display, config, shareContext ?? nullptr, attributeList);
@@ -778,6 +785,7 @@ enum EglValue {
778785

779786
/// EGL_OPENGL_ES2_BIT
780787
openglEs2Bit,
788+
openglEs3Bit,
781789
}
782790

783791
extension EglValueExtension on EglValue {
@@ -787,6 +795,8 @@ extension EglValueExtension on EglValue {
787795
return EGL_NONE;
788796
case EglValue.openglEs2Bit:
789797
return EGL_OPENGL_ES2_BIT;
798+
case EglValue.openglEs3Bit:
799+
return EGL_OPENGL_ES3_BIT;
790800
default:
791801
throw UnsupportedError('Unsupported value: $this');
792802
}

pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ packages:
9393
description:
9494
path: "."
9595
ref: HEAD
96-
resolved-ref: c429ec4f118242ac6b42a38f26b9264e8e34a9b0
96+
resolved-ref: "45053cea3e4f3c13d1acfb6a42b5b80123189e67"
9797
url: "https://github.com/FlutterGL/opengl_es_bindings"
9898
source: git
9999
version: "1.0.0"

test/flutter_web_gl_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ void main() {
1818
});
1919

2020
test('getPlatformVersion', () async {
21-
expect(await FlutterWebGl.platformVersion, '42');
21+
expect(await FlutterWebGL.platformVersion, '42');
2222
});
2323
}

windows/CMakeLists.txt

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@ set_target_properties(${PLUGIN_NAME} PROPERTIES
1515
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
1616
target_include_directories(${PLUGIN_NAME} INTERFACE
1717
"${CMAKE_CURRENT_SOURCE_DIR}/include")
18-
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
19-
20-
set(LIB_GLES_NAME "libGLESv2.dll")
21-
set(LIB_EGL_NAME "libEGL.dll")
22-
set(ZLIB_NAME "zlib.dll")
23-
set(ANGLE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/angle")
24-
set(OPENGL_ARCH ${MSVC_CXX_ARCHITECTURE_ID})
25-
set(OPENGL_BUILD_TYPE "$<$<CONFIG:Debug>:debug>$<$<CONFIG:Release>:release>")
26-
set(OPENGL_LIB_DIR "${ANGLE_DIR}/${OPENGL_ARCH}/${OPENGL_BUILD_TYPE}")
27-
set(OPENGL_LIB "${OPENGL_LIB_DIR}/${LIB_GLES_NAME}")
28-
set(EGL_LIB "${OPENGL_LIB_DIR}/${LIB_EGL_NAME}")
29-
set(ZLIB_LIB "${OPENGL_LIB_DIR}/${ZLIB_NAME}")
30-
18+
19+
set(LIB_GLES_NAME "libGLESv2.dll")
20+
set(LIB_EGL_NAME "libEGL.dll")
21+
set(ZLIB_NAME "zlib.dll")
22+
set(ANGLE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/angle")
23+
set(OPENGL_ARCH ${MSVC_CXX_ARCHITECTURE_ID})
24+
set(OPENGL_BUILD_TYPE "$<$<CONFIG:Debug>:debug>$<$<CONFIG:Release>:release>")
25+
set(OPENGL_LIB_DIR "${ANGLE_DIR}/${OPENGL_ARCH}/${OPENGL_BUILD_TYPE}")
26+
set(OPENGL_LIB "${OPENGL_LIB_DIR}/${LIB_GLES_NAME}")
27+
set(EGL_LIB "${OPENGL_LIB_DIR}/${LIB_EGL_NAME}")
28+
set(ZLIB_LIB "${OPENGL_LIB_DIR}/${ZLIB_NAME}")
29+
30+
target_link_directories(${PLUGIN_NAME} PUBLIC ${OPENGL_LIB_DIR} )
31+
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin ${LIB_GLES_NAME}.lib ${LIB_EGL_NAME}.lib)
3132
# List of absolute paths to libraries that should be bundled with the plugin
3233
set(flutter_web_gl_bundled_libraries
3334
"${OPENGL_LIB}"

0 commit comments

Comments
 (0)