You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
18 KiB
368 lines
18 KiB
(import "Dependencies.cake" "CHelpers.cake" "ComptimeHelpers.cake"
|
|
"DynamicArray.cake" ;; For dynstring text widgets
|
|
&defs-only "Licenses.cake")
|
|
|
|
(c-import "imgui.h")
|
|
|
|
(register-module-license "dear imgui" s-imgui-license-string)
|
|
(register-module-license "Ubuntu font" s-ubuntu-font-license-string)
|
|
|
|
;; The main interface into imgui.
|
|
(defmacro imgui-call (function symbol &rest &optional arguments any)
|
|
(if arguments
|
|
(tokenize-push output
|
|
(call (in ImGui (token-splice function)) (token-splice-rest arguments tokens)))
|
|
(tokenize-push output
|
|
(call (in ImGui (token-splice function)))))
|
|
(return true))
|
|
|
|
(defun imgui-do-tooltip (text (addr (const char)) shortcut (addr (const char)))
|
|
(when (imgui-call IsItemHovered)
|
|
(imgui-call BeginTooltip)
|
|
(imgui-call PushTextWrapPos (* (imgui-call GetFontSize) 35.0f))
|
|
(imgui-call TextWrapped "%s" text)
|
|
(when shortcut
|
|
(imgui-call TextDisabled "%s" shortcut))
|
|
(imgui-call EndTooltip)))
|
|
|
|
(defun imgui-first-time-window-size (x float y float width float height float)
|
|
(var main-viewport (addr (const ImGuiViewport)) (imgui-call GetMainViewport))
|
|
(var imgui-style (ref ImGuiStyle) (imgui-call GetStyle))
|
|
(var menu-bar-approx-offset float (+ (* 2 (field imgui-style FramePadding y))
|
|
(imgui-call GetFontSize)))
|
|
(imgui-call SetNextWindowPos (ImVec2 (+ (path main-viewport > WorkPos . x)
|
|
(* x (path main-viewport > WorkSize . x)))
|
|
(+ (path main-viewport > WorkPos . y)
|
|
(* y (- (path main-viewport > WorkSize . y)
|
|
menu-bar-approx-offset))
|
|
menu-bar-approx-offset))
|
|
ImGuiCond_FirstUseEver)
|
|
(imgui-call SetNextWindowSize (ImVec2 (* (path main-viewport > WorkSize . x) width)
|
|
(* (- (path main-viewport > WorkSize . y)
|
|
menu-bar-approx-offset)
|
|
height))
|
|
ImGuiCond_FirstUseEver))
|
|
|
|
(defun-local imgui-input-text-dynstring-resize (data (addr ImGuiInputTextCallbackData)
|
|
&return int)
|
|
(when (= (path data > EventFlag) ImGuiInputTextFlags_CallbackResize)
|
|
(var-cast-to dynstring-out (addr (addr char)) (path data > UserData))
|
|
;; Minimize reallocations by making sure we have a decent amount of capacity
|
|
(var resize-at-capacity (unsigned int)
|
|
;; 75% of the current capacity
|
|
(+ (* (/ (dynarray-capacity (deref dynstring-out)) 4) 3)))
|
|
;; This factor should always be larger than the resize-at-capacity percentage
|
|
(var resize-factor (unsigned int) 2)
|
|
;; Use the BufSize rather than the dynarray-length to ensure if the buffer has greatly
|
|
;; increased, we have room for it. This happens when the user e.g. copy pastes a block of text
|
|
;; rather than types a single character.
|
|
(when (>= (path data > BufSize) resize-at-capacity)
|
|
(var new-capacity (unsigned int) (* resize-factor (dynarray-capacity (deref dynstring-out))))
|
|
;; Finally, if the BufSize is much much larger than even our resize, just use it to set our new size
|
|
(when (< new-capacity (path data > BufSize))
|
|
(set new-capacity (* 2 (path data > BufSize))))
|
|
(dynarray-set-capacity (deref dynstring-out)
|
|
new-capacity))
|
|
(dynarray-set-length (deref dynstring-out) (path data > BufSize))
|
|
(set (path data > Buf) (deref dynstring-out)))
|
|
(return 0))
|
|
|
|
(defun imgui-input-text-multiline-to-dynstring (label (addr (const char))
|
|
dynstring-out (addr (addr char))
|
|
width float
|
|
height float
|
|
flags int ;; ImGuiInputTextFlags
|
|
&return bool)
|
|
;; ImGui can't work with a completely null buffer
|
|
(unless (deref dynstring-out)
|
|
(dynstring-make-empty-string dynstring-out 64))
|
|
|
|
(return (imgui-call InputTextMultiline label (deref dynstring-out)
|
|
;; Note we use the full length because ImGui expects space for null terminator
|
|
(dynarray-length (deref dynstring-out))
|
|
(ImVec2 width height)
|
|
(bit-or flags ImGuiInputTextFlags_CallbackResize)
|
|
imgui-input-text-dynstring-resize (type-cast dynstring-out (addr void)))))
|
|
|
|
;; When you just don't care about the details and want a ImGui window
|
|
(defmacro make-imgui-sdl-gl3-application (entry-point-name symbol
|
|
window-name string
|
|
initialization array
|
|
once-per-frame array
|
|
shutdown array)
|
|
;; This is somewhat unusual. Make unique font data variable names due to "var" always being a
|
|
;; global declaration to Cakelisp. The data will still only be bundled once.
|
|
;; TODO think of a way to clean this up. DataBundle should handle this better for us.
|
|
(var start-font-data-name Token (deref entry-point-name))
|
|
(token-contents-snprintf start-font-data-name "start-font-data-%s"
|
|
(call-on c_str (field start-font-data-name contents)))
|
|
(var end-font-data-name Token (deref entry-point-name))
|
|
(token-contents-snprintf end-font-data-name "end-font-data-%s"
|
|
(call-on c_str (field end-font-data-name contents)))
|
|
|
|
(tokenize-push output
|
|
(import "DataBundle.cake")
|
|
(bundle-file (token-splice-addr start-font-data-name) (token-splice-addr end-font-data-name)
|
|
(unsigned char) "data/Fonts/Ubuntu-R.ttf")
|
|
|
|
(defun (token-splice entry-point-name) (&return int)
|
|
(comptime-cond
|
|
('Windows
|
|
;; We are handling DPI scaling, so don't let Windows scale us again
|
|
(SetProcessDpiAwarenessContext DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)))
|
|
|
|
(data-bundle-load-all-resources)
|
|
|
|
;; Must do this before choosing the GL version
|
|
(SDL_Init SDL_INIT_VIDEO)
|
|
;; Not actually used: ImGuiSDLOpenGL_SetAttributes override these for SDL_GL_CreateContext
|
|
(SDL_GL_SetAttribute SDL_GL_CONTEXT_MAJOR_VERSION 3)
|
|
(SDL_GL_SetAttribute SDL_GL_CONTEXT_MINOR_VERSION 2)
|
|
|
|
(var display-bounds SDL_Rect (array 0))
|
|
;; Primary display
|
|
(SDL_GetDisplayBounds 0 (addr display-bounds))
|
|
|
|
;; Define the window size as a factor of the display size so that it should always fit
|
|
(var window-display-ratio float 0.75f)
|
|
|
|
(var window (addr SDL_Window) null)
|
|
(set window
|
|
(SDL_CreateWindow (token-splice window-name)
|
|
SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED
|
|
(* window-display-ratio (field display-bounds w))
|
|
(* window-display-ratio (field display-bounds h))
|
|
(bit-or SDL_WINDOW_RESIZABLE SDL_WINDOW_OPENGL)))
|
|
(unless window
|
|
(sdl-print-error)
|
|
(return 1))
|
|
|
|
(var glsl-version (addr (const char)) null)
|
|
(ImGuiSDLOpenGL_SetAttributes (addr glsl-version))
|
|
|
|
(var gl-context SDL_GLContext (SDL_GL_CreateContext window))
|
|
(SDL_GL_MakeCurrent window gl-context)
|
|
(SDL_GL_SetSwapInterval 1) ;; Enable vsync
|
|
|
|
(unless (ImGuiSDLOpenGL_InitializeGLLoader)
|
|
(fprintf stderr "Failed ImGuiSDLOpenGL_InitializeGLLoader\n")
|
|
(return 1))
|
|
|
|
(imgui-call CreateContext)
|
|
|
|
(scope ;; Enable docking
|
|
(var imgui-io (ref ImGuiIO) (imgui-call GetIO))
|
|
(set (field imgui-io ConfigFlags) (bit-or (field imgui-io ConfigFlags)
|
|
ImGuiConfigFlags_DockingEnable)))
|
|
|
|
(scope ;; Enable keyboard navigation
|
|
(var imgui-io (ref ImGuiIO) (imgui-call GetIO))
|
|
(set (field imgui-io ConfigFlags) (bit-or (field imgui-io ConfigFlags)
|
|
ImGuiConfigFlags_NavEnableKeyboard)))
|
|
|
|
;; DPI scaling
|
|
(var g-dpi-scale float 1.f)
|
|
;; Somewhat arbitrary numbers here which seemed to make sense on my 4k screen
|
|
(when (> (field display-bounds h) 1440)
|
|
(set g-dpi-scale 1.6f))
|
|
(scope
|
|
(var style (ref ImGuiStyle) (imgui-call GetStyle))
|
|
(call-on ScaleAllSizes style g-dpi-scale))
|
|
|
|
(scope ;; Font
|
|
(var imgui-io (ref ImGuiIO) (imgui-call GetIO))
|
|
(var g-font-size-pixels int 16)
|
|
(var font-config ImFontConfig)
|
|
;; The data is bundled in the executable, so don't try to delete it
|
|
(set (field font-config FontDataOwnedByAtlas) false)
|
|
(var ubuntu-mono-font (addr ImFont)
|
|
(call-on-ptr AddFontFromMemoryTTF (field imgui-io Fonts)
|
|
(token-splice-addr start-font-data-name)
|
|
(- (token-splice-addr end-font-data-name)
|
|
(token-splice-addr start-font-data-name))
|
|
(* g-font-size-pixels g-dpi-scale)
|
|
(addr font-config)))
|
|
;; imgui-io.Fonts->GetTexDataAsRGBA32();
|
|
(call-on-ptr Build (field imgui-io Fonts)))
|
|
|
|
;; (imgui-call StyleColorsDark)
|
|
(imgui-set-style-red-dark)
|
|
|
|
;; Note: Passing in null for the context will break Viewports branch of ImGui
|
|
(unless (ImGui_ImplSDL2_InitForOpenGL window gl-context)
|
|
(fprintf stderr "Failed ImGui_ImplSDL2_InitForOpenGL\n")
|
|
(return 1))
|
|
(ImGui_ImplOpenGL3_Init glsl-version)
|
|
|
|
(token-splice initialization)
|
|
|
|
(var exit-reason (addr (const char)) null)
|
|
(while (not exit-reason)
|
|
(var event SDL_Event)
|
|
(while (SDL_PollEvent (addr event))
|
|
(ImGui_ImplSDL2_ProcessEvent (addr event))
|
|
(when (= (field event type) SDL_QUIT)
|
|
(set exit-reason "Window event"))
|
|
(when (and (= (field event type) SDL_WINDOWEVENT)
|
|
(= (field event window event) SDL_WINDOWEVENT_CLOSE)
|
|
(= (SDL_GetWindowID window) (field event window windowID)))
|
|
(set exit-reason "Window event")))
|
|
|
|
(var currentKeyStates (addr (const Uint8)) (SDL_GetKeyboardState null))
|
|
|
|
(ImGui_ImplOpenGL3_NewFrame)
|
|
(ImGui_ImplSDL2_NewFrame window)
|
|
(imgui-call NewFrame)
|
|
|
|
(scope ;; Probably will be handled by your game instead
|
|
(var imgui-io (ref ImGuiIO) (imgui-call GetIO))
|
|
(var clear-color ImVec4 (array 0.1f 0.1f 0.1f 1.f))
|
|
(ImGuiSDLOpenGL_ClearWindow (addr imgui-io) clear-color))
|
|
|
|
(imgui-call DockSpaceOverViewport (imgui-call GetMainViewport)
|
|
;; Allow inputs and graphics to go through the dock
|
|
ImGuiDockNodeFlags_PassthruCentralNode)
|
|
|
|
(token-splice once-per-frame)
|
|
|
|
(imgui-call Render)
|
|
(ImGui_ImplOpenGL3_RenderDrawData (imgui-call GetDrawData))
|
|
|
|
(SDL_GL_SwapWindow window))
|
|
|
|
(when exit-reason
|
|
(SDL_HideWindow window)
|
|
(fprintf stderr "Exiting. Reason: %s\n" exit-reason))
|
|
|
|
(token-splice shutdown)
|
|
|
|
(ImGui_ImplOpenGL3_Shutdown)
|
|
(ImGui_ImplSDL2_Shutdown)
|
|
|
|
(imgui-call DestroyContext)
|
|
|
|
(sdl-shutdown window)
|
|
(return 0)))
|
|
(return true))
|
|
|
|
(defun imgui-set-style-red-dark ()
|
|
;; copied and modified from https://github.com/ocornut/imgui/issues/707
|
|
(var colors (addr ImVec4) (field (imgui-call GetStyle) Colors))
|
|
(set (at ImGuiCol_Text colors) (ImVec4 0.75f 0.75f 0.75f 1.00f))
|
|
(set (at ImGuiCol_TextDisabled colors) (ImVec4 0.35f 0.35f 0.35f 1.00f))
|
|
(set (at ImGuiCol_WindowBg colors) (ImVec4 0.00f 0.00f 0.00f 0.94f))
|
|
(set (at ImGuiCol_ChildBg colors) (ImVec4 0.00f 0.00f 0.00f 0.00f))
|
|
(set (at ImGuiCol_PopupBg colors) (ImVec4 0.08f 0.08f 0.08f 0.94f))
|
|
(set (at ImGuiCol_Border colors) (ImVec4 0.00f 0.00f 0.00f 0.50f))
|
|
(set (at ImGuiCol_BorderShadow colors) (ImVec4 0.00f 0.00f 0.00f 0.00f))
|
|
(set (at ImGuiCol_FrameBg colors) (ImVec4 0.25f 0.25f 0.25f 0.54f))
|
|
(set (at ImGuiCol_FrameBgHovered colors) (ImVec4 0.37f 0.14f 0.14f 0.67f))
|
|
(set (at ImGuiCol_FrameBgActive colors) (ImVec4 0.39f 0.20f 0.20f 0.67f))
|
|
(set (at ImGuiCol_TitleBg colors) (ImVec4 0.04f 0.04f 0.04f 1.00f))
|
|
(set (at ImGuiCol_TitleBgActive colors) (ImVec4 0.48f 0.16f 0.16f 1.00f))
|
|
(set (at ImGuiCol_TitleBgCollapsed colors) (ImVec4 0.48f 0.16f 0.16f 1.00f))
|
|
(set (at ImGuiCol_MenuBarBg colors) (ImVec4 0.14f 0.14f 0.14f 1.00f))
|
|
(set (at ImGuiCol_ScrollbarBg colors) (ImVec4 0.02f 0.02f 0.02f 0.53f))
|
|
(set (at ImGuiCol_ScrollbarGrab colors) (ImVec4 0.31f 0.31f 0.31f 1.00f))
|
|
(set (at ImGuiCol_ScrollbarGrabHovered colors) (ImVec4 0.41f 0.41f 0.41f 1.00f))
|
|
(set (at ImGuiCol_ScrollbarGrabActive colors) (ImVec4 0.51f 0.51f 0.51f 1.00f))
|
|
(set (at ImGuiCol_CheckMark colors) (ImVec4 0.56f 0.10f 0.10f 1.00f))
|
|
(set (at ImGuiCol_SliderGrab colors) (ImVec4 1.00f 0.19f 0.19f 0.40f))
|
|
(set (at ImGuiCol_SliderGrabActive colors) (ImVec4 0.89f 0.00f 0.19f 1.00f))
|
|
(set (at ImGuiCol_Button colors) (ImVec4 1.00f 0.19f 0.19f 0.40f))
|
|
(set (at ImGuiCol_ButtonHovered colors) (ImVec4 0.80f 0.17f 0.00f 1.00f))
|
|
(set (at ImGuiCol_ButtonActive colors) (ImVec4 0.89f 0.00f 0.19f 1.00f))
|
|
(set (at ImGuiCol_Header colors) (ImVec4 0.33f 0.35f 0.36f 0.53f))
|
|
(set (at ImGuiCol_HeaderHovered colors) (ImVec4 0.76f 0.28f 0.44f 0.67f))
|
|
(set (at ImGuiCol_HeaderActive colors) (ImVec4 0.47f 0.47f 0.47f 0.67f))
|
|
(set (at ImGuiCol_Separator colors) (ImVec4 0.32f 0.32f 0.32f 1.00f))
|
|
(set (at ImGuiCol_SeparatorHovered colors) (ImVec4 0.32f 0.32f 0.32f 1.00f))
|
|
(set (at ImGuiCol_SeparatorActive colors) (ImVec4 0.32f 0.32f 0.32f 1.00f))
|
|
(set (at ImGuiCol_ResizeGrip colors) (ImVec4 1.00f 1.00f 1.00f 0.85f))
|
|
(set (at ImGuiCol_ResizeGripHovered colors) (ImVec4 1.00f 1.00f 1.00f 0.60f))
|
|
(set (at ImGuiCol_ResizeGripActive colors) (ImVec4 1.00f 1.00f 1.00f 0.90f))
|
|
(set (at ImGuiCol_Tab colors) (ImVec4 0.07f 0.07f 0.07f 0.51f))
|
|
(set (at ImGuiCol_TabHovered colors) (ImVec4 0.86f 0.23f 0.43f 0.67f))
|
|
(set (at ImGuiCol_TabActive colors) (ImVec4 0.19f 0.19f 0.19f 0.57f))
|
|
(set (at ImGuiCol_TabUnfocused colors) (ImVec4 0.05f 0.05f 0.05f 0.90f))
|
|
(set (at ImGuiCol_TabUnfocusedActive colors) (ImVec4 0.13f 0.13f 0.13f 0.74f))
|
|
(set (at ImGuiCol_DockingPreview colors) (ImVec4 0.47f 0.47f 0.47f 0.47f))
|
|
(set (at ImGuiCol_DockingEmptyBg colors) (ImVec4 0.20f 0.20f 0.20f 1.00f))
|
|
(set (at ImGuiCol_PlotLines colors) (ImVec4 0.61f 0.61f 0.61f 1.00f))
|
|
(set (at ImGuiCol_PlotLinesHovered colors) (ImVec4 1.00f 0.43f 0.35f 1.00f))
|
|
(set (at ImGuiCol_PlotHistogram colors) (ImVec4 0.90f 0.70f 0.00f 1.00f))
|
|
(set (at ImGuiCol_PlotHistogramHovered colors) (ImVec4 1.00f 0.60f 0.00f 1.00f))
|
|
(set (at ImGuiCol_TableHeaderBg colors) (ImVec4 0.19f 0.19f 0.20f 1.00f))
|
|
(set (at ImGuiCol_TableBorderStrong colors) (ImVec4 0.31f 0.31f 0.35f 1.00f))
|
|
(set (at ImGuiCol_TableBorderLight colors) (ImVec4 0.23f 0.23f 0.25f 1.00f))
|
|
(set (at ImGuiCol_TableRowBg colors) (ImVec4 0.00f 0.00f 0.00f 0.00f))
|
|
(set (at ImGuiCol_TableRowBgAlt colors) (ImVec4 1.00f 1.00f 1.00f 0.07f))
|
|
(set (at ImGuiCol_TextSelectedBg colors) (ImVec4 0.26f 0.59f 0.98f 0.35f))
|
|
(set (at ImGuiCol_DragDropTarget colors) (ImVec4 1.00f 1.00f 0.00f 0.90f))
|
|
(set (at ImGuiCol_NavHighlight colors) (ImVec4 0.26f 0.59f 0.98f 1.00f))
|
|
(set (at ImGuiCol_NavWindowingHighlight colors) (ImVec4 1.00f 1.00f 1.00f 0.70f))
|
|
(set (at ImGuiCol_NavWindowingDimBg colors) (ImVec4 0.80f 0.80f 0.80f 0.20f))
|
|
(set (at ImGuiCol_ModalWindowDimBg colors) (ImVec4 0.80f 0.80f 0.80f 0.35f)))
|
|
|
|
;;
|
|
;; Building
|
|
;;
|
|
|
|
(add-dependency-git-submodule clone-imgui "https://github.com/ocornut/imgui"
|
|
"Dependencies/imgui"
|
|
"docking")
|
|
|
|
;; TODO This is a hack: add build output dir as search directory. Should be built in?
|
|
(defun-comptime add-search-build-directory (manager (ref ModuleManager) module (addr Module)
|
|
&return bool)
|
|
(call-on push_back (path module > cSearchDirectories)
|
|
(call-on c_str (field manager buildOutputDir)))
|
|
(return true))
|
|
|
|
(export-and-evaluate
|
|
;; Different loaders are available. Loader selection could be done via macro to allow that flexibility
|
|
(import "OpenGL.cake")
|
|
(import "SDL.cake")
|
|
(c-import "imgui.h"
|
|
"imgui_impl_sdl.h" ;; Platform (inputs etc.)
|
|
"imgui_impl_opengl3.h") ;; Rendering
|
|
;; From ImGuiSDLOpenGL.cpp
|
|
(declare-extern-function ImGuiSDLOpenGL_SetAttributes (glsl-version (addr (addr (const char)))))
|
|
(declare-extern-function ImGuiSDLOpenGL_InitializeGLLoader (&return bool))
|
|
(declare-extern-function ImGuiSDLOpenGL_ClearWindow (io (addr ImGuiIO) clear-color ImVec4))
|
|
|
|
(add-c-search-directory-module
|
|
"Dependencies/gamelib/src"
|
|
"Dependencies/imgui"
|
|
"Dependencies/imgui/backends")
|
|
|
|
(add-compile-time-hook-module pre-build add-search-build-directory)
|
|
|
|
(comptime-cond
|
|
('Unix
|
|
(add-library-dependency "GL" "dl"))
|
|
('Windows
|
|
(add-static-link-objects "opengl32.lib"))))
|
|
|
|
(add-cpp-build-dependency "imgui.cpp"
|
|
"imgui_demo.cpp"
|
|
"imgui_draw.cpp"
|
|
"imgui_tables.cpp"
|
|
"imgui_widgets.cpp")
|
|
(add-cpp-build-dependency "imgui_impl_sdl.cpp" "ImGuiSDLOpenGL.cpp" "imgui_impl_opengl3.cpp")
|
|
|
|
;;
|
|
;; Testing
|
|
;;
|
|
|
|
(comptime-cond
|
|
('auto-test
|
|
(c-import "<stdio.h>")
|
|
|
|
(make-imgui-sdl-gl3-application ;; If you want your own entry point, check this macro's body
|
|
test--imgui-main
|
|
"GameLib ImGui test"
|
|
(scope (fprintf stderr "Initializing\n")) ;; Initialization
|
|
(scope ;; Once per frame
|
|
(imgui-call ShowDemoWindow))
|
|
(scope (fprintf stderr "Shut down\n"))))) ;; Shutdown
|
|
|