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.
291 lines
7.2 KiB
291 lines
7.2 KiB
(defpackage :imgui |
|
(:use :cl)) |
|
|
|
(in-package :imgui) |
|
|
|
(pushnew "/home/eta/common-lisp/imgui/" cffi:*foreign-library-directories* |
|
:test #'equal) |
|
|
|
(cffi:define-foreign-library cimgui |
|
(t (:default "cimgui"))) |
|
|
|
(cffi:define-foreign-library cimgui-sdl |
|
(t (:default "libcimgui_sdl"))) |
|
|
|
(cffi:define-foreign-library gl3w |
|
(t (:default "libgl3w"))) |
|
|
|
(cffi:define-foreign-library sdl |
|
(t (:default "libSDL2"))) |
|
|
|
(cffi:use-foreign-library cimgui) |
|
(cffi:use-foreign-library gl3w) |
|
(cffi:use-foreign-library sdl) |
|
(cffi:use-foreign-library cimgui-sdl) |
|
|
|
(defparameter +sdl2-init-video+ #x00000020) |
|
(defparameter +sdl2-windowpos-centred+ #x2FFF0000) |
|
(defparameter +sdl2-window-opengl+ #x00000002) |
|
(defparameter +sdl2-window-resizable+ #x00000020) |
|
|
|
(cffi:defcfun "SDL_Init" :int |
|
(flags :uint32)) |
|
|
|
(cffi:defcenum sdl2-glattr |
|
:red-size |
|
:green-size |
|
:blue-size |
|
:alpha-size |
|
:buffer-size |
|
:doublebuffer |
|
:depth-size |
|
:stencil-size |
|
:accum-red-size |
|
:accum-green-size |
|
:accum-blue-size |
|
:accum-alpha-size |
|
:stereo |
|
:multisamplebuffers |
|
:multisamplesamples |
|
:accelerated-visual |
|
:retained-backing |
|
:context-major-version |
|
:context-minor-version |
|
:context-egl |
|
:context-flags |
|
:context-profile-mask |
|
:share-with-current-context |
|
:framebuffer-srgb-capable |
|
:context-release-behavior |
|
:context-reset-notification |
|
:context-no-error) |
|
|
|
(cffi:defcfun "SDL_GetError" :string) |
|
|
|
(defun sdlcall (value) |
|
(when (< value 0) |
|
(error "SDL error ~A: ~A" value (sdl-geterror))) |
|
value) |
|
|
|
(cffi:defcfun "SDL_GL_SetAttribute" :int |
|
(attr sdl2-glattr) |
|
(value :int)) |
|
|
|
(cffi:defctype sdl-window :pointer) |
|
|
|
(cffi:defcfun "SDL_CreateWindow" sdl-window |
|
(title :string) |
|
(x :int) |
|
(y :int) |
|
(w :int) |
|
(h :int) |
|
(flags :uint32)) |
|
|
|
(cffi:defctype sdl-glcontext :pointer) |
|
|
|
(cffi:defcfun "SDL_GL_CreateContext" sdl-glcontext |
|
(window sdl-window)) |
|
|
|
(cffi:defctype imgui-ctx :pointer) |
|
(cffi:defctype imgui-io :pointer) |
|
|
|
(cffi:defcfun "igCreateContext" imgui-ctx |
|
(font-atlas :pointer)) |
|
|
|
(cffi:defcfun "igGetIO" imgui-io) |
|
|
|
(cffi:defcfun "ImGui_ImplSDL2_InitForOpenGL" :bool |
|
(window sdl-window) |
|
(gl-context sdl-glcontext)) |
|
|
|
(cffi:defcfun "ImGui_ImplOpenGL3_Init" :bool |
|
(glsl-version :string)) |
|
|
|
(cffi:defcfun "igStyleColorsDark" :void |
|
(style :pointer)) |
|
|
|
(cffi:defcfun "SDL_PollEvent" :int |
|
(event :pointer)) |
|
|
|
(cffi:defcfun "ImGui_ImplSDL2_ProcessEvent" :bool |
|
(event :pointer)) |
|
|
|
;; HACK: copied from SDL_Event->padding in SDL_events.h |
|
(defparameter +sdl-event-size+ |
|
(let ((pointer-size (cffi:foreign-type-size :pointer))) |
|
(cond |
|
((<= pointer-size 8) 56) |
|
((eql pointer-size 16) 64) |
|
(t (* 3 pointer-size))))) |
|
|
|
(defparameter *sdl-window-ptr* nil) |
|
(defparameter *sdl-gl-context-ptr* nil) |
|
(defparameter *imgui-context-ptr* nil) |
|
(defparameter *imgui-io-ptr* nil) |
|
(defparameter *last-sdl-event-ptr* nil) |
|
|
|
(defparameter *frames-per-second* 60) |
|
|
|
(defun process-one-sdl-event () |
|
(when (eql (sdlcall (sdl-pollevent *last-sdl-event-ptr*)) 1) |
|
(imgui-implsdl2-processevent *last-sdl-event-ptr*))) |
|
|
|
(cffi:defcfun "ImGui_ImplOpenGL3_NewFrame" :void) |
|
|
|
(cffi:defcfun "ImGui_ImplSDL2_NewFrame" :void |
|
(window sdl-window)) |
|
|
|
(cffi:defcfun "igNewFrame" :void) |
|
|
|
(cffi:defcfun "glClearColor" :void |
|
(red :float) |
|
(green :float) |
|
(blue :float) |
|
(alpha :float)) |
|
|
|
(cffi:defcfun "glClear" :void |
|
(mask :uint)) |
|
|
|
(cffi:defcfun "glEnable" :void |
|
(capab :uint32)) |
|
|
|
(cffi:defcfun "glDepthFunc" :void |
|
(func :uint32)) |
|
|
|
(defparameter +gl-color-buffer-bit+ #x00004000) |
|
(defparameter +gl-depth-buffer-bit+ #x00000100) |
|
(defparameter +gl-depth-test+ #x0B71) |
|
(defparameter +gl-less+ #x0201) |
|
|
|
(defun start-new-frame () |
|
(glclearcolor 0.1 0.3 0.4 0.1) |
|
(glclear (logior +gl-color-buffer-bit+ |
|
+gl-depth-buffer-bit+)) |
|
(glenable +gl-depth-test+) |
|
(gldepthfunc +gl-less+) |
|
(imgui-implopengl3-newframe) |
|
(imgui-implsdl2-newframe *sdl-window-ptr*) |
|
(ignewframe)) |
|
|
|
(cffi:defcfun "igRender" :void) |
|
|
|
(cffi:defcfun "ImGui_ImplOpenGL3_RenderDrawData" :void |
|
(draw-data :pointer)) |
|
|
|
(cffi:defcfun "igGetDrawData" :pointer) |
|
|
|
(cffi:defcfun "SDL_GL_SwapWindow" :void |
|
(window sdl-window)) |
|
|
|
(cffi:defcfun "SDL_RaiseWindow" :void |
|
(window sdl-window)) |
|
|
|
(defun end-frame () |
|
(igrender) |
|
(let ((drawdata (iggetdrawdata))) |
|
(if (cffi:null-pointer-p drawdata) |
|
(warn "Draw data empty!") |
|
(progn |
|
(imgui-implopengl3-renderdrawdata drawdata)))) |
|
(sdl-gl-swapwindow *sdl-window-ptr*)) |
|
|
|
(defun imgui-init () |
|
(sdlcall (sdl-init +sdl2-init-video+)) |
|
(sdlcall (sdl-gl-setattribute :context-major-version 3)) |
|
(sdlcall (sdl-gl-setattribute :context-minor-version 2)) |
|
(setf |
|
*sdl-window-ptr* |
|
(sdl-createwindow "wiggly donkers" |
|
+sdl2-windowpos-centred+ |
|
+sdl2-windowpos-centred+ |
|
1024 768 |
|
(logior +sdl2-window-opengl+ +sdl2-window-resizable+))) |
|
(when (cffi:null-pointer-p *sdl-window-ptr*) |
|
(error "SDL_CreateWindow failed: ~A" (sdl-geterror))) |
|
(setf |
|
*sdl-gl-context-ptr* |
|
(sdl-gl-createcontext *sdl-window-ptr*)) |
|
(when (cffi:null-pointer-p *sdl-gl-context-ptr*) |
|
(error "SDL_GL_CreateContext failed: ~A" (sdl-geterror))) |
|
(setf *imgui-context-ptr* (igcreatecontext (cffi:null-pointer))) |
|
(when (cffi:null-pointer-p *imgui-context-ptr*) |
|
(error "igCreateContext failed")) |
|
(setf *imgui-io-ptr* (iggetio)) |
|
(imgui-implsdl2-initforopengl *sdl-window-ptr* *sdl-gl-context-ptr*) |
|
(imgui-implopengl3-init "#version 150") |
|
(igstylecolorsdark (cffi:null-pointer)) |
|
(setf |
|
*last-sdl-event-ptr* |
|
(cffi:foreign-alloc :char :count +sdl-event-size+))) |
|
|
|
(cffi:defcfun "igBegin" :bool |
|
(name :string) |
|
(p-open :pointer) |
|
(flags :int)) |
|
|
|
(cffi:defcfun "igEnd" :void) |
|
|
|
(cffi:defcfun "igText" :void |
|
(fmt :string)) |
|
|
|
(cffi:defcfun "igSmallButton" :bool |
|
(label :string)) |
|
|
|
(cffi:defcfun "igShowDemoWindow" :void |
|
(p-open :pointer)) |
|
|
|
(cffi:defcstruct vec2 |
|
(x :float) |
|
(y :float)) |
|
|
|
(cffi:defcfun "igButton" :bool |
|
(label :string) |
|
(size (:struct vec2))) |
|
|
|
(defparameter *win-opened* (cffi:foreign-alloc :bool)) |
|
|
|
(defmacro with-window ((name &key (flags 0)) &body body) |
|
`(unwind-protect |
|
(when (igbegin ,name (cffi:null-pointer) ,flags) |
|
(progn ,@body)) |
|
(igend))) |
|
|
|
(defparameter *wiggled* nil) |
|
|
|
(defun render-func () |
|
(with-window ("wiggly donkers?") |
|
(igtext (format nil "time = ~F" (/ (get-internal-real-time) |
|
internal-time-units-per-second)))) |
|
(with-window ("macro donkers?") |
|
(when (igbutton "big wiggle" '(x 100.0f0 y 40.0f0)) |
|
(setf *wiggled* (not *wiggled*))) |
|
(when *wiggled* |
|
(igtext "w i g g l e")))) |
|
|
|
(declaim (notinline render-func)) |
|
|
|
(defun render-one-frame () |
|
(loop |
|
while (process-one-sdl-event)) |
|
(start-new-frame) |
|
(unwind-protect |
|
(render-func) |
|
(end-frame))) |
|
|
|
(defun render-loop () |
|
(loop |
|
(let ((frame-start (get-internal-real-time))) |
|
(render-one-frame) |
|
(let* ((frame-end (get-internal-real-time)) |
|
(frame-time (/ (- frame-end frame-start) |
|
internal-time-units-per-second)) |
|
(diff (- (/ 1 *frames-per-second*) frame-time))) |
|
(when (plusp diff) |
|
(sleep diff)))))) |
|
|
|
(defun start-backgrounded-ui () |
|
(bt:make-thread |
|
(lambda () |
|
(imgui-init) |
|
(render-loop)) |
|
:name "background renderer thread"))
|
|
|