Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples/example_emscripten_wgpu: Initialize and change the size of the viewport and framebuffer according to the size of the canvas #6751

Closed
wants to merge 9 commits into from
43 changes: 43 additions & 0 deletions backends/imgui_impl_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ struct ImGui_ImplGlfw_Data
ImVec2 LastValidMousePos;
bool InstalledCallbacks;
bool CallbacksChainForAllWindows;
#ifdef __EMSCRIPTEN__
const char* CanvasSelector;
#endif

// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
Expand Down Expand Up @@ -807,6 +810,46 @@ void ImGui_ImplGlfw_NewFrame()
ImGui_ImplGlfw_UpdateGamepads();
}

#ifdef __EMSCRIPTEN__
static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data)
{
ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data *) user_data;

double canvas_width, canvas_height;
emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height);

glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height);

return true;
}

static EM_BOOL ImGui_ImplGlfw_OnFullscreenChange(int event_type, const EmscriptenFullscreenChangeEvent* event, void* user_data)
{
ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data *) user_data;

double canvas_width, canvas_height;
emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height);

glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height);

return true;
}

/**
* @param canvas_selector A CSS selector, the event listener is applied to the first element that matches the query.
*/
void ImGui_ImplGlfw_SetEmscriptenCanvasSelector(const char *canvas_selector)
{
IM_ASSERT(canvas_selector != nullptr);
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplGlfw_InitForXXX()?");
bd->CanvasSelector = canvas_selector;

emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, bd, false, ImGui_ImplGlfw_OnCanvasSizeChange);
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, bd, false, ImGui_ImplGlfw_OnFullscreenChange);
}
#endif

//-----------------------------------------------------------------------------

#if defined(__clang__)
Expand Down
5 changes: 5 additions & 0 deletions backends/imgui_impl_glfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();

// Emscripten related initialization phase methods
#ifdef __EMSCRIPTEN__
IMGUI_IMPL_API void ImGui_ImplGlfw_SetEmscriptenCanvasSelector(const char* canvas_selector);
#endif

// GLFW callbacks install
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
Expand Down
8 changes: 7 additions & 1 deletion examples/example_emscripten_wgpu/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ static WGPUSwapChain wgpu_swap_chain = nullptr;
static int wgpu_swap_chain_width = 0;
static int wgpu_swap_chain_height = 0;

const char* canvas_selector = "#canvas";

// Forward declarations
static void MainLoopStep(void* window);
static bool InitWGPU();
Expand All @@ -39,10 +41,13 @@ int main(int, char**)
if (!glfwInit())
return 1;

double canvas_width, canvas_height;
emscripten_get_element_css_size(canvas_selector, &canvas_width, &canvas_height);

// Make sure GLFW does not initialize any graphics context.
// This needs to be done explicitly later.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr);
GLFWwindow* window = glfwCreateWindow((int)canvas_width, (int)canvas_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr);
if (!window)
{
glfwTerminate();
Expand Down Expand Up @@ -76,6 +81,7 @@ int main(int, char**)

// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOther(window, true);
ImGui_ImplGlfw_SetEmscriptenCanvasSelector(canvas_selector);
ImGui_ImplWGPU_Init(wgpu_device, 3, wgpu_preferred_fmt, WGPUTextureFormat_Undefined);

// Load Fonts
Expand Down
4 changes: 2 additions & 2 deletions examples/example_glfw_opengl3/Makefile.emscripten
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# (On Windows, you may need to execute emsdk_env.bat or encmdprompt.bat ahead)
#
# Running `make -f Makefile.emscripten` will produce three files:
# - web/index.html
# - web/index.html (current stored in the repository)
# - web/index.js
# - web/index.wasm
#
Expand All @@ -16,7 +16,7 @@
CC = emcc
CXX = em++
WEB_DIR = web
EXE = $(WEB_DIR)/index.html
EXE = $(WEB_DIR)/index.js
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
Expand Down
17 changes: 16 additions & 1 deletion examples/example_glfw_opengl3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@

// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif

const char* canvas_selector = "#canvas";

static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
Expand Down Expand Up @@ -64,8 +68,16 @@ int main(int, char**)
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
#endif

double canvas_width, canvas_height;
#ifdef __EMSCRIPTEN__
emscripten_get_element_css_size(canvas_selector, &canvas_width, &canvas_height);
#else
canvas_width = 1280;
canvas_height = 720;
#endif

// Create window with graphics context
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", nullptr, nullptr);
GLFWwindow* window = glfwCreateWindow((int)canvas_width, (int)canvas_height, "Dear ImGui GLFW+OpenGL3 example", nullptr, nullptr);
if (window == nullptr)
return 1;
glfwMakeContextCurrent(window);
Expand All @@ -84,6 +96,9 @@ int main(int, char**)

// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
#ifdef __EMSCRIPTEN__
ImGui_ImplGlfw_SetEmscriptenCanvasSelector(canvas_selector);
#endif
ImGui_ImplOpenGL3_Init(glsl_version);

// Load Fonts
Expand Down
80 changes: 80 additions & 0 deletions examples/example_glfw_opengl3/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<title>Dear ImGui Emscripten+GLFW+OpenGL3 example</title>
<style>
body { margin: 0; background-color: black }
.emscripten {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<script type='text/javascript'>
var Module;
(async () => {
Module = {
preRun: [],
postRun: [],
print: (function() {
return function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
})(),
printErr: function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
//canvas.addEventListener("webglcontextlost", function(e) { alert('FIXME: WebGL context lost, please reload the page'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
console.log("status: " + text);
},
monitorRunDependencies: function(left) {
// no run dependencies to log
}
};
window.onerror = function() {
console.log("onerror: " + event);
};

// Initialize the graphics adapter
{
const adapter = await navigator.gpu.requestAdapter();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this code really necessary for the opengl3 example? Isn't this code used for webgpu?

const device = await adapter.requestDevice();
Module.preinitializedWebGPUDevice = device;
}

{
const js = document.createElement('script');
js.async = true;
js.src = "index.js";
document.body.appendChild(js);
}
})();
</script>
</body>
</html>