Skip to content

Instantly share code, notes, and snippets.

@chinmaygarde
Last active December 3, 2024 07:09
Show Gist options
  • Save chinmaygarde/8abf44921f7d87f6da7bf026267c4792 to your computer and use it in GitHub Desktop.
Save chinmaygarde/8abf44921f7d87f6da7bf026267c4792 to your computer and use it in GitHub Desktop.
Flutter Embedder API Example (GLFW with OpenGL)
#include <assert.h>
#include <chrono>
#include <embedder.h>
#include <glfw3.h>
#include <iostream>
static_assert(FLUTTER_ENGINE_VERSION == 1, "");
static const size_t kInitialWindowWidth = 800;
static const size_t kInitialWindowHeight = 600;
void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window,
FlutterPointerPhase phase, double x,
double y) {
FlutterPointerEvent event = {};
event.struct_size = sizeof(event);
event.phase = phase;
event.x = x;
event.y = y;
event.timestamp =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
FlutterEngineSendPointerEvent(
reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)), &event,
1);
}
void GLFWcursorPositionCallback(GLFWwindow *window, double x, double y) {
GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kMove, x, y);
}
void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action,
int mods) {
if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS) {
double x, y;
glfwGetCursorPos(window, &x, &y);
GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kDown, x, y);
glfwSetCursorPosCallback(window, GLFWcursorPositionCallback);
}
if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_RELEASE) {
double x, y;
glfwGetCursorPos(window, &x, &y);
GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kUp, x, y);
glfwSetCursorPosCallback(window, nullptr);
}
}
static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode,
int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
}
void GLFWwindowSizeCallback(GLFWwindow *window, int width, int height) {
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = width;
event.height = height;
event.pixel_ratio = 1.0;
FlutterEngineSendWindowMetricsEvent(
reinterpret_cast<FlutterEngine>(glfwGetWindowUserPointer(window)),
&event);
}
bool RunFlutter(GLFWwindow *window) {
FlutterRendererConfig config = {};
config.type = kOpenGL;
config.open_gl.struct_size = sizeof(config.open_gl);
config.open_gl.make_current = [](void *userdata) -> bool {
glfwMakeContextCurrent((GLFWwindow *)userdata);
return true;
};
config.open_gl.clear_current = [](void *) -> bool {
glfwMakeContextCurrent(nullptr); // is this even a thing?
return true;
};
config.open_gl.present = [](void *userdata) -> bool {
glfwSwapBuffers((GLFWwindow *)userdata);
return true;
};
config.open_gl.fbo_callback = [](void *) -> uint32_t {
return 0; // FBO0
};
#define MY_PROJECT "/Volumes/Mojo/flutter/examples/flutter_gallery"
FlutterProjectArgs args = {
.struct_size = sizeof(FlutterProjectArgs),
.assets_path = MY_PROJECT "/build/fluttter_assets", // This directory is generated by `flutter build bundle`
.icu_data_path = "path_to/icudtl.dat", // Find this in your bin/cache directory.
};
FlutterEngine engine = nullptr;
auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, // renderer
&args, window, &engine);
assert(result == kSuccess && engine != nullptr);
glfwSetWindowUserPointer(window, engine);
GLFWwindowSizeCallback(window, kInitialWindowWidth, kInitialWindowHeight);
return true;
}
int main(int argc, const char *argv[]) {
auto result = glfwInit();
assert(result == GLFW_TRUE);
auto window = glfwCreateWindow(kInitialWindowWidth, kInitialWindowHeight,
"Flutter", NULL, NULL);
assert(window != nullptr);
bool runResult = RunFlutter(window);
assert(runResult);
glfwSetKeyCallback(window, GLFWKeyCallback);
glfwSetWindowSizeCallback(window, GLFWwindowSizeCallback);
glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback);
while (!glfwWindowShouldClose(window)) {
std::cout << "Looping..." << std::endl;
glfwWaitEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return EXIT_SUCCESS;
}
@lesnitsky
Copy link

.assets_path = MY_PROJECT "/build/fluttter_assets"
is this typo (fluttter_assets) intentional to track those who try to embed the engine based on this gist? :)

@xzhan96
Copy link

xzhan96 commented Jul 16, 2020

Hi Why I always got below error in the line " auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, // renderer
&args, window, &engine);"

0x0000000182897460 (flutter_engine.dll) (flutter_glfw.exe 中)exception : 0xC0000005: read postion 0xFFFFFFFFFFFFFFFF has conflict.....

@kururu-abdo
Copy link

nice to be here and see how actual embedder's code

@chinmaygarde
Copy link
Author

This gist is now in the repo itself.

@ZhenFTW
Copy link

ZhenFTW commented Mar 25, 2022

Is there a plan to support SDL as embedder?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment