UNPKG

@imgui-js-xyz/target-web

Version:

imgui.js for games

905 lines (904 loc) 37.2 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { imgui } from "@imgui-js-xyz/core"; import { imgui as imgui2 } from "@imgui-js-xyz/core"; class ImGuiCanvas2DRenderer { constructor(context) { __publicField(this, "_context"); this._context = context; } get width() { return this._context.canvas.scrollWidth; } get height() { return this._context.canvas.scrollHeight; } destroy() { } newFrame() { } renderDrawData(drawData, fb_width, fb_height) { const pos = drawData.DisplayPos; drawData.IterateDrawLists((draw_list) => { draw_list.IterateDrawCmds((draw_cmd) => { if (draw_cmd.UserCallback !== null) { draw_cmd.UserCallback(draw_list, draw_cmd); } else { const clip_rect = new imgui.Vec4(draw_cmd.ClipRect.x - pos.x, draw_cmd.ClipRect.y - pos.y, draw_cmd.ClipRect.z - pos.x, draw_cmd.ClipRect.w - pos.y); if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0 && clip_rect.w >= 0) { this._executeDrawCmd(draw_list, draw_cmd, clip_rect); } } }); }); } createFontsTexture(pixels, width, height) { const imageCanvas = document.createElement("canvas"); imageCanvas.width = width; imageCanvas.height = height; const imageCtx = imageCanvas.getContext("2d"); if (imageCtx === null) { return null; } const imageData = imageCtx.getImageData(0, 0, width, height); imageData.data.set(pixels); imageCtx.putImageData(imageData, 0, 0); return imageCanvas; } _executeDrawCmd(drawList, drawCmd, clipRect) { const { _context: ctx } = this; ctx.save(); ctx.beginPath(); ctx.rect(clipRect.x, clipRect.y, clipRect.z - clipRect.x, clipRect.w - clipRect.y); ctx.clip(); const idx = imgui.DrawIdxSize === 4 ? new Uint32Array(drawList.IdxBuffer.buffer, drawList.IdxBuffer.byteOffset + drawCmd.IdxOffset * imgui.DrawIdxSize) : new Uint16Array(drawList.IdxBuffer.buffer, drawList.IdxBuffer.byteOffset + drawCmd.IdxOffset * imgui.DrawIdxSize); for (let i = 0; i < drawCmd.ElemCount; i += 3) { const i0 = idx[i + 0]; const i1 = idx[i + 1]; const i2 = idx[i + 2]; const v0 = new imgui.DrawVert(drawList.VtxBuffer.buffer, drawList.VtxBuffer.byteOffset + i0 * imgui.DrawVertSize); const v1 = new imgui.DrawVert(drawList.VtxBuffer.buffer, drawList.VtxBuffer.byteOffset + i1 * imgui.DrawVertSize); const v2 = new imgui.DrawVert(drawList.VtxBuffer.buffer, drawList.VtxBuffer.byteOffset + i2 * imgui.DrawVertSize); const i3 = idx[i + 3]; const i4 = idx[i + 4]; const i5 = idx[i + 5]; const v3 = new imgui.DrawVert(drawList.VtxBuffer.buffer, drawList.VtxBuffer.byteOffset + i3 * imgui.DrawVertSize); const v4 = new imgui.DrawVert(drawList.VtxBuffer.buffer, drawList.VtxBuffer.byteOffset + i4 * imgui.DrawVertSize); const v5 = new imgui.DrawVert(drawList.VtxBuffer.buffer, drawList.VtxBuffer.byteOffset + i5 * imgui.DrawVertSize); let quad = true; let minMin = v0; let minMax = v0; let maxMin = v0; let maxMax = v0; for (const v of [v1, v2, v3, v4, v5]) { let found = false; if (v.pos[0] <= minMin.pos[0] && v.pos[1] <= minMin.pos[1]) { minMin = v; found = true; } if (v.pos[0] <= minMax.pos[0] && v.pos[1] >= minMax.pos[1]) { minMax = v; found = true; } if (v.pos[0] >= maxMin.pos[0] && v.pos[1] <= maxMin.pos[1]) { maxMin = v; found = true; } if (v.pos[0] >= maxMax.pos[0] && v.pos[1] >= maxMax.pos[1]) { maxMax = v; found = true; } if (!found) { quad = false; } } quad = quad && minMin.pos[0] === minMax.pos[0]; quad = quad && maxMin.pos[0] === maxMax.pos[0]; quad = quad && minMin.pos[1] === maxMin.pos[1]; quad = quad && minMax.pos[1] === maxMax.pos[1]; if (quad) { if (minMin.uv[0] === maxMax.uv[0] || minMin.uv[1] === maxMax.uv[1]) { ctx.beginPath(); ctx.rect(minMin.pos[0], minMin.pos[1], maxMax.pos[0] - minMin.pos[0], maxMax.pos[1] - minMin.pos[1]); ctx.fillStyle = `rgba(${v0.col[0] >> 0 & 255}, ${v0.col[0] >> 8 & 255}, ${v0.col[0] >> 16 & 255}, ${(v0.col[0] >> 24 & 255) / 255})`; ctx.fill(); } else { const image = drawCmd.TextureId; let width = 0; let height = 0; if (image instanceof HTMLVideoElement) { width = image.videoWidth; height = image.videoHeight; } else if (image instanceof VideoFrame) { width = image.displayWidth; height = image.displayHeight; } else if (image instanceof SVGAnimatedLength) { width = typeof image.width === "number" ? image.width : image.width.animVal.value; height = typeof image.height === "number" ? image.height : image.height.animVal.value; } else { width = image.width; height = image.height; } image && ctx.drawImage( image, minMin.uv[0] * width, minMin.uv[1] * height, (maxMax.uv[0] - minMin.uv[0]) * width, (maxMax.uv[1] - minMin.uv[1]) * height, minMin.pos[0], minMin.pos[1], maxMax.pos[0] - minMin.pos[0], maxMax.pos[1] - minMin.pos[1] ); } i += 3; } else { ctx.beginPath(); ctx.moveTo(v0.pos[0], v0.pos[1]); ctx.lineTo(v1.pos[0], v1.pos[1]); ctx.lineTo(v2.pos[0], v2.pos[1]); ctx.closePath(); ctx.fillStyle = `rgba(${v0.col[0] >> 0 & 255}, ${v0.col[0] >> 8 & 255}, ${v0.col[0] >> 16 & 255}, ${(v0.col[0] >> 24 & 255) / 255})`; ctx.fill(); } } ctx.restore(); } } class ImGuiWebGLRenderer { constructor(context) { __publicField(this, "_context"); __publicField(this, "_gl2"); __publicField(this, "_gl_vao"); __publicField(this, "g_ShaderHandle"); __publicField(this, "g_VertHandle"); __publicField(this, "g_FragHandle"); __publicField(this, "g_AttribLocationTex"); __publicField(this, "g_AttribLocationProjMtx"); __publicField(this, "g_AttribLocationPosition", -1); __publicField(this, "g_AttribLocationUV", -1); __publicField(this, "g_AttribLocationColor", -1); __publicField(this, "g_VboHandle"); __publicField(this, "g_ElementsHandle"); __publicField(this, "g_FontTexture", null); this._context = context; if (typeof WebGL2RenderingContext !== "undefined" && context instanceof WebGL2RenderingContext) { this._gl2 = context; } else { this._gl_vao = context.getExtension("OES_vertex_array_object") ?? void 0; } { const gl = context; const vertex_shader = [ "uniform mat4 ProjMtx;", "attribute vec2 Position;", "attribute vec2 UV;", "attribute vec4 Color;", "varying vec2 Frag_UV;", "varying vec4 Frag_Color;", "void main() {", " Frag_UV = UV;", " Frag_Color = Color;", " gl_Position = ProjMtx * vec4(Position.xy,0,1);", "}" ]; const fragment_shader = [ "precision mediump float;", // WebGL requires precision specifiers "uniform sampler2D Texture;", "varying vec2 Frag_UV;", "varying vec4 Frag_Color;", "void main() {", " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV);", "}" ]; const g_ShaderHandle = this.g_ShaderHandle = assertNonNull(gl.createProgram()); const g_VertHandle = this.g_VertHandle = assertNonNull(gl.createShader(gl.VERTEX_SHADER)); const g_FragHandle = this.g_FragHandle = assertNonNull(gl.createShader(gl.FRAGMENT_SHADER)); gl.shaderSource(g_VertHandle, vertex_shader.join("\n")); gl.shaderSource(g_FragHandle, fragment_shader.join("\n")); gl.compileShader(g_VertHandle); gl.compileShader(g_FragHandle); gl.attachShader(g_ShaderHandle, g_VertHandle); gl.attachShader(g_ShaderHandle, g_FragHandle); gl.linkProgram(g_ShaderHandle); this.g_AttribLocationTex = assertNonNull(gl.getUniformLocation(g_ShaderHandle, "Texture")); this.g_AttribLocationProjMtx = assertNonNull(gl.getUniformLocation(g_ShaderHandle, "ProjMtx")); this.g_AttribLocationPosition = gl.getAttribLocation(g_ShaderHandle, "Position") || 0; this.g_AttribLocationUV = gl.getAttribLocation(g_ShaderHandle, "UV") || 0; this.g_AttribLocationColor = gl.getAttribLocation(g_ShaderHandle, "Color") || 0; this.g_VboHandle = assertNonNull(gl.createBuffer()); this.g_ElementsHandle = assertNonNull(gl.createBuffer()); } } get width() { return this._context.drawingBufferWidth; } get height() { return this._context.drawingBufferHeight; } destroy() { const { _context: gl } = this; if (this.g_FontTexture) { gl.deleteTexture(this.g_FontTexture); this.g_FontTexture = null; } gl.deleteBuffer(this.g_VboHandle); gl.deleteBuffer(this.g_ElementsHandle); this.g_AttribLocationPosition = -1; this.g_AttribLocationUV = -1; this.g_AttribLocationColor = -1; gl.deleteProgram(this.g_ShaderHandle); gl.deleteShader(this.g_VertHandle); gl.deleteShader(this.g_FragHandle); } newFrame() { } renderDrawData(drawData, frameBufferWidth, frameBufferHeight) { const { _context: gl, _gl2: gl2, _gl_vao: gl_vao } = this; const last_active_texture = gl.getParameter(gl.ACTIVE_TEXTURE) || null; const last_program = gl.getParameter(gl.CURRENT_PROGRAM) || null; const last_texture = gl.getParameter(gl.TEXTURE_BINDING_2D) || null; const last_array_buffer = gl.getParameter(gl.ARRAY_BUFFER_BINDING) || null; const last_element_array_buffer = gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING) || null; const last_vertex_array_object = gl2 && gl2.getParameter(gl2.VERTEX_ARRAY_BINDING) || gl && gl_vao && gl.getParameter(gl_vao.VERTEX_ARRAY_BINDING_OES) || null; const last_viewport = gl.getParameter(gl.VIEWPORT) || null; const last_scissor_box = gl.getParameter(gl.SCISSOR_BOX) || null; const last_blend_src_rgb = gl.getParameter(gl.BLEND_SRC_RGB) || null; const last_blend_dst_rgb = gl.getParameter(gl.BLEND_DST_RGB) || null; const last_blend_src_alpha = gl.getParameter(gl.BLEND_SRC_ALPHA) || null; const last_blend_dst_alpha = gl.getParameter(gl.BLEND_DST_ALPHA) || null; const last_blend_equation_rgb = gl.getParameter(gl.BLEND_EQUATION_RGB) || null; const last_blend_equation_alpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA) || null; const last_enable_blend = gl.getParameter(gl.BLEND) || null; const last_enable_cull_face = gl.getParameter(gl.CULL_FACE) || null; const last_enable_depth_test = gl.getParameter(gl.DEPTH_TEST) || null; const last_enable_scissor_test = gl.getParameter(gl.SCISSOR_TEST) || null; this._doRenderDrawData(drawData, frameBufferWidth, frameBufferHeight); gl && last_program !== null && gl.useProgram(last_program); gl && last_texture !== null && gl.bindTexture(gl.TEXTURE_2D, last_texture); gl && last_active_texture !== null && gl.activeTexture(last_active_texture); gl2 && gl2.bindVertexArray(last_vertex_array_object) || gl_vao && gl_vao.bindVertexArrayOES(last_vertex_array_object); gl && last_array_buffer !== null && gl.bindBuffer(gl.ARRAY_BUFFER, last_array_buffer); gl && last_element_array_buffer !== null && gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, last_element_array_buffer); gl && (last_blend_equation_rgb !== null && last_blend_equation_alpha !== null) && gl.blendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); gl && (last_blend_src_rgb !== null && last_blend_src_alpha !== null && last_blend_dst_rgb !== null && last_blend_dst_alpha !== null) && gl.blendFuncSeparate(last_blend_src_rgb, last_blend_src_alpha, last_blend_dst_rgb, last_blend_dst_alpha); gl && (last_enable_blend ? gl.enable(gl.BLEND) : gl.disable(gl.BLEND)); gl && (last_enable_cull_face ? gl.enable(gl.CULL_FACE) : gl.disable(gl.CULL_FACE)); gl && (last_enable_depth_test ? gl.enable(gl.DEPTH_TEST) : gl.disable(gl.DEPTH_TEST)); gl && (last_enable_scissor_test ? gl.enable(gl.SCISSOR_TEST) : gl.disable(gl.SCISSOR_TEST)); gl && last_viewport !== null && gl.viewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3]); gl && last_scissor_box !== null && gl.scissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3]); } createFontsTexture(pixels, width, height) { const { _context: gl } = this; const last_texture = gl.getParameter(gl.TEXTURE_BINDING_2D); try { const fontTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, fontTexture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels); this.g_FontTexture = fontTexture; return fontTexture; } finally { last_texture && gl.bindTexture(gl.TEXTURE_2D, last_texture); } } _doRenderDrawData(drawData, frameBufferWidth, frameBufferHeight) { const { _context: gl, _gl2: gl2, _gl_vao: gl_vao } = this; const vertex_array_object = gl2 ? gl2.createVertexArray() : gl_vao ? gl_vao.createVertexArrayOES() : null; gl.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); gl.disable(gl.CULL_FACE); gl.disable(gl.DEPTH_TEST); gl.enable(gl.SCISSOR_TEST); gl.viewport(0, 0, frameBufferWidth, frameBufferHeight); const L = drawData.DisplayPos.x; const R = drawData.DisplayPos.x + drawData.DisplaySize.x; const T = drawData.DisplayPos.y; const B = drawData.DisplayPos.y + drawData.DisplaySize.y; const ortho_projection = new Float32Array([ 2 / (R - L), 0, 0, 0, 0, 2 / (T - B), 0, 0, 0, 0, -1, 0, (R + L) / (L - R), (T + B) / (B - T), 0, 1 ]); gl.useProgram(this.g_ShaderHandle); gl.uniform1i(this.g_AttribLocationTex, 0); this.g_AttribLocationProjMtx && gl.uniformMatrix4fv(this.g_AttribLocationProjMtx, false, ortho_projection); gl2 && gl2.bindVertexArray(vertex_array_object) || gl_vao && gl_vao.bindVertexArrayOES(vertex_array_object); gl.bindBuffer(gl.ARRAY_BUFFER, this.g_VboHandle); gl.enableVertexAttribArray(this.g_AttribLocationPosition); gl.enableVertexAttribArray(this.g_AttribLocationUV); gl.enableVertexAttribArray(this.g_AttribLocationColor); gl.vertexAttribPointer(this.g_AttribLocationPosition, 2, gl.FLOAT, false, imgui.DrawVertSize, imgui.DrawVertPosOffset); gl.vertexAttribPointer(this.g_AttribLocationUV, 2, gl.FLOAT, false, imgui.DrawVertSize, imgui.DrawVertUVOffset); gl.vertexAttribPointer(this.g_AttribLocationColor, 4, gl.UNSIGNED_BYTE, true, imgui.DrawVertSize, imgui.DrawVertColOffset); const pos = drawData.DisplayPos; const idx_buffer_type = gl && (imgui.DrawIdxSize === 4 ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT) || 0; drawData.IterateDrawLists((draw_list) => { gl.bindBuffer(gl.ARRAY_BUFFER, this.g_VboHandle); gl.bufferData(gl.ARRAY_BUFFER, draw_list.VtxBuffer, gl.STREAM_DRAW); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.g_ElementsHandle); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, draw_list.IdxBuffer, gl.STREAM_DRAW); draw_list.IterateDrawCmds((draw_cmd) => { if (draw_cmd.UserCallback !== null) { draw_cmd.UserCallback(draw_list, draw_cmd); } else { const clip_rect = new imgui.Vec4(draw_cmd.ClipRect.x - pos.x, draw_cmd.ClipRect.y - pos.y, draw_cmd.ClipRect.z - pos.x, draw_cmd.ClipRect.w - pos.y); if (clip_rect.x < frameBufferWidth && clip_rect.y < frameBufferHeight && clip_rect.z >= 0 && clip_rect.w >= 0) { gl.scissor(clip_rect.x, frameBufferHeight - clip_rect.w, clip_rect.z - clip_rect.x, clip_rect.w - clip_rect.y); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, draw_cmd.TextureId); gl.drawElements(gl.TRIANGLES, draw_cmd.ElemCount, idx_buffer_type, draw_cmd.IdxOffset * imgui.DrawIdxSize); } } }); }); gl2 && gl2.deleteVertexArray(vertex_array_object) || gl_vao && gl_vao.deleteVertexArrayOES(vertex_array_object); } } function assertNonNull(v) { if (v === null) { throw new Error("null assertion failed"); } return v; } var __defProp2 = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __decorateClass = (decorators, target, key, kind) => { var result = __getOwnPropDesc(target, key); for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = decorator(target, key, result) || result; if (result) __defProp2(target, key, result); return result; }; const mouseButtonMap = [0, 2, 1, 3, 4]; const keyCodeToIndex = { NumpadEnter: 176 }; const boundMethods = /* @__PURE__ */ new Set(); const bound = (_, propertyKey) => { boundMethods.add(propertyKey); }; class ImGuiWebContext { constructor(value, { wantEvents = true } = {}) { __publicField(this, "_canvas"); __publicField(this, "_renderer"); __publicField(this, "_prevTime", 0); __publicField(this, "_clipboardText", ""); __publicField(this, "_destroyingController", new AbortController()); this.value = value; for (const method of boundMethods) { this[method] = this[method].bind(this); } const io = imgui.GetIO(); { if (typeof window !== "undefined") { io.BackendPlatformName = "imgui_impl_browser"; imgui.LoadIniSettingsFromMemory(window.localStorage.getItem("imgui.ini") || ""); } else { io.BackendPlatformName = "imgui_impl_console"; } if (typeof navigator !== "undefined") { io.ConfigMacOSXBehaviors = navigator.platform.match(/Mac/) !== null; } if (typeof document !== "undefined") { document.body.addEventListener("copy", this._documentOnCopy); document.body.addEventListener("cut", this._documentOnCut); document.body.addEventListener("paste", this._documentOnPaste); } io.SetClipboardTextFn = (_userData, text) => { this._clipboardText = text; if (typeof navigator !== "undefined" && typeof navigator.clipboard !== "undefined") { navigator.clipboard.writeText(this._clipboardText).then(() => { }, (err) => { console.error(err); }); } }; io.GetClipboardTextFn = (_user_data) => { return this._clipboardText; }; io.ClipboardUserData = null; if (typeof window !== "undefined") { window.addEventListener("gamepadconnected", this._windowOnGamePadConnected); window.addEventListener("gamepaddisconnected", this._windowOnGamePadDisconnected); } } { let canvas; if (value instanceof HTMLCanvasElement || value instanceof OffscreenCanvas) { canvas = value; const context = canvas.getContext("webgl2", { alpha: false }) || canvas.getContext("webgl", { alpha: false }) || canvas.getContext("2d"); if (!context) { throw new Error("This browser can not provide any drawing context."); } value = context; } if (typeof WebGL2RenderingContext !== "undefined" && value instanceof WebGL2RenderingContext) { io.BackendRendererName = "imgui_impl_webgl2"; canvas = value.canvas; this._renderer = new ImGuiWebGLRenderer(value); } else if (typeof WebGLRenderingContext !== "undefined" && value instanceof WebGLRenderingContext) { io.BackendRendererName = "imgui_impl_webgl"; canvas = value.canvas; this._renderer = new ImGuiWebGLRenderer(value); } else if (typeof CanvasRenderingContext2D !== "undefined" && value instanceof CanvasRenderingContext2D) { io.BackendRendererName = "imgui_impl_2d"; canvas = value.canvas; this._renderer = new ImGuiCanvas2DRenderer(value); } else { throw new Error("You must provide a valid canvas or rendering context."); } this._canvas = canvas; } if (wantEvents) { const { _canvas: canvas } = this; if (canvas instanceof HTMLCanvasElement) { canvas.style.touchAction = "none"; const signal = this._destroyingController.signal; canvas.addEventListener("blur", this._canvasOnBlur, { signal }); canvas.addEventListener("keydown", this._canvasOnKeyDown, { signal }); canvas.addEventListener("keyup", this._canvasOnKeyUp, { signal }); canvas.addEventListener("keypress", this._canvasOnKeyPress, { signal }); canvas.addEventListener("pointermove", this._canvasOnPointerMove, { signal }); canvas.addEventListener("pointerdown", this._canvasOnPointerDown, { signal }); canvas.addEventListener("contextmenu", this._canvasOnContextMenu, { signal }); canvas.addEventListener("pointerup", this._canvasOnPointerUp, { signal }); canvas.addEventListener("wheel", this._canvasOnWheel, { signal }); } } io.BackendFlags |= imgui.BackendFlags.HasMouseCursors; io.KeyMap[imgui.Key.Tab] = 9; io.KeyMap[imgui.Key.LeftArrow] = 37; io.KeyMap[imgui.Key.RightArrow] = 39; io.KeyMap[imgui.Key.UpArrow] = 38; io.KeyMap[imgui.Key.DownArrow] = 40; io.KeyMap[imgui.Key.PageUp] = 33; io.KeyMap[imgui.Key.PageDown] = 34; io.KeyMap[imgui.Key.Home] = 36; io.KeyMap[imgui.Key.End] = 35; io.KeyMap[imgui.Key.Insert] = 45; io.KeyMap[imgui.Key.Delete] = 46; io.KeyMap[imgui.Key.Backspace] = 8; io.KeyMap[imgui.Key.Space] = 32; io.KeyMap[imgui.Key.Enter] = 13; io.KeyMap[imgui.Key.Escape] = 27; io.KeyMap[imgui.Key.KeyPadEnter] = keyCodeToIndex["NumpadEnter"]; io.KeyMap[imgui.Key.A] = 65; io.KeyMap[imgui.Key.C] = 67; io.KeyMap[imgui.Key.V] = 86; io.KeyMap[imgui.Key.X] = 88; io.KeyMap[imgui.Key.Y] = 89; io.KeyMap[imgui.Key.Z] = 90; this._createFontTexture(); } destroy() { const io = imgui.GetIO(); io.Fonts.TexID = null; this._destroyingController.abort(); this._renderer.destroy(); if (typeof window !== "undefined") { window.removeEventListener("gamepadconnected", this._windowOnGamePadConnected); window.removeEventListener("gamepaddisconnected", this._windowOnGamePadDisconnected); } if (typeof document !== "undefined") { document.body.removeEventListener("copy", this._documentOnCopy); document.body.removeEventListener("cut", this._documentOnCut); document.body.removeEventListener("paste", this._documentOnPaste); } } newFrame(time) { const io = imgui.GetIO(); if (io.WantSaveIniSettings) { io.WantSaveIniSettings = false; if (typeof window !== "undefined") { window.localStorage.setItem("imgui.ini", imgui.SaveIniSettingsToMemory()); } } let canvasWidth = 0; let canvasHeight = 0; if (this._canvas instanceof HTMLCanvasElement) { canvasWidth = this._canvas.width; canvasHeight = this._canvas.height; } else { canvasWidth = this._canvas.width; canvasHeight = this._canvas.height; } const w = canvasWidth || 640; const h = canvasHeight || 480; const display_w = this._renderer.width || w; const display_h = this._renderer.height || h; io.DisplaySize.x = w; io.DisplaySize.y = h; io.DisplayFramebufferScale.x = w > 0 ? display_w / w : 0; io.DisplayFramebufferScale.y = h > 0 ? display_h / h : 0; const dt = time - this._prevTime; this._prevTime = time; io.DeltaTime = dt / 1e3; if (io.WantSetMousePos) { console.log("TODO: MousePos", io.MousePos.x, io.MousePos.y); } if (typeof document !== "undefined") { if (io.MouseDrawCursor) { document.body.style.cursor = "none"; } else { switch (imgui.GetMouseCursor()) { case imgui.MouseCursor.None: document.body.style.cursor = "none"; break; default: case imgui.MouseCursor.Arrow: document.body.style.cursor = "default"; break; case imgui.MouseCursor.TextInput: document.body.style.cursor = "text"; break; // When hovering over InputText, etc. case imgui.MouseCursor.ResizeAll: document.body.style.cursor = "all-scroll"; break; // Unused case imgui.MouseCursor.ResizeNS: document.body.style.cursor = "ns-resize"; break; // When hovering over an horizontal border case imgui.MouseCursor.ResizeEW: document.body.style.cursor = "ew-resize"; break; // When hovering over a vertical border or a column case imgui.MouseCursor.ResizeNESW: document.body.style.cursor = "nesw-resize"; break; // When hovering over the bottom-left corner of a window case imgui.MouseCursor.ResizeNWSE: document.body.style.cursor = "nwse-resize"; break; // When hovering over the bottom-right corner of a window case imgui.MouseCursor.Hand: document.body.style.cursor = "move"; break; case imgui.MouseCursor.NotAllowed: document.body.style.cursor = "not-allowed"; break; } } } for (let i = 0; i < io.NavInputs.length; ++i) { } if (io.ConfigFlags & imgui.ConfigFlags.NavEnableGamepad) { const gamepads = typeof navigator !== "undefined" && typeof navigator.getGamepads === "function" ? navigator.getGamepads() : []; for (let i = 0; i < gamepads.length; ++i) { const gamepad = gamepads[i]; if (!gamepad) { continue; } io.BackendFlags |= imgui.BackendFlags.HasGamepad; const buttons_count = gamepad.buttons.length; const axes_count = gamepad.axes.length; const MAP_BUTTON = (NAV_NO, BUTTON_NO) => { if (!gamepad) { return; } if (buttons_count > BUTTON_NO && gamepad.buttons[BUTTON_NO].pressed) io.NavInputs[NAV_NO] = 1; }; const MAP_ANALOG = (NAV_NO, AXIS_NO, V0, V1) => { if (!gamepad) { return; } let v = axes_count > AXIS_NO ? gamepad.axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1) v = 1; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }; const match = gamepad.id.match(/^([0-9a-f]{4})-([0-9a-f]{4})-.*$/); const match_chrome = gamepad.id.match(/^.*\(.*Vendor: ([0-9a-f]{4}) Product: ([0-9a-f]{4})\).*$/); const vendor = match && match[1] || match_chrome && match_chrome[1] || "0000"; const product = match && match[2] || match_chrome && match_chrome[2] || "0000"; switch (vendor + product) { case "046dc216": MAP_BUTTON(imgui.NavInput.Activate, 1); MAP_BUTTON(imgui.NavInput.Cancel, 2); MAP_BUTTON(imgui.NavInput.Menu, 0); MAP_BUTTON(imgui.NavInput.Input, 3); MAP_ANALOG(imgui.NavInput.DpadLeft, 4, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.DpadRight, 4, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.DpadUp, 5, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.DpadDown, 5, 0.3, 0.9); MAP_BUTTON(imgui.NavInput.FocusPrev, 4); MAP_BUTTON(imgui.NavInput.FocusNext, 5); MAP_BUTTON(imgui.NavInput.TweakSlow, 6); MAP_BUTTON(imgui.NavInput.TweakFast, 7); MAP_ANALOG(imgui.NavInput.LStickLeft, 0, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickRight, 0, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.LStickUp, 1, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickDown, 1, 0.3, 0.9); break; case "046dc21d": MAP_BUTTON(imgui.NavInput.Activate, 0); MAP_BUTTON(imgui.NavInput.Cancel, 1); MAP_BUTTON(imgui.NavInput.Menu, 2); MAP_BUTTON(imgui.NavInput.Input, 3); MAP_BUTTON(imgui.NavInput.DpadLeft, 14); MAP_BUTTON(imgui.NavInput.DpadRight, 15); MAP_BUTTON(imgui.NavInput.DpadUp, 12); MAP_BUTTON(imgui.NavInput.DpadDown, 13); MAP_BUTTON(imgui.NavInput.FocusPrev, 4); MAP_BUTTON(imgui.NavInput.FocusNext, 5); MAP_ANALOG(imgui.NavInput.TweakSlow, 6, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.TweakFast, 7, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.LStickLeft, 0, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickRight, 0, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.LStickUp, 1, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickDown, 1, 0.3, 0.9); break; case "2dc86001": // 8Bitdo SN30 Pro 8Bitdo SN30 Pro (Vendor: 2dc8 Product: 6001) case "2dc86101": MAP_BUTTON(imgui.NavInput.Activate, 1); MAP_BUTTON(imgui.NavInput.Cancel, 0); MAP_BUTTON(imgui.NavInput.Menu, 4); MAP_BUTTON(imgui.NavInput.Input, 3); MAP_ANALOG(imgui.NavInput.DpadLeft, 6, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.DpadRight, 6, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.DpadUp, 7, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.DpadDown, 7, 0.3, 0.9); MAP_BUTTON(imgui.NavInput.FocusPrev, 6); MAP_BUTTON(imgui.NavInput.FocusNext, 7); MAP_BUTTON(imgui.NavInput.TweakSlow, 8); MAP_BUTTON(imgui.NavInput.TweakFast, 9); MAP_ANALOG(imgui.NavInput.LStickLeft, 0, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickRight, 0, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.LStickUp, 1, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickDown, 1, 0.3, 0.9); break; default: MAP_BUTTON(imgui.NavInput.Activate, 0); MAP_BUTTON(imgui.NavInput.Cancel, 1); MAP_BUTTON(imgui.NavInput.Menu, 2); MAP_BUTTON(imgui.NavInput.Input, 3); MAP_BUTTON(imgui.NavInput.DpadLeft, 14); MAP_BUTTON(imgui.NavInput.DpadRight, 15); MAP_BUTTON(imgui.NavInput.DpadUp, 12); MAP_BUTTON(imgui.NavInput.DpadDown, 13); MAP_BUTTON(imgui.NavInput.FocusPrev, 4); MAP_BUTTON(imgui.NavInput.FocusNext, 5); MAP_BUTTON(imgui.NavInput.TweakSlow, 6); MAP_BUTTON(imgui.NavInput.TweakFast, 7); MAP_ANALOG(imgui.NavInput.LStickLeft, 0, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickRight, 0, 0.3, 0.9); MAP_ANALOG(imgui.NavInput.LStickUp, 1, -0.3, -0.9); MAP_ANALOG(imgui.NavInput.LStickDown, 1, 0.3, 0.9); break; } } } imgui.NewFrame(); } endFrame() { imgui.EndFrame(); } render() { imgui.Render(); const drawData = imgui.GetDrawData(); if (drawData === null) { throw new Error(`Empty draw data.`); } this._doRenderDrawData(drawData); } _doRenderDrawData(drawData) { const io = imgui.GetIO(); const fb_width = io.DisplaySize.x * io.DisplayFramebufferScale.x; const fb_height = io.DisplaySize.y * io.DisplayFramebufferScale.y; if (fb_width === 0 || fb_height === 0) { return; } drawData.ScaleClipRects(io.DisplayFramebufferScale); this._renderer.renderDrawData(drawData, fb_width, fb_height); } _createFontTexture() { const io = imgui.GetIO(); const { width, height, pixels } = io.Fonts.GetTexDataAsRGBA32(); const texture = this._renderer.createFontsTexture(pixels, width, height); io.Fonts.SetTexID(texture); } _documentOnCopy(event) { if (event.clipboardData) { event.clipboardData.setData("text/plain", this._clipboardText); } event.preventDefault(); } _documentOnCut(event) { if (event.clipboardData) { event.clipboardData.setData("text/plain", this._clipboardText); } event.preventDefault(); } _documentOnPaste(event) { if (event.clipboardData) { this._clipboardText = event.clipboardData.getData("text/plain"); } event.preventDefault(); } _windowOnGamePadConnected(event) { console.log( "Gamepad connected at index %d: %s. %d buttons, %d axes.", event.gamepad.index, event.gamepad.id, event.gamepad.buttons.length, event.gamepad.axes.length ); } _windowOnGamePadDisconnected(event) { console.log( "Gamepad disconnected at index %d: %s.", event.gamepad.index, event.gamepad.id ); } _canvasOnBlur(_event) { const io = imgui.GetIO(); io.KeyCtrl = false; io.KeyShift = false; io.KeyAlt = false; io.KeySuper = false; for (let i = 0; i < io.KeysDown.length; ++i) { io.KeysDown[i] = false; } for (let i = 0; i < io.MouseDown.length; ++i) { io.MouseDown[i] = false; } } _canvasOnKeyDown(event) { const io = imgui.GetIO(); io.KeyCtrl = event.ctrlKey; io.KeyShift = event.shiftKey; io.KeyAlt = event.altKey; io.KeySuper = event.metaKey; const key_index = keyCodeToIndex[event.code] || event.keyCode; imgui.ASSERT(key_index >= 0 && key_index < imgui.ARRAYSIZE(io.KeysDown)); io.KeysDown[key_index] = true; if ( /* io.WantCaptureKeyboard || */ event.key === "Tab" ) { event.preventDefault(); } } _canvasOnKeyUp(event) { const io = imgui.GetIO(); io.KeyCtrl = event.ctrlKey; io.KeyShift = event.shiftKey; io.KeyAlt = event.altKey; io.KeySuper = event.metaKey; const key_index = keyCodeToIndex[event.code] || event.keyCode; imgui.ASSERT(key_index >= 0 && key_index < imgui.ARRAYSIZE(io.KeysDown)); io.KeysDown[key_index] = false; if (io.WantCaptureKeyboard) { event.preventDefault(); } } _canvasOnKeyPress(event) { const io = imgui.GetIO(); io.AddInputCharacter(event.charCode); if (io.WantCaptureKeyboard) { event.preventDefault(); } } _canvasOnPointerMove(event) { const io = imgui.GetIO(); io.MousePos.x = event.offsetX; io.MousePos.y = event.offsetY; if (io.WantCaptureMouse) { event.preventDefault(); } } _canvasOnPointerDown(event) { const io = imgui.GetIO(); io.MousePos.x = event.offsetX; io.MousePos.y = event.offsetY; io.MouseDown[mouseButtonMap[event.button]] = true; if (io.WantCaptureMouse) { event.preventDefault(); } } _canvasOnContextMenu(event) { const io = imgui.GetIO(); if (io.WantCaptureMouse) { event.preventDefault(); } } _canvasOnPointerUp(event) { const io = imgui.GetIO(); io.MouseDown[mouseButtonMap[event.button]] = false; if (io.WantCaptureMouse) { event.preventDefault(); } } _canvasOnWheel(event) { const io = imgui.GetIO(); let scale = 1; switch (event.deltaMode) { case event.DOM_DELTA_PIXEL: scale = 0.01; break; case event.DOM_DELTA_LINE: scale = 0.2; break; case event.DOM_DELTA_PAGE: scale = 1; break; } io.MouseWheelH = event.deltaX * scale; io.MouseWheel = -event.deltaY * scale; if (io.WantCaptureMouse) { event.preventDefault(); } } } __decorateClass([ bound ], ImGuiWebContext.prototype, "_documentOnCopy"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_documentOnCut"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_documentOnPaste"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_windowOnGamePadConnected"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_windowOnGamePadDisconnected"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnBlur"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnKeyDown"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnKeyUp"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnKeyPress"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnPointerMove"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnPointerDown"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnContextMenu"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnPointerUp"); __decorateClass([ bound ], ImGuiWebContext.prototype, "_canvasOnWheel"); export { ImGuiWebContext, imgui2 as imgui };